本文学习建议和用到的知识点:
1、学习建议:在画人物关系图的时候,建议提前先整理好自己需要的数据,缕清人物关系;本文提供了一个完整的案例,可以正常运行查看效果; 2、本文用到的Python知识点为Python的network模块的使用、列表的基本操作、循环的使用、excel文件的读写、pandas应用、matplotlib应用、类的使用、元组的操作等,便于大家阅读本文前提前对相关知识进行回顾。
1 简单引入
- 日常工作、生活中我们经常会遇到一些复杂的事务关系,比如人物关系,那如何才能清楚直观的看清楚这些任务关系呢?
- 比如我们从网上搜索1个人物关系图,大家看看:
声明:以下图片来源于网络,如果涉及版权问题,请联系作者删除。本文仅供学习,不做他用。
- 那我们如何使用Python来实现类似的人物关系图呢?
- 这里我们需要用到Python的networkx模块,它可以帮助我们很好的显示我们需要的效果。
2 关于Networkx
2.1 Networkx简单说明
- NetworkX是一个用于创建、操作和研究复杂网络的 Python 库;
- 可以创建、分析和可视化各种类型的网络,例如社交网络、Web图、生物网络等;
- NetworkX可以用来创建各种类型的网络,包括有向图和无向图;
- 提供各种方法来添加、删除和修改网络中的节点和边;
- NetworkX还提供许多图的算法和分析工具;
- NetworkX还提供多种方式来可视化网络。
2.2 Networkx部分源码
- NetworkX支持四种图,从以下源码可以看出:
Python37Libsite-packagesnetworkxclasses__init__.py 以下是源码内容 from .graph import Graph from .digraph import DiGraph from .multigraph import MultiGraph from .multidigraph import MultiDiGraph from .ordered import * from .function import *from networkx.classes import filtersfrom networkx.classes import coreviews from networkx.classes import graphviews from networkx.classes import reportviews
- 四种图即为:
图 | 说明 |
---|---|
Graph | 无多重边无向图 |
DiGraph | 无多重边有向图 |
MultiGraph | 有多重边无向图 |
MultiDiGraph | 有多重边有向图 |
- 而本文我们要用的是 Graph,它主要是用点和线来刻画离散事务集合,每对事务之间以某种方式相联系的数学模型;
- Graph可以用来表示的关系图为人物关系图、流程图等等;
- 以下为Graph的几个方法源码:
Python37Libsite-packagesnetworkxclassesgraph.py
- 以下为draw_networkx_nodes方法源码:
def draw_networkx_nodes( G, pos, nodelist=None, node_size=300, node_color="#1f78b4", node_shape="o", alpha=None, cmap=None, vmin=None, vmax=None, ax=None, linewidths=None, edgecolors=None, label=None, margins=None, ): """Draw the nodes of the graph G.
- 以下为draw_networkx_edges源码:
def draw_networkx_edges( G, pos, edgelist=None, width=1.0, edge_color="k", style="solid", alpha=None, arrowstyle="-|>", arrowsize=10, edge_cmap=None, edge_vmin=None, edge_vmax=None, ax=None, arrows=None, label=None, node_size=300, nodelist=None, node_shape="o", connectionstyle="arc3", min_source_margin=0, min_target_margin=0, ): r"""Draw the edges of the graph G.
- 以下为draw_networkx_labels源码:
def draw_networkx_labels( G, pos, labels=None, font_size=12, font_color="k", font_family="sans-serif", font_weight="normal", alpha=None, bbox=None, horizontalalignment="center", verticalalignment="center", ax=None, clip_on=True, ): """Draw node labels on the graph G.
- 以下为circular_layout源码:
def circular_layout(G, scale=1, center=None, dim=2):dim=2 only """Position nodes on a circle. Parametersundefined G : NetworkX graph or list of nodes A position will be assigned to every node in G. scale : number (default: 1) Scale factor for positions. center : array-like or None Coordinate pair around which to center the layout. dim : int Dimension of layout. If dim>2, the remaining dimensions are set to zero in the returned positions. If dim<2, a ValueError is raised.
2.3 Networkx一个示例
- 比如一个几个节点的有向图:
# -*- coding: utf-8 -*-
import subprocess
import sys
# 如果需要通过本文运行器运行代码,需要加上这句
subprocess.check_call([sys.executable, "-m", "pip", "install", "networkx"])
import networkx as nx
import matplotlib.pyplot as plt
# 设置画布大小
plt.figure(figsize=(6, 7))
# 创建有向图对象
G = nx.DiGraph()
# 添加节点
my_node = ["nodeA", "nodeB", "nodeC", "nodeD", "nodeE", "nodeF"]
for node in my_node:
G.add_node(node)
# 添加有向边
for edge in range(len(my_node)-1):
print(edge)
G.add_edge(my_node[edge], my_node[edge 1])
# 绘制
# 布局算法
pos = nx.spring_layout(G)
nx.draw(G, pos, with_labels=True)
# plt.show()
plt.savefig("pic01.jpg")
- 输出如下图示: 在这里插入图片描述
3 人物关系图绘制过程
3.1 创建原始数据
- 我们以西游记和封神榜部分重点人物关系为例,先整理好一个任务关系
excel
文档relation.xls
:
character1 character2 color num relation 菩提祖师 孙悟空 antiquewhite 9 第一任师傅 唐僧 孙悟空 aqua 9 师徒 如来佛祖 孙悟空 aquamarine 9 五指山 观音菩萨 孙悟空 azure 9 紧箍咒 牛魔王 孙悟空 beige 9 结拜兄弟 猪八戒 孙悟空 bisque 9 大师兄 沙和尚 孙悟空 black 9 大师兄 白龙马 孙悟空 blanchedalmond 9 大师兄 孙悟空 唐僧 aliceblue 6 师徒 猪八戒 唐僧 bisque 6 师徒 沙和尚 唐僧 black 6 师徒 白龙马 唐僧 blanchedalmond 6 师徒 观音菩萨 唐僧 azure 6 委派西天取经 老鼠精 唐僧 blue 6 欲嫁 老鼠精 托塔天王 blue 4 义父女 哪吒 托塔天王 blueviolet 4 父子 木吒 托塔天王 brown 4 父子 金吒 托塔天王 burlywood 4 父子 木吒 观音菩萨 brown 2 大弟子 红孩儿 观音菩萨 cadetblue 2 善财童子 金吒 如来佛祖 burlywood 1 前部护法 铁扇公主 牛魔王 darkkhaki 2 夫妻 红孩儿 牛魔王 cadetblue 2 父子 红孩儿 铁扇公主 cadetblue 1 母子 哪吒 太乙真人 blueviolet 1 师徒 太乙真人 元始天尊 chartreuse 7 师徒 云中子 元始天尊 chocolate 7 师徒 玉鼎真人 元始天尊 coral 7 师徒 王母娘娘 元始天尊 cornflowerblue 7 父女 鸿钧老祖 元始天尊 cornsilk 7 师徒 姜子牙 元始天尊 crimson 7 师徒 太上老君 鸿钧老祖 cyan 3 师徒 灵宝天尊 鸿钧老祖 darkblue 3 师徒 雷震子 云中子 darkcyan 1 师徒 杨戬 玉鼎真人 darkgoldenrod 1 师徒 沉香 杨戬 darkgray 2 舅舅 三圣母 杨戬 darkgreen 2 兄妹 元始天尊 鸿钧老祖 darkmagenta 3 师徒 托塔天王 孙悟空 darkgrey 9 上下级
- 这里需要注意一点,人物的数量和颜色的数量要对应起来,不然会报错:
ValueError: 'c' argument has 23 elements, which is inconsistent with 'x' and 'y' with size 29.
- 从上边的错误看,其实就是我的人物角色有29个,但是颜色只有23个,没有对应起来;
- 为了避免错误,我们把人物和颜色列一个表,需要的时候选对应的数据就行:
孙悟空 aliceblue 菩提祖师 antiquewhite 唐僧 aqua 如来佛祖 aquamarine 观音菩萨 azure 牛魔王 beige 猪八戒 bisque 沙和尚 black 白龙马 blanchedalmond 老鼠精 blue 哪吒 blueviolet 木吒 brown 金吒 burlywood 红孩儿 cadetblue 太乙真人 chartreuse 云中子 chocolate 玉鼎真人 coral 王母娘娘 cornflowerblue 鸿钧老祖 cornsilk 姜子牙 crimson 太上老君 cyan 灵宝天尊 darkblue 雷震子 darkcyan 杨戬 darkgoldenrod 沉香 darkgray 三圣母 darkgreen 托塔天王 darkgrey 铁扇公主 darkkhaki 元始天尊 darkmagenta
3.2 获取目标文件数据
- 读取
excel
中的文件数据:
class TestRelation(): def init(self): super(TestRelation, self).init()获取目标文件数据 self.data = "./relation.xls" self.data_content = pd.DataFrame(pd.read_excel(self.data)>) self.character = self.data_content'character1'.>drop_duplicates().values.tolist() self.characters = self.data_content['character1', 'character2', 'num']
- 比如我们打印一下self.characters:
0 菩提祖师 孙悟空 9 1 唐僧 孙悟空 9 2 如来佛祖 孙悟空 9 3 观音菩萨 孙悟空 9 4 牛魔王 孙悟空 9 5 猪八戒 孙悟空 9 6 沙和尚 孙悟空 9 7 白龙马 孙悟空 9 8 孙悟空 唐僧 6 9 猪八戒 唐僧 6 10 沙和尚 唐僧 6 11 白龙马 唐僧 6 12 观音菩萨 唐僧 6 13 老鼠精 唐僧 6 14 老鼠精 托塔天王 4 15 哪吒 托塔天王 4 16 木吒 托塔天王 4 17 金吒 托塔天王 4 18 木吒 观音菩萨 2 19 红孩儿 观音菩萨 2 20 金吒 如来佛祖 1 21 铁扇公主 牛魔王 2 22 红孩儿 牛魔王 2 23 红孩儿 铁扇公主 1 24 哪吒 太乙真人 1 25 太乙真人 元始天尊 7 26 云中子 元始天尊 7 27 玉鼎真人 元始天尊 7 28 王母娘娘 元始天尊 7 29 鸿钧老祖 元始天尊 7 30 姜子牙 元始天尊 7 31 太上老君 鸿钧老祖 3 32 灵宝天尊 鸿钧老祖 3 33 雷震子 云中子 1 34 杨戬 玉鼎真人 1 35 沉香 杨戬 2 36 三圣母 杨戬 2 37 元始天尊 鸿钧老祖 3 38 托塔天王 孙悟空 9
3.3 获取颜色数据
获取颜色数据self.colors = self.data_content'color'.drop_duplicates().values.tolist() print(self.colors)
- 颜色获取如下:
颜色的输出:'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige', 'bisque', 'black', 'blanchedalmond', 'aliceblue', 'blue', 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'darkkhaki', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkmagenta', 'darkgrey'
3.4 添加边数据
self.my_graph = nx.Graph() for i in self.characters.index: self.my_graph.add_edge(self.characters.character1i, self.characters.character2i, weight=self.characters.numi)
3.5 定义边及权重
定义两个边,边给权重,s起点,e终点,w权重edge1 = (s, e) for (s, e, w) in self.my_graph.edges(data=True) if (w'weight' >= 1) edge2 = (s, e) for (s, e, w) in self.my_graph.edges(data=True) if (w'weight' >= 5)
3.6 图的布局、点、边和标签
图的布局pos = nx.circular_layout(self.my_graph)点 nx.draw_networkx_nodes(self.my_graph, pos, alpha=1, node_size=300, node_color=self.colors, node_shape='o') 边 nx.draw_networkx_edges(self.my_graph, pos, edgelist=edge1, width=1, alpha=0.3, edge_color='g', style='dashed') nx.draw_networkx_edges(self.my_graph, pos, edgelist=edge2, width=1.5, alpha=0.5, edge_color='red') 标签 nx.draw_networkx_labels(self.my_graph, pos, font_size=9)
3.7 展示结果
结果显示 plt.axis('off') plt.title('西游记重点人物简单关系图(只是示例)') plt.rcParams'font.size' = 8plt.rcParams'font.sans-serif' = 'SimHei' plt.show()
3.8 完整源码
代码语言:python代码运行次数:8复制# -*- coding:utf-8 -*-
# 作者:虫无涯
# 作用:network应用
import subprocess
import sys
# 如果需要通过本文运行器运行代码,需要加上这句
subprocess.check_call([sys.executable, "-m", "pip", "install", "networkx"])
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
class TestRelation():
def __init__(self):
super(TestRelation, self).__init__()
# 获取目标文件数据
self.data = "./relation.xls"
self.data_content = pd.DataFrame(pd.read_excel(self.data))
self.character = self.data_content['character1'].drop_duplicates().values.tolist()
self.characters = self.data_content[['character1', 'character2', 'num']]
print(self.characters)
def test_relation(self):
# 设置画布大小,可以使用默认的
# plt.figure(figsize=(4, 5))
# 获取颜色数据
self.colors = self.data_content['color'].drop_duplicates().values.tolist()
print(self.colors)
self.my_graph = nx.Graph()
# 添加边
for i in self.characters.index:
self.my_graph.add_edge(self.characters.character1[i],
self.characters.character2[i],
weight=self.characters.num[i])
# 定义两个边,边给权重,s起点,e终点,w权重
edge1 = [(s, e) for (s, e, w) in self.my_graph.edges(data=True) if (w['weight'] >= 1)]
edge2 = [(s, e) for (s, e, w) in self.my_graph.edges(data=True) if (w['weight'] >= 5)]
# 图的布局
pos = nx.circular_layout(self.my_graph)
# 点
nx.draw_networkx_nodes(self.my_graph, pos, alpha=1, node_size=300,
node_color=self.colors, node_shape='o')
# 边
nx.draw_networkx_edges(self.my_graph, pos, edgelist=edge1, width=1,
alpha=0.3, edge_color='g', style='dashed')
nx.draw_networkx_edges(self.my_graph, pos, edgelist=edge2, width=1.5,
alpha=0.5, edge_color='red')
# 标签
nx.draw_networkx_labels(self.my_graph, pos, font_size=9)
# 结果显示
plt.axis('off')
plt.title('西游记重点人物简单关系图(只是示例)')
plt.rcParams['font.size'] = 8
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决中文乱码
# plt.show()
plt.savefig("pic02.jpg")
if __name__ == "__main__":
relation = TestRelation()
relation.test_relation()
4 人物关系效果图
- 运行上边的完整源码得到如下效果: 在这里插入图片描述
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!