Фильтрация источника диаграммы Bokeh с использованием выбора диаграммы - PullRequest
0 голосов
/ 28 апреля 2019

Я пытаюсь изменить источник для диаграммы боке, делая выбор лассо / коробки.

Обратный вызов работает один раз, но перестает работать после первого изменения источника.Кроме того, я не могу сказать, почему некоторые точки подсвечиваются после нажатия кнопки.

Я бы хотел постепенно сузить источник данных, сделав выборки.

Вот небольшой пример:

import bokeh
import pandas as pd
import numpy as np
from bokeh.plotting import figure, curdoc, show
from bokeh.layouts import column, row, Spacer
from bokeh.models import ColumnDataSource,GMapOptions, HoverTool
from bokeh.models.widgets import Button


df1 = pd.DataFrame(np.random.randint(0,100,size=(3000, 2)), columns=["X","Y"], index=[str(i) for i in range(1,3000+1)])

pointchart=figure(plot_width=800, plot_height=700, tools=['box_select','lasso_select'])
pointchart_source= ColumnDataSource(df1)
pointchart_glyph= pointchart.circle("X","Y",source=pointchart_source, size=3.5) 


def on_selection_change(attr, old, new):
    global newdataframe
    newdataframe= pd.DataFrame(pointchart_source.data).loc[new]
pointchart_glyph.data_source.selected.on_change('indices', on_selection_change) 


def on_update_button_click():
    pointchart_source.data= ColumnDataSource(newdataframe).data

update_button = Button(label="Update", button_type="success")
update_button.on_click(on_update_button_click)


layout =row(pointchart,update_button)
curdoc().add_root(layout)
!powershell -command {'bokeh serve --show Source_update_interaction.ipynb'}

Спасибо

Ответы [ 2 ]

2 голосов
/ 29 апреля 2019

Я думаю, это то, что вы ищете (Bokeh v1.1.0):

import bokeh
import pandas as pd
import numpy as np
from bokeh.plotting import figure, curdoc, show
from bokeh.layouts import column, row, Spacer
from bokeh.models import ColumnDataSource, GMapOptions, HoverTool
from bokeh.models.widgets import Button

df1 = pd.DataFrame(np.random.randint(0, 100, size = (3000, 2)), columns = ["X", "Y"], index = [str(i) for i in range(1, 3000 + 1)])
pointchart_source = ColumnDataSource(df1)
pointchart = figure(plot_width = 800, plot_height = 700, tools = ['box_select', 'lasso_select'])
pointchart_glyph = pointchart.circle("X", "Y", source = pointchart_source, size = 3.5)

newdataframe = None

def on_selection_change(attr, old, new):
    global newdataframe
    newdataframe = pd.DataFrame(pointchart_source.data).loc[new]
    newdataframe.index = newdataframe['index']
    newdataframe = newdataframe.drop(['index'], axis = 1)

pointchart_glyph.data_source.selected.on_change('indices', on_selection_change)

def on_update_button_click():
    global newdataframe
    if newdataframe is not None:
        if pointchart_source.selected.indices:
            pointchart_source.data = {'X': newdataframe['X'].values, 'Y': newdataframe['Y'].values, 'index': newdataframe.index.values}
            pointchart_source.selected.indices = []

update_button = Button(label = "Update", button_type = "success")
update_button.on_click(on_update_button_click)

layout = row(pointchart, update_button)
curdoc().add_root(layout)

Результат:

enter image description here

1 голос
/ 29 апреля 2019

Не делай этого:

def on_update_button_click():
    pointchart_source.data = ColumnDataSource(newdataframe).data

Атрибут .data ведет себя как dict, но на самом деле это сильно инструментированный объект, который связан с источником данных, на котором он создан, и заботится обо всей автоматической синхронизации между Python и JS. Один .data из CDS никогда не должен быть назначен другому другому CDS, и попытка сделать это, вероятно, вызовет явное исключение в будущем.

Вы должны всегда обновлять .data из простого Python dict . Вы можете использовать метод класса from_df на CDS, чтобы создать dict соответствующей формы:

source.data = ColumnDataSource.from_df(newdataframe)
...