moe_95
moe_95

Reputation: 417

Assign color to NetworkX node based on column name

I am attempting to build a network graph using NetworkX and Bokeh. I am using the NetworkX from_pandas_edgelist function to add data for the graph. I would like to color the node of the graph based on the column in the initial data input.

The relation DataFrame is as follows:

company   client

Google    AT&T
Google    Cisco       
Amazon    Facebook
Amazon    Snap
Amazon    Microsoft
Apple     Intel
Apple     IBM
Apple     Visa

The above snippet is only a portion of the DataFrame.

I would like all of the nodes from company to return in a different color to client.

The code below produces a network graph where all nodes are the same color.

G=nx.from_pandas_edgelist(relation, 'company', 'client')

# Show with Bokeh
plot = Plot(plot_width=1000, plot_height=800,
            x_range=Range1d(-1.1, 1.1), y_range=Range1d(-1.1, 1.1))
plot.title.text = "Company - Client Network"

node_hover_tool = HoverTool(tooltips=[("Company Name", "@index")])
plot.add_tools(node_hover_tool, BoxZoomTool(), ResetTool())

graph_renderer = from_networkx(G, nx.spring_layout, scale=1, center=(0, 0))

graph_renderer.node_renderer.glyph = Circle(size=20)

graph_renderer.edge_renderer.glyph = MultiLine(line_color="red", line_alpha=0.8, line_width=1)
plot.renderers.append(graph_renderer)

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

Any assistance anyone could provide would be greatly appreciated.

Upvotes: 3

Views: 5455

Answers (2)

Victoria Stuart
Victoria Stuart

Reputation: 5082

Good question, and accepted answer (from which I was able to extend my code to give colored nodes based on the Pandas dataframe column).

import warnings
warnings.filterwarnings("ignore", category=UserWarning)

import networkx as nx
import matplotlib.pyplot as plt
import pandas as pd

df = pd.read_csv('pers_org.tsv', sep='\t')
# (TSV copied from a PostgreSQL database, hence the "id" column.)
df.sort_values(by=['id'])
'''
      id          person      organization
  0    1  Robert_Bigelow             BAASS
  1    2  Robert_Bigelow             AATIP
  2    3  Robert_Bigelow              NIDS
  3    4  Robert_Bigelow  Skinwalker_Ranch
  14   5   Luis_Elizondo             AATIP
  4    6   Colm_Kelleher             AATIP
  5    7   Colm_Kelleher              NIDS
  6    8   Colm_Kelleher  Skinwalker_Ranch
  7    9     Tom_DeLonge              TTSA
  8   10   Luis_Elizondo              TTSA
  9   11     Hal_Puthoff              TTSA
  10  12    Chris_Mellon              TTSA
  11  13   Douglas_Kurth           US_Navy
  12  14   Douglas_Kurth          Lockheed
  13  15   Douglas_Kurth             BAASS
'''

G = nx.from_pandas_edgelist(df, source='person', target='organization', \
    create_using=nx.DiGraph)
colors = []
for node in G:
    if node in df["person"].values:
        colors.append("lightblue")
    else: colors.append("lightgreen")

print(colors)
# ['lightblue', 'lightgreen', 'lightgreen', 'lightgreen', 'lightgreen',
#  'lightblue', 'lightblue', 'lightgreen', 'lightblue', 'lightblue',
#  'lightblue', 'lightblue', 'lightgreen', 'lightgreen']

plt.figure(figsize=(15,10))
# <Figure size 1500x1000 with 0 Axes>

nx.draw(G, pos = nx.nx_pydot.graphviz_layout(G), \
    node_size=1200, node_color=colors, linewidths=0.25, \
    font_size=10, font_weight='bold', with_labels=True)
plt.show()

See also How to set colors for nodes in networkx python?

pers_org.tsv

id  person  organization
1   Robert_Bigelow  BAASS
2   Robert_Bigelow  AATIP
3   Robert_Bigelow  NIDS
4   Robert_Bigelow  Skinwalker_Ranch
5   Luis_Elizondo   AATIP
6   Colm_Kelleher   AATIP
7   Colm_Kelleher   NIDS
8   Colm_Kelleher   Skinwalker_Ranch
9   Tom_DeLonge TTSA
10  Luis_Elizondo   TTSA
11  Hal_Puthoff TTSA
12  Chris_Mellon    TTSA
13  Douglas_Kurth   US_Navy
14  Douglas_Kurth   Lockheed
15  Douglas_Kurth   BAASS

networkx_from_pandas_nodes_colored_by_df_column


Although I did not do this here, if you want to add node borders and thicken the node border lines (node edge thickness: linewidths), do the following.

nx.draw(G, pos = nx.nx_pydot.graphviz_layout(G), \
    node_size=1200, node_color=colors, linewidths=2.0, \
    font_size=10, font_weight='bold', with_labels=True)

# Get current axis:
ax = plt.gca()
ax.collections[0].set_edgecolor('r')
# r : red (can also use #FF0000) | b : black (can also use #000000) | ...
plt.show()

Upvotes: 6

ilamaaa
ilamaaa

Reputation: 421

After the old Edit:

Can't give too much context as I am not super familiar with bokeh, but looks like you can use a similar approach to what I did initially just instead of passing the "color_map" do your draw function you have to stick your data in here graph_renderer.node_renderer.data_source.data['colors'] Anyway this seems to do the job, Good luck dude.

relation = pd.DataFrame({
                "company":["Google", "Google", "Amazon", "Amazon", "Amazon",
                            "Apple", "Apple", "Apple"],
                "client":["AT&T", "Cisco", "Facebook", "Snap", "Microsoft",
                          "Intel", "IBM", "Visa"]})

G=nx.from_pandas_edgelist(relation, 'company', 'client')
colors = []

for node in G:
    if node in relation["client"].values:
        colors.append("blue")
    else: colors.append("green")

plot = Plot(plot_width=1000, plot_height=800,
            x_range=Range1d(-1.1, 1.1), y_range=Range1d(-1.1, 1.1))
plot.title.text = "Company - Client Network"

node_hover_tool = HoverTool(tooltips=[("Company Name", "@index")])
plot.add_tools(node_hover_tool, BoxZoomTool(), ResetTool())

graph_renderer = from_networkx(G, nx.spring_layout, scale=1, center=(0, 0))

graph_renderer.node_renderer.data_source.data['colors'] = colors
graph_renderer.node_renderer.glyph = Circle(size=20, fill_color='colors')

graph_renderer.edge_renderer.glyph = MultiLine(line_color="red", line_alpha=0.8, line_width=1)
plot.renderers.append(graph_renderer)

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


Upvotes: 4

Related Questions