我最近才开始使用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服务器时得到的图。
然后我有一个回调函数 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)。
是否应该在数据框中添加“颜色”列?我觉得有一种更容易/更方便的方法。
编辑:这是一个使用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个圆圈,分别用绿色,黄色和红色上色。
答案 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))
这是原始剧情:
这是单击按钮后的更新图