一,项目简介:
利用networkx官方中的CircularTree案例,修改节点的名称,利用唐代诗人姓名与其诗作中的关键字生成的边,形成以诗人关键字为代表的三层环形树状图。
附上原官方的CircularTree图,以及官方代码的链接。
https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_circular_tree.html#sphx-glr-auto-examples-drawing-plot-circular-tree-py
二,实现方法:
1,从全唐诗文本中提取指定诗人的作品,我找到的版本标题含有中文【】,对于处理标题相当有利。
2,逐字解析指定诗人作品中的字,并按出现频率的高低排序,提取出现频率最高的m个字作为关键字(关键字不宜太多);
3,使用关键字搜索指定诗人的作品,将关键字前后的字+关键字组成的词语提取出来,形成列表,并按出现的频率排序,提取m个;
4,将m个关键字与m*m个词语组合成元组,形成networkx中的边;
5,引入networkx画关系图,使用balanced_tree和graphviz_layout组合形成节点名称+位置的字典,替换节点名称为诗人名称+关键字+词语的节点列表;
6,生成圆形树状图。
三,使用到的内置库和第三方库
1,collections中的Counter,用来统计列表中字和词语的个数,生成一个由字词语为键,出现的频率为值的字典;
2,re库,统计关键字在文本中出现的位置k,为提取(k-1)+k和k+(k+1)做必要的准备;
3,networkx中的balanced_tree生成指定的节点,graphviz_layout生成节点信息;Graph和draw生成图形;
4,matplot.pyplot输出图形。
四,附上几张生成的效果,就放李杜白元的作品吧,毕竟他们的作品在全唐诗中出现的比例也是最高的。
五,附上源代码。
from collections import Counter
import re
import networkx as nx
import matplotlib.pyplot as plt
def getTxtByWriter(fn,writer,stopword,n):#获取全唐诗中指定作者的诗
fo=open(fn,'r',encoding='utf-8-sig').readlines()
peomWithWriter=''#诗的内容+作者标题
for i in fo:
if '【' in i:
i=i.replace(i,'!'+i[i.find('【'):])#如果行有中文括号,表示此行为标题
peomWithWriter+=(i.strip('\n'))
else:
peomWithWriter+=(i.strip('\n'))
writerPoemWithIcon=''#诗的内容+标点符号
for i in peomWithWriter.split('!'):#使用split分段开成列表
if '】'+writer in i:#遍历列表是否有作者名称,有的话加入作者诗的字符串集
i=i.split('】')[1]
writerPoemWithIcon+=i.replace(writer,'')#replace(',','').replace('。','').replace(' ','')
return writerPoemWithIcon
def getKeyWord(fn,writer,stopword,n):#获取出现频率最高的字
writerPoemWithIcon=getTxtByWriter(fn,writer,stopword,n)
WordDict=Counter(list(writerPoemWithIcon))#将生成的字符串List成列表,并统计每个字出现的次数
sw=open(stopword,'r',encoding='utf-8').read().split('.')
keyWordList=[]#关键字列表
for k,v in WordDict.items():
if k not in sw and v>n:#如果元素不在stopword中且出现的次数超过n次,就可以加入列表中。
keyWordList.append(k)
return keyWordList
# print(getKeyWord('全唐诗.txt','杜甫','ChineseStopWord.txt',400))
def getConnectWord(fn,writer,stopword,n,m):#文本,作者,停用词,关键字出现的频率,前m个关键字
keyWordList=getKeyWord(fn,writer,stopword,n)[:m]#获取前m个关键字
writerPoemWithIcon=getTxtByWriter(fn,writer,stopword,n)
connectWordList=[]
kwl=[]
a=[writer]+keyWordList
wk=[]
for i in keyWordList:
wk.append((writer,i))
singleWord=[]
list=[j.start() for j in re.finditer(i,writerPoemWithIcon)]#list是关键字i出现位置的列表
for k in list:
if writerPoemWithIcon[k+1] not in ',。 ' and writerPoemWithIcon[k-1] not in ',。 ':
singleWord.append(writerPoemWithIcon[k:k+2])
singleWord.append(writerPoemWithIcon[k-1:k+1])
connectWord=[]
kw=[]
for k,v in sorted(Counter(singleWord).items(),key= lambda x:x[1],reverse=True):#关键字关联词的前m个
connectWord.append((i,k))
kw.append(k)
connectWordList+=connectWord[:m]
kwl=kwl+kw[:m]
return wk+connectWordList,a+kwl
# print(getConnectWord('全唐诗.txt','杜甫','ChineseStopWord.txt',400,6))
def createCircularTree(fn,writer,stopword,n,m):#生成树形分支图
connectWordList, nodeList = getConnectWord(fn, writer, stopword, n,m)
try:
import pygraphviz
from networkx.drawing.nx_agraph import graphviz_layout
except ImportError:
try:
import pydot
from networkx.drawing.nx_pydot import graphviz_layout
except ImportError:
raise ImportError("This example needs Graphviz and either "
"PyGraphviz or pydot")
plt.figure(figsize=(10, 10),facecolor='blue')
g=nx.Graph()
pos=graphviz_layout(nx.balanced_tree(m,3),prog='twopi')
g.add_edges_from(connectWordList)
p=dict(zip(nodeList,pos.values()))
d=dict(g.degree)
nx.draw(g,p,with_labels=True,nodelist=d.keys(),node_size=[v*400 for v in d.values()],node_color=range(len(nodeList)),
cmap=plt.cm.Blues,alpha=0.8)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.savefig('%s诗的主要意象.png'% writer,dpi=100)