Получить выбор Боке в блокноте - PullRequest
4 голосов
/ 21 апреля 2020

Я хотел бы выбрать некоторые точки на графике (например, из box_select или lasso_select) и извлечь их в блокнот Jupyter для дальнейшего исследования данных. Как я могу это сделать?

Например, в приведенном ниже коде, как экспортировать выделение из Bokeh в блокнот? Если мне нужен сервер Bokeh, это тоже хорошо (я видел в документах , что я мог добавить «двустороннюю связь» с сервером, но мне не удалось адаптировать пример для достижения моей цели).

from random import random
from bokeh.io import output_notebook, show
from bokeh.plotting import figure
from bokeh.models.sources import ColumnDataSource

output_notebook()

x = [random() for x in range(1000)]
y = [random() for y in range(1000)]

s = ColumnDataSource(data=dict(x=x, y=y))
fig = figure(tools=['box_select', 'lasso_select', 'reset'])
fig.circle("x", "y", source=s, alpha=0.6)

show(fig)
# Select on the plot
# Get selection in a ColumnDataSource, or index list, or pandas object, or etc.?

Примечания

  • Я видел несколько связанных вопросов по SO, но большинство ответов относятся к устаревшим версиям Bohek, 0.x или 1.x , Я ищу ответ для v> = 2.
  • Я открыт для решений с другими библиотеками визуализации, такими как altair, et c.

Ответы [ 2 ]

2 голосов
/ 26 апреля 2020

Чтобы выбрать некоторые точки на графике и получить их в блокноте Jupyter, вы можете использовать Пользовательский JS обратный вызов .

В пользовательском JS обратном вызове javascript код, вы можете получить доступ к ядру ноутбука Jupyter, используя IPython.notebook.kernel. Затем вы можете использовать kernal.execute(python_code) для запуска Python кода и (например) экспорта данных из вызова javascript в записную книжку Jupyter.

Таким образом, сервер bokeh не требуется для двусторонней связи связь между графиком боке и записной книжкой Jupyter.

Ниже я расширил ваш пример кода, добавив в него пользовательский обратный вызов JS, который срабатывает при событии геометрии выбора на рисунке. Всякий раз, когда делается выбор, обратный вызов запускается и экспортирует индексы выбранных точек данных в переменную в записной книжке Jupyter с именем selected_indices.

Чтобы получить ColumnDataSource, который содержит выбранные точки данных, кортеж selected_indices проходит по циклу для создания списков выбранных значений x и y, которые затем передаются в конструктор ColumnDataSource.

from random import random
from bokeh.io import output_notebook, show
from bokeh.plotting import figure
from bokeh.models.sources import ColumnDataSource
from bokeh.models.callbacks import CustomJS

output_notebook()

x = [random() for x in range(1000)]
y = [random() for y in range(1000)]

s = ColumnDataSource(data=dict(x=x, y=y))

fig = figure(tools=['box_select', 'lasso_select', 'reset'])
fig.circle("x", "y", source=s, alpha=0.6)

# make a custom javascript callback that exports the indices of the selected points to the Jupyter notebook
callback = CustomJS(args=dict(s=s), 
                    code="""
                         console.log('Running CustomJS callback now.');
                         var indices = s.selected.indices;
                         var kernel = IPython.notebook.kernel;
                         kernel.execute("selected_indices = " + indices)
                         """)

# set the callback to run when a selection geometry event occurs in the figure
fig.js_on_event('selectiongeometry', callback)

show(fig)
# make a selection using a selection tool 

# inspect the selected indices
selected_indices

# use the indices to create lists of the selected values
x_selected, y_selected = [], []
for indice in selected_indices:
    x_val = s.data['x'][indice]
    y_val = s.data['y'][indice]
    x_selected.append(x_val)
    y_selected.append(y_val)

# make a column data souce containing the selected values
selected = ColumnDataSource(data=dict(x=x_selected, y=y_selected))

# inspect the selected data
selected.data
1 голос
/ 28 апреля 2020

Если у вас запущен сервер bokeh, вы можете получить доступ к индексам выбора источника данных через datasource.selection.indices. Ниже приведен пример того, как вы это сделаете (см. Официальный пример Встраивание сервера Bokeh в Jupyter ):

from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
from bokeh.io import show, output_notebook

from bokeh.sampledata.sea_surface_temperature import sea_surface_temperature

output_notebook()

df = sea_surface_temperature.copy()[:100]
source = ColumnDataSource(data=df)

def bkapp(doc):

    plot = figure(x_axis_type='datetime', y_range=(0, 25), tools="lasso_select",
                  y_axis_label='Temperature (Celsius)',
                  title="Sea Surface Temperature at 43.18, -70.43")
    plot.circle('time', 'temperature', source=source)

    doc.add_root( plot)

show(bkapp)

После того, как вы что-то выбрали, вы можете получить выбранные данные. следующим образом:

selected_data = df.iloc[source.selected.indices]
print(selected_data)

Который должен показывать вам выбранные значения.

Хотя этот вопрос выходит за рамки этого вопроса, обратите внимание, что существует разрыв между записными книжками Jupyter и интерактивной природой приложений боке. : Это решение вводит состояние, которое не сохраняется ноутбуком jupyter, поэтому его перезапуск и выполнение всех ячеек не дают одинаковых результатов. Один из способов решить эту проблему - сохранить выбор с помощью pickle:

df = sea_surface_temperature.copy()[:100]
source = ColumnDataSource(data=df)
if os.path.isfile("selection.pickle"):
    with open("selection.pickle", mode="rb") as f:
        source.selected.indices = pickle.load(f)

... # interactive part

with open("selection.pickle", mode="wb") as f:
    pickle.dump(source.selected.indices, f)
...