python数据可视化之画箱形图

最近接到锅让画几个数据图。其实第一反应是用origin来画图,但问了一圈周围没有用Origin画过箱形图的,有些问题无法解决又百度不到。但好在略懂一点python的matplotlib画图,于是决定换个更适合程序员的画图工具。

人生苦短,我用python。

话不多说,为节约搜索画图方法小伙伴的时间先展示一下最终效果。

#导入要用到的几个库
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import math
#准备数据
y1 = np.random.normal(10, 3, (10, 9) )
y2 = np.random.normal(100, 30, (10, 9))
y3 = np.random.normal(1000, 300, (10, 9))
y4 = np.random.normal(10000, 3000, (10, 9))

将几组数据print出来。

y1
y2
y3
y4

可以看出这是四组满足指数递增的数据。

下面正式进入画图部分。

#这里是后面要用到的一些属性
text = ['100', '210', '400', '600', '2500', '3500', '5000', '6500', '10000']
pos = [math.log10(int(x)) for x in text]   #调整每个box的位置,因为一组数据中有9个box,而由于箱形图的特殊性其
y轴不是x轴的函数,而我们又希望每个box对应某个具体的x坐标。因此利用pos来调整box的位置,可以看出pos也是指数递增的数据
WIDTH = [0.08]*9    #设置每个box的宽度
LINEWIDTH=2         #设置每个box的线宽
fig, ax = plt.subplots(figsize=(12,10))        #设置图像的大小为(12,10)

plt.boxplot(x=y1,
            positions=pos,                                          #上一节中计算的位置
            boxprops={'color':'black', 'linewidth':LINEWIDTH},      #设置box的颜色和线宽
            widths=WIDTH,                                           #设置box的宽度
            flierprops={'marker':'x','markeredgecolor':'black'},    #设置异常点的形状和颜色
            medianprops={'linestyle':'-','color':'black', 'linewidth':LINEWIDTH},    #设置中位线的属性
            capprops={'color':'black', 'linewidth':LINEWIDTH},      #设置上下四分位线的属性
            whiskerprops={'color':'black', 'linewidth':LINEWIDTH})  #设置须的属性

plt.boxplot(x=y2,
            positions=pos,
            boxprops={'color':'blue','linewidth':LINEWIDTH},
            widths=WIDTH ,
            flierprops={'marker':'x','markeredgecolor':'blue'},
            medianprops={'linestyle':'-','color':'blue', 'linewidth':LINEWIDTH},
            capprops={'color':'blue', 'linewidth':LINEWIDTH},
            whiskerprops={'color':'blue', 'linewidth':LINEWIDTH})

plt.boxplot(x=y3,
            positions=pos,
            boxprops={'color':'red', 'linewidth':LINEWIDTH},
            widths=WIDTH ,
            flierprops={'marker':'x','markeredgecolor':'red'},
            medianprops={'linestyle':'-','color':'red', 'linewidth':LINEWIDTH},
            capprops={'color':'red', 'linewidth':LINEWIDTH},
            whiskerprops={'color':'red', 'linewidth':LINEWIDTH})

plt.boxplot(x=y4,
            positions=pos,
            widths=WIDTH ,
            boxprops={'color':'green', 'linewidth':LINEWIDTH},
            flierprops={'marker':'x','markeredgecolor':'green'},
            medianprops={'linestyle':'-','color':'green', 'linewidth':LINEWIDTH},
            capprops={'color':'green', 'linewidth':LINEWIDTH},
            whiskerprops={'color':'green', 'linewidth':LINEWIDTH})

接下来设置坐标轴

#这一段计算x轴的major ticks和minor ticks的位置,因为二者在某些属性上要有所区分因此分开。major ticks为主刻度点,为
10的整数倍,其余为副刻度点。

log_minor = []
log_major = []
base = 10
for i in range(4):
    log_major.append(base)
    for j in range(2, 10):
        log_minor.append(j*base)
    base *= 10
ax.set_xticks([math.log10(x) for x in log_major[1:]])    #设置主刻度点的位置,由于用对数坐标因此这里要取对数,这里从100开始
ax.set_xticklabels(['$\mathregular{10^{2}}$','$\mathregular{10^{3}}$','$\mathregular{10^{4}}$'])  #设置主刻度的label,后面是设置主刻度label为上标形式
ax.set_xticks([math.log10(x) for x in log_minor[3:-8]], minor=True)   #minor=True表示这是对数坐标
ax.set_xticklabels([], minor=True)   #由于我们不希望显示副刻度点的label,因此直接传入一个空列表

