前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python数据可视化之画箱形图

python数据可视化之画箱形图

原创
作者头像
我爱自然语言处理
修改2018-07-15 01:09:32
6.2K2
修改2018-07-15 01:09:32
举报
文章被收录于专栏:我的python我的python

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

人生苦短,我用python。

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

代码语言:python
复制
#导入要用到的几个库
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import math
代码语言:python
复制
#准备数据
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
y1
y2
y2
y3
y3
y4
y4

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

下面正式进入画图部分。

代码语言:python
复制
#这里是后面要用到的一些属性
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的线宽
代码语言:python
复制
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})

接下来设置坐标轴

代码语言:python
复制
#这一段计算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
代码语言:python
复制
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
代码语言:python
复制
#设置上下左右四个边框的宽度为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)

此时画出的图是这样的

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

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

代码语言:python
复制
#减少两侧空白
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轴是数值型的因此直接对应刻度来调整限制范围
代码语言:python
复制
#添加图例
#由于直接用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))
代码语言:python
复制
#最后是图像的保存于显示,这里保存一定要在显示之前,否则就保存下来了显示完后自动刷新的空白图片
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的大小

完整代码如下:

代码语言: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))

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()

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档