0

I'm plotting the NetworkX graph using Bokeh where I have node IDs, edges IDs, edges length, width, and edges coordinates as follows:

import pandas as pd
import networkx as nx
##Graph data
d = {'Node 1': [54524, 56577, 53689, 55961, 54524],
     'Node 2': [56577, 76969, 54524, 56354, 54525],
     'len': [51.3, 107.7, 27.7, 32.4, 124.8],
     'Stick ID': [27967, 27968, 27969, 27970, 27971],
     'D': [55.419, 43.543499999999995, 100.282, 100.282, 100.282],
     'start_coord': [(507188.35, 6110791.95),
      (507159.94, 6110749.25),
      (507212.47, 6110778.24),
      (507089.54, 6110904.91),
      (507188.35, 6110791.95)],
     'end_coord': [(507159.94, 6110749.25),
      (507248.37, 6110689.01),
      (507188.35, 6110791.95),
      (507075.96, 6110933.93),
      (507098.76, 6110872.37)]}

df = pd.DataFrame(data=d)
#Build NetworkX graph
G_1=nx.from_pandas_edgelist(df, 'Node 1', 'Node 2', edge_attr=["len", "Stick ID", 'D', 'start_coord', 'end_coord'])
#Convert diameters to meters
df['D'] = df['D']/1000

#GRAPH VISUALIZATION
from bokeh.io import output_file, show
from bokeh.plotting import figure, from_networkx
from bokeh.models import Range1d, Circle, ColumnDataSource, MultiLine, BoxZoomTool, HoverTool, Plot, ResetTool

plot = figure(title="Networkx Integration Demonstration", x_range=(-10.1,10.1), y_range=(-10.1,10.1),
              tools="pan,wheel_zoom,save,reset", active_scroll='wheel_zoom', toolbar_location=None)

network_graph = from_networkx(G_1, nx.spring_layout, scale=2, center=(0,0))

#Set node size and color
network_graph.node_renderer.glyph = Circle(size=5, fill_color='skyblue')

#Set edge opacity and width
network_graph.edge_renderer.glyph = MultiLine(line_alpha=0.5)

plot.renderers.append(network_graph)

output_file("networkx_graph.html")
show(plot)

From the final results I can see that my nodes are randomly distributted on the plot. enter image description here

How can I add my starting coordinates and ending coordinates from my DataFram into MultiLine, so that lines located accordinly?? (Since coordinates have with 500, 600 the center should be changed? ) Additionally, I would like to see the edge Len, Stick ID, and D when I hoover my mouth over the edges. How can I add that to?

1 Answers1

1

You can pass whichever layout you want to from_networkx function. It can be a networkx layout (in your code you are using nx.spring_layout) or a dictionnary mapping nodes to coordinates (see doc here).

In terms of setting up your hover tool, you can use:

hover = HoverTool(tooltips=[("len","@len"),("Stick ID","@Stick_ID"), ("D","@D")],renderers=[network_graph.edge_renderer],show_arrow=False)

To make sure that the tooltip shows up while hovering the edges make sure to set renderers to [network_graph.edge_renderer]. See more SO examples here.

Overall the code looks like that:

import pandas as pd
import networkx as nx
import numpy as np

##Graph data
d = {'Node 1': [54524, 56577, 53689, 55961, 54524],
     'Node 2': [56577, 76969, 54524, 56354, 54525],
     'len': [51.3, 107.7, 27.7, 32.4, 124.8],
     'Stick_ID': [27967, 27968, 27969, 27970, 27971],
     'D': [55.419, 43.543499999999995, 100.282, 100.282, 100.282],
     'start_coord': [(507188.35, 6110791.95),
      (507159.94, 6110749.25),
      (507212.47, 6110778.24),
      (507089.54, 6110904.91),
      (507188.35, 6110791.95)],
     'end_coord': [(507159.94, 6110749.25),
      (507248.37, 6110689.01),
      (507188.35, 6110791.95),
      (507075.96, 6110933.93),
      (507098.76, 6110872.37)]}

df = pd.DataFrame(data=d)
#Build NetworkX graph
G_1=nx.from_pandas_edgelist(df, 'Node 1', 'Node 2', edge_attr=["len", "Stick_ID", 'D', 'start_coord', 'end_coord'])

pos_1={d['Node 1'][i]:d['start_coord'][i] for i in range(len(d['Node 1']))} #getting positions of starting nodes
pos_2={d['Node 2'][i]:d['end_coord'][i] for i in range(len(d['Node 2']))} #getting positions of ending nodes
pos= {**pos_1, **pos_2} #concatenating the two dictionnary removes overlaps

#Convert diameters to meters
df['D'] = df['D']/1000

#GRAPH VISUALIZATION
from bokeh.io import output_file, show
from bokeh.plotting import figure, from_networkx
from bokeh.models import Range1d, Circle, ColumnDataSource, MultiLine, BoxZoomTool, HoverTool, Plot, ResetTool

plot = figure(title="Networkx Integration Demonstration",tools="pan,wheel_zoom,save,reset",active_scroll='wheel_zoom', toolbar_location=None) #removed previous xlims and ylims  

network_graph = from_networkx(G_1, pos, scale=1)

#Set node size and color
network_graph.node_renderer.glyph = Circle(size=20, fill_color='skyblue')

#Set edge opacity and width
network_graph.edge_renderer.glyph = MultiLine(line_alpha=1,line_width=2)
hover = HoverTool(tooltips=[("len","@len"),("Stick ID","@Stick_ID"), ("D","@D")],renderers=[network_graph.edge_renderer],show_arrow=False)

plot.renderers.append(network_graph)
plot.tools.append(hover)

output_file("networkx_graph.html")
show(plot)

And below is what the hovering looks like:

enter image description here

jylls
  • 4,395
  • 2
  • 10
  • 21
  • Thank you for the answer. But my point is, that I already have coordinates for the edges: 'start_coord' and 'end_coord', how can I map this coordinates with layout? – errenmike1806 Nov 02 '22 at 15:07
  • 1
    My bad for the misunderstanding. See my edited response that takes what you described into account. – jylls Nov 02 '22 at 15:41
  • Man, I was trying also myself to add Nodes IDs when I hoover over them follwoing the link you sent by adding `hover2 = HoverTool(tooltips=[('Node','@Node 1'), ('Node','@Node 2')],renderers=[network_graph.node_renderer],show_arrow=False) `and then `plot.tools.append(hover2)`. But I'm getting ????? for the nodes IDs. Could, you, please tell me what is worng ? – errenmike1806 Nov 02 '22 at 17:28
  • 1
    You need to add your node labels to the `network_graph.node_renderer`. You can do that by adding the line `network_graph.node_renderer.data_source.data['Node'] = [n for n in G_1.nodes()]` right under the line `network_graph.node_renderer.glyph = Circle(size=20, fill_color='skyblue')`. You can then add `hover2 = HoverTool(tooltips=[("Node","@Node")],renderers=[network_graph.node_renderer],show_arrow=False) ` and `plot.tools.append(hover2) ` at the end and everything should work. – jylls Nov 02 '22 at 19:12