Как передать значение слайдера в Bokeh обратно в код Python - PullRequest
1 голос
/ 26 марта 2019

Я хочу передать значение ползунка (которое я построил с помощью Bokeh) обратно в мой код Python.Код генерирует 2 линии на графике и позволяет мне изменять наклон и пересечение одной из них.Но происходит сбой, когда я представляю JavaScript обратного вызова для передачи значения ползунка как "ff" обратно в мой код Python.
Можете ли вы помочь мне с синтаксисом обратного вызова для получения значения ползунка обратно в python (например, см. print(ff)последняя строка кода) - я хочу сделать что-то более интересное, чем просто распечатать это в конечном итоге!
Сообщение об ошибке от обратного вызова:

ValueError: ожидается элемент Dict (String, Instance (Model)), получил {'my_dict': {'s': 0.5}}

Мой код: -

from ipywidgets import interact  
import numpy as np  
from bokeh.io import push_notebook, show, output_notebook  
from bokeh.plotting import figure  
from bokeh.models import ColumnDataSource  
from bokeh.models.callbacks import CustomJS  
output_notebook()  
x = np.linspace(0, 20, 200) # create equally spaced points.  
s = 0.5 # slope.  
i = 3 # intercept.  
y = s * x + i # straight line.  
my_dict = dict(s=s) # need to create a dict object to hold what gets passed in the callback.  

callback = CustomJS(args=dict(my_dict=my_dict), code="""  
  var ff = cb_obj.value  
  my_dict.change.emit()  
""")  
// ff should be the slider value.  

p = figure(title="simple line example", plot_height=300, plot_width=600, y_range=(-20,20),  
           background_fill_color='#efefef')  
r = p.line(x, y, color="#8888cc", line_width=1.5, alpha=0.8) # 1st line. This line can be controlled by sliders.  
q = p.line(x, 2*x+1.2, color="#0088cc", line_width=1.9, alpha=0.2) # 2nd line.  
def update(w=s, a=i):  
    r.data_source.data['y'] = w * x + a  # allow updates for the line r.  
    push_notebook()  
show(p, notebook_handle=True)  
interact(update, w=(-10,10), a=(-12,12) )  
print(ff)  # Return what the slider value is. I want ff accessible back in my python code.

Ответы [ 2 ]

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

Это решение. Это создает серверное приложение bokeh. Он запускается (из spyder) с использованием файла с именем: 20190328_start_bokeh_server.py Существует прямая линия, построенная и контролируемая ползунками. Нажатие кнопки сохраняет значения ползунка в CSV-файле.

Чтобы получить приведенный ниже код для запуска, используйте этот код (он содержится в 20190404_start_bokeh_server.py) в консоли:

импорт ОС os.chdir ("C: \ Users") # Измените рабочий каталог на местоположение сценария. os.system ("start call bokeh serve --show 20190404_bokeh_server.py") # В качестве альтернативы: эту команду можно ввести в приглашении anacondas, как только я перейду в каталог, содержащий файл .py. "" "

import pandas as pd
import numpy as np
from random import random
from numpy.random import randn

from bokeh.plotting import figure, show, curdoc
from bokeh.models import Slider, CustomJS, Range1d, Button
from bokeh.layouts import column
from bokeh.plotting import figure, curdoc
import os

slider_slope = Slider(title = 'Slope', start = 0, end = 1, value = 0.5, step = 0.1)
slider_intercept = Slider(title = 'Intercept', start = 0, end = 20, value = 10, step = 1)

s = slider_slope.value  # slope.
i = slider_intercept.value  # intercept.

x = np.linspace(-40, 20, 200)
y = [(s * xx + i) for xx in x]

p = figure(title = "simple line example", plot_height = 500, plot_width = 600, y_range = Range1d(start = -80, end = 40), background_fill_color = '#efefef')
r = p.line(x, y, color = "red", line_width = 1.5, alpha = 0.8)  # 1st line. This line can be controlled by sliders.
q = p.line(x, 2 * x + 1.2, color = "blue", line_width = 1.9, alpha = 0.2)  # 2nd line. This could be actuals.

def update(attr, old, new):
    s = slider_slope.value  # slope.
    i = slider_intercept.value  # intercept
    x = r.data_source.data['x'];
    y = []

    for value in x:
        y.append((s * value) + i)

    r.data_source.data['y'] = y

