python bokeh:在回调上更新散点图颜色

时间:2018-12-18 01:58:39

标签: python pandas plot bokeh

我最近才开始使用Bokeh。我有一个散点图,在该图中,我想根据某个第三属性(例如数量,而x轴是日期,y轴是该时间点的给定值)为每个标记着色。 / p>

假设我的数据在数据框中,我设法使用线性颜色图做到了这一点,如下所示:

min_q = df.quantity.min()
max_q = df.quantity.max()
mapper = linear_cmap(field_name='quantity', palette=palettes.Spectral6, low=min_q, high=max_q)
source = ColumnDataSource(data=get_data(df))

p = figure(x_axis_type="datetime")
p.scatter(x="date_column", y="value", marker="triangle", fill_color=mapper, line_color=None, source=source)
color_bar = ColorBar(color_mapper=mapper['transform'], width=8,  location=(0,0))
p.add_layout(color_bar, 'right')

这似乎按预期工作。下面是启动bokeh服务器时得到的图。

enter image description here

然后我有一个回调函数 update(),该回调函数是在某些小部件(选择或时间选择器)中更改值时触发的。

def update():
    # get new df (according to new date/select)
    df = get_df()
    # update min/max for colormap
    min_q = df.quantity.min()
    max_q = df.quantity.max()
    # I think I should not create a new mapper but doing so I get closer
    mapper = linear_cmap(field_name='quantity', palette=palettes.Spectral6 ,low=min_q, high=max_q)
    color_bar.color_mapper=mapper['transform'] 
    source.data = get_data(df)
    # etc

这是我能得到的最接近的。颜色图将使用新值进行更新,但是标记的颜色似乎仍然遵循原始图案。参见下面的图片(鉴于该数量,我希望看到绿色,但是它是蓝色的,因为在回调之前的第一个绘图中它仍然被视为<4000)。

enter image description here

是否应该在数据框中添加“颜色”列?我觉得有一种更容易/更方便的方法。

编辑:这是一个使用bigreddot答案的最小工作示例:

from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.plotting import figure
from bokeh.models import Button, ColumnDataSource, ColorBar, HoverTool
from bokeh.palettes import Spectral6
from bokeh.transform import linear_cmap
import numpy as np

x = [1,2,3,4,5,7,8,9,10]
y = [1,2,3,4,5,7,8,9,10]
z = [1,2,3,4,5,7,8,9,10]



source = ColumnDataSource(dict(x=x, y=y, z=z))

#Use the field name of the column source
mapper = linear_cmap(field_name='z', palette=Spectral6 ,low=min(y) ,high=max(y))

p = figure(plot_width=300, plot_height=300, title="Linear Color Map Based on Y")
p.circle(x='x', y='y', line_color=mapper,color=mapper, fill_alpha=1, size=12, source=source)

color_bar = ColorBar(color_mapper=mapper['transform'], width=8,  location=(0,0))
p.add_tools(HoverTool(tooltips="@z", show_arrow=False, point_policy='follow_mouse'))
p.add_layout(color_bar, 'right')

b = Button()

def update():
    new_z = np.exp2(z)
    mapper = linear_cmap(field_name='z', palette=Spectral6 ,low=min(new_z), high=max(new_z))
    color_bar.color_mapper=mapper['transform'] 
    source.data = dict(x=x, y=y, z=new_z)

b.on_click(update)

curdoc().add_root(column(b, p))

更新后,圆圈将按照原始比例进行着色:大于10的所有内容均为红色。相反,我希望所有东西都是蓝色,直到顶部的最后3个圆圈,分别用绿色,黄色和红色上色。

1 个答案:

答案 0 :(得分:1)

这可能是一个错误,请随时打开GitHub问题。

也就是说,以上代码并不代表使用Bokeh的最佳做法,即:始终尽可能进行最小的更新。在这种情况下,这意味着在现有的颜色转换上设置新的属性值,而不是替换现有的颜色转换。

这是一个完整的工作示例(由Bokeh 1.0.2制作),演示了字形的色图颜色随着数据列的变化而更新:

from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.plotting import figure
from bokeh.models import Button, ColumnDataSource, ColorBar
from bokeh.palettes import Spectral6
from bokeh.transform import linear_cmap

x = [1,2,3,4,5,7,8,9,10]
y = [1,2,3,4,5,7,8,9,10]
z = [1,2,3,4,5,7,8,9,10]

#Use the field name of the column source
mapper = linear_cmap(field_name='z', palette=Spectral6 ,low=min(y) ,high=max(y))

source = ColumnDataSource(dict(x=x, y=y, z=z))

p = figure(plot_width=300, plot_height=300, title="Linear Color Map Based on Y")
p.circle(x='x', y='y', line_color=mapper,color=mapper, fill_alpha=1, size=12, source=source)

color_bar = ColorBar(color_mapper=mapper['transform'], width=8,  location=(0,0))
p.add_layout(color_bar, 'right')

b = Button()

def update():
    new_z = np.exp2(z)

    # update the existing transform
    mapper['transform'].low=min(new_z)
    mapper['transform'].high=max(new_z)

    source.data = dict(x=x, y=y, z=new_z)

b.on_click(update)

curdoc().add_root(column(b, p))

这是原始剧情:

enter image description here

这是单击按钮后的更新图

enter image description here