JavaScript回调以获取Bokeh中的选定字形索引 [英] JavaScript callback to get selected glyph index in Bokeh
问题描述
我使用Bokeh创建了一个可视化图形,显示了我使用Networkx创建的网络。我现在想使用TapTool显示与我点击的图表上的任何节点相关的信息。图表只是节点和边缘。我知道我应该能够在JavaScript回调函数中使用 var inds = cb_obj.selected ['1d'] .index;
来获取节点的索引(字形)已被点击,但这不起作用,我收到错误消息,未捕获TypeError:无法读取未定义的属性'1d'
。非常感谢正确方向的推动。
I've created a visual graph using Bokeh that shows a network I created using Networkx. I now want to use TapTool to show information pertinent to any node on the graph that I click on. The graph is just nodes and edges. I know I should be able to use var inds = cb_obj.selected['1d'].indices;
in the JavaScript callback function to get the indices of the nodes (glyphs) that were clicked on, but that's not working somehow and I get the error message, Uncaught TypeError: Cannot read property '1d' of undefined
. A nudge in the right direction would be greatly appreciated.
以下是我的代码。请注意,我已将我的情节定义为Plot()而不是数字()。我不认为这是问题的原因,但只是想提一下。另外,我正在使用 window.alert(inds);
只是为了看看我得到了什么值。这不是我的最终目的,但我希望无论如何都能有效。
Below is my code. Please note that I've defined my plot as a Plot() and not as a figure(). I don't think that's the reason for the issue, but just wanted to mention it. Also, I'm using window.alert(inds);
just to see what values I get. That's not my ultimate purpose, but I expect that bit to work anyway.
def draw_graph_____(self, my_network):
self.graph_height, self.graph_width, self.graph_nodes, self.graph_edges, self.node_coords, self.node_levels = self.compute_graph_layout(my_network)
graph = nx.DiGraph()
graph.add_nodes_from(self.graph_nodes)
graph.add_edges_from(self.graph_edges)
plot = Plot(plot_width = self.graph_width, plot_height = self.graph_height, x_range = Range1d(0.0, 1.0), y_range = Range1d(0.0, 1.0))
plot.title.text = "Graph Demonstration"
graph_renderer = from_networkx(graph, self.graph_layout, scale = 1, center = (-100, 100))
graph_renderer.node_renderer.data_source.data["node_names"] = self.graph_nodes
graph_renderer.node_renderer.data_source.data["index"] = self.graph_nodes
graph_renderer.node_renderer.glyph = Circle(size = 40, fill_color = Spectral4[0])
graph_renderer.node_renderer.selection_glyph = Circle(size = 40, fill_color = Spectral4[2])
graph_renderer.node_renderer.hover_glyph = Circle(size = 40, fill_color = Spectral4[1])
graph_renderer.edge_renderer.glyph = MultiLine(line_color = "#CCCCCC", line_alpha = 0.8, line_width = 5)
graph_renderer.edge_renderer.selection_glyph = MultiLine(line_color = Spectral4[2], line_width = 5)
graph_renderer.edge_renderer.hover_glyph = MultiLine(line_color = Spectral4[1], line_width = 5)
graph_renderer.selection_policy = NodesAndLinkedEdges()
graph_renderer.inspection_policy = NodesAndLinkedEdges()
x_coord = [coord[0] for coord in self.node_coords]
y_coord = [coord[1] for coord in self.node_coords]
y_offset = []
for level in self.node_levels:
for item in self.node_levels[level]:
if self.node_levels[level].index(item) % 2 == 0:
y_offset.append(20)
else:
y_offset.append(-40)
graph_renderer.node_renderer.data_source.data["x_coord"] = x_coord
graph_renderer.node_renderer.data_source.data["y_coord"] = y_coord
graph_renderer.node_renderer.data_source.data["y_offset"] = y_offset
labels_source = graph_renderer.node_renderer.data_source
labels = LabelSet(x = "x_coord", y = "y_coord", text = 'node_names', text_font_size = "12pt", level = 'glyph',
x_offset = -50, y_offset = "y_offset", source = labels_source, render_mode = 'canvas')
plot.add_layout(labels)
callback = CustomJS(args = dict(source = graph_renderer.node_renderer.data_source), code =
"""
console.log(cb_obj)
var inds = cb_obj.selected['1d'].indices;
window.alert(inds);
""")
plot.add_tools(HoverTool(tooltips = [("Node", "@node_names"), ("Recomm", "Will put a sample recommendation message here later")]))
plot.add_tools(TapTool(callback = callback))
plot.renderers.append(graph_renderer)
output_file("interactive_graphs.html")
show(plot)
我的进口如下,方式:
import collections
import networkx as nx
import numpy as np
from bokeh.io import output_file, show
from bokeh.models import Circle, ColumnDataSource, CustomJS, Div, HoverTool, LabelSet, MultiLine, OpenURL, Plot, Range1d, TapTool
from bokeh.models.graphs import from_networkx, NodesAndLinkedEdges
from bokeh.palettes import Spectral4
我很抱歉没有发布整个代码,但这需要对m进行相当多的更改ake虚拟数据并显示其他文件和功能(我应该拥有),但我认为这一个功能可能足以识别问题。如果没有,我很乐意分享更多代码。谢谢!
I'm sorry for not posting entire code, but that would require quite a few changes to make dummy data and show other files and functions (which I should have), but I thought just this one function may suffice for the identification of the issue. If not, I'm happy to share more code. Thanks!
推荐答案
问题是回调没有附加到数据源。 cb_obj
的值是触发回调的任何对象。但只有 ColumnDataSource
对象具有选中的
属性,因此只有数据源上的回调才会有 cb_obj .selected
。如果您希望每当选择更改时都会触发回调,即每当单击某个节点时,您都希望在数据源上进行回调。 [1]
The problem is that the callback is not attached to a data source. The value of cb_obj
is whatever object triggers the callback. But only ColumnDataSource
objects have a selected
property, so only callbacks on data sources will have cb_obj.selected
. If you are wanting to have a callback fire whenever a selection changes, i.e. whenever a node is clicked on, then you'd want to have the callback on the data source. [1]
但是,如果您希望在节点仅仅悬停(但未点击)时进行回调,那就是检查,而不是选择。您将要遵循以下示例:
However, if you want to have a callback when a node is merely hovered over (but not clicked on) that is an inspection, not a selection. You will want to follow this example:
https://bokeh.pydata.org/en/latest/docs/user_guide/interaction/callbacks.html#customjs-for-hover
虽然它不经常使用(因此没有很好地记录),悬停工具的回调在 cb_data $ c $中传递了附加信息c>参数。此
cb_data
参数用作工具的全能机制,以便能够将特定于工具的额外内容传递给回调。对于悬停工具, cb_data
是一个具有 .index
和 .geometry的对象。
属性。所以 cb_data.index ['1d']。indices
包含当前悬停的点的索引。 .geometry
属性作为有关所执行的命中测试类型的信息(即单点?或垂直或水平跨度?该点的位置是什么?或者跨度?)
Although it is not often used (and thus not documented terribly well) the callback for hover tools gets passed additional information in a cb_data
parameter. This cb_data
parameter is used as a catch-all mechanism for tools to be able to pass extra things, specific to the tool, on to the callback. In the case of hover tools, cb_data
is an object that has .index
and .geometry
attributes. So cb_data.index['1d'].indices
has the indices of the points that are currently hovered over. The .geometry
attribute as information about the kind of hit test that was performed (i.e. was a single point? or a vertical or horizontal span? And what was the location of the point or span?)
[1]或者,点击工具也会传递专门的 cb_data
,如上所述。它是一个带有 .source
属性的对象,它是进行选择的数据源。所以 cb_data.source.selected
应该可行。实际上我从不使用它,因为数据源的回调同样有效。
[1] Alternatively, tap tools also pass a specialized cb_data
as described above. It is an object with a .source
property that the the data source that made a selection. So cb_data.source.selected
should work. In practice I never use this though, since a callback on the data source works equally well.
这篇关于JavaScript回调以获取Bokeh中的选定字形索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!