散景1.0.4-在带有交互式图例的多个字形中进行选择并不包括所有字形

时间:2019-03-03 21:10:24

标签: selection legend bokeh

我正在使用交互式图例,如下例所示

import pandas as pd

from bokeh.palettes import Spectral4
from bokeh.plotting import figure, output_file, show
from bokeh.sampledata.stocks import AAPL, IBM, MSFT, GOOG

p = figure(plot_width=800, plot_height=250,
           tools=('pan, lasso_select, reset'),
           active_drag='lasso_select',
           x_axis_type="datetime")
p.title.text = 'Click on legend entries to mute the corresponding lines'

for data, name, color in zip([AAPL, IBM, MSFT, GOOG], ["AAPL", "IBM", "MSFT", "GOOG"], Spectral4):
    df = pd.DataFrame(data)
    df['date'] = pd.to_datetime(df['date'])
    p.circle(df['date'], df['close'], line_width=2, color=color, alpha=0.8,
             #selection_color='black',
             nonselection_color='gray',
             muted_color='gray', muted_alpha=0.2, legend=name)

p.legend.location = "top_left"
p.legend.click_policy="mute"

output_file("interactive_legend.html", title="interactive_legend.py example")

show(p)

如果我使用套索工具做出这样的选择: while selecting with lasso

释放鼠标后,我看到:

after selecting

请注意,即使MSFT和GOOG的点均未处于选择区域内,也将保持选中状态。

在这种情况下,我希望它们不被选中(灰色)。

显然,如果一个字形中的所有点均不在选择区域之内,则该字形的所有点都将保持选中状态(即,选择工具未包括图中的所有字形)。

谢谢您的帮助!

1 个答案:

答案 0 :(得分:0)

不幸的是,这是LassoSelectTool的默认行为。但是,我可以为您提供一个不错的解决方法,如果未选择它们的点,它将隐藏该字形。然后,您可以使用ResetTool将它们显示回来。我希望它对您有用。

import pandas as pd
from bokeh.palettes import Spectral4
from bokeh.models import LassoSelectTool, ResetTool, CustomJS, LegendItem, Legend, ColumnDataSource
from bokeh.plotting import figure, output_file, show
from bokeh.sampledata.stocks import AAPL, IBM, MSFT, GOOG

p = figure(plot_width = 800, plot_height = 250,
           tools = ('pan,reset'),
           x_axis_type = "datetime")
p.title.text = 'Click on legend entries to mute the corresponding lines'

sources = []
backup_colors = []
stocks = ["AAPL", "IBM", "MSFT", "GOOG"]
for data, name, color in zip([AAPL, IBM, MSFT, GOOG], stocks, Spectral4):
    df = pd.DataFrame(data)
    df['date'] = pd.to_datetime(df['date'])
    sources.append(ColumnDataSource(dict(x = df['date'], y = df['close'], color = len(df['close'].values) * [color])))
    backup_colors.append(len(df['close'].values) * [color])

renderers = []
for index, name in enumerate(['AAPL', 'IBM', 'MSFT', 'GOOG']):
    source = sources[index]
    renderers.append(p.circle(x = 'x',
                              y = 'y',
                              color = 'color',
                              source = source,
                              line_width = 2,
                              alpha = 0.8,
                              nonselection_color = 'gray',
                              muted_color = 'gray',
                              muted_alpha = 0.2,
                              legend = name))

legend_items = [LegendItem(label = stocks[index], renderers = [renderer], name = stocks[index]) for index, renderer in enumerate(renderers)]
legend = Legend(items = legend_items, name = 'stocks_legend')
p.add_layout(legend)
p.legend.click_policy = 'hide'

greys = len(backup_colors[0]) * ['#888888']
code = '''  selected_line = null;
            for (index in renderers){
                renderer = renderers[index];
                if (renderer.data_source.selected.indices.length > 0)
                {
                    selected_line = renderer.data_source.selected.indices.length
                    break;
                }
            }
            if (selected_line != null){
                for (index in renderers){
                    renderer = renderers[index];
                    if (renderer.data_source.selected.indices.length == 0){     
                        renderer.data_source.data['color'] = greys
                        renderer.data_source.change.emit();
                    }
                }
            }'''
lasso_select_tool = LassoSelectTool(select_every_mousemove = False)
lasso_select_tool.callback = CustomJS(args = dict(renderers = renderers, greys = greys), code = code)
p.add_tools(lasso_select_tool)

p.legend.location = "top_left"
p.legend.click_policy = "mute"

code = '''  for (index in renderers){
                renderer = renderers[index];
                renderer.data_source.data['color'] = colors[index];
                renderer.data_source.change.emit();
            } '''
p.js_on_event('reset', CustomJS(args = dict(renderers = renderers, colors = backup_colors), code = code))

show(p)

结果:

enter image description here