如何用Python绘制深小卫推文中的病例图
前面的文章介绍了如何用Python绘制南丁格尔玫瑰图,链接:循序渐进,学会用pyecharts绘制玫瑰图
南丁格尔玫瑰图最初被用于统计军医数据,现在也常用于疫情数据统计。例如在深圳,大家基本每天都会看卫健委的数据,里面就有玫瑰图。
本文介绍如何使用Python实现相同的玫瑰图。
数据录入
根据原始图形中的数据,先将数据录入到代码中。
import pandas as pd
from pyecharts.charts import Pie
from pyecharts import options as opts
data = {
'中国香港': [1234, 2], '美国': [66, 0], '日本': [58, 0], '新加坡': [52, 1], '俄罗斯': [49, 0],
'加拿大': [43, 1], '韩国': [38, 0], '南非': [23, 0], '泰国': [16, 0], '柬埔寨': [15, 0],
'印尼': [11, 0], '英国': [9, 0], '阿联酋': [8, 0], '菲律宾': [7, 0], '几内亚': [4, 0],
'马来西亚': [3, 0], '印度': [3, 0], '尼日利亚': [3, 0], '伊拉克': [2, 0], '毛里求斯': [2, 0],
'阿尔及利亚': [2, 0], '刚果(金)': [2, 0], '德国': [2, 0], '中国台湾': [2, 0], '土耳其': [1, 0],
'瑞士': [1, 0], '斯里兰卡': [1, 0], '巴西': [1, 0], '奥地利': [1, 0], '约旦': [1, 0],
'秘鲁': [1, 0], '塞拉利昂': [1, 0], '加纳': [1, 0], '墨西哥': [1, 0], '澳大利亚': [1, 0],
'匈牙利': [1, 0], '新西兰': [1, 0], '加蓬': [1, 0], '伊朗': [1, 0], '蒙古': [1, 0],
'卡塔尔': [1, 0], '肯尼亚': [1, 0], '沙特阿拉伯': [1, 0], '越南': [1, 0]
}
原始数据用字典的方式录入,key表示国家,值使用列表,第一个值表示现有数量,第二个值表示新增数量。
绘制南丁格尔图
current_no_repeat = sorted(list(set([num[0] for num in data.values()])))
height_graph = [v for v in range(50, 50+len(current_no_repeat))]
area_dict = {k: v for k, v in zip(current_no_repeat, height_graph)}
overseas = {
'country': [c for c in data.keys()],
'current': [num[0] for num in data.values()],
'new': [num[1] for num in data.values()],
'area': [area_dict[k] for k in [num[0] for num in data.values()]]
}
df_overseas = pd.DataFrame(overseas)
pie = Pie(init_opts=opts.InitOpts(width='800px', height='600px', bg_color='white'))
pie.add(
'', [list(z) for z in zip(list(reversed(list(df_overseas['country']))), sorted(list(df_overseas['area'])))],
radius=['25%', '80%'], center=['50%', '50%'], rosetype="area",
itemstyle_opts=opts.ItemStyleOpts(border_width=1, border_color='white'),
label_opts=opts.LabelOpts(formatter="{b}", position='inside', color='white', font_size=8, font_weight='bolder')
).set_global_opts(
title_opts=opts.TitleOpts(title='深圳境外输入\n 确诊病例', pos_left='44%', pos_top='43%',
title_textstyle_opts=opts.TextStyleOpts(color='rgb(43, 70, 213)', font_size=14)),
legend_opts=opts.LegendOpts(is_show=False)
).render('overseas1.html')
代码要点介绍:
-
使用area模式:rosetype参数设置为area,所有扇形圆心角相同,仅通过半径展现数据大小。 -
绘图半径调整:原始数据中最大的数是1234,最小的数是1,差距太大。如果按照数据大小来展示玫瑰图的半径,数据为1的组看不到图形。 所以代码中先提取了数据中非重复的值,然后给每个非重复值从50开始递增设置绘图的半径高度。 -
调整显示比例:运行代码,如果结果显示的范围与原图的差异很大,则调整半径等数据。
设置图形颜色和内部环形
玫瑰图的形状绘制好后,继续设置颜色等其他部分。
gap1, gap2 = 7, 14
color_graph = [v for v in range(60, 60+gap1*(len(current_no_repeat)//2), gap1)] + \
[v for v in range(60+gap1*(len(current_no_repeat)//2), 60+gap1*(len(current_no_repeat)//2) +
gap2*(len(current_no_repeat)-len(current_no_repeat)//2), gap2)]
color_dict = {k: v for k, v in zip(current_no_repeat, sorted(color_graph, reverse=True))}
color = ['rgb({a},{a},{a})'.format(a=color_dict[v[0]]) if v[1] == 0 else 'rgb(43, 70, 213)' for v in data.values()]
pie = Pie(init_opts=opts.InitOpts(width='800px', height='600px', bg_color='white'))
pie.add(
'', [list(z) for z in zip(list(reversed(list(df_overseas['country']))), sorted(list(df_overseas['area'])))],
radius=['25%', '80%'], center=['50%', '50%'], rosetype="area",
itemstyle_opts=opts.ItemStyleOpts(border_width=1, border_color='white'),
label_opts=opts.LabelOpts(formatter="{b}", position='inside', color='white', font_size=8, font_weight='bolder')
).add(
'', [list(z) for z in zip([1], [1])],
radius=['24%', '25.5%'], center=['50%', '50%'],
itemstyle_opts=opts.ItemStyleOpts(color='rgb(43, 70, 213)'),
label_opts=opts.LabelOpts(is_show=False)
).add(
'', [list(z) for z in zip([1], [1])],
radius=['22%', '22.5%'], center=['50%', '50%'],
itemstyle_opts=opts.ItemStyleOpts(color='rgb(43, 70, 213)'),
label_opts=opts.LabelOpts(is_show=False)
).set_global_opts(
title_opts=opts.TitleOpts(title='深圳境外输入\n 确诊病例', pos_left='44%', pos_top='43%',
title_textstyle_opts=opts.TextStyleOpts(color='rgb(43, 70, 213)', font_size=14)),
legend_opts=opts.LegendOpts(is_show=False)
).set_colors(
list(reversed(color))
).render('overseas.html')
代码要点介绍:
- 颜色渐变设置:原图中的颜色由渐变的灰色构成,如果新增病例大于0,则对应的扇形变为蓝色。
灰色是RGB三原色都相等的颜色,代码中用两个变量gap1和gap2来调整颜色值的渐变,蓝色用取色器从原图中获取其颜色值。 - 玫瑰图内部环形:在Pie对象绘制主图形的后面继续链式调用add()方法,在内部绘制两个环形图,调整大小和颜色等参数满足要求。
- 调整标题的位置:设置标题的位置、颜色,使其显示在图形的中间。
绘制的图形和原图对比:
整体上对比,图形一样了,但图形里的数据标签位置不一样。
用办公软件处理数据标签
我用pyecharts设置标签时,调试了很多时间,都没有完成原图中的效果。
所以我推测,原图的标签不是用代码完成的,原因为:
- 原图中的国家名和数据的位置不统一,大小等格式也不一样。标签设置时使用富文本rich参数也基本实现不了。
- 绘图的数据不是病例数据,而是处理后的半径高度数据,标签设置时使用formatter参数无法传入绘图外的数据。
所以,我将数据标签隐藏了,然后手动用办公软件给图形加数据标签,结果如下:
总结
本文以深圳卫健委中的图形为例,实践如何用Python画展示病例的南丁格尔玫瑰图。
如果文中有不妥之处,欢迎指正,如果本文对你有帮忙,欢迎点赞、在看和分享。
相关阅读 循序渐进,学会用pyecharts绘制玫瑰图
|