Pandas, Bokeh, or using any plotting library for s

2019-09-15 16:30发布

问题:

I want to display seasonal snow data for the seasonal year from July 01 - June 30.

df = pd.DataFrame({'date1':['1954-03-20','1955-02-23','1956-01-01','1956-11-21','1958-01-07'],
               'date2':['1954-03-25','1955-02-26','1956-02-11','1956-11-30','1958-01-17']},
              index=['1954','1955','1956','1957','1958'])

It is an extension to my previous question Pandas: Visualizing Changes in Event Dates for Multiple Years using Bokeh or any other plotting library

Scott Boston, in his answer to my comment in that question, suggested using Range1D and modifyng the answer in How can I accomplish `set_xlim` or `set_ylim` in Bokeh?. It works for continuous scalars, but I couldn't get it to work with a discontinuous ranges like [182:366], [1:181].

Adding x_range=Range1d(182, 366) shows me the first half of the seasonal year, but I can't get the second half of the seasonal year (1, 181).

df['date2'] = pd.to_datetime(df['date2'])

df['date1'] = pd.to_datetime(df['date1'])

df=df.assign(date2_DOY=df.date2.dt.dayofyear)
df=df.assign(date1_DOY=df.date1.dt.dayofyear)

from bokeh.plotting import figure, show
from bokeh.io import output_notebook
from bokeh.models import FuncTickFormatter, FixedTicker
p1 = figure(plot_width=1000, plot_height=300,x_range=Range1d(180, 366))

p1.circle(df.date1_DOY,df.index, color='red', legend='Date1')
p1.circle(df.date2_DOY,df.index, color='green', legend='Date2')
p1.xaxis[0].ticker=FixedTicker(ticks=[1,32,60,91,121,152,182,213,244,274,305,335,366])
p1.xaxis.formatter = FuncTickFormatter(code="""
 var labels = {'1':'Jan',32:'Feb',60:'Mar',91:'Apr',121:'May',152:'Jun',182:'Jul',213:'Aug',244:'Sep',274:'Oct',305:'Nov',335:'Dec',366:'Jan'}
 return labels[tick];
""")
show(p1)

#(Code from Scott's answer to my previous question.)

回答1:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.DataFrame({'date1':['1954-03-20','1955-02-23','1956-01-01','1956-11-21','1958-01-07'],
               'date2':['1954-03-25','1955-02-26','1956-02-11','1956-11-30','1958-01-17']},
              index=['1954','1955','1956','1957','1958'])
df['date2'] = pd.to_datetime(df['date2'])

df['date1'] = pd.to_datetime(df['date1'])

Adjusted mapping day of year to axis starting with Jun 1st.

df['date2_DOY_map'] = np.where(df['date2'].dt.dayofyear<151,df['date2'].dt.dayofyear-151+365,df['date2'].dt.dayofyear-151)

df['date1_DOY_map'] = np.where(df['date1'].dt.dayofyear<151,df['date1'].dt.dayofyear-151+365,df['date1'].dt.dayofyear-151)

from bokeh.plotting import figure, show
from bokeh.io import output_notebook

Add Range1d import form bokeh.models

from bokeh.models import FuncTickFormatter, FixedTicker,Range1d
p1 = figure(plot_width=1000, plot_height=300,x_range=Range1d(1, 366))

p1.circle(df.date1_DOY_map,df.index, color='red', legend='Date1')
p1.circle(df.date2_DOY_map,df.index, color='green', legend='Date2')

Fixed x-ticks and labels to match Jun 1st start

p1.xaxis[0].ticker=FixedTicker(ticks=[1,31,62,93,123,154,184,215,246,274,305,335,366])
p1.xaxis.formatter = FuncTickFormatter(code="""
 var labels = {'1':'Jun',31:'Jul',62:'Aug',93:'Sep',123:'Oct',154:'Nov',184:'Dec',215:'Jan',246:'Feb',274:'Mar',305:'Apr',335:'May',366:'Jun'}
 return labels[tick];
""")
show(p1)

EDIT (oops I started on the wrong month above)

Pretty easy to fix, we just need to modify the x-axis mapping of dates and redo the ticks and lables.

Use 181 vs 151 because Jul 1st is the 181st day where June 1st was the 151st day.

df['date2_DOY_map'] = np.where(df['date2'].dt.dayofyear<181,df['date2'].dt.dayofyear-181+365,df['date2'].dt.dayofyear-181)

df['date1_DOY_map'] = np.where(df['date1'].dt.dayofyear<181,df['date1'].dt.dayofyear-181+365,df['date1'].dt.dayofyear-181)

p1.xaxis[0].ticker=FixedTicker(ticks=[1,32,63,93,124,154,185,216,244,275,305,336,366])
p1.xaxis.formatter = FuncTickFormatter(code="""
 var labels = {'1':'Jul',32:'Aug',63:'Sep',93:'Oct',124:'Nov',154:'Dec',185:'Jan',216:'Feb',244:'Mar',275:'Apr',305:'May',336:'Jun',366:'Jul'}
 return labels[tick];
""")