python设置y轴的值_Python数据可视化,我是如何做出泡泡堆积关联图

公众号发送"可视化",获取源码与数据

前言

有小伙伴说,使用 matplotlib 做出来的图表比不上其他的基于 js 包装的库(pyechart、bokeh、plotly等)漂亮,他们可以还可以交互。同时,基于 matplotlib  包装的 seaborn 似乎也比较省代码。

本想写一篇文章整体说一下这些库的对比,但是如果没有实际例子不太符合我的风格。

因此,今天的目标图表是其他上层可视化库难以做到(或者根本无法完成):

fce6a2f49de42124001fc383454f4e5d.png
  • 此图表是模仿《经济学人》,是关于加拿大移民与出生地相关的图表

那些基于 js 包装的可视化库,在js环境下,按理应该是可以做到。但在 Python 中就不会这么乐观

有机会我会分享 d3.js 的做法,你会发现他与 matplotlib  的思路很相似

本文所需要的库如下:

e8ce195d3c4d863a80d05b5866a5a03a.png
  • 行8:cycler 包只是为了方便定义颜色板

数据是这样子:

d732321241f613950ff6350a2fbf37f5.png
  • 行3:泡泡图的数据列

  • 行4:堆积图的数据列

本文所有的通用函数以宽表作为依据,行索引放 X 轴,每一列作为不同的图表系列

这是颜色的定义:

fa6c2ec4f891b4d0fb70fe1b4a6be492.png
  • m_color_cycle 定义了7个系列的颜色,颜色值提取自示例图表

  • m_bubble_color 是泡泡图的颜色

篇幅有限,我不会对所有的知识点都作详细讲解


逐一击破

通常复杂的可视化是通过多种类型的图形组合而成,显然这次的目标图表是由3个部分组成:

  1. 堆积图,实际就是四边形图形而已

  2. 泡泡图,实际就是圆圈图形

  3. 中间作为连接修饰的长方形

为什么我用"图形"去描述他们?

如果你使用一些上层的可视化库,你会发现他们会在图表类型层面归类,这无疑让你能快速作图。但缺点就是无法随心所欲定制化图表。

而 matplotlib  提供了底层"图形"的控制,同时也提供了基本图表操作。

首先看看如何做出堆积图,下面以2个系列作为示例:

dd8514402c79e0d3fcd07c434f9fd9e4.png
  • 行7:使用 Axes.bar 方法可以画出柱状图,其中 bottom 参数决定了每个柱子的起始位置,默认情况下全是0

  • 行11:当画第二个系列时,只要把第一个系列的 y 值设置为 第二系列 的 起始点,自然而然就做出了堆积图的效果

图表如下:

deda526de7411fd8dd1d1432d1ded365.png

知道这个原理,那么就可以定义通用的函数:

c401a24fb53364def974d16926a1427d.png
  • 本文所有的通用函数都基于宽表数据

  • 行3:通过累计求和+偏移操作,求出每个系列的 bottom 值

  • 行5:直接从 DataFrame 中遍历取出每一列,分别画柱子。m_color_cycle 是之前定义好的颜色板

行3是基本的 pandas 操作,有兴趣可以参考我的 pandas 专栏

调用如下:

db73d538edff022fd091528d251f2ce3.png
  • 行3:原数据有多余的列,要选出需要的列,然后按第一年的值,横向排序一下

图表如下:

b7d42789ffb0271042c9cd576def31a6.png

基本的图表做出来,最后再调整一些细节(比如y轴的位置,刻度线等等),因为这些只是一些操作,非常简单。

接下来做泡泡图


图形属性映射

数据可视化的本质,实际是数据到图形元素的映射。

看看之前的堆积图,我们成功把数据中的3种维度数据映射上去:

  1. 年份,映射到柱子的水平位置(x轴位置)

  2. 数值,映射到柱子的高度(调用 bar 方法时的参数 height)

  3. 地区,映射到柱子的颜色

看一个极端的例子。数据中还有一列移民人数(migrant),我们仍然可以往堆积图上映射:

d2d855c383c3be08c2af40fc85992a0d.png

虽然现在图表看起来非常奇怪,但的确是可行:

36338a869944df2ec59453fcef31aaa9.png
  • 每一年的柱子宽度与数据 migrant 关联起来,柱子越宽,表示那一年移民人数越多

现在,你应该感受到数据可视化的本质,同时也看到,每一种的图表可以合理映射的维度是有限的。

比如上面的堆积图的柱子宽度显然不是一个合理映射属性。

解决方法就是用其他的"图形"继续做映射。

我们在同一个坐标系上画散点图,映射关系如下:

  • 圆点的水平位置映射为年份

  • 圆点的垂直位置映射为固定值(只要在柱子的下方就可以)

  • 圆点的半径映射为数据 migrant

代码如下:

4b7161c5681a726de2c5bbec1033a680.png
  • 本文所有通用函数基于 DataFrame 固定列名。比如数据中需要有名为 size 的列,此列作为泡泡的大小。

  • 行6:Axes.scatter 即可画出圆点,参数 s 就是圆点的半径

  • 参数 clip_on 设置为 False,可以防止圆点太大超出了可视区被裁剪

调用如下:

a69a2e5f3d9cd6ee7b8c06231b59d4ac.png
  • 行6:把列名修改合适

  • 行7:参数y,决定泡泡的位置。注意这里的 -25 是对应图表上y轴的数值

看看图表:

e30b9d9b58ad539178c91859796a3b1e.png

下一步,加上中间连接修饰的矩形框


画图形

matplotlib 内置了许多基本图形,因此创建图形不是什么难事:

584ce5d07a4f672730decbd003a6ef48.png
  • 这是在

  • 行9:创建一个矩形,第一个参数是系列,表示 x、y 的位置。

  • 行10:往坐标系中加入这个图形

注意,上面行9中设置的参数的数值,默认是按数据表示。

比如,[0,40] 的40,相当于指定矩形的左下角点位于 y 轴值为 40 的位置

但是,[0,40] 的 0 应该表示的是 x 轴,为什么是0?

这是因为我们作图时,传给 x 轴的是字符串:

134aad5b391f4a16982484bc783e09fa.png

此时坐标系 x 轴被 matplotlib 转成 0 开始的升序编码

matplotlib 有6种坐标系转换,这是最重要的核心机制,这里不深入讲解

看看效果:

600a19c9a44123a61684ab4c0fc8fb63.png
  • 矩形左下角在 第一个柱子中间,y 轴点40的位置

  • 高度刚好占 y 轴 20个单位的长度

  • 宽度刚好是 10 个柱子宽度总和

知道了原理,那么需求就非常容易了:

1c52959f8773ba48daf102fd1b7fff58.png

看看效果:

b599181842155477ab7d0e5e1f388223.png

非常好,为泡泡图加上数据标签,原理与之前一样:

b7d7e945245e33de7f99ac551ee2e68b.png
bc8cb28b7ca04f14f40982bb34bbc9a3.png

最后,按要求调整轴的细节即可:

50bfc8bc8427d70ad91183230664c850.png

完整调用如下:

62a3138c4d9a2cc76bd605ef0e525809.png

效果如下:

fce6a2f49de42124001fc383454f4e5d.png

你会发现,整个过程我们一直在设置数据与图形的关联,这就是 matplotlib 的核心思路!

看似需要很多代码,但是我们非常容易就可以使他们在不同的数据之间重复使用。

接下来我会继续编写更多非常规要求的图表,敬请关注!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值