参考博客在这里:https://blog.youkuaiyun.com/yaoyefengchen/article/details/79427475
Echarts 已经更新到了 ver.4 版本,原文用的是网页版的 Echarts,获取数据后还要在网页中修改数据生成图表,有大神基于 Echarts 写了一个 pyecharts 库,这样就可以一键获取数据生成图表了,代价就是多写几行代码,Python 3.6 测试通过。
1. 准备工作
准备库:
- wxpy
- pyecharts
- echarts-countries-pypkg
- jieba
- pandas
- numpy
都可以直接用 pip 命令进行安装,没有用到原文中的 scipy 和 wordcloud 库,因为我直接用了 pyecharts 里的 wordcloud,也没有用自定义图像。
自从 v0.3.2 开始,为了缩减项目本身的体积以及维持 pyecharts 项目的轻量化运行,pyecharts 将不再自带地图 js 文件。如用户需要用到地图图表,可自行安装对应的地图文件包。
echarts-countries-pypkg 就是我们需要的地图包,包含世界地图和 213 个国家,其中包括中国地图。
2. 获取数据
获取微信好友的性别、位置和个性签名等方法跟原文一样,所以我就不写了,主要是 pyecharts 库的使用。
3. 绘制图表
3.1 微信好友男女比例
饼图主要用于表现不同类目的数据在总和中的占比。每个的弧度表示数据数量的比例。
Pie.add() 方法:
add(name, attr, value,
radius=None,
center=None,
rosetype=None, **kwargs)
name -> str
图例名称attr -> list
属性名称value -> list
属性所对应的值radius -> list
饼图的半径,数组的第一项是内半径,第二项是外半径,默认为 [0, 75],默认设置成百分比,相对于容器高宽中较小的一项的一半center -> list
饼图的中心(圆心)坐标,数组的第一项是横坐标,第二项是纵坐标,默认为 [50, 50]
默认设置成百分比,设置成百分比时第一项是相对于容器宽度,第二项是相对于容器高度rosetype -> str
是否展示成南丁格尔图,通过半径区分数据大小,有"radius"
和"area"
两种模式。默认为"radius"
radius
:扇区圆心角展现数据的百分比,半径展现数据的大小area
:所有扇区圆心角相同,仅通过半径展现数据大小
from pyecharts import Pie
pie = Pie("微信好友男女比例", width=1200, height=400)
pie.add("", sex_dict.keys(), sex_dict.values(), is_label_show=True)
pie.render()
sex_dict
是第二步中获取的性别字典。
调用 render()
方法默认会在相同目录下生成一个 render.html
文件,打开就可以看到结果
3.2 微信好友全国分布图
地图主要用于地理区域数据的可视化。
Map.add() 方法:
add(name, attr, value,
maptype='china',
is_roam=True,
is_map_symbol_show=True, **kwargs)
name -> str
图例名称attr -> list
属性名称value -> list
属性所对应的值maptype -> str
地图类型is_roam -> bool/str
是否开启鼠标缩放和平移漫游,默认为True
。如果只想要开启缩放或者平移,可以设置成"scale"
或者"move"
。设置成True
为都开启is_map_symbol_show -> bool
是否显示地图标记红点,默认为True
。
from pyecharts import Map
friends_map = Map("微信好友全国分布图", width=1200, height=600)
friends_map.add(
"",
province_dict.keys(),
province_dict.values(),
is_label_show=True,
is_visualmap=True,
visual_range=[0, max(province_dict.values())],
visual_range_text=['少', '多'],
visual_range_color=['#FFFF00', '#D6292B'] # [黄,红]由低到高
)
friends_map.render()
province_dict
就是获取的省份统计字典。
is_visualmap
设为 True
启用视觉映射组件。
visual_range
指定组件的允许的最小值与最大值。这里最大值设为省份数的最大值。
visual_range_text
两端文本。
visual_range_color
过渡颜色,这里设置为由黄到红,没有设为纯红,因为太亮眼了。
3.3 微信好友签名统计
WordCloud(词云图)
WordCloud.add() 方法:
add(name, attr, value,
shape="circle",
word_gap=20,
word_size_range=None,
rotate_step=45)
name -> str
图例名称attr -> list
属性名称value -> list
属性所对应的值shape -> list
词云图轮廓,有'circle'
,'cardioid'
,'diamond'
,'triangle-forward'
,'triangle'
,'pentagon'
,'star'
可选word_gap -> int
单词间隔,默认为 20。word_size_range -> list
单词字体大小范围,默认为 [12, 60]。rotate_step -> int
旋转单词角度,默认为 45
from pyecharts import WordCloud
words_cloud = WordCloud("微信好友个性签名词云", width=1200, height=600)
word_freq = {x[0]: x[1] for x in words_stat.head(100).values}
words_cloud.add(
"",
word_freq.keys(),
word_freq.values(),
shape="circle"
)
word_cloud.render()
word_stat
是统计的词频。
3.4 在同一页面显示
from pyecharts import Page
page = Page("")
page.add(pie).add(friends_map).add(words_cloud)
page.render()
使用 add()
向 page 中添加之前生成的三个图。打开 render.html
文件就可以看到三个图表直接显示在一个网页中,十分方便查看。
4. 总结
pyecharts 官网上还有很多可用的图表,官方例程也十分简洁明了,而且已经支持 Django/Flask 等框架,可以部署在网页上,也正是我现在在做的。wxpy 还有很多功能没有被用到,多多发掘就会有更多有趣的应用产生。
5. 完整代码
代码基于原博进行了适当的修改
from wxpy import Bot
from pyecharts import Pie, Map, WordCloud, Page
import re
import jieba
import pandas as pd
import numpy
def write_txt_file(path, txt):
"""
写入 txt 文本
"""
with open(path, 'a', newline='') as f:
f.write(txt)
def read_txt_file(path):
'''
读取 txt 文本
'''
with open(path, 'r', newline='') as f:
return f.read()
def login():
# 初始化机器人,扫码登录
bot = Bot()
# 获取所有好友
my_friends = bot.friends()
return my_friends
def get_sex_ratio(friends):
"""
统计好友男性和女性的数量
"""
sex_dict = {'男性': 0, '女性': 0}
for friend in friends:
if friend.sex == 1:
sex_dict['男性'] += 1
elif friend.sex == 2:
sex_dict['女性'] += 1
return sex_dict
def get_area_distribution(friends):
"""
统计各省好友数量
"""
province_dict = {
'北京': 0, '上海': 0, '天津': 0, '重庆': 0, '河北': 0,
'山西': 0, '吉林': 0, '辽宁': 0, '黑龙江': 0, '陕西': 0,
'甘肃': 0, '青海': 0, '山东': 0, '福建': 0, '浙江': 0,
'台湾': 0, '河南': 0, '湖北': 0, '湖南': 0, '江西': 0,
'江苏': 0, '安徽': 0, '广东': 0, '海南': 0, '四川': 0,
'贵州': 0, '云南': 0, '内蒙古': 0, '新疆': 0, '宁夏': 0,
'广西': 0, '西藏': 0, '香港': 0, '澳门': 0
}
for friend in friends:
# 统计省份
if friend.province in province_dict:
province_dict[friend.province] += 1
return province_dict
def get_signatures(friends):
"""
统计签名
"""
for friend in friends:
# 对数据进行清洗,将标点符号等对词频统计造成影响的因素剔除
pattern = re.compile(r'[一-龥]+')
filterdata = re.findall(pattern, friend.signature)
write_txt_file('signatures.txt', ''.join(filterdata))
content = read_txt_file('signatures.txt')
segment = jieba.lcut(content)
words_df = pd.DataFrame({'segment': segment})
stopwords = pd.read_csv(
'chineseStopWords.txt',
index_col=False,
quoting=3,
sep=' ',
names=['stopword']
)
words_df = words_df[~words_df.segment.isin(stopwords.stopword)]
words_stat = words_df.groupby(by=['segment'])['segment'].agg({"计数": numpy.size})
words_stat = words_stat.reset_index().sort_values(by=['计数'], ascending=False)
return words_stat
def show_page(sex_dict, province_dict, words_stat):
"""
将图表渲染为一个 html 页面
"""
pie = Pie("微信好友男女比例", width=1200, height=400)
pie.add("", sex_dict.keys(), sex_dict.values(), is_label_show=True)
friends_map = Map("微信好友全国分布图", width=1200, height=600)
friends_map.add(
"",
province_dict.keys(),
province_dict.values(),
is_label_show=True,
is_visualmap=True,
visual_range=[0, max(province_dict.values())],
visual_range_text=['少', '多'],
visual_range_color=['#FFFF00', '#D6292B'] # [黄,红]由低到高
)
words_cloud = WordCloud("微信好友个性签名词云", width=1200, height=600)
word_freq = {x[0]: x[1] for x in words_stat.head(100).values}
words_cloud.add(
"",
word_freq.keys(),
word_freq.values(),
shape="circle"
)
# 使用 Page,将图表添加至一个页面
page = Page("")
page.add(pie).add(friends_map).add(words_cloud)
page.render()
if __name__ == '__main__':
friends = login()
sex_dict = get_sex_ratio(friends)
province_dict = get_area_distribution(friends)
words_stat = get_signatures(friends)
show_page(sex_dict, province_dict, words_stat)