【问题标题】:Highlighting multiple hex_tiles by hovering in bokeh通过悬停在散景中突出显示多个 hex_tiles
【发布时间】:2019-05-02 06:58:18
【问题描述】:

我尝试在十六进制地图中可视化我的数据。为此,我在图形类中使用了 python bokeh 和相应的 hex_tile 函数。我的数据属于 8 个不同类别之一,每个类别都有不同的颜色。下图显示了当前的可视化:

我想添加当鼠标悬停在元素上时更改元素(以及理想情况下的所有类成员)颜色的可能性。

我知道,这在一定程度上是可能的,因为散景本身提供了以下示例: https://docs.bokeh.org/en/latest/docs/gallery/hexbin.html

但是,我自己不知道如何实现(因为这似乎是 hexbin 函数的特性,而不是简单的 hex_tile 函数)

目前我在 ColumnDataSource 中提供我的数据:

source = ColumnDataSource(data=dict(
r=x_row,
q=y_col,
color=colors_array,
ipc_class=ipc_array
))

其中“ipc_class”描述了该元素所属的 8 个类之一。 对于鼠标悬停工具提示,我使用了以下代码:

TOOLTIPS = [
("index", "$index"),
("(r,q)", "(@r, @q)"),
("ipc_class", "@ipc_class")
]

然后我将所有内容可视化:

p = figure(plot_width=1600, plot_height=1000, title="Ipc to Hexes with colors", match_aspect=True,
       tools="wheel_zoom,reset,pan", background_fill_color='#440154', tooltips=TOOLTIPS)
p.grid.visible = False
p.hex_tile('q', 'r', source=source, fill_color='color')

我希望可视化添加一个功能,将鼠标悬停在一个元素上将导致以下结果之一: 1.通过改变颜色来高亮当前元素 2.通过更改颜色来突出显示同一类的多个元素 3.改变hex_tile元素(或完整类)在元素悬停时外线的颜色

散景可以实现这些功能中的哪些功能,我将如何实现它?

编辑: 在尝试重新实施 Tony 的建议后,只要我的鼠标碰到图表,所有元素都会变成粉红色,并且颜色不会变回。我的代码如下所示:

source = ColumnDataSource(data=dict(
    x=x_row,
    y=y_col,
    color=colors_array,
    ipc_class=ipc_array
))

p = figure(plot_width=800, plot_height=800, title="Ipc to Square with colors", match_aspect=True,
           tools="wheel_zoom,reset,pan", background_fill_color='#440154')
p.grid.visible = False
p.hex_tile('x', 'y', source=source, fill_color='color')

###################################

code = ''' 
for (i in cb_data.renderer.data_source.data['color'])
    cb_data.renderer.data_source.data['color'][i] = colors[i];

if (cb_data.index.indices != null) {
    hovered_index = cb_data.index.indices[0];
    hovered_color = cb_data.renderer.data_source.data['color'][hovered_index];
    for (i = 0; i < cb_data.renderer.data_source.data['color'].length; i++) {
        if (cb_data.renderer.data_source.data['color'][i] == hovered_color)
            cb_data.renderer.data_source.data['color'][i] = 'pink';
    }
}
cb_data.renderer.data_source.change.emit();
'''

TOOLTIPS = [
    ("index", "$index"),
    ("(x,y)", "(@x, @y)"),
    ("ipc_class", "@ipc_class")
]

callback = CustomJS(args=dict(colors=colors), code=code)
hover = HoverTool(tooltips=TOOLTIPS, callback=callback)
p.add_tools(hover)
########################################

output_file("hexbin.html")

show(p)

基本上,我从图形功能中删除了工具提示并将它们放到悬停工具中。由于我的图表中已经有红色,我将悬停颜色替换为“粉红色”。由于我不太确定“代码”变量中的每一行应该做什么,我对此很无助。我认为一个错误可能是,我的 ColumnDataSource 看起来与 Tony 的有所不同,我不知道如何将第一个和第三个元素以及第二个和第四个元素一起“分类”。对我来说,如果分类由“ipc_class”变量完成,那将是完美的。

