Sky_7
Sky_7

Reputation: 97

How to change the node sizes individually in a networkx graph in Plotly Dash

I am creating a networkx graph and while developing in Python I can change the node size using the following code in networkx.draw_shell() -

vertices = df_final.columns.values.tolist()
edges = [((u,v),df_final[u].corr(df_final[v])) for u,v in itertools.combinations(vertices, 2)]
edges = [(u,v,{'weight': abs(c)}) for (u,v),c in edges if abs(c) >= 0.5]
G = networkx.Graph()

G.add_edges_from(edges)

size = F_imp.Score.to_list()

from matplotlib.pyplot import figure

figure(figsize=(9,9), dpi=500)

networkx.draw_shell(G, with_labels=True, node_size= (np.array(size) *10000), font_size=8)
plt.show()

But when I am trying to integrate the same plot in Dash, I can't use the networkx.draw_shell() in built function anymore and hence can't use the node_size attribute anymore. Rather I have to transform the network graph into a plotly graph in the following way -

vertices = df_final.columns.values.tolist()
edges = [((u,v),df_final[u].corr(df_final[v])) for u,v in itertools.combinations(vertices, 2)]
#edges = [(u,v,{'weight': c}) for (u,v),c in edges if abs(c) >= 0.5]
edges = [(u,v,{'weight': abs(c)}) for (u,v),c in edges if abs(c) >= 0.5]
G = networkx.Graph()

G.add_edges_from(edges)

#size = F_imp.Score.to_list()

pos = networkx.shell_layout(G)

networkx.shell_layout

import plotly.graph_objects as go
# edges trace
edge_x = []
edge_y = []
for edge in G.edges():
    x0, y0 = pos[edge[0]]
    x1, y1 = pos[edge[1]]
    edge_x.append(x0)
    edge_x.append(x1)
    edge_x.append(None)
    edge_y.append(y0)
    edge_y.append(y1)
    edge_y.append(None)

edge_trace = go.Scatter(
    x=edge_x, y=edge_y,
    line=dict(color='black', width=1),
    hoverinfo='none',
    showlegend=False,
    mode='lines')

# nodes trace
node_x = []
node_y = []
text = []
for node in G.nodes():
    x, y = pos[node]
    node_x.append(x)
    node_y.append(y)
    text.append(node)

node_trace = go.Scatter(
    x=node_x, y=node_y, text=text,
    mode='markers+text',
    showlegend=False,
    hoverinfo='none',
    marker=dict(
        color='pink',
        size=50,
        line=dict(color='black', width=1)))

# size nodes by degree
# deg_dict = {deg[0]:int(deg[1]) for deg in list(G.degree())}
# for node, degree in enumerate(deg_dict):
#     node_trace['marker']['size'] = (deg_dict[degree])

# layout
layout = dict(plot_bgcolor='white',
              paper_bgcolor='white',
              margin=dict(t=10, b=10, l=10, r=10, pad=0),
              xaxis=dict(linecolor='black',
                         showgrid=False,
                         showticklabels=False,
                         mirror=True),
              yaxis=dict(linecolor='black',
                         showgrid=False,
                         showticklabels=False,
                         mirror=True))

# figure
fig = go.Figure(data=[edge_trace, node_trace], layout=layout)


fig

This does generate the network graph but I am not being able to assign different node sizes to the nodes based on some score as I could in the first case.

The size component in the node_trace['marker']['size'] seems to be applicable for all nodes and cannot be changed for each node. Here I tried to change the node size as per degree. The code has been commented out above under #size nodes by degree

As reference, I have followed the following questions -

  1. Plotly Dash: Plotting networkx in Python
  2. Customizing a Networkx graph (or Scatter) with Python Plotly

Does anyone know the solution?

Upvotes: 1

Views: 1028

Answers (1)

Robert
Robert

Reputation: 337

You can define a dictionary containing the node sizes and pass it list to the node_trace variable.

I do not have your dataset, so I made just a small example.

Let's say this is your dictionary containing the sizes:

node_size = {
        'Brown bear': 4,
        'fur': 3,
        'claw': 3,
        'sharp': 2,
        'brown': 2 
        }

While looping over your nodes, you create a list that contains the sizes of the corresponding nodes:

# nodes trace
node_x = []
node_y = []
text = []
sizes = []

for node in G.nodes():
    x, y = pos[node]
    node_x.append(x)
    node_y.append(y)
    text.append(node)
    # Append the sizes
    size = node_size[node]
    sizes.append(size)

You pass this list as a parameter to the go.Scatter():

node_trace = go.Scatter(
    x=node_x, y=node_y, text=text,
    mode='markers+text',
    showlegend=False,
    # Add the sizes,
    size=node_sizes,
    hoverinfo='none',
    marker=dict(
        color='pink',
        size=50,
        line=dict(color='black', width=1)))

Run the rest of your code, and your plot has not variable node sizes. See my output screenshot as example:

enter image description here

Upvotes: 1

Related Questions