0

我正在生成一个使用标签的散景报告,有时我可以获得很多这些,并且导航文档变得非常麻烦。幸运的是,这些图有一些属性,可用于将一些图组合在一起。所以我试图实现一种基于这些属性过滤可见选项卡数量的方法。我在使用散景服务器草绘解决方案方面非常成功,但我的最终解决方案需要实现 CustomJS 回调,因为我需要分发 html 报告。我有点迷茫,因为我不熟悉如何实现 CustomJS 回调,或者即使我想要实现的目标在没有散景服务器的情况下也是可能的。我试图根据其他人的帖子来实现一个 CustomJS,但到目前为止我还没有成功。

我的主要目标是用 CustomJS 回调替换“change_plot”回调,如果有人知道这怎么可能,我将不胜感激。

我在下面提供了我的脚本的一个最小示例。任何帮助或指示将不胜感激。

我想要实现的散景服务器版本:

from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Tabs, Panel, Dropdown, PreText
from bokeh.plotting import figure, curdoc


#Initialize variables
nplots = 6 # Number of plots
ngroup = 4 # Number of plots assigned to first group

# Definition of report structure
groups = [f'Quad' if i < ngroup else f'Linear' for i in range(nplots)] # Arbitrary grouping of plots
tabnames = [f'Title_{i}' for i in range(nplots)] # Individual plot names

# Creates list of unique groups without modifying first appearance order
cnt = 0
unq_grp = []
original_groups = groups[:]
while len(groups):
    cnt = cnt + 1
    unq_grp.append(groups[0])
    groups = list(filter(lambda group: group != groups[0], groups))
    if cnt > len(groups):
        break

# Data Variables
x = [None]*nplots
y = [None]*nplots

# Plot Variables
fig = [None]*nplots
source = [None]*nplots

# Generates figures with plots from data with custom process
for i in range(nplots):
    x[i] = [x[i] for x[i] in range(0, 10)]
    if i < ngroup:        
        y[i] = [(i*n)**2 for n in x[i]]
    else:
        y[i] = [(i*n) for n in x[i]]
    source[i] = ColumnDataSource(data=dict(x=x[i], y=y[i]))
    fig[i] = figure()
    fig[i].line('x', 'y', source=source[i], line_width=3, line_alpha=0.6)

# Callback to change Plot and Plot Title
def change_plot(attr, old, new):
    index = int(new.split(',')[0])
    group = int(new.split(',')[1])
    title[group].text = f'Plot: {subgroup[group][index][0]}'
    col[group].children[2] = fig[index]

subgroup = [None]*len(unq_grp) #List of tuples ('plot_name', ['tabname_index','unique_group_index'])
menu = [None]*len(unq_grp) #List that populates dropdown menu
group_dd = [None]*len(unq_grp) #Placeholder for dropdown GUI elements
tab = [None]*len(unq_grp) #Placeholder for tab GUI elements
title = [None]*len(unq_grp) #Placeholder for title GUI elements
col = [None]*len(unq_grp) #Placeholder for column GUI elements

# Cycle through each unique group
for i, group in enumerate(unq_grp):
    # Filter the figures correspondig to current group
    subgroup[i] = [(tabnames[j],str(f'{j},{i}')) if original_group == group else None for j, original_group in enumerate(original_groups)]
    # Populates the dropdown menu
    menu[i] = list(filter(None,subgroup[i]))
    # Reference default figure index (first in the menu)
    default = int(menu[i][0][1].split(',')[0])
    # Creates GUI/Report elements
    group_dd[i] = Dropdown(label = "Select Group", button_type = "default", menu=menu[i])
    title[i] = PreText(text=f'Plot: {menu[i][0][0]}', width=200)
    col[i] = column([group_dd[i],title[i],fig[default]])

    # Listens to callback event
    group_dd[i].on_change('value', change_plot)
    # Creates tabs
    tab[i] = Panel(child = col[i], title = group)
out_tabs = Tabs(tabs = tab)

curdoc().title = "Plotting Tool"
curdoc().add_root(out_tabs)

独立报告(我的代码到目前为止......)

from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Tabs, Panel, Dropdown, PreText, CustomJS
from bokeh.plotting import figure, output_file, show


#Initialize variables
nplots = 6 # Number of plots
ngroup = 4 # Number of plots assigned to first group

