
网络图使用节点和连接线来显示事物之间的连接关系,用于说明实体之间的关系。一般分为定向网络图和非定向网络图。
基于pyecharts
from pyecharts import options as opts
from pyecharts.charts import Graph
nodes = [
{"name": "结点1", "symbolSize": 10},
{"name": "结点2", "symbolSize": 20},
{"name": "结点3", "symbolSize": 30},
{"name": "结点4", "symbolSize": 40},
{"name": "结点5", "symbolSize": 50},
{"name": "结点6", "symbolSize": 40},
{"name": "结点7", "symbolSize": 30},
{"name": "结点8", "symbolSize": 20},
]
links = []
for i in nodes:
for j in nodes:
links.append({"source": i.get("name"), "target": j.get("name")})
c = (
Graph()
.add("", nodes, links, repulsion=8000)
.set_global_opts(title_opts=opts.TitleOpts(title="基本网络图"))
)
c.render_notebook()

基于networkx
import pandas as pd
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
# 自定义数据
df = pd.DataFrame({ 'from':['A', 'B', 'C','A'], 'to':['D', 'A', 'E','C']})
# 构造网络图数据格式
G=nx.from_pandas_edgelist(df, 'from', 'to')
# 绘制网络图
nx.draw(G, with_labels=True)
plt.show()

自定义网络图一般是结合使用场景对相关参数进行修改,并辅以其他的绘图知识。参数信息可以通过官网进行查看,其他的绘图知识则更多来源于实战经验,大家不妨将接下来的绘图作为一种学习经验,以便于日后总结。
点线网络
import requests
import json
from pyecharts import options as opts
from pyecharts.charts import Graph
# 获取官方的数据
url = "https://raw.githubusercontent.com/pyecharts/pyecharts-gallery/master/Graph/weibo.json"
response = requests.get(url)
j = json.loads(response.text)
nodes, links, categories, cont, mid, userl = j
c = (
Graph()
.add(
"",
nodes,
links,
categories,
repulsion=50,
linestyle_opts=opts.LineStyleOpts(curve=0.2),
label_opts=opts.LabelOpts(is_show=False),
)
.set_global_opts(
legend_opts=opts.LegendOpts(is_show=False),
title_opts=opts.TitleOpts(title="微博转发关系网络"),
)
)
c.render_notebook()

球状网络
import pyecharts.options as opts
from pyecharts.charts import Graph
# 获取官方的数据
url = 'https://echarts.apache.org/examples/data/asset/data/npmdepgraph.min10.json'
response = requests.get(url)
data = response.json() # 将响应内容解析为JSON
nodes = [
{
"x": node["x"],
"y": node["y"],
"id": node["id"],
"name": node["label"],
"symbolSize": node["size"],
"itemStyle": {"normal": {"color": node["color"]}},
}
for node in data["nodes"]
]
edges = [
{"source": edge["sourceID"], "target": edge["targetID"]} for edge in data["edges"]
]
c = (
Graph()
.add(
series_name="",
nodes=nodes,
links=edges,
layout="none",
is_roam=True,
is_focusnode=True,
label_opts=opts.LabelOpts(is_show=False),
linestyle_opts=opts.LineStyleOpts(width=0.5, curve=0.3, opacity=0.7),
)
.set_global_opts(title_opts=opts.TitleOpts(title="NPM Dependencies网络"))
)
c.render_notebook()

更多用法可参考:Networkx Tutorial[1]
修改参数
import pandas as pd
import numpy as np
import networkx as nx
import matplotlib as mpl
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
# 初始化布局
fig = plt.figure(figsize=(16,8))
# 自定义数据
df = pd.DataFrame({ 'from':['A', 'B', 'C','A'], 'to':['D', 'A', 'E','C']})
# 构造网络图数据格式
G=nx.from_pandas_edgelist(df, 'from', 'to')
# 自定义参数
plt.subplot(2, 4, 1)
nx.draw(G, with_labels=True, node_size=1500, node_color="skyblue", node_shape="o", alpha=0.5, linewidths=4, font_size=25,
font_color="grey", font_weight="bold", width=2, edge_color="grey")
plt.title('自定义参数')
# 自定义布局-fruchterman_reingold
plt.subplot(2, 4, 2)
nx.draw(G, with_labels=True, node_size=1500, node_color="skyblue", pos=nx.fruchterman_reingold_layout(G))
plt.title('自定义布局-fruchterman_reingold')
# 自定义布局-circular
plt.subplot(2, 4, 3)
nx.draw(G, with_labels=True, node_size=1500, node_color="skyblue", pos=nx.circular_layout(G))
plt.title('自定义布局-circular')
# 自定义布局-random
plt.subplot(2, 4, 4)
nx.draw(G, with_labels=True, node_size=1500, node_color="skyblue", pos=nx.random_layout(G))
plt.title('自定义布局-random')
# 自定义布局-spectral
plt.subplot(2, 4, 5)
nx.draw(G, with_labels=True, node_size=1500, node_color="skyblue", pos=nx.spectral_layout(G))
plt.title('自定义布局-spectral')
# 自定义布局-spring
plt.subplot(2, 4, 6)
nx.draw(G, with_labels=True, node_size=1500, node_color="skyblue", pos=nx.spring_layout(G))
plt.title('自定义布局-spring')
# 有向网络
plt.subplot(2, 4, 7)
GD=nx.from_pandas_edgelist(df, 'from', 'to', create_using=nx.DiGraph() )
nx.draw(GD, with_labels=True, node_size=1500, alpha=0.3, arrows=True)
plt.title('有向网络')
# 无向网络
plt.subplot(2, 4, 8)
GUD=nx.from_pandas_edgelist(df, 'from', 'to', create_using=nx.Graph() )
nx.draw(GUD, with_labels=True, node_size=1500, alpha=0.3, arrows=True)
plt.title('无向网络')
plt.show()

