Interactively change glyphs in bokeh plot

走远了吗. 提交于 2021-02-10 08:04:34

问题


I'm trying to generate a bokeh application which allows the user to change the glyphs of a plot. Unfortunately, the glyphs don't change after calling on_change() method of the dropdown button although I'm able to change the axis label in a similar way. However, changing plot.glyph outside of the called function works fine.

from bokeh.layouts import layout
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Dropdown
from bokeh.plotting import figure
from bokeh.io import curdoc
from bokeh.models.markers import Cross, Circle

source=ColumnDataSource(dict(x=[1,2,3],y=[4,5,6]))

fig=figure()
plot=fig.circle(x='x', y='y',source=source)
fig.xaxis.axis_label='This is a label'

#this changes the glyphs from circle to cross
plot.glyph=Cross(x='x', y='y', size=20, line_color='firebrick',
fill_color='firebrick', line_alpha=0.8, fill_alpha=0.3)

def update_plot(attr,old,new):
    if dropdown.value=='cross':
        #this changes the axis label but not the glyphs
        fig.xaxis.axis_label='Label changed'
        plot.glyph=Cross(x='x', y='y', size=20, line_color='firebrick',
        fill_color='firebrick', line_alpha=0.8, fill_alpha=0.3)
    elif dropdown.value=='circle':
        #this also only changes the axis label but not the glyphs
        fig.xaxis.axis_label='Label changed again'
        plot.glyph=Circle(x='x', y='y', size=20, line_color='firebrick',
        fill_color='firebrick', line_alpha=0.8, fill_alpha=0.3)

menu=[('Circle','circle'),('Cross', 'cross')]
dropdown=Dropdown(label="Select marker", menu=menu, value='circle')
dropdown.on_change('value', update_plot)

lay_out=layout([fig, dropdown])

curdoc().add_root(lay_out)

回答1:


I'm not sure about the exact reasons why your approach doesn't work, but this one works:

from bokeh.io import curdoc
from bokeh.layouts import layout
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Dropdown
from bokeh.plotting import figure

source = ColumnDataSource(dict(x=[1, 2, 3], y=[4, 5, 6]))

plot = figure()

renderers = {rn: getattr(plot, rn)(x='x', y='y', source=source,
                                   **extra, visible=False)
             for rn, extra in [('circle', dict(size=10)),
                               ('line', dict()),
                               ('cross', dict(size=10)),
                               ('triangle', dict(size=15))]}


def label_fn(item):
    return 'Select marker ({})'.format(item)


menu = [('No renderer', None)]
menu.extend((rn.capitalize(), rn) for rn in renderers)

dropdown = Dropdown(label=label_fn(None), menu=menu, value=None)


def update_plot(attr, old, new):
    dropdown.label = label_fn(new)
    for renderer_name, renderer in renderers.items():
        renderer.visible = (renderer_name == new)


dropdown.on_change('value', update_plot)

lay_out = layout([plot, dropdown])

curdoc().add_root(lay_out)

Basically, I create all necessary renderers beforehand, and then just switch visible flag of each one.

Also, note the correct terminology. What you're calling a plot, is not actually a plot but a glyph renderer. And plot and figure are basically the same thing.



来源:https://stackoverflow.com/questions/47500045/interactively-change-glyphs-in-bokeh-plot

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!