(在模仿中精进数据可视化05)疫情期间市值增长top25公司
本文完整代码及数据已上传至我的
Github
仓库https://github.com/CNFeffery/FefferyViz
1 简介
新冠疫情对很多实体经济带来冲击的同时,也给很多公司带来了新的增长点。前段时间我看到图1所示的数据可视化作品,针对2020年1月1日到6月16日之间,世界范围内市值增大最多的25家公司进行可视化:
图1
这样一张典型的商业图表,看起来形式巧妙,且表现出很多数据信息。而今天的文章,我就将带大家学习如何利用matplotlib
来条理清楚地制作出这种类型的可视化作品。
2 模仿过程
首先我们还是像过往的文章中一样分析一下原作品的元素构成:
- 立体感的营造
其实原作品咋一看起来的立体感,只是玩了个花招,我们本质上只需要创建出最左列竖直方向上等分25份的填充区域,再向右偏移适合的距离后,缩小竖直方向上的总体范围再25等分,最后将这两部分等分的填充区域连接起来,最后再为中间的连接区域蒙上一层等大小的带透明度的暗色蒙版即可~
- logo与国旗图片的插入
原作品中众多图片,只要仔细观察就可以发现是手动PS上去的,存在着一些微小的瑕疵,而我们既然要用matplotlib
来制作这张图,当然直接写循环控制图片的插入即可。
在matplotlib
中向画板插入其他图片有很多方法,我们为了控制好众多logo之间的协调,可以使用matplotlib
中的inset_axes()
来插入指定位置和尺寸的子图。
- 数值标注的控制
原作品中不同公司市值增长的不同体现在不同长度柱体以及不同大小文字标注的映射之上的,我们可以配合简单的归一化变换,来约束字体和柱体长度的映射。
搞明白原作品中主要元素的实现方式之后,我们首先来读入原始数据(你可以在文章开头的Github
仓库中找到原始数据及相关附件):
import matplotlib.pyplot as plt
import pandas as pd
# 设置默认字体
plt.rcParams['font.sans-serif'] = ['Times New Roman']
raw = pd.read_excel('data.xlsx')
raw.head()
图2
接着为了方便处理公司类型向指定配色的映射,我们先来创建一个映射字典:
type2color = {
'Technology': '#e2a080',
'E-Commerce': '#ebb66a',
'Automotive': '#c198ba',
'Finance': '#aab5d8',
'Tele-communications': '#bdd7e4',
'Media': '#efcfde',
'Software': '#d5c1c4',
'Pharmaceutical': '#f9e4ad',
'Alcohol': '#c3d3ac',
'Retail': '#88bb70'
}
而为了创建出原作品中最重要的不同条带,我们可以配合matplotlib
中的fill_between()
。
而为了处理好左侧与右侧的竖直方向25等分区域,我们可以在对原数据每一行循环的过程中,自定义下列函数来计算区域范围:
def create_fill_area(row, top_y=0.8, bottom_y=0.01):
# 初始化包围填充区域的上下线条y坐标
line1, line2 = [1 - 0.04*row, 1 - 0.04*row], [1- 0.04*(row+1), 1- 0.04*(row+1)]
# 追加阴影段y坐标
line1.append(0.01 + (25 - row) * (0.8 - 0.01) / 25)
line2.append(0.01 + (25 - row - 1) * (0.8 - 0.01) / 25)
# 追加最后一段平行段y坐标
line1.append(0.01 + (25 - row) * (0.8 - 0.01) / 25)
line2.append(0.01 + (25 - row - 1) * (0.8 - 0.01) / 25)
return line1, line2
做好这些准备工作之后,剩余的绘图过程就很简单了,最终得到的模仿作品如下:
图3
完整代码如下,虽然看起来略多,其实大部分都是重复的逻辑传入不同的参数而已,还是比较简单的:
fig, ax = plt.subplots(figsize=(4.8, 6))
ax.set_xlim(0, 1.01)
ax.set_ylim(0, 1)
for row in range(raw.shape[0]):
# 定义区域填充对应的x坐标
x = [0, 0.15, 0.215, 0.6+raw.at[row, 'Grown'] / 1000]
# 生成区域填充对应的y坐标
line1, line2 = create_fill_area(row)
# 对指定区域进行填充
ax.fill_between(x,
line1,
line2,
color=type2color[raw.at[row, 'Type']],
edgecolor='none')
# 从logo文件夹下读取对应logo图片
try:
logo = plt.imread(f'logo/{raw.at[row, "Company"]}.png')
except FileNotFoundError:
logo = plt.imread(f'logo/{raw.at[row, "Company"]}.jpg')
# 插入公司logo
ax_logo = ax.inset_axes((0.05, 1 - 0.04*(row+1)+0.005, 0.08, 0.025))
ax_logo.imshow(logo)
ax_logo.axis('off')
ax_logo.set_facecolor(type2color[raw.at[row, 'Type']])
# 处理单个及多个国家情况下的国旗绘制
for idx, country in enumerate(raw.at[row, 'Country'].split('&')[::-1]):
# 读取对应国旗图片
flag = plt.imread(f'flag/{country}.png')
# 插入国旗子图
ax_flag = ax.inset_axes((0.545-idx*0.06, 0.013+(25 - row - 1)*((0.8 - 0.01) / 25), 0.1, 0.025))
ax_flag.imshow(flag)
ax_flag.axis('off')
ax_flag.set_facecolor(type2color[raw.at[row, 'Type']])
# 绘制排名
ax.text(0.025, (1 - 0.04*row + 1 - 0.04*(row+1)) / 2, str(row+1),
ha='center', va='center',
fontsize=5, color='black')
# 绘制公司名称
ax.text(0.215+0.01, 0.5 * (0.01 + (25 - row - 1) * (0.8 - 0.01) / 25 + 0.01 + (25 - row) * (0.8 - 0.01) / 25),
raw.at[row, 'Company'],
ha='left', va='center',
fontsize=6, color='#494948',
weight='bold')
# 处理第一名文字在填充区域内部,其余文字在填充区域外的情况
if raw.at[row, 'Company'] == 'Amazon':
ax.text(1, 0.5 * (0.01 + (25 - row) * (0.8 - 0.01) / 25
+ 0.01 + (25 - row - 1) * (0.8 - 0.01) / 25)-0.0025,
'$'+str(raw.at[row, 'Grown'])+'B',
color='white',
fontsize=10,
ha='right',
va='center',
weight='bold')
else:
# 配合归一化对字体进行大小映射
ax.text(0.6+raw.at[row, 'Grown'] / 1000 + 0.01,
0.5 * (0.01 + (25 - row) * (0.8 - 0.01) / 25 + 0.01 + (25 - row - 1) * (0.8 - 0.01) / 25)-0.0025,
'$'+str(raw.at[row, 'Grown'])+'B',
color=type2color[raw.at[row, 'Type']],
fontsize=5+((raw.at[row, 'Grown'] - raw['Grown'].min())
/ (raw['Grown'].max() - raw['Grown'].min())) * 5,
ha='left',
va='center',
weight='bold')
# 对指定区域进行带透明度的黑色蒙版,以达到阴影效果
ax.fill_between([0.15, 0.215],
[0, 0.01],
[1, 0.8],
color='black',
alpha=0.2, # 设置透明度
edgecolor='none')
# 补充其余文字标注
ax.text(0.215+0.01, 0.805, 'Company',
color='#565555', fontsize=5,
ha='left')
ax.text(0.6, 0.805, 'Country',
color='#565555', fontsize=5,
ha='center')
# 补充上方数值刻度
ax.text(0.6, 0.825, '0',
color='#a9a8a8', fontsize=4,
ha='center')
for i in range(1, 5):
ax.text(0.6+0.1*i, 0.825, f'${i}00B',
color='#a9a8a8', fontsize=4,
ha='center')
ax.vlines(0.6+0.1*i, 0.01, 0.82,
color='#dcdcdb', linewidth=0.2)
ax.set_xticks([])
ax.set_yticks([])
ax.spines['left'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_color('none')
# 补充下排图例
ax_bar1 = ax.inset_axes((0.215, 0.88, 0.57, 0.02), transform=ax.transAxes)
ax_bar1.set_xlim(-0.45, 4.45)
ax_bar1.bar(range(5), height=1, width=0.9,
color=['#efcfde', '#d5c1c4', '#f9e4ad', '#c3d3ac', '#88bb70'])
ax_bar1.set_xticks(range(5))
ax_bar1.set_xticklabels(['Media', 'Software', 'Pharmaceutical', 'Alcohol', 'Retail'],
fontsize=5, color='#4f4e4e', weight='bold')
ax_bar1.set_yticks([])
ax_bar1.spines['left'].set_color('none')
ax_bar1.spines['right'].set_color('none')
ax_bar1.spines['top'].set_color('none')
ax_bar1.spines['bottom'].set_color('none')
ax_bar1.tick_params(color='none', pad=-2)
ax_bar1.set_facecolor('#f8f8f8')
# 补充上排图例
ax_bar2 = ax.inset_axes((0.215, 0.98, 0.57, 0.02), transform=ax.transAxes)
ax_bar2.set_xlim(-0.45, 4.45)
ax_bar2.bar(range(5), height=1, width=0.9,
color=['#e2a080', '#ebb66a', '#c198ba', '#aab5d8', '#bdd7e4'])
ax_bar2.set_xticks(range(5))
ax_bar2.set_xticklabels(['Technology', 'E-Commerce', 'Automotive', 'Finance', 'Tele-\ncommunications'],
fontsize=5, color='#4f4e4e', weight='bold')
ax_bar2.set_yticks([])
ax_bar2.spines['left'].set_color('none')
ax_bar2.spines['right'].set_color('none')
ax_bar2.spines['top'].set_color('none')
ax_bar2.spines['bottom'].set_color('none')
ax_bar2.tick_params(color='none', pad=-2)
ax_bar2.set_facecolor('#f8f8f8')
ax.set_facecolor('#f8f8f8')
fig.set_facecolor('#f8f8f8')
fig.savefig('图3.png', dpi=800, bbox_inches='tight')
你可以自由尝试不同的配色方案,或者换成你的数据,快速制作出同样别致的可视化作品
(在模仿中精进数据可视化05)疫情期间市值增长top25公司的更多相关文章
- (在模仿中精进数据可视化03)OD数据的特殊可视化方式
本文完整代码已上传至我的Github仓库https://github.com/CNFeffery/FefferyViz 1 简介 OD数据是交通.城市规划以及GIS等领域常见的一类数据,特点是每一条数 ...
- 在模仿中精进数据分析与可视化01——颗粒物浓度时空变化趋势(Mann–Kendall Test)
本文是在模仿中精进数据分析与可视化系列的第一期--颗粒物浓度时空变化趋势(Mann–Kendall Test),主要目的是参考其他作品模仿学习进而提高数据分析与可视化的能力,如果有问题和建议,欢迎 ...
- Python利用Plotly实现对MySQL中的数据可视化
Mysql表数据: demo.sql内容 create table demo( id int ,product varchar(50) ,price decimal(18,2) ,quantity i ...
- CNN中tensorboard数据可视化
1.CNN_my_test.py import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data ...
- Python - matplotlib 数据可视化
在许多实际问题中,经常要对给出的数据进行可视化,便于观察. 今天专门针对Python中的数据可视化模块--matplotlib这块内容系统的整理,方便查找使用. 本文来自于对<利用python进 ...
- 数据可视化利器pyechart和matplotlib比较
python中用作数据可视化的工具有多种,其中matplotlib最为基础.故在工具选择上,图形美观之外,操作方便即上乘. 本文着重说明常见图表用基础版matplotlib和改良版pyecharts作 ...
- Python数据可视化——散点图
PS: 翻了翻草稿箱. 发现竟然存了一篇去年2月的文章...尽管naive.还是发出来吧... 本文记录了python中的数据可视化--散点图scatter, 令x作为数据(50个点,每一个30维), ...
- 利用AJAX JAVA 通过Echarts实现豆瓣电影TOP250的数据可视化
mysql表的结构 数据(数据是通过爬虫得来的,本篇文章不介绍怎么爬取数据,只介绍将数据库中的数据可视化): 下面就是写代码了: 首先看一下项目目录: 数据库层 业务逻辑层 pac ...
- R语言与医学统计图形-【30】流行病学数据可视化
sjPlot包适用于社会科学.流行病学中调查数据可视化,且能和SPSS数据无缝对接(流行病学问卷调查录入Epidata软件后,都会转成SPSS格式或EXCEL格式保存). 辅助包sjmisc进行数据转 ...
随机推荐
- Java学习的第二十四天
1. 目录管理 2.文件方法太多记不清 3.明天学习流和流的分类
- Asp.Net Core学习笔记:入门篇
Asp.Net Core 学习 基于.Net Core 2.2版本的学习笔记. 常识 像Django那样自动检查代码更新,自动重载服务器(太方便了) dotnet watch run 托管设置 设置项 ...
- Ideas and Tricks
1.树上拓扑排序计数 结论$\dfrac{n!}{\prod\limits_{i=1}^n size_i}$ 对于节点$i$,其子树随意排序的结果是$size[i]!$ 但$i$需要排在第一位,只有$ ...
- MySQL查询这一篇就够了
1. 条件 使用where子句对表中的数据筛选,结果为true的行会出现在结果集中 语法如下: select * from 表名 where 条件; 例: select * from students ...
- php抽奖程序
//php概率抽奖算法 1.获取总的概率数 2.随机从1到总概率数 3.判断获取的随机数是否在小于等于(就是你随机的数是否在数组值得范围中比如数组为array(1,2,3,4,5,6)则随机出了一个数 ...
- 21 Ajax
21 Ajax AJAX,Asynchronous JavaScript and XML(异步的 JavaScript 和 XML), 是与在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页 ...
- Java实现FTP跨服务器文件操作
在过去的几年工作中,曾经多次需要把文件上传到单独的服务器,而程序是在单独的服务器上部署的,在进行文件操作的时候就需要跨服务器进行操作包括:文件上传.文件下载.文件删除等.跨服务器文件操作一般是需要FT ...
- excel导出csv包括逗号等的处理
/** * @Title: trimRubbishChar * @Description: 导出的时候需要对一格的内容进行检查,看是否有非法字符,以免串行 * @Since: 2016年8月2日 下午 ...
- jdk+tomcat 文件下载
1.下载jdk+tomcat 链接:https://pan.baidu.com/s/1DQ-l2S4th9BoucWqAymmLg :密码: zdd3 备:tomcat是解压包,直接解压就能用,但需配 ...
- orphan sockets
orphan sockets 介绍一下什么是 orphan sockets,简单来说就是该 socket 不与任何一个文件描述符相关联.例如,当应用调用 close() 关闭一个链接时,此时该 soc ...