Интерактивная панель Bokeh не может удалять линии с графика

Я работаю над своей первой интерактивной панелью Python Bokeh. График по умолчанию показывает линии для группы = a и группы = b. Когда установлен флажок [1], график добавит линии для группы = a1 и группы = 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)

person jean    schedule 31.03.2019    source источник


Ответы (1)


Скорее всего проблема (которую вы уже исправили) была с подчеркиванием в этой строке:

temp.append(selection1.labels[i]+ "_" + selection2.labels[b])

Что должно быть, конечно:

temp.append(selection1.labels[i] + selection2.labels[b])

Итак, вы ссылались на a_1 в источнике (которого не существует) вместо a1.

Я не стеснялся улучшать ваш код, чтобы также скрыть строки, если вы снимите флажки. Этот код предназначен для сервера Bokeh версии 1.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)

Результат:

введите здесь описание изображения

person Tony    schedule 01.04.2019
comment
Большое спасибо! теперь линию можно добавить/удалить из графика (именно то, что мне нужно), но легенда всегда показывает «a, b, a1, b1». Не могли бы вы также изменить легенду соответственно с линиями? Действительно ценю это !. - person jean; 01.04.2019
comment
Я перемещаю p3.legend.click_policy = 'hide' в нужное место, и теперь легенда отключается, когда вы снимаете флажки - person Tony; 02.04.2019
comment
Спасибо, Тони! Есть ли способ удалить строку, а не скрывать ее? - person jean; 02.04.2019
comment
Удаление глифов официально не поддерживается. Это не невозможно, но кажется мне сложным, так как вы можете легко все испортить. Если вы хотите удалить или добавить легенду, вы можете использовать p3.legend[0].items.pop() и p3.legend[0].items.append(LegendItem(label = 'label', renderers = [renderer]) ) но я бы не стал этого делать. - person Tony; 02.04.2019
comment
как вы записываете игру с приборной панелью боке, как показано в результате выше? - person jean; 12.04.2019
comment
На Mac я использую Quick Time Player (Файл => Новая запись экрана) для записи короткого видео, а затем использую FFMPEG для преобразования его в изображение GIF. FFMPEG не входит в стандартную комплектацию Mac, поэтому его необходимо установить. Команда FFMPEG: ffmpeg -i input.mov -r 10 -pix_fmt rgb24 -f gif - | gifsicle --delay=8 > output.gif - person Tony; 23.04.2019