Help custom js_on_event for graph

I am trying to add custom JS code when someone clicks on one of the glyphs (mainly the edges) on the graph that I’ve created. I was not able to get it to work and was hoping I could get some help, this is running as part of a Django project. Thanks in advance!

def bokeh_plot(self):
        edge_index = {}
        cmap = {}
        for e in self.graph.edges:
            cmap[e] = random.choice(['red', 'blue'])
            edge_index[e] = e

        nx.set_edge_attributes(self.graph, 12, 'score')
        nx.set_edge_attributes(self.graph, cmap, 'edge_color')
        nx.set_edge_attributes(self.graph, edge_index, 'link')
        
        plot = Plot(plot_width=1700, plot_height=800,
            x_range=Range1d(-1.1,1.1), y_range=Range1d(-1.1,1.1))

        ht = HoverTool(tooltips=[("link", "@link"), ("score", "@score")])

        plot.add_tools(ht, TapTool(), BoxSelectTool(), BoxZoomTool(), ResetTool())

        pos = nx.spring_layout(self.graph)
        graph_renderer = from_networkx(self.graph, pos, scale=1, center=(0,0))

        graph_renderer.node_renderer.glyph = Circle(size=15, fill_color=Spectral4[0])
        graph_renderer.node_renderer.selection_glyph = Circle(size=15, fill_color=Spectral4[2])
        graph_renderer.node_renderer.hover_glyph = Circle(size=15, fill_color=Spectral4[1])

        graph_renderer.edge_renderer.glyph = MultiLine(line_color='edge_color', 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=10)

        graph_renderer.selection_policy = NodesAndLinkedEdges()
        graph_renderer.inspection_policy = EdgesAndLinkedNodes()

        plot.renderers.append(graph_renderer)

        x,y=zip(*pos.values())
        source = ColumnDataSource({'x':x,'y':y,'index':[n for n in self.graph.nodes]})
        labels = LabelSet(x='x', y='y', text='index', source=source, text_font_size = '20pt')
        plot.renderers.append(labels)
        plot.sizing_mode = 'scale_width' 

        return components(plot)

Have you seen this? python - bokeh server on_change from selected glyph not working - Stack Overflow

And to get the data source used for edges, you can use graph_renderer.edge_renderer.data_source.

1 Like

Hello @p-himik,

I did see that but I hadn’t realized that I could access the data source used for the edges by doing what you suggested. I was able to figure it out thanks to you, I really appreciate it. My apologies as I am very new to Bokeh and web-development in general. I will add the solution below for anyone else who may need it.

def bokeh_plot(self):
        edge_index = {}
        cmap = {}
        for e in self.graph.edges:
            cmap[e] = random.choice(['red', 'blue'])
            edge_index[e] = e

        nx.set_edge_attributes(self.graph, 12, 'score')
        nx.set_edge_attributes(self.graph, cmap, 'edge_color')
        nx.set_edge_attributes(self.graph, edge_index, 'link')
        
        plot = Plot(plot_width=1700, plot_height=800,
            x_range=Range1d(-1.1,1.1), y_range=Range1d(-1.1,1.1))

        ht = HoverTool(tooltips=[("link", "@link"), ("score", "@score")])

        plot.add_tools(ht, TapTool(), BoxSelectTool(), BoxZoomTool(), ResetTool())

        pos = nx.spring_layout(self.graph)
        graph_renderer = from_networkx(self.graph, pos, scale=1, center=(0,0))

        graph_renderer.node_renderer.glyph = Circle(size=15, fill_color=Spectral4[0])
        graph_renderer.node_renderer.selection_glyph = Circle(size=15, fill_color=Spectral4[2])
        graph_renderer.node_renderer.hover_glyph = Circle(size=15, fill_color=Spectral4[1])

        graph_renderer.edge_renderer.glyph = MultiLine(line_color='edge_color', 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=10)

        graph_renderer.selection_policy = EdgesAndLinkedNodes()
        graph_renderer.inspection_policy = EdgesAndLinkedNodes()

        edge_data = graph_renderer.edge_renderer.data_source
        edge_js = '''
        var ind = cb_obj.indices[0]
        console.log(edge_data['attributes']['data']['link'][ind])
        '''
        callback = CustomJS(args = dict(edge_data = edge_data), code=edge_js)
        edge_data.selected.js_on_change('indices', callback)
        

        plot.renderers.append(graph_renderer)

        x,y=zip(*pos.values())
        source = ColumnDataSource({'x':x,'y':y,'index':[n for n in self.graph.nodes]})
        labels = LabelSet(x='x', y='y', text='index', source=source, text_font_size = '20pt')
        plot.renderers.append(labels)
        plot.sizing_mode = 'scale_width' 

        

        return components(plot)
2 Likes