使用Bokeh hbar和ColumnDataSource逐个标记标签

时间:2017-07-24 12:12:30

标签: python pandas bokeh

我有一个hbar - 由ColumnDataSource驱动的情节,在y轴上有分类标签和两个数字x轴。为了在y轴上每个标签有两组条形,我构造了两个范围(Things1=df.Thing.index + 1 - 0.2Things2=df.Thing.index + 1 + 0.2)并将两个hbar - 实例分配给其中一个范围。

当且仅当Things1中的Things2ColumnDataSource范围构造为预定义的偏移量为1时,才能为我提供正确的布局;否则,所有标签和条形都只有一个条目。

我现在构建情节的方式如下:

df = pandas.DataFrame([('Store', 'Juice', 3, 19.0),
                       ('Warehouse', 'Paint', 7, 21.0),
                       ('Store', 'Fruit', 2, 6.0),
                       ('Warehouse', 'Grass', 4, 15.0),
                       ('Store', 'Leaves', 9, 32.0)],
                      columns=('Storage', 'Thing', 'Quantity', 'Valueation'))


source = bokeh.models.ColumnDataSource(dict(Quantity=df.Quantity,
                                            Things1=df.Thing.index + 1 - 0.2,  # Why +1 ?
                                            Things2=df.Thing.index + 1 + 0.2,  # Why +1 ?
                                            Valueation=df.Valueation,
                                            Storage=df.Storage))

plot = bokeh.plotting.figure(plot_width=800, plot_height=300,
                             y_range=list(df.Thing.unique()),
                             x_range=(0, df.Quantity.max() * 1.1))
plot.hbar(y='Things1', right='Quantity', height=0.3, alpha=0.7, source=source)
plot.hbar(y='Things2', right='Valueation', height=0.3, alpha=1, source=source,
          x_range_name="ValueationRange")
plot.yaxis.axis_label = 'Thing'
plot.xaxis.axis_label = 'Quantity'
plot.extra_x_ranges = {"ValueationRange":
                       bokeh.models.Range1d(start=0, end=df.Valueation.max() * 1.1)}
plot.add_layout(bokeh.models.LinearAxis(x_range_name="ValueationRange",
                                        axis_label='Valueation'), 'above')
bokeh.plotting.show(plot)

Things1/2=df.Thing.index + 1 -/+ 0.2给出了正确的情节:

Correct plot

Things1/2=df.Thing.index -/+ 0.2我得到了

Wrong plot

我的猜测是,这是由于不同的范围是基于0或1。这是一个简单的问题还是我做错了?

1 个答案:

答案 0 :(得分:1)

编辑结果证明,原始值(与真正的分类数据相对)与因子范围的使用未记录和未经测试。分类数据的处理将在0.12.7中更改,这将允许正确使用分类数据所需的功能 - 请参阅下面的bigreddots(lead bokeh dev)评论。

从观察结果来看,分类范围的默认行为似乎是将整数y值从1开始映射到类别。

如果在初始化绘图对象后添加y_range,则会显示原始刻度: plot no label

正如你所提到的,它只是由于范围。第一个绘制的数据系列从0开始,但第一个标签从1开始。您可以使用functickformatter设置偏移或将显式y刻度映射到值,这可以精确控制值和标签之间的映射。

如果您查看http://bokeh.pydata.org/en/latest/docs/gallery/categorical.html等示例,您可以看到数据已映射到类别,但这是因为y值是作为因子本身输入的。在您的示例中,您只是更改y轴,但偏移了您无法使用原始类别本身的值。

暂且不说: 编辑偏移属性可能不存在于0.12.7中,因此最好不要依赖它/假设它存在。

查看文档,它说默认偏移量是0.所以我认为你想要一个偏移量-1来解释这个问题。见http://bokeh.pydata.org/en/latest/docs/reference/models/ranges.html#bokeh.models.ranges.FactorRange.offset

import pandas

import bokeh
import bokeh.models, bokeh.plotting

df = pandas.DataFrame([('Store', 'Juice', 3, 19.0),
                       ('Warehouse', 'Paint', 7, 21.0),
                       ('Store', 'Fruit', 2, 6.0),
                       ('Warehouse', 'Grass', 4, 15.0),
                       ('Store', 'Leaves', 9, 32.0)],
                      columns=('Storage', 'Thing', 'Quantity', 'Valueation'))


source = bokeh.models.ColumnDataSource(dict(Quantity=df.Quantity,
                                            Things1=df.Thing.index - 0.2,  # Why +1 ?
                                            Things2=df.Thing.index + 0.2,  # Why +1 ?
                                            Valueation=df.Valueation,
                                            Storage=df.Storage))

plot = bokeh.plotting.figure(plot_width=800, plot_height=300,
                             y_range=list(df.Thing.unique()),
                             x_range=(0, df.Quantity.max() * 1.1))

plot.y_range.offset = -1

plot.hbar(y='Things1', right='Quantity', height=0.3, alpha=0.7, source=source)
plot.hbar(y='Things2', right='Valueation', height=0.3, alpha=1, source=source,
          x_range_name="ValueationRange")
plot.yaxis.axis_label = 'Thing'
plot.xaxis.axis_label = 'Quantity'
plot.extra_x_ranges = {"ValueationRange":
                       bokeh.models.Range1d(start=0, end=df.Valueation.max() * 1.1)}
plot.add_layout(bokeh.models.LinearAxis(x_range_name="ValueationRange",
                                        axis_label='Valueation'), 'above')
bokeh.plotting.show(plot)