#python #plot #bokeh #dashboard #interaction
#python #график #bokeh #Информационная панель #взаимодействие
Вопрос:
Я работаю над своей первой интерактивной панелью управления Python Bokeh. График по умолчанию показывает строки для group = a и group = b. При установке флажка [1] график добавит строки для group = a1 и group = b1. Когда снимите флажок [1], строки a1, b1 должны быть удалены из графика, но они все еще остаются на графике.
Ниже приведены мои примеры данных и пример кода. Она может выполняться непосредственно в вашем ноутбуке jupyter. Может ли кто-нибудь мне помочь? Большое вам спасибо!
import pandas as pd
import numpy as np
import matplotlib.pylab as plt
from bokeh.io import show, output_notebook, push_notebook
from bokeh.plotting import figure
from bokeh.models import CategoricalColorMapper, HoverTool, ColumnDataSource, Panel
from bokeh.models.widgets import CheckboxGroup, Slider, RangeSlider, Tabs
from bokeh.layouts import column, row, WidgetBox
from bokeh.palettes import Category20_16
from bokeh.application.handlers import FunctionHandler
from bokeh.application import Application
from bokeh.palettes import Category10
output_notebook()
data=[['a',1,0],['a',2,1],['a1',1,0],['a1',2,2],['b',1,0],['b',2,3],['b1',1,0],['b1',2,4]]
df=pd.DataFrame(data,columns=['group','time','rate'])
def modify_doc(doc):
def update(attr,old,new):
temp=[]
for i in selection1.active:
for b in selection2.active:
temp.append(selection1.labels[i] selection2.labels[b] )
to_plot=temp
for i in range(len(to_plot)):
source = ColumnDataSource(
data={'x':df.loc[df.group == to_plot[i]].time,
'group':df.loc[df.group == to_plot[i]].group,
'y':df.loc[df.group == to_plot[i]].rate})
p3.line(x='x',
y='y',
source=source,
legend=to_plot[i],
color = (Category10[10])[i])
selection1=CheckboxGroup(labels=['a','b'],active=[0,1] )
selection1.on_change('active',update)
selection2=CheckboxGroup(labels=['1'] )
selection2.on_change('active',update)
to_plot=['a','b']
p3 = figure()
for i in range(len(to_plot)):
source = ColumnDataSource(
data={'x':df.loc[df.group == to_plot[i]].time,
'group':df.loc[df.group == to_plot[i]].group,
'y':df.loc[df.group == to_plot[i]].rate})
p3.line(x='x',
y='y',
source=source,
legend=to_plot[i],
color = (Category10[10])[i])
controls=WidgetBox(selection1,selection2)
layout=row(controls,p3)
tab=Panel(child=layout,title='test')
tabs=Tabs(tabs=[tab])
doc.add_root(tabs)
handler=FunctionHandler(modify_doc)
app=Application(handler)
show(app)
Ответ №1:
Скорее всего, проблема (которую вы уже исправили) была с подчеркиванием в этой строке:
temp.append(selection1.labels[i] "_" selection2.labels[b])
Что, конечно, должно быть:
temp.append(selection1.labels[i] selection2.labels[b])
Итак, вы ссылались a_1
на исходный код (который не существует) вместо a1
.
Я не стеснялся улучшать ваш код, чтобы также скрывать строки, если вы снимите флажки. Этот код предназначен для сервера Bokeh версии v1.0.4, но также должен работать для Jupyter Notebook после удаления отмеченного блока строк и раскомментирования прокомментированных строк)
import random
import pandas as pd
from tornado.ioloop import IOLoop
from bokeh.server.server import Server
from bokeh.application import Application
from bokeh.application.handlers.function import FunctionHandler
from bokeh.plotting import figure, ColumnDataSource
from bokeh.models import CheckboxGroup, Panel, Tabs, WidgetBox, Row
from bokeh.palettes import Category10
data = [['a', 1, 0], ['a', 2, 1], ['a1', 1, 0], ['a1', 2, 2], ['b', 1, 0], ['b', 2, 3], ['b1', 1, 0], ['b1', 2, 4]]
df = pd.DataFrame(data, columns = ['group', 'time', 'rate'])
def modify_doc(doc):
lines = []
def create_plots(to_plot):
for i in range(len(to_plot)):
source = ColumnDataSource(
data = {'x':df.loc[df.group == to_plot[i]].time,
'group':df.loc[df.group == to_plot[i]].group,
'y':df.loc[df.group == to_plot[i]].rate})
lines.append(p3.line(x = 'x',
y = 'y',
source = source,
legend = to_plot[i],
color = (Category10[10])[i]))
p3.legend.click_policy = 'hide'
def update(attr, old, new):
for i in [0, 1]:
if i not in selection1.active:
lines[i].visible = False
else:
lines[i].visible = True
if selection2.active:
if len(lines) < 3:
temp = []
for i in selection1.active:
lines[i].visible = True
for b in selection2.active:
temp.append(selection1.labels[i] selection2.labels[b])
create_plots(temp)
else:
for i in range(2, 4):
if (i - 2) in selection1.active:
lines[i].visible = True
else:
lines[i].visible = False
elif len(lines) > 2:
for i in range(2, 4):
if (i - 2) in selection1.active:
lines[i].visible = False
selection1 = CheckboxGroup(labels = ['a', 'b'], active = [0, 1], width = 40)
selection1.on_change('active', update)
selection2 = CheckboxGroup(labels = ['1'], width = 40)
selection2.on_change('active', update)
p3 = figure()
create_plots(['a', 'b'])
controls = WidgetBox(selection1, selection2, width = 40)
layout = Row(controls, p3)
tab = Panel(child = layout, title = 'test')
tabs = Tabs(tabs = [tab])
doc.add_root(tabs)
# handler = FunctionHandler(modify_doc)
# app = Application(handler)
#########################################################################
io_loop = IOLoop.current()
server = Server(applications = {'/myapp': Application(FunctionHandler(modify_doc))}, io_loop = io_loop, port = 5001)
server.start()
server.show('/myapp')
io_loop.start()
#########################################################################
# show(app)
Результат:
Комментарии:
1. Большое вам спасибо! теперь строка может быть добавлена / удалена из графика (именно то, что мне нужно), но в легенде всегда отображаются ‘a, b, a1, b1’. Не могли бы вы, пожалуйста, также соответствующим образом изменить легенду с помощью lines? Действительно ценю это!.
2. Я перемещаю p3.legend.click_policy = ‘hide’ в нужное место, и теперь легенда отключается, когда вы снимаете флажки
3. Спасибо тебе, Тони! Есть ли какой-либо способ удалить строку, вместо того, чтобы скрывать ее?
4. Удаление глифов официально не поддерживается. Это не невозможно, но мне кажется сложным, поскольку вы можете легко все испортить. Если вы хотите удалить или добавить легенду, вы могли бы использовать p3.legend[0].items.pop() и p3.legend[0].items.append(LegendItem(label = ‘label’, renderers = [средство визуализации])), но я бы этого не стал делать.
5. как вы записываете воспроизведение с помощью панели управления bokeh, как показано в приведенном выше результате?