颜色映射
import pandas as pd
import numpy as np
import networkx as nx
import matplotlib as mpl
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
# 自定义数据
df = pd.DataFrame({ 'from':['A', 'B', 'C','A'],
'to':['D', 'A', 'E','C'],
'value1':[1, 10, 5, 5],
'value2':['typeA', 'typeA', 'typeB', 'typeB']
})
# 具有节点特征的数据1-连续颜色分配
carac1 = pd.DataFrame({ 'ID':['A', 'B', 'C','D','E'], 'myvalue':['123','25','76','12','34'] })
# 具有节点特征的数据2-离散颜色分配
carac2 = pd.DataFrame({ 'ID':['A', 'B', 'C','D','E'], 'myvalue':['group1','group1','group2','group3','group3'] })
# 构造网络图数据格式
G=nx.from_pandas_edgelist(df, 'from', 'to', create_using=nx.Graph() )
# 利用节点顺序排序carac1
carac1 = carac1.set_index('ID')
carac1 = carac1.reindex(G.nodes())
# 利用节点顺序排序carac2,并转化为Categorical编码
carac2 = carac2.set_index('ID')
carac2 = carac2.reindex(G.nodes())
carac2['myvalue']=pd.Categorical(carac2['myvalue'])
carac2['myvalue'].cat.codes
# 将value2化为Categorical编码
df['value2']=pd.Categorical(df['value2'])
df['value2'].cat.codes
# 初始化布局
fig = plt.figure(figsize=(16,8))
# 将连续颜色映射到节点
plt.subplot(2, 2, 1)
nx.draw(G, with_labels=True, node_color=carac1['myvalue'].astype(int), cmap=plt.cm.Blues)
plt.title('将连续颜色映射到节点')
# 将离散颜色映射到节点
plt.subplot(2, 2, 2)
nx.draw(G, with_labels=True, node_color=carac2['myvalue'].cat.codes, cmap=plt.cm.Set1, node_size=1500)
plt.title('将离散颜色映射到节点')
# 将连续颜色映射到边线
plt.subplot(2, 2, 3)
nx.draw(G, with_labels=True, node_color='skyblue', node_size=1500, edge_color=df['value1'], width=10.0, edge_cmap=plt.cm.Blues)
plt.title('将连续颜色映射到边线')
# 将离散颜色映射到边线
plt.subplot(2, 2, 4)
nx.draw(G, with_labels=True, node_color='skyblue', node_size=1500, edge_color=df['value2'].cat.codes, width=10.0, edge_cmap=plt.cm.Set2)
plt.title('将离散颜色映射到边线')
plt.show()

基于相关矩阵的网络图
import pandas as pd
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
# 自定义数据
ind1=[5,10,3,4,8,10,12,1,9,4]
ind5=[1,1,13,4,18,5,2,11,3,8]
df = pd.DataFrame({ 'A':ind1,
'B':ind1 + np.random.randint(10, size=(10)) ,
'C':ind1 + np.random.randint(10, size=(10)) ,
'D':ind1 + np.random.randint(5, size=(10)) ,
'E':ind1 + np.random.randint(5, size=(10)),
'F':ind5,
'G':ind5 + np.random.randint(5, size=(10)) ,
'H':ind5 + np.random.randint(5, size=(10)),
'I':ind5 + np.random.randint(5, size=(10)),
'J':ind5 + np.random.randint(5, size=(10))})
# 计算相关性
corr = df.corr()
# 转化为长格式
links = corr.stack().reset_index()
links.columns = ['var1', 'var2', 'value']
# 过滤数据,仅保留高相关性,并删除自相关
links_filtered=links.loc[ (links['value'] > 0.8) & (links['var1'] != links['var2']) ]
# 构造网络图数据格式
G=nx.from_pandas_edgelist(links_filtered, 'var1', 'var2')
# 绘制相关矩阵网络图
nx.draw(G, with_labels=True, node_color='orange', node_size=400, edge_color='black', linewidths=1, font_size=15)
plt.show()

拓展-绘制具有边缘捆绑的网络图
%%capture --no-display
# 上述代码隐藏警告信息输出
import matplotlib.pyplot as plt
import networkx as nx
from netgraph import Graph
# 自定义数据
partition_sizes = [10, 20, 30, 40]
g = nx.random_partition_graph(partition_sizes, 0.5, 0.1)
# 将数据按照partition_sizes分为4类
node_to_community = dict()
node = 0
for community_id, size in enumerate(partition_sizes):
for _ in range(size):
node_to_community[node] = community_id
node += 1
# 针对各类自定义颜色
community_to_color = {
0 : 'tab:blue',
1 : 'tab:orange',
2 : 'tab:green',
3 : 'tab:red',
}
node_color = {node: community_to_color[community_id] \
for node, community_id in node_to_community.items()}
fig, ax = plt.subplots()
Graph(g,
node_color=node_color, # 节点颜色
node_edge_width=0, # 去除节点边缘的边框
edge_width=0.1, # 边缘宽度
edge_alpha=0.5, # 边缘透明度
node_layout='community', node_layout_kwargs=dict(node_to_community=node_to_community),
edge_layout='bundled', # 带捆绑的束
ax=ax,
)
plt.show()

以上通过pyecharts和networkx快速绘网络图。并通过修改参数或者辅以其他绘图知识自定义各种各样的网络图来适应相关使用场景。
共勉~
[1]
Networkx Tutorial:https://networkx.org/documentation/stable/tutorial.html