[英]JavaScript callback to get selected glyph index in Bokeh
我已经使用Bokeh创建了一个可视图形,该图形显示了我使用Networkx创建的网络。 现在,我想使用TapTool在单击的图形上显示与任何节点有关的信息。 该图仅是节点和边。 我知道我应该能够使用var inds = cb_obj.selected['1d'].indices;
在JavaScript回调函数中获取被单击的节点(字形)的索引,但是以某种方式无法正常工作,并且我收到错误消息Uncaught TypeError: Cannot read property '1d' of undefined
。 朝正确方向轻推将不胜感激。
下面是我的代码。 请注意,我已将绘图定义为Plot()而不是Figure()。 我不认为这是问题的原因,只是想提一下。 另外,我正在使用window.alert(inds);
只是看我得到什么价值。 那不是我的最终目的,但我希望无论如何都能起作用。
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
抱歉,我没有发布完整的代码,但是需要进行一些更改才能生成伪数据并显示其他文件和功能(我应该有),但是我认为仅此一个功能就足以确定问题了。 。 如果没有,我很乐意分享更多代码。 谢谢!
问题在于回调未附加到数据源。 cb_obj
的值是触发回调的任何对象。 但是只有ColumnDataSource
对象具有selected
属性,因此只有数据源上的回调才具有cb_obj.selected
。 如果您希望每当选择更改时(即,每当单击一个节点时)都发生回调,那么您希望在数据源上进行回调。 [1]
但是,如果要在仅将节点悬停(而不是单击)节点时进行回调,这只是检查 ,而不是选择 。 您将需要遵循以下示例:
https://docs.bokeh.org/en/latest/docs/user_guide/interaction/callbacks.html#customjs-for-hover
尽管它不经常使用(因此无法很好地记录),但悬停工具的回调在cb_data
参数中传递了其他信息。 此cb_data
参数用作工具的cb_data
机制,以便能够将特定于工具的其他内容传递给回调。 对于悬停工具, cb_data
是具有.index
和.geometry
属性的对象。 因此, cb_data.index['1d'].indices
具有当前悬停的点的索引。 .geometry
属性是有关执行的命中测试类型的信息(即,是单个点还是垂直或水平跨度?该点或跨度的位置在哪里?)
[1]或者,敲击工具也如上所述传递专门的cb_data
。 具有.source
属性的对象是进行选择的数据源。 因此cb_data.source.selected
应该可以工作。 但实际上,我从未使用过它,因为数据源上的回调同样有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.