# create a callback that will save the slider settings to a csv file when the button is clicked.
def callback():
    os.chdir("C:\\Users") # Change the working directory to where I want to save the csv.
    mydf = pd.DataFrame.from_dict({'slope':[0],'intercept':[0]}) # Create a DataFrame using pandas, based on a dictionary definition. Set the values to be 0 by default.
    mydf.loc[0] = [slider_slope.value, slider_intercept.value] # Assign the first row to slope and intercept.
    mydf.to_csv('slider.csv',index=True) # Write to the csv the final values of the button.  

# add a button widget and configure with the call back
button = Button(label="Save slope and intercept to csv")
button.on_click(callback)

slider_slope.on_change('value', update)
slider_intercept.on_change('value', update)

layout = column(p, slider_slope, slider_intercept, button)
curdoc().add_root(layout)
show(layout, notebook_handle = True) # Launch the chart in the web browser.
0 голосов
/ 26 марта 2019

У меня нет Jupyter Notebook, поэтому эти 2 примера являются чисто приложениями Bokeh, первый использует обратный вызов JS, а второй - обратный вызов Python (Bokeh v1.0.4).

import numpy as np
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, Slider, CustomJS, Range1d
from bokeh.layouts import column

slider_slope = Slider(start = 0, end = 1, value = 0.5, step = 0.1)
slider_intercept = Slider(start = 0, end = 20, value = 10, step = 1)

slider_code = '''   i = slider_intercept.value
                    s = slider_slope.value
                    x = r.data_source.data['x'];
                    y = [];

                    for (index = 0; index < x.length; index ++)
                        y.push((s * x[index]) + i);

                    r.data_source.data['y'] = y
                    r.data_source.change.emit(); '''

s = slider_slope.value  # slope.
i = slider_intercept.value  # intercept.

x = np.linspace(-40, 20, 200)
y = [(s * xx + i) for xx in x]

p = figure(title = "simple line example", plot_height = 500, plot_width = 600, y_range = Range1d(start = -80, end = 40), background_fill_color = '#efefef')
r = p.line(x, y, color = "red", line_width = 1.5, alpha = 0.8)  # 1st line. This line can be controlled by sliders.
q = p.line(x, 2 * x + 1.2, color = "blue", line_width = 1.9, alpha = 0.2)  # 2nd line.

slider_callback = CustomJS(args = dict(slider_slope = slider_slope,
                                slider_intercept = slider_intercept,
                                r = r), code = slider_code)

slider_slope.callback = slider_callback
slider_intercept.callback = slider_callback

layout = column(p, slider_slope, slider_intercept)
show(layout, notebook_handle = True)

Вы можете легко перевести его в приложение сервера Bokeh с обратным вызовом Python:

import numpy as np
from bokeh.plotting import figure, show, curdoc
from bokeh.models import Slider, CustomJS
from bokeh.layouts import column

slider_slope = Slider(title = 'Slope', start = 0, end = 1, value = 0.5, step = 0.1)
slider_intercept = Slider(title = 'Intercept', start = 0, end = 20, value = 10, step = 1)

s = slider_slope.value  # slope.
i = slider_intercept.value  # intercept.

x = np.linspace(-40, 20, 200)
y = [(s * xx + i) for xx in x]

p = figure(title = "simple line example", plot_height = 500, plot_width = 600, y_range = Range1d(start = -80, end = 40), background_fill_color = '#efefef')
r = p.line(x, y, color = "red", line_width = 1.5, alpha = 0.8)  # 1st line. This line can be controlled by sliders.
q = p.line(x, 2 * x + 1.2, color = "blue", line_width = 1.9, alpha = 0.2)  # 2nd line.

def update(attr, old, new):
    s = slider_slope.value  # slope.
    i = slider_intercept.value  # intercept
    x = r.data_source.data['x'];
    y = []

    for value in x:
        y.append((s * value) + i)

    r.data_source.data['y'] = y

slider_slope.on_change('value', update)
slider_intercept.on_change('value', update)

layout = column(p, slider_slope, slider_intercept)
curdoc().add_root(layout)

Результат:

enter image description here

...