обратный вызов кнопки боке работает только частично

Я рисую сложную интерактивную кольцевую диаграмму в боке. Приведенный ниже код является упрощением компонента этой диаграммы.

У меня есть функция, которая компилирует фрейм данных для пончика, а затем преобразует его в CDS. Затем эти данные отображаются в виде кольцевых клиньев. Группа радиокнопок должна запускать переключение на другой фрейм данных (как CDS) и перераспределять глифы кольцевого клина.

Пример provide (для Jupyter Lab) работает в одном направлении. При первоначальном построении button.active == 0 (outer_1). Когда выбран external_2, диаграмма правильно изменяется и отображает второй фрейм данных (cds).

Но когда нажата кнопка outer_1, глифы не меняются обратно. Обратный вызов срабатывает - при изменении заголовка. Но глифы не меняются.

Почему глифы не меняются при последующих нажатиях кнопок / обратных вызовах?

Я прочитал несколько похожих сообщений SO, а также просмотрел несколько примеров боке (пример погоды здесь аналогично)

import pandas as pd
from math import pi

from bokeh.plotting import figure

from bokeh.layouts import column, row 
from bokeh.models.widgets import RadioButtonGroup
from bokeh.io import curdoc
from bokeh.models.sources import ColumnDataSource
from bokeh.layouts import column, row

from bokeh.plotting import show, output_notebook
output_notebook()

df = pd.DataFrame({'start':[pi/2, pi, 3*pi/2],
                   'end' :[pi/2+1.5, pi+1.5, (3*pi/2)+1.5],
                   'inner': [100,100,100],
                   'outer': [200,200,200],
                   'color':['red','green','blue']})

df_2 = pd.DataFrame({'start':[pi/2, pi, 3*pi/2],
                   'end' :[pi/2+1, pi+1, (3*pi/2)+1],
                   'inner': [100,100,100],
                   'outer': [250,300,350],
                    'color':['orange','gray','purple']})

data_1 = ColumnDataSource(data=df)
data_2 = ColumnDataSource(data=df_2)


def create_doc(doc):

    button = RadioButtonGroup(labels=["outer_1", "outer_2"], active=0)

    inputs = column(button)

    p = figure(plot_width=600, plot_height=600, title="data_1",
                   x_axis_type=None, y_axis_type=None,
                   x_range=(-300, 300), y_range=(-300, 300),
                   min_border=0, outline_line_color=None,
                   background_fill_color='white', toolbar_location="above")

    circle = p.circle(0,0, radius=100, fill_alpha=0, line_color='grey', line_alpha=0.4)

    source = [data_1, data_2][button.active]

    segments = p.annular_wedge(0,0,'inner', 'outer', 'start', 'end', color='color', alpha=0.6, source=source, name='segments')


    r = row (inputs,p)


    def callback(attr, old, new):
        if button.active == 1:
            p.title.text = 'data_2  {}'.format(button.active)
            source.data.update(data_2.data)
        elif button.active == 0:
            p.title.text = 'data_1 {}'.format(button.active)
            source.data.update(data_1.data)

    button.on_change('active', callback)

    doc.add_root(r)


show(create_doc)

Glpyhs успешно меняются один раз, но не снова, хотя изменяющийся текст заголовка (при нажатии кнопки) указывает, что кнопки и обратный вызов продолжают работать частично.


person chrisrb10    schedule 17.05.2019    source источник
comment
Обратите внимание, что это очень упрощенный пример. В реальном приложении критерии отбора и выбора для определения данных, которые будут использоваться, сложны и требуют использования pandas df. Как только это будет сделано, я могу преобразовать в компакт-диски (как в связанном примере погоды) для построения графика. Так что мне действительно нужно понять, что именно в этом подходе вызывает проблему. Я не могу избежать использования df в качестве основного источника данных.   -  person chrisrb10    schedule 18.05.2019


Ответы (1)


Зачем переходить к DataFrame, зная, что данные ColumnDataSource внутри являются словарем? Следующий код отлично работает для Bokeh v1.1.0.

from math import pi
from bokeh.plotting import figure, show, curdoc, Row, Column, output_notebook
from bokeh.models import RadioButtonGroup

output_notebook()

data1 = {'start':[pi/2, pi, 3*pi/2],
        'end' :[pi/2+1.5, pi+1.5, (3*pi/2)+1.5],
        'inner': [100,100,100],
        'outer': [200,200,200],
        'color':['red','green','blue']}

data2 = {'start':[pi/2, pi, 3*pi/2],
         'end' :[pi/2+1, pi+1, (3*pi/2)+1],
         'inner': [100,100,100],
         'outer': [250,300,350],
         'color':['orange','gray','purple']}

def create_doc(doc):

    button = RadioButtonGroup(labels=["outer_1", "outer_2"], active=0)

    p = figure(plot_width=600, plot_height=600, title="data_1",
                   x_axis_type=None, y_axis_type=None,
                   x_range=(-300, 300), y_range=(-300, 300),
                   min_border=0, outline_line_color=None,
                   background_fill_color='white', toolbar_location="above")

    circle = p.circle(0,0, radius=100, fill_alpha=0, line_color='grey', line_alpha=0.4)
    segments = p.annular_wedge(0,0,'inner', 'outer', 'start', 'end', color='color', alpha=0.6, source = data1, name='segments')

    def callback(attr, old, new):
        if button.active == 0:
            print '000'
            p.title.text = 'data_1 {}'.format(button.active)
            segments.data_source.data = data1
        elif button.active == 1:
            print '111'
            p.title.text = 'data_2  {}'.format(button.active)
            segments.data_source.data = data2 

    button.on_change('active', callback)

    inputs = Column(button)
    r = Row(inputs,p)
    doc.add_root(r)

show(create_doc)

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

person Tony    schedule 17.05.2019
comment
Это очень упрощенный пример. Фактические кадры данных велики, а критерии выбора сложны. Но принцип таков, что представлен здесь - необходимость применить изменения к df, преобразованному в CDS. - person chrisrb10; 18.05.2019
comment
Кроме того, ссылка на приведенный выше пример погоды с боке, похоже, следует аналогичному процессу: - Выберите данные с помощью df - Преобразуйте df в CDS - используйте синтаксис обратного вызова в моем примере, чтобы изменить график. пример не работает так, как этот. - person chrisrb10; 18.05.2019