Я пытаюсь разработать относительно сложное приложение для построения графиков, в котором есть огромный выбор данных для построения. Используя выпадающие списки, пользователь может выбрать, какие линии он хотел бы построить. Я разработал значительно упрощенную версию кода (показанную ниже), чтобы проиллюстрировать, на что похоже мое приложение.
import bokeh.plotting.figure as bk_figure
import random
import numpy as np
from bokeh.io import show
from bokeh.layouts import row, column, widgetbox
from bokeh.models import ColumnDataSource, Legend, LegendItem, Line
from bokeh.models.widgets import MultiSelect
from bokeh.io import output_notebook # enables plot interface in J notebook
from bokeh.application import Application
from bokeh.application.handlers import FunctionHandler
global x, ys
output_notebook()
plot = bk_figure(plot_width=950, plot_height=800, title="Legend Test Plot"\
, x_axis_label="X Value", y_axis_label="Y Value")
lines = ['0','1','2']
line_select = MultiSelect(title='Line Select', value = [lines[0]],options=lines)
x = np.linspace(0,10,10)
ys = []
#generates three different lines
for i in range(len(lines)):
ys.append(x*i)
#add line 0 to plot initially
source = ColumnDataSource(data={'x':x,'y':ys[0]})
glyph = Line(x='x',y='y')
glyph = plot.add_glyph(source,glyph)
def change_line(attr,old,new):
#remove old lines
render_copy = list(plot.renderers)
for line in render_copy:
plot.renderers.remove(line)
legend_items = []
#add selected lines to plot
for i,line in enumerate(line_select.value):
y = ys[int(line)]
source = ColumnDataSource(data={'x':x,'y':y})
glyph = Line(x='x',y='y')
glyph = plot.add_glyph(source,glyph)
line_select.on_change('value',change_line)
layout = column(line_select,plot)
def modify_doc(doc):
doc.add_root(row(layout,width=800))
doc.title = "PlumeDataVis"
handler = FunctionHandler(modify_doc)
app = Application(handler)
show(app)
Я решил динамически добавлять и удалять линейные глифы из графика по мере их выбора. в MultiSelect. Это потому, что если я просто скрываю строки, производительность программы ухудшается, учитывая, что в реальном наборе данных так много параметров строк.
Проблема: Я хочу добавить легенду на график, который содержит только записи для глифов линий, которые в данный момент находятся на графике (в реальном наборе данных слишком много параметров линий, чтобы все они были видны в легенде в любое время.) У меня возникли проблемы с поиском любые ресурсы, которые помогут с этим: для большинства приложений что-то вроде этого достаточно, но это не работает с тем, как я определил линии, которые я строю.
I Добавляю легенды вручную , например:
#add line 0 to plot initially
source = ColumnDataSource(data={'x':x,'y':ys[0]})
glyph = Line(x='x',y='y')
glyph = plot.add_glyph(source,glyph)
#create first legend
legend_item = [LegendItem(label=lines[0],\
renderers=[glyph])]
legend = Legend(items=legend_item)
plot.add_layout(legend,place='right')
, но я не могу понять, как эффективно удалять макеты легенд из графика после их добавления. Прочитав исходный код для add_layout, я понял, что вы можете получить список макетов в данном месте, используя что-то вроде getattr (plot, 'right'). Пытаясь использовать это, я заменил функцию change_line следующим:
def change_line(attr,old,new):
#remove old lines
render_copy = list(plot.renderers)
for line in render_copy:
plot.renderers.remove(line)
#remove old legend
right_attrs_copy = list(getattr(plot,'right'))
for legend in right_attrs_copy:
getattr(plot,'right').remove(legend)
legend_items = []
#add selected lines to plot
for i,line in enumerate(line_select.value):
y = ys[int(line)]
source = ColumnDataSource(data={'x':x,'y':y})
glyph = Line(x='x',y='y')
glyph = plot.add_glyph(source,glyph)
legend_items.append(LegendItem(label='line '+str(line),\
renderers=[glyph]))
#create legend
legend = Legend(items=legend_items)
plot.add_layout(legend,place='right')
Проверяя атрибуты графика, это, кажется, добавляет и удаляет легенды и линии правильно, но заставляет график полностью останавливаться визуально обновление.
Кто-нибудь знает, как выполнить sh такое поведение? Возможно, я даже не добавляю легенду правильным образом, но я не мог понять, как еще добавить их, когда строки определены как объекты Glyph.