Как использовать customjs для динамического обновления вариантов выпадающего меню в Bokeh

Я пытаюсь обновить раскрывающееся меню в зависимости от выбора, сделанного пользователем в предыдущем раскрывающемся меню, с помощью обратных вызовов customjs в Bokeh. В приведенном ниже примере пользователь может создать базовый график на основе выбора common_name ИЛИ путем выбора квадрата. Но я хотел бы, чтобы пользователь мог сначала выбрать common_name, а затем выбрать квадрат на основе данных, доступных для этого common_name (т.е. на основе первого выбранного common_name). Есть идеи ?

from bokeh.models import CustomJS, ColumnDataSource, MultiSelect, Column

from bokeh.plotting import figure, show
from bokeh.layouts import row, column
import pandas as pd

# data
data = dict(common_name = ['A','A','B','C','B','B','A','C','C','B','A','B','C'],
length = [10, 20, 10, 20, 30, 20, 20, 30, 20, 30, 30, 20, 30],
weight = [100, 200, 100, 300, 100, 400, 100, 300, 100, 400, 500, 600, 450],
quadrat = ['N', 'N', 'N', 'N', 'M', 'M', 'M', 'M', 'O', 'O', 'M', 'N', 'O'])

data = pd.DataFrame(data)

data_source = ColumnDataSource(data)

# Empty source so the plot is empty before data is selected
source = ColumnDataSource(dict(length = [], weight = []))

plot = figure()

plot.circle(x = 'length', y = 'weight', source = source)


# Select species
available_species = list(set(data['common_name']))
available_species.sort()

species_callback = CustomJS(args = {'source': source, 'data_source': data_source},
code = """
var data = data_source.data;
var source_data = source.data;
var common_name = data['common_name'];
var selected_species = cb_obj.value;
var length_data = data['length'];
var weight_data = data['weight'];
var length = source_data['length'];
length.length = 0;
var weight = source_data['weight'];
weight.length = 0;
 for (var i = 0; i < length_data.length; i++) {
  if (selected_species.indexOf(common_name[i]) >= 0) {
   length.push(length_data[i]);
   weight.push(weight_data[i]);
    }
  }
  source.change.emit();
  """)

multiselect_species = MultiSelect(title = 'Species:', value = [], options = available_species, width = 240)


# Select quadrat
available_quadrat = list(set(data['quadrat']))
available_quadrat.sort()

quadrat_callback = CustomJS(args = {'source': source, 'data_source': data_source},
code = """
var data = data_source.data;
var source_data = source.data;
var quadrat = data['quadrat'];
var selected_quadrat = cb_obj.value;
var length_data = data['length'];
var weight_data = data['weight'];
var length = source_data['length'];
length.length = 0;
  var weight = source_data['weight'];
  weight.length = 0;
  for (var i = 0; i < length_data.length; i++) {
    if (selected_quadrat.indexOf(quadrat[i]) >= 0) {
      length.push(length_data[i]);
      weight.push(weight_data[i]);
    }
  }
  source.change.emit();
  """)

multiselect_quadrat = MultiSelect(title = 'Set:', value = [], options = available_quadrat, width = 240)
multiselect_quadrat.js_on_change('value', quadrat_callback)

multiselect_species.js_on_change('value', species_callback, CustomJS(args = dict(multiselect_quadrat = multiselect_quadrat,
                                                                                 available_quadrat = available_quadrat),
code = """
const available_quadrat = %s
multiselect_quadrat.options = "available_quadrat[cb_obj.value]"
""" % available_quadrat))

  # Set up widgets layout
widgets_layout = column(multiselect_species, multiselect_quadrat)

page_layout = row(widgets_layout, plot)

show(page_layout)


Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
0
1 236
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот полный пример, который обновляет MultiSelect на основе обратного вызова CustomJS для другого виджета:

from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import RadioButtonGroup, CustomJS, MultiSelect

opts = {
    0: ["foo", "bar"],
    1: ["baz", "quux"],
}

bg = RadioButtonGroup(labels=["Stuff", "Things"], active=0)

ms = MultiSelect(options=opts[0])

bg.js_on_change('active', CustomJS(args=dict(ms=ms), code = """
    const opts = %s
    ms.options = opts[cb_obj.active]
""" % opts))

show(column(bg, ms)

Спасибо bigreddot, ваша помощь неоценима. Однако я изо всех сил пытаюсь применить ваш совет. Я обновил код, чтобы учесть ваши предложения. Не могли бы вы указать, что я делаю неправильно? С помощью этого кода я могу только выбрать и нанести на карту вид (мультиселект квадрата пуст). Спасибо.

user11516234 30.05.2019 20:54

В виджетах с множественным выбором нет свойства active, поэтому available_quadrat[cb_obj.active] не определено. Вместо этого есть свойство value, которое представляет собой список (поскольку при множественном выборе можно выбрать более одной вещи), НО значения также являются строками, например. «C», поэтому вам нужно будет использовать словарь, а не список, для available_quadrat

bigreddot 30.05.2019 23:34

также, конечно, multiselect_quadrat.options должно быть установлено значение списка. Я бы порекомендовал узнать о команде debugger JS. Вы можете поместить его в свой код обратного вызова, чтобы иметь возможность пройти через него и проверить переменные и т. д.

bigreddot 30.05.2019 23:40

Другие вопросы по теме