在散景区域图的 x 轴上显示日期

Displaying dates in x axis of Bokeh Area plot

像这样传递我的数据框可以显示绘图,但当我指定 x 对应于我的日期列时则不会。你能建议这里可能是什么问题吗?我尝试将日期列转换为 stringdatetime 和其他格式,但没有成功。

import pandas as pd
from bokeh.charts import output_file, Area, defaults
from bokeh.io import show, output_notebook
output_notebook()

xf = pd.DataFrame([{'Cat1': 112.04, 'Cat2': 0.0, 'REDUCED_DATE': '2011-12'},
 {'Cat1': 359.57449999999994, 'Cat2': 579.35, 'REDUCED_DATE': '2012-01'},
 {'Cat1': 376.99000000000007, 'Cat2': 552.64, 'REDUCED_DATE': '2012-02'},
 {'Cat1': 416.86000000000007, 'Cat2': 543.35, 'REDUCED_DATE': '2012-03'},
 {'Cat1': 320.5847000000001, 'Cat2': 543.35, 'REDUCED_DATE': '2012-04'},
 {'Cat1': 521.0349999999999, 'Cat2': 553.33, 'REDUCED_DATE': '2012-05'},
 {'Cat1': 330.84, 'Cat2': 667.94, 'REDUCED_DATE': '2012-06'}])

xf["Date"] =xf.REDUCED_DATE.astype(str)
area1 = Area(xf,y=["Cat1","Cat2"], title="Area chart", legend="top_left",
             xlabel="Date",ylabel="Amount",stack=True)

show(area1, notebook_handle=True)

将日期作为 x 列根本不显示任何数据:

xf["Date"] =xf.REDUCED_DATE.astype(str)
area1 = Area(xf, x="REDUCED_DATE", y=["Cat1","Cat2"], title="Area chart",
             legend="top_left",xlabel="Date",ylabel="Amount",stack=True)

show(area1, notebook_handle=True)

显然 bokeh.charts.Area 中存在错误,如果得到确认,应该在 bokeh repository 中报告。我正在使用散景版本 0.12.4,并且对用作 xaxis 刻度标签的字符串值感到好奇(在本示例中为 REDUCED_DATE)。如果第三个值是“2”并且第四个值以“3”(或 4,5,...9)开头,则面积图显示正常,否则不显示面积图(如问题所示):

import pandas as pd
from bokeh.charts import output_file, Area
from bokeh.io import show, output_notebook
output_notebook()

xf = pd.DataFrame([
     {'Cat1': 112.04, 'Cat2': 0.0, 'REDUCED_DATE': '2011-12'},
     {'Cat1': 359.57449999999994, 'Cat2': 579.35, 'REDUCED_DATE': '2012-01'},
     {'Cat1': 376.99000000000007, 'Cat2': 552.64, 'REDUCED_DATE': '2'},
     {'Cat1': 416.86000000000007, 'Cat2': 543.35, 'REDUCED_DATE': '3'},
     {'Cat1': 320.5847000000001, 'Cat2': 543.35, 'REDUCED_DATE': '2012-04'},
     {'Cat1': 521.0349999999999, 'Cat2': 553.33, 'REDUCED_DATE': '2012-05'},
     {'Cat1': 330.84, 'Cat2': 667.94, 'REDUCED_DATE': '2012-06'}
])

area1 = Area(xf, x="REDUCED_DATE", y=["Cat1","Cat2"], title="Area chart",
             legend="top_left",xlabel="Date",ylabel="Amount",stack=True)
show(area1, notebook_handle=True)

输出:

对我有用的解决方法是使用 bokeh.plotting.figure 创建一个图形,其中 x_rangebokeh.models.FactorRange 定义并添加 patches 字形:

import pandas as pd
import bokeh.plotting
from bokeh.charts import output_file
from bokeh.io import show, output_notebook
output_notebook()