ax.tick_params(which='major',direction='in', length=5, width=2, labelsize=15) #设置tick的方向,长短粗细和label的大小
ax.tick_params(which='minor',direction='in', length=3, width=2)
plt.yscale(('log'))    #设置y为对数坐标形式。x轴无法这样设置因此需要像上述手动操作
plt.xlabel(r'$\mathregular{data^{superscript}}$', fontdict={'fontsize':15})    #设置X轴的label
plt.ylabel(r'$\mathregular{data_{subscript}}$', fontdict={'fontsize':15})      #设置y轴的label
#设置上下左右四个边框的宽度为2
ax.spines['bottom'].set_linewidth(2)
ax.spines['top'].set_linewidth(2)
ax.spines['left'].set_linewidth(2)
ax.spines['right'].set_linewidth(2)

此时画出的图是这样的

上述操作之后图,还有一些不足

可以看出现在的图还没有图例,并且左右的空白有点多,需要调整

#减少两侧空白
ax.set_xlim(1.7, len([math.log10(x) for x in log_major[1:]])+1.2)    #由于x轴是手动指定的刻度(并不是真正的表示数值),因此用x轴的长度来调整右侧宽度
ax.set_ylim(1, 20000)    #由于y轴是数值型的因此直接对应刻度来调整限制范围
#添加图例
#由于直接用plt.legend来画图例会有警告并且无法显示,官方推荐用这种方法来给boxes添加图例

black_patch = mpatches.Patch(color='green', label='data1')   #这里设置图例的颜色和label
blue_patch = mpatches.Patch(color='red', label='data2')
red_patch = mpatches.Patch(color='blue', label='data3')
green_patch = mpatches.Patch(color='black', label='data4')

l1 = plt.legend(handles=[black_patch], bbox_to_anchor=(0.15,0.85))   #将前面的patch加入handles中,用bbox_to_anchor来手动调整图例显示位置,前一个参数表示左右,后一个表示上下
l2 = plt.legend(handles=[blue_patch], bbox_to_anchor=(0.15,0.6))
l3 = plt.legend(handles=[red_patch], bbox_to_anchor=(0.15,0.4))
plt.gca().add_artist(l1)   #由于每次进行plt.legend都会抹去之前画的,在这里通过这个命令来重新添加之前画的图例
plt.gca().add_artist(l2)
plt.gca().add_artist(l3)
l4 = plt.legend(handles=[green_patch], bbox_to_anchor=(0.15,0.15))
#最后是图像的保存于显示,这里保存一定要在显示之前,否则就保存下来了显示完后自动刷新的空白图片
plt.savefig('tutorial1.png', format='png')  #可以指定png, pdf等多种格式,如果要输出矢量图可以保存为svg
plt.show()

最后来个总结吧:

1:flierprops={'marker':'x','markeredgecolor':'red'},比如在这段代码中,修改异常点颜色的参数名为markeredgecolor,之前在百度搜索时看见一篇博客写color参数来修改颜色,试了之后发现自己的异常点颜色并没有变化,在这上面花了很多功夫。其实他人博客应该仅供参考,毕竟人都有失误的时候,而将他人方法视作标准答案导致自己这次花了很多时间

2:还是上面那个问题。用百度搜索一堆答非所问的解答,google直接搜到原因。总结起来还是google更适合程序员

3:面向搜索编程。自己设置坐标轴的搜索流程就是:如何用matplotlib修改坐标轴粗细?->如何修改坐标轴label->如何设置坐标轴label的大小->如何修改坐标轴tick的粗细和长短->如何让minor ticks的label不显示->如何设置坐标轴label的大小

完整代码如下:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import math

y1 = np.random.normal(10, 3, (10, 9) )
y2 = np.random.normal(100, 30, (10, 9))
y3 = np.random.normal(1000, 300, (10, 9))
y4 = np.random.normal(10000, 3000, (10, 9))

log_minor = []
log_major = []
base = 10
for i in range(4):
    log_major.append(base)
    for j in range(2, 10):
        log_minor.append(j*base)
    base *= 10
    
text = ['100', '210', '400', '600', '2500', '3500', '5000', '6500', '10000']
pos = [math.log10(int(x)) for x in text]
WIDTH = [0.08]*9
LINEWIDTH=2

fig, ax = plt.subplots(figsize=(12,10))

plt.boxplot(x=y1,
            positions=pos,
            boxprops={'color':'black', 'linewidth':LINEWIDTH},
            widths=WIDTH,
            flierprops={'marker':'x','markeredgecolor':'black'},
            medianprops={'linestyle':'-','color':'black', 'linewidth':LINEWIDTH},
            capprops={'color':'black', 'linewidth':LINEWIDTH},
            whiskerprops={'color':'black', 'linewidth':LINEWIDTH})

plt.boxplot(x=y2,
            positions=pos,
            boxprops={'color':'blue','linewidth':LINEWIDTH},
            widths=WIDTH ,
            flierprops={'marker':'x','markeredgecolor':'blue'},
            medianprops={'linestyle':'-','color':'blue', 'linewidth':LINEWIDTH},
            capprops={'color':'blue', 'linewidth':LINEWIDTH},
            whiskerprops={'color':'blue', 'linewidth':LINEWIDTH})

