python боке динамически обновляет категорический x_range - PullRequest
0 голосов
/ 08 апреля 2020

Я хочу создать подсвечник в боке и динамически обновлять ось X в соответствии с пользовательским вводом через виджет MultiSelect. В основном пользователь выберет несколько элементов в MultiSelect, а затем я бы хотел, чтобы они стали значениями оси x. Я уже настроил виджет MultiSelect и подтвердил, что он работает, подключив DataTable к MultiSelect и обновив его соответствующим образом (что он и делает). Мне просто нужна помощь, чтобы получить значения из виджета MultiSelect и установить их как мой plot.x_range. Основываясь на нескольких сообщениях GitHub / Issues (вроде этого: https://github.com/bokeh/bokeh/issues/4022), я попытался использовать FactorRange, но он не работает. В настоящее время поведение заключается в том, что метки оси x остаются установленными в значения, которые установлены во время начальной конфигурации MultiSelect ('aaa' и 'bbb'), и не меняются, когда я выбираю другие значения в виджете MultiSelect.

Вот пример кода:

### SET UP SOURCE DF INFO ###
tab2_source = ColumnDataSource(df)
tab2_original_source = ColumnDataSource(df)
columns_t2 = [TableColumn(field='Gene', title='Gene'), TableColumn(field='row_min', title='min'), TableColumn(field='row_max', title='max'), 
             TableColumn(field='quantile_25', title='25th quantile'), TableColumn(field='quantile_50', title='50th quantile'), TableColumn(field='quantile_75', title='75th quantile')]
data_table_t2 = DataTable(source=tab2_source, columns=columns_t2, reorderable=False)

### STUFF FOR THE WIDGETS ###
# customJS stuff
tab2_callback_code = """
var t2_data = tab2_source.data;
var t2_original_data = tab2_original_source.data;
var gene_t2 = gene_select_obj_t2.value;
console.log("gene: " + gene_t2);
for (var key in t2_original_data) {
    t2_data[key] = [];
    for (var i = 0; i < t2_original_data['Gene'].length; ++i) {
        if (t2_original_data['Gene'][i] === gene_t2[0] || t2_original_data['Gene'][i] === gene_t2[1]) {
            t2_data[key].push(t2_original_data[key][i]);
        }
    }
}

tab2_source.change.emit();
target_obj_t2.change.emit();
"""

# make drop-down selectors
select_gene_t2 = MultiSelect(title = "Select up to 2 Genes to View:", value=['aaa', 'bbb'], options=list(df.Gene.unique()))

# define the callback objects now that the select widgets exist
tab2_callback = CustomJS(
    args=dict(tab2_source=tab2_source,
             tab2_original_source=tab2_original_source,
             gene_select_obj_t2=select_gene_t2,
             target_obj_t2=data_table_t2),
    code=tab2_callback_code)

# connect the callbacks to the filter widgets
select_gene_t2.js_on_change('value', tab2_callback)


## PLOTTING ##
p2 = figure(plot_width=500, plot_height=400, title='Avg Gene Exp', y_range=(-2,12), x_range=FactorRange())
p2.x_range.factors = list(select_gene_t2.value)
p2.vbar(x='Gene', top='quantile_75', bottom='quantile_25', source=tab2_source, width=0.5, fill_color="#D5E1DD", line_color="black")
tab2 = Panel(child=column(select_gene_t2, p2, data_table_t2), title="Exp by Gene")
tabs = Tabs(tabs=[tab2])
save(tabs)

1 Ответ

0 голосов
/ 08 апреля 2020

Для всех, кого это интересует, это лучшее решение, которое я нашел:

Добавьте эту строку в код tab2_callback_code (plot_xr ссылается на мой рисунок p2 - вам также необходимо добавить эти ссылки в Custom JS args dict):

plot_xr.x_range.factors = gene_t2;

Также важно создать экземпляр, прежде чем вызывается код tab2_callback_code. Это сработало для меня, и теперь мои значения x_range меняются, когда я выбираю разные опции в MultiSelect.

...