xf = pd.DataFrame([
     {'Cat1': 112.04, 'Cat2': 0.0, 'REDUCED_DATE': '2011-12'},
     {'Cat1': 359.57449999999994, 'Cat2': 579.35, 'REDUCED_DATE': '2012-01'},
     {'Cat1': 376.99000000000007, 'Cat2': 552.64, 'REDUCED_DATE': '2012-02'},
     {'Cat1': 416.86000000000007, 'Cat2': 543.35, 'REDUCED_DATE': '2012-03'},
     {'Cat1': 320.5847000000001, 'Cat2': 543.35, 'REDUCED_DATE': '2012-04'},
     {'Cat1': 521.0349999999999, 'Cat2': 553.33, 'REDUCED_DATE': '2012-05'},
     {'Cat1': 330.84, 'Cat2': 667.94, 'REDUCED_DATE': '2012-06'}
])

# getting the coordinates of the patches:
nvals = xf.shape[0]
accum = pd.np.zeros(nvals)
vals = []
for cat in ['Cat1','Cat2']:
    prev_accum = accum.copy()
    accum += xf[cat].get_values()
    vals += [pd.np.concatenate((prev_accum,accum[::-1]))]

p = bokeh.plotting.figure(
        x_range=bokeh.models.FactorRange(factors=list(xf["REDUCED_DATE"]),offset=-1))
p.patches(xs=[range(nvals)+range(nvals-1,-1,-1)], ys=[vals[0]],
                color=['#f22c40'],alpha=0.8 ,legend='Cat1')
p.patches(xs=[range(nvals)+range(nvals-1,-1,-1)], ys=[vals[1]],
                color=['#5ab738'],alpha=0.8 ,legend='Cat2')
p.xaxis.major_label_orientation = 3.4142/4
p.legend[0].location = 'top_left'
p.xaxis.axis_label = "Date"
p.yaxis.axis_label = "Amount"
show(p)

这里的输出是正确的:

更新散景版本 0.12.16

offset 在最新版本的 bokeh 中 FactorRange 不再受支持。在以下代码中(在版本 0.12.16 中测试)我使用 datetime 作为 x 轴值。同样受到以下代码的启发:brewer.py and github issue #6376:

import pandas as pd
import bokeh.plotting
from bokeh.io import show, output_notebook

xf = pd.DataFrame([
     {'Cat1': 112.04, 'Cat2': 0.0, 'REDUCED_DATE': '2011-12'},
     {'Cat1': 359.57449999999994, 'Cat2': 579.35, 'REDUCED_DATE': '2012-01'},
     {'Cat1': 376.99000000000007, 'Cat2': 552.64, 'REDUCED_DATE': '2012-02'},
     {'Cat1': 416.86000000000007, 'Cat2': 543.35, 'REDUCED_DATE': '2012-03'},
     {'Cat1': 320.5847000000001, 'Cat2': 543.35, 'REDUCED_DATE': '2012-04'},
     {'Cat1': 521.0349999999999, 'Cat2': 553.33, 'REDUCED_DATE': '2012-05'},
     {'Cat1': 330.84, 'Cat2': 667.94, 'REDUCED_DATE': '2012-06'}
])

def stacked(df,N=2):
    df_top = df.iloc[:,0:N].cumsum(axis=1) # accumulates first N columns
    df_bottom = df_top.shift(axis=1).fillna({'Cat1': 0})[::-1]
    df_stack = pd.concat([df_bottom, df_top], ignore_index=True)
    return df_stack

dates  = [pd.datetime.strptime(x,'%Y-%m') for x in xf['REDUCED_DATE']]
x2 = np.hstack((dates[::-1], dates))
areas = stacked(xf)

source = bokeh.models.ColumnDataSource(dict(
    xs=[x2] * areas.shape[1],
    ys=[areas[c].values for c in areas],
    color=['#f22c40','#5ab738'],
    label=['Cat1','Cat2']
))

p = bokeh.plotting.figure( x_axis_type='datetime')
p.patches( xs='xs', ys='ys', color='color', legend='label', source=source,alpha=0.8)
p.xaxis.formatter = bokeh.models.formatters.DatetimeTickFormatter(months=["%Y-%m"])
p.xaxis.major_label_orientation = 3.4142/4
p.legend.location = 'top_left'
p.xaxis.axis_label = "Date"
p.yaxis.axis_label = "Amount"

output_notebook()
show(p)