plt.boxplot(x=y3,
            positions=pos,
            boxprops={'color':'red', 'linewidth':LINEWIDTH},
            widths=WIDTH ,
            flierprops={'marker':'x','markeredgecolor':'red'},
            medianprops={'linestyle':'-','color':'red', 'linewidth':LINEWIDTH},
            capprops={'color':'red', 'linewidth':LINEWIDTH},
            whiskerprops={'color':'red', 'linewidth':LINEWIDTH})

plt.boxplot(x=y4,
            positions=pos,
            widths=WIDTH ,
            boxprops={'color':'green', 'linewidth':LINEWIDTH},
            flierprops={'marker':'x','markeredgecolor':'green'},
            medianprops={'linestyle':'-','color':'green', 'linewidth':LINEWIDTH},
            capprops={'color':'green', 'linewidth':LINEWIDTH},
            whiskerprops={'color':'green', 'linewidth':LINEWIDTH})


ax.set_xticks([math.log10(x) for x in log_major[1:]])
ax.set_xticklabels(['$\mathregular{10^{2}}$','$\mathregular{10^{3}}$','$\mathregular{10^{4}}$'])
ax.set_xticks([math.log10(x) for x in log_minor[3:-8]], minor=True)
ax.set_xticklabels([], minor=True)

ax.spines['bottom'].set_linewidth(2)
ax.spines['top'].set_linewidth(2)
ax.spines['left'].set_linewidth(2)
ax.spines['right'].set_linewidth(2)

ax.tick_params(which='major',direction='in', length=5, width=2, labelsize=15)
ax.tick_params(which='minor',direction='in', length=3, width=2)
plt.yscale(('log'))
plt.xlabel(r'$\mathregular{data^{superscript}}$', fontdict={'fontsize':15})
plt.ylabel(r'$\mathregular{data_{subscript}}$', fontdict={'fontsize':15})

#reduce the blank area of the graph
ax.set_xlim(1.7, len([math.log10(x) for x in log_major[1:]])+1.2)
ax.set_ylim(1, 20000)

black_patch = mpatches.Patch(color='green', label='data1')
blue_patch = mpatches.Patch(color='red', label='data2')
red_patch = mpatches.Patch(color='blue', label='data3')
green_patch = mpatches.Patch(color='black', label='data4')

l1 = plt.legend(handles=[black_patch], bbox_to_anchor=(0.15,0.85))
l2 = plt.legend(handles=[blue_patch], bbox_to_anchor=(0.15,0.6))
l3 = plt.legend(handles=[red_patch], bbox_to_anchor=(0.15,0.4))
plt.gca().add_artist(l1)
plt.gca().add_artist(l2)
plt.gca().add_artist(l3)
l4 = plt.legend(handles=[green_patch], bbox_to_anchor=(0.15,0.15))

plt.savefig('tutorial1.png', format='png')
plt.show()

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据小魔方

think-cell chart系列15——蝴蝶图

今天跟大家分享think-cell chart系列的第15篇——蝴蝶图。 ? 当然think-cell chart中是无法直接制作蝴蝶图的,需要通过一对开口方向...

50740
来自专栏向治洪

FLAnimatedImage -ios gif图片加载框架介绍

简介 FLAnimatedImage 是 Flipboard 团队开发的在它们 App 中渲染 GIF 图片使用的库。 后来 Flipboard 将 FLAni...

34770
来自专栏Grace development

PHP GD库解析一张简单图片并输出

15900
来自专栏邵靖的专栏

使用 plotly 绘制数据图表

不少小伙伴在开发过程中都有对模块进行压测的经历,压测结束后大家往往喜欢使用Excel处理压测数据并绘制数据可视化视图,但这样不能很方便的使用web页面进行数据展...

1.3K60
来自专栏阿凯的Excel

金字塔图绘制(Excel绘制图表系列课程)

今天和大家分享金字塔图的绘制 什么是金字塔图呢?就是长得很像金字塔的图! 哦! 问:那是长这样? ? 答:额,有点像,但是不是! 问:那是怎样? 答:如下图。...

43530
来自专栏DannyHoo的专栏

iOS中将字体设置成斜体且加粗

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/...

48810
来自专栏理论坞

【教程】复古电影海报效果设计

2、新建一个图层命名cloud,用吸管工具吸取人像上最暗地方的颜色,选择滤镜—渲染—云彩,如下。

8020
来自专栏小古哥的博客园

CSS3边框图片-像素虚边的问题

虽然CSS3新增了这个功能,但是在W3school里面并没有给出具体详细的解释,还好网上不乏大神给你我们很全面的解释其中的原理-css3:border-imag...

27240
来自专栏PPV课数据科学社区

《用地图说话》之:十字绣中国热力数据地图

作图思路: 准备一块300*300小单元格组成的区域,对照地图图形,在每个省图形范围内的单元格填入该省的数据,然后对这些单元格应用条件格式->色阶,就形成了一幅...

31730
来自专栏王大锤

UI渲染回顾简单笔记

30180

扫码关注云+社区

领取腾讯云代金券