【问题讨论】:

    标签: python bokeh


    【解决方案1】:

    根据上一篇文章的讨论,这里出现了针对 OP 代码 (Bokeh v1.1.0) 的解决方案。我所做的是:

    1) 添加了一个悬停工具

    2) 为 HoverTool 添加了一个 JS 回调:

    • 将十六进制颜色重置为原始颜色(在回调中传递colors_array
    • 检查当前悬停的十六进制的索引 (hovered_index)
    • 获取当前悬停的十六进制的ip_class (hovered_ip_class)
    • 遍历data_source.data['ip_class'] 并找到所有与悬停的具有相同ip_class 的六边形并为其设置新颜色 (pink)
    • 向 BokehJS 发送 source.change.emit() 信号以更新模型

    代码:

    from bokeh.plotting import figure, show, output_file
    from bokeh.models import ColumnDataSource, CustomJS, HoverTool
    
    colors_array = ["green", "green", "blue", "blue"]
    x_row = [0, 1, 2, 3]
    y_col = [1, 1, 1, 1]
    ipc_array = ['A', 'B', 'A', 'B']
    
    source = ColumnDataSource(data = dict(
        x = x_row,
        y = y_col,
        color = colors_array,
        ipc_class = ipc_array
    ))
    
    p = figure(plot_width = 800, plot_height = 800, title = "Ipc to Square with colors", match_aspect = True,
               tools = "wheel_zoom,reset,pan", background_fill_color = '#440154')
    p.grid.visible = False
    p.hex_tile('x', 'y', source = source, fill_color = 'color')
    
    ###################################
    code = ''' 
    for (let i in cb_data.renderer.data_source.data['color'])
        cb_data.renderer.data_source.data['color'][i] = colors[i];
    
    if (cb_data.index.indices != null) {
        const hovered_index = cb_data.index.indices[0];
        const hovered_ipc_class = cb_data.renderer.data_source.data['ipc_class'][hovered_index];
        for (let i = 0; i < cb_data.renderer.data_source.data['ipc_class'].length; i++) {
            if (cb_data.renderer.data_source.data['ipc_class'][i] == hovered_ipc_class)
                cb_data.renderer.data_source.data['color'][i] = 'pink';
        }
    }
    cb_data.renderer.data_source.change.emit();
    '''
    
    TOOLTIPS = [
        ("index", "$index"),
        ("(x,y)", "(@x, @y)"),
        ("ipc_class", "@ipc_class")
    ]
    
    callback = CustomJS(args = dict(ipc_array = ipc_array, colors = colors_array), code = code)
    hover = HoverTool(tooltips = TOOLTIPS, callback = callback)
    p.add_tools(hover)
    ########################################
    
    output_file("hexbin.html")
    
    show(p)
    

    结果:

    【讨论】:

    • 感谢您提供此解决方案。解释真的很有帮助。以前,我认为着色取决于特定的类(因为这是我的问题),我在你的代码中找不到这个。现在我看到,您只是跳过了课堂部分并专注于颜色,这是有道理的。非常感谢!
    • 我将color 连接到ipc_class 以使其更清晰,但您是对的,它们可以是独立的。查看更新的代码。
    【解决方案2】:

    也许这样开始(Bokeh v1.1.0):

    from bokeh.plotting import figure, show
    from bokeh.models import ColumnDataSource, CustomJS, HoverTool
    
    colors = ["green", "blue", "green", "blue"]
    source = ColumnDataSource(dict(r = [0, 1, 2, 3], q = [1, 1, 1, 1], color = colors))
    plot = figure(plot_width = 300, plot_height = 300, match_aspect = True)
    plot.hex_tile('r', 'q', fill_color = 'color', source = source)
    
    code = ''' 
    for (i in cb_data.renderer.data_source.data['color'])
        cb_data.renderer.data_source.data['color'][i] = colors[i];
    
    if (cb_data.index.indices != null) {
        hovered_index = cb_data.index.indices[0];
        hovered_color = cb_data.renderer.data_source.data['color'][hovered_index];
        for (i = 0; i < cb_data.renderer.data_source.data['color'].length; i++) {
            if (cb_data.renderer.data_source.data['color'][i] == hovered_color)
                cb_data.renderer.data_source.data['color'][i] = 'red';
        }
    }
    cb_data.renderer.data_source.change.emit();
    '''
    callback = CustomJS(args = dict(colors = colors), code = code)
    hover = HoverTool(tooltips = [('R', '@r')], callback = callback)
    plot.add_tools(hover)
    show(plot)
    

    结果:

    【讨论】:

    • 感谢第一个建议。然而,在使用这个之后,我的所有元素都会立即变成悬停颜色,只要鼠标点击图表。我在对该问题的编辑中写了一些关于此的内容。我会很高兴,如果你能看看它。此外,您从 bokeh.models 导入 ColumnDataSource,而我事先使用了 bokeh.plotting。有区别吗?
    • 我的例子展示了一种方法。您不能在没有任何修改的情况下将其复制/粘贴到您的代码中。您至少应该将回调 args 替换为 args = dict(colors = colors_array) 当您提供一个最小但有效的代码作为一个整体时,它总是工作得最好,以便其他人可以运行它并为您提供完整的解决方案。
    • 我知道,但遗憾的是,我不理解这种方法,主要是“代码”中的部分。因此,我无法将其转移到我的案例中。如果您能解释一下您的实际操作,我可能会很高兴
    猜你喜欢
    • 1970-01-01
    • 2018-10-24
    • 2023-03-12
    • 2023-03-14
    • 2014-06-21
    • 2013-04-08
    • 2012-03-23
    • 1970-01-01
    • 2014-10-20
    相关资源
    最近更新 更多