# Definition of report structure
groups = [f'Quad' if i < ngroup else f'Linear' for i in range(nplots)] # Arbitrary grouping of plots
tabnames = [f'Title_{i}' for i in range(nplots)] # Individual plot names
output_file("tabs.html")

# Creates list of unique groups without modifying first appearance order
cnt = 0
unq_grp = []
original_groups = groups[:]
while len(groups):
    cnt = cnt + 1
    unq_grp.append(groups[0])
    groups = list(filter(lambda group: group != groups[0], groups))
    if cnt > len(groups):
        break

# Data Variables
x = [None]*nplots
y = [None]*nplots

# Plot Variables
fig = [None]*nplots
source = [None]*nplots

# Generates figures with plots from data with custom process
for i in range(nplots):
    x[i] = [x[i] for x[i] in range(0, 10)]
    if i < ngroup:        
        y[i] = [(i*n)**2 for n in x[i]]
    else:
        y[i] = [(i*n) for n in x[i]]
    source[i] = ColumnDataSource(data=dict(x=x[i], y=y[i]))
    fig[i] = figure()
    fig[i].line('x', 'y', source=source[i], line_width=3, line_alpha=0.6)
figcol = column(fig)


output_file("tabs.html")
subgroup = [None]*len(unq_grp) #List of tuples ('plot_name', ['tabname_index','unique_group_index'])
menu = [None]*len(unq_grp) #List that populates dropdown menu
group_dd = [None]*len(unq_grp) #Placeholder for dropdown GUI elements
tab = [None]*len(unq_grp) #Placeholder for tab GUI elements
title = [None]*len(unq_grp) #Placeholder for title GUI elements
col = [None]*len(unq_grp) #Placeholder for column GUI elements
cjs = [None]*len(unq_grp) #Placeholder for column GUI elements

# Cycle through each unique group
for i, group in enumerate(unq_grp):
    # Filter the figures correspondig to current group
    subgroup[i] = [(tabnames[j],str(f'{j},{i}')) if original_group == group else None for j, original_group in enumerate(original_groups)]
    # Populates the dropdown menu
    menu[i] = list(filter(None,subgroup[i]))
    # Reference default figure index (first in the menu)
    default = int(menu[i][0][1].split(',')[0])
    # Creates GUI/Report elements
    group_dd[i] = Dropdown(label = "Select Group", button_type = "default", menu=menu[i])
    col[i] = column([group_dd[i],fig[default]])
    cjs[i] = CustomJS(args=dict(col=col[i], select=group_dd[i], allfigs=figcol), code="""
    // Split the index
    var dd_val = (select.value)
    var valARR = dd_val.split(',')
    var index = parseInt(valARR[0])

    // replace with appropiate figure?
    col.children[1] = allfigs.children[index]

    // send new column, maybe?
    col.change.emit();
    """)    

    # Listens to callback event
    group_dd[i].js_on_change('value',cjs[i])
    # Creates tabs
    tab[i] = Panel(child = col[i], title = group)
out_tabs = Tabs(tabs = tab)

show(out_tabs)

4

1 回答 1

0

您可以在列布局中显示所有图形,并通过设置visible属性显示/隐藏图形。这是一个例子:

import numpy as np
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Tabs, Panel, Select, PreText, CustomJS
from bokeh.plotting import figure, output_file, show

output_file("tabs.html")

x = np.linspace(0, 10)

def create_figure(x, y, label):
    source = ColumnDataSource(data=dict(x=x, y=y))
    fig = figure(name=label)
    fig.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
    return fig

def create_select(figs, title="Select Group"):
    names = [fig.name for fig in figs]
    drop = Select(title=title, value=names[0], options=names)
    for fig in figs[1:]:
        fig.visible = False

    callback = CustomJS(args=dict(figs=figs), code="""
        let selected = cb_obj.value;
        for(let fig of figs){
            fig.visible = fig.name == selected;
        }
    """)

    drop.js_on_change("value", callback)
    return [drop] + figs

quad_figs = [create_figure(x, (i * x)**2, f"Quad {i}") for i in range(3)]
linear_figs = [create_figure(x, (i * x), f"Linear {i}") for i in range(3)]

tabs = Tabs(tabs=[
    Panel(child=column(create_select(quad_figs)), title="Quad"),
    Panel(child=column(create_select(linear_figs)), title="Linear")
])

show(tabs)
于 2019-07-23T02:33:36.570 回答