目录
一、 本文简介
本文基于python的matplotlib库进行基本图形的绘制,包括:柱状图,条形图,直方图,饼图,极线图,气泡图(散点图),箱线图。但不会很死磕参数,作者能力有限,平时写论文最常用的只有几个,望读者见谅。关于这几类图的作用,本文会有所提及,但不深。作者认为实践出真知,用多了,自然就知道该用什么了。
希望本文可以给各位读者提供一定的帮助。作者也在不断学习,有什么写错的地方,欢迎批评指正。本文要导入的库如下。
import matplotlib.pyplot as plt
import numpy as np
如果希望做出来的图形可以使用中文标注的情况 ,需要导入以下代码。其中的SimHei是黑体的意思,如果需要设置特定字体,可以去查阅其他资料。
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
二、 基本图形
2.1 柱状图
bar():柱状图在于展示不同类别或者不同时间上的数据差异。基本参数有:
bar(x,y,width,bottom,align,hatch,color,lw,tick_label,edgecolor,label...)
x | 柱子在x轴上的坐标,也可以是字符串序列 |
y | 柱子的高度,即y轴上的值,也可以理解为要展示的值。浮点数,支持列表和ndarray(numpy数组) |
width | 柱子的宽度,默认是0.8。设置width,可以绘制分组柱状图 |
bottom | bottom,柱子的基准高度,默认0开始,当数值较大时可以设置较符合的基准高度,突出差异 |
align | 柱子在x轴上的对齐方式,可以设置center和edge,center即居中,edge时靠右,若想靠左,需要同时设置width为负数 |
hatch | 柱子的填充符号,可以使用/,|,-,+,x,o,O,.,*,\(易作为转义字符)等。 |
color | 柱子填充颜色,字符串,可以固定一个值,也接受字符串数组 |
lw | linewidth的简写,柱子边框的宽度,浮点数。与此类似的还有linestyle(简写:ls) |
tick_label | 可以设置x轴上的标签,数组类型 |
edgecolor | 柱子的边框颜色,可以指定一个颜色,也可以指定一个数组 |
label | 要展示的图例,字符串,需要配合plt.legend函数一起使用。但如果设置的颜色不是统一的或者说在分组柱状图中展示,只会显示第一个出现的颜色并标上意思。 |
2.1.1 普通柱状图
carray和earray中的颜色是填充颜色的简写,如果要设置独特的颜色,需要完整输入。
x = [1, 2, 3, 4, 5]
# x = list("ABCDE")
y = [2.3, 2.6, 3.7, 4.1, 4.7]
width = [0.8, 0.2, 0.3, 0.5, 0.1]
carray = ['r', 'g', 'b', 'c', 'm'] # 柱子填充颜色
earray = ['r', 'y', 'k', 'g', 'b'] # 边框颜色
linewidth = 0.2
tlabel = ["a", 'b', 'c', 'd', 'e']
plt.bar(x, y, width=width, align="center",
bottom=None,
lw=linewidth,
tick_label=tlabel,
color=carray,
edgecolor=earray,
hatch='+', # 柱子填充符号
label="zzzz")
plt.legend()
plt.show()
效果如下,可以发现,在图列部分,也会将填充的符号包括进去。x轴上的值是可以自定义的,也可以用plt.xticks()设置。
2.1.2 堆积柱状图
堆积柱状图,可以显示一种大类下某种小类的占比,在matplotlob中,就是多画一个柱状图进行覆盖。但需要注意覆盖的顺序,“大类在前,小类在后”。防止被覆盖住。
x = [1, 2, 3, 4, 5]
y = [2.3, 2.6, 3.7, 4.1, 4.7]
y1 = [1, 1.5, 2.3, 1.8, 3.2]
width = [0.8, 0.2, 0.3, 0.5, 0.1]
carray = ['k', 'g', 'b', 'c', 'm']
earray = ['r', 'y', 'k', 'g', 'b']
linewidth = 0.2
tlabel = ["a", 'b', 'c', 'd', 'e']
plt.bar(x, y, width=width, align="center",
bottom=None,
lw=linewidth,
tick_label=tlabel,
color=carray,
edgecolor=earray,
hatch='/') # 柱子填充符号
plt.bar(x, y1, width, align="center",
lw=linewidth, hatch='\\')
plt.show()
效果如下,需要注意的是,有时会出现没有如此明显的分层,可能的原因在于两个柱状图的顺序不对;或者是y轴的设置不对,造成在某一量纲上差距很小,可以通过改变y轴的范围解决。
2.1.3 分组柱状图
前面提到,通过width可以设置,但此时第一个参数x不能为字符串,因在字符串无法和浮点数进行相加。分组柱状图可以显示不同类别的不同分组对比状况。例如不同年度间不同季节的消费人数对比。
x = np.arange(5)
y = [6, 10, 4, 5, 1]
y1 = [2, 6, 3, 8, 5]
bar_width = 0.35
tick_label = [2016, 2017, 2018, 2019, 2020]
plt.bar(x, y, bar_width, color='c', align='center', label='A类', alpha=0.5)
plt.bar(x+bar_width, y1, bar_width,
color='b', align='center',
alpha=0.5, label="B类",
tick_label=tick_label) # 与堆积柱状图相比,在x轴方向加入数值
plt.xlabel("不同年度不同产品类别销售情况")
plt.ylabel("销售量")
plt.legend()
plt.show()
结果如下,其实就是通过改变第二幅柱状图在x轴的位置实现。可能发现代码中出现了一个alpha参数,在上面的参数介绍中没出现,它是在**kwargs中,bar中**kwargs是属于Rectange属性中,这边不做过多解释,作者也没怎么搞清楚,不过,这个alpha参数,是透明度的意思,设置柱子的透明度,基本在任意图形绘制中都可以使用。
2.2 条形图
barh():和柱状图基本一致的效果,比较不同类别的差距。在某一些场景上,展现效果优于柱状图。基本参数有:
barh(y,width,height,left,align,....
y | 表示y坐标轴,接受字符串序列或者int数组,相当于bar中的x |
width | 即条的宽度,同bar的width |
height | 同bar中的height |
left | 相当于bar中的bottom,即设置条的初始位置,接受数组或者int类型 |
其他参数基本和bar()函数中一致,这里不再赘述。
2.2.1 普通条形图
普通的条形图就相当于柱状图旋转了90°。
y = [2, 7, 4, 5, 6]
width = [2.3, 2.6, 3.7, 4.1, 4.7]
height = 0.2
carray = 'b'
earray = 'm'
tlabel = ['cc', 'mm', 'r', 'uu', 'pp'] # y轴上标签
plt.barh(y, width, height,
align='center',
tick_label=tlabel,
edgecolor=earray,
color=carray,
left=10)
plt.show()
2.2.2 复式条形图
复式条形图对应分组柱状图。注意:无论是复式条形图还是分组柱状图,一定要加上图例
y = np.arange(5)
h = [6, 10, 4, 5, 1]
h1 = [2, 6, 3, 8, 5]
bar_width = 0.35
tick_label = [2016, 2017, 2018, 2019, 2020]
plt.barh(y, h, bar_width, color='c', align='center', label='A类', alpha=0.5)
plt.barh(y+bar_width, h1, bar_width,
color='b', align='center',
alpha=0.5, label="B类",
tick_label=tick_label) # 与堆积柱状图相比,在x轴方向加入数值
plt.xlabel("不同年度不同产品类别销售情况")
plt.ylabel("销售量")
plt.legend()
plt.show()
2.2.3 堆积条形图
对于它的名字,不明白这样讲正不正确,但是意思就是这个意思,也是对比大类中小类的情况,也要注意不同条形图的绘制顺序,防止被覆盖。
y = np.arange(5)
h = [2.3, 2.6, 3.7, 4.1, 4.7]
h1 = [1, 1.5, 2.3, 1.8, 3.2]
width = 0.8
linewidth = 0.2
tlabel = [2017, 2018, 2019, 2020, 2021]
plt.barh(y, h, height=width, align="center",
lw=linewidth,
tick_label=tlabel,
color="blue",
label="粮食产量")
plt.barh(y, h1, height=width, align="center", color='red',
lw=linewidth, label="小麦产量")
plt.title("不同年度小麦产量占比")
plt.xlabel("产量/亿吨")
plt.legend()
plt.show()
效果如下。对于lw,width,作者这边建议,一般情况下,设置一个数值就行,不用设置数组,展示起来很不美观,作图的目的就是直观的展示数据,切勿本末倒置。
2.3 直方图
hist():直方图用于展示数据的分布。
和柱状图的区别:
(1) 柱状图在于比较数据的大小,直方图展示数据的分布情况;
(2)柱状图柱子间是隔开的,直方图是相邻的。
(3)柱状图x轴基本是定类数据,而直方图是定量数据
常用参数有
hist(x, bins=None, range=None, density=False,
cumulative=False, bottom=None, histtype='bar',
align='mid',rwidth=None, log=False,
color=None,label=None)
x | 整数值或者数组序列 |
bins | 整数或者序列。若为整数,即柱子个数,否则为每个柱子的范围值 |
range | 设置直方图x轴的范围,可以借此剔除一些离群值,格式为(xmin,xmax) |
density | bool类型,若为True,则显示概率密度 |
cumulative | boo类型,若为True,计算累计频率 |
bottom | 数组或者证书,对应初始位置,和bar和barh一样 |
histtype | 直方图类型。bar表示最普通的;barstacked表示堆叠的直方图;step表示未填充的直方图;
stepfilled表示有填充的直方图,和bar差不了太多
|
align | 柱子位置。left表示柱子的中心位于bins的左边缘;mid为中间;right为右边缘。 |
rwidth | 整数值,柱子宽度占bins宽的比例 |
log | bool类。是否将x轴对数化,降低量纲 |
color设置颜色,label设置柱子标签,alpha设置透明度。
2.3.1 普通直方图
x = np.random.normal(size=1000)
plt.hist(x, bins=100, density=False,
histtype="bar", # 用于选择条形图的样式
align="mid",
alpha=0.6)
plt.show()
np.random.normal(size=1000)表示生成1000个标准正态分布随机数。
2.3.2 概率分布直方图
x = np.random.normal(size=1000)
plt.hist(x, bins=100, density=True,
histtype="bar", # 用于选择条形图的样式
align="mid",
alpha=0.6)
plt.show()
和普通直方图最大的不同在于y轴的刻度,普通直方图表示的是频数,下图表示概率。
2.4 饼图
pie():直观反映一维数据中各项之间的比例大小。但要求数据中没有负值和零值。饼图较常使用的参数比较多,如下:
pie(x, explode=None, labels=None, colors=None,
autopct=None,pctdistance=0.6, shadow=False,
labeldistance=1.1,startangle=0, radius=1,
wedgeprops=None,textprops=None, center=(0, 0),
rotatelabels=False)
x | 一维数组,每个板块占的大小 |
explode |
每个板块相对于饼圆半径的偏移距离,取值为小数。
|
labels | 每个板块的标签,字符串序列 |
autopct | 板块占比标签。%d%%:整数百分比;%0.1f:一位小数;%0.1f%%:一位小数百分比;%0.2f%%:两位小数百分比 |
pctdistance |
板块内标签与圆心的距离。浮点数
|
shadow | 饼图下是否有阴影,略微展现立体感 |
labeldistance
|
饼块外标签与圆心的距离
|
startangle
|
饼块起始角度。浮点数,默认为 0,即从 x 轴开始,角度逆时针旋转
|
radius
|
饼图半径。浮点数,默认为 1,若>1,需要设置好画布大小
|
wedgeprops
|
饼块属性。字典,可以设置饼块边框大小,填充颜色等
|
textpropss
|
标签的文本属性,字典,可以设置字体、字号、颜色等 |
center | 饼图中心坐标,包含两个浮点数元素的元组 |
rotatelabels
|
bool类型,饼块外标签是否按饼块角度旋转。 |
2.4.1 非分裂饼图(常规饼图)
x = [10, 30, 50, 20, 45]
colors = ['#377eb8', "#4daf4a", "#984ea3", "#ff7f00", "#e7c3b2"] # 颜色
labels = ['A', 'B', 'C', 'D', 'E']
plt.pie(x, colors=colors, labels=labels,
autopct='%0.1f%%',
startangle=45,
pctdistance=0.7,
labeldistance=1.2)
plt.show()
2.4.2 分列式饼图
labels = ['A类', 'B类', 'C类', 'D类', 'E类']
x = [0.35, 0.20, 0.15, 0.05, 0.25]
colors = ['r', 'g', 'b', 'c', 'm']
explode = [0.1, 0.2, 0.05, 0.1, 0.06] # 每个板块相对于饼原半径的偏移距离
wedgeprops = {'linewidth': 1, 'edgecolor': "black"}
plt.pie(x, explode, labels, colors,
pctdistance=0.6, # 板块内标签与圆心的距离
autopct='%0.2f%%', # 板块内的标签
shadow=True,
labeldistance=1.1, # 饼块外标签与圆心的距离
startangle=0.00, # 饼块的其实角度
radius=1, # 兵源半径
wedgeprops=wedgeprops, # 饼块的属性
textprops={'fontsize': 12, 'color': 'black', "font": 'Kaiti'},
center=(0, 0), # 饼原中心坐标
rotatelabels=False) # 饼块外标签是否按照饼块角度旋转
plt.show()
分裂饼图最主要的参数即为explode。分裂饼图可以突出某一项所占比例,使得用户第一眼可以聚焦到想看到的地方。
2.4.3 环形图
在matplotlib中,环形图的原理即在一个圆中减去一个小圆,即用和背景颜色相同的单位圆覆盖住中间位置。
x = [15, 20, 17, 25]
explode = (0, 0.1, 0, 0)
label = ['a', 'b', 'c', 'd']
x_0 = [1, 0, 0, 0]
plt.pie(x, explode,
labels=label,
autopct="%3.1f%%",
startangle=90,
shadow=True)
plt.pie(x_0, radius=0.5, colors='w')
plt.axis('equal')
plt.show()
环形图要显示好标签,需要设置标签距离圆心的位置,确保足够美观。单位圆即只有一类,其余类没有,或者为0。
2.5 散点图
scatter():也称为气泡图。散点图可以展示两组数据中的关系,或者分析一种趋势,和折线图的作用有点类似。基本参数如下:
scatter(x, y, s=None, c=None, marker=None,
norm=None, vmin=None, vmax=None, alpha=None,
linewidths=None,edgecolors=None)
x,y | 对应二维坐标轴上的坐标,分别对应x轴、y轴 |
s |
指定图点的大小,默认 20
|
c
|
指定散点图的颜色,默认为蓝色
|
marker
|
指定散点的形状,默认为空心圆。可以设置:. , o v ^ > < * | _ + x d
|
norm |
设置数据亮度,范围0-1,使用该参数时仍需要参数 c
|
linewidths
|
设置散点边界线的宽度
|
edgecolor
|
设置散点边界线的颜色
|
vmin,vmax
|
亮度设置,与 norm 类似,如果使用 norm 参数,此参数无效
|
alpha即设置散点的透明度。示例如下:
x = np.random.randn(1000) # 返回1000个样本服从标准正态的数
y = np.random.randn(1000)
plt.scatter(x, y,
s=20, # 指定点的大小,若传入一维数组,则表示每个点的大小
c='g',
marker='o', # 指定散点形状
vmin=0, vmax=20,
alpha=0.5,
linewidths=1,
edgecolors='c')
plt.show()
2.5 极线图(雷达图)
polar():雷达图可以很好的对比不同个体在各个指标上的差异。也可以体现个体在各个方面的平衡。常用参数如下:
polar(thera,r,marker,linestyle,linewidth,color,ms...)
thera | 每个标记所在射线于极径的角度 |
r | 标记点到原点的距离 |
marker | 标记点样式,有 . , o v ^ > < * | + _ x d |
linestyle | 线的样式,-,--,-.,: |
linewidth | 浮点数,线的宽度 |
color | 线的颜色 |
ms | 标记点的大小 |
2.5.1 普通极线图
angles = np.linspace(0, 2*np.pi, 6)
r = np.random.randint(1, 10, 6)
plt.polar(angles, r)
plt.show()
np.linspace表示从0~2Π均匀分成6个数,random.randint(1,10,6)表示在1-10中选6个数,普通极线图是没有闭合的。效果如下。
2.5.2 雷达图
区别于普通的极线图,雷达图是闭合的。若要在极坐标上添加标签,需要使用此函数:plt.thetagrids()。
angles = np.linspace(0, 2*np.pi, 6)
labels = ['能力A', '能力B', "能力C", "能力D", "能力E", "能力F"]
r = np.random.randint(1, 10, 6)
r = np.append(r, r[0])
angles = np.append(angles, angles[0])
plt.polar(angles, r)
plt.thetagrids(angles=(np.linspace(0, 360, 6)), labels=labels, fontsize=15)
plt.show()
(注:有时候angles即角度用0到2的方法会导致绘制出来的图像一条直线,可以换成0到360)
想让极线图闭合,在matplotlib中,即在r中添加最初的位置,角度也要加上去。thetagrids的第一个参数是角度,第二个是标签。
若想要中间有填充效果,可以使用fill函数进行添加。
函数为:plt.fill(thera,r,color,alpha) ,效果如下:
angles = np.linspace(0, 2*np.pi, 6)
labels = ['能力A', '能力B', "能力C", "能力D", "能力E", "能力F"]
r = np.random.randint(1, 10, 6)
r = np.append(r, r[0])
angles = np.append(angles, angles[0])
plt.polar(angles, r, marker='*', lw=1, ls='--', ms=10, color='r')
plt.thetagrids(angles=(np.linspace(0, 360, 6)), labels=labels, fontsize=15)
plt.fill(angles, r, color='r', alpha=0.25)
plt.show()
2.5.3 复式雷达图
其实就是多个对象之间不同能力的对比,相比较分组柱状图,更加直观。
angles = np.linspace(0, 2*np.pi, 6)
labels = ['能力A', '能力B', "能力C", "能力D", "能力E", "能力F"]
r = np.random.randint(1, 10, 6)
r = np.append(r, r[0])
r1 = np.random.randint(1, 10, 6)
r1 = np.append(r1, r1[0])
angles = np.append(angles, angles[0])
plt.polar(angles, r, marker='*', lw=1, ls='--', ms=10, color='r', label="A")
plt.thetagrids(angles=(np.linspace(0, 360, 6)), labels=labels, fontsize=15)
plt.fill(angles, r, color='r', alpha=0.25)
plt.polar(angles, r1, marker='*', lw=1, ls='--', ms=10, color='g', label="B")
plt.fill(angles, r1, color='m', alpha=0.25)
plt.legend()
plt.show()
2.6 箱线图
boxplot():可以展示一组数据的分散情况,直方图虽然也能查看分散情况,但不够明显。参数如下:
boxplot(x, notch=None, sym=None, vert=None, whis=None,
positions=None, widths=None, patch_artist=None,
bootstrap=None, usermedians=None, conf_intervals=None,
meanline=None, showmeans=None, showcaps=None, showbox=None,
showfliers=None, boxprops=None, labels=None, flierprops=None,
medianprops=None, meanprops=None, capprops=None,
whiskerprops=None)
x | 指定数据,可以是一维数组,也可以是多维,即绘制多个图 |
notch |
bool类型,是否凹口的形式展示箱线图,默认非凹口
|
sym
|
指定异常点的形状,默认为+号显示
|
vert
|
bool类型,是否需要将箱线图垂直摆放,默认垂直拜访
|
whis
|
指定上下须与上下四分位的距离,默认为 1.5 倍的四分位差
|
positions
|
指定箱线图的位置
|
widths
|
指定箱线图的宽度,默认为 0.5
|
patch_artist
|
是否填充箱体的颜色
|
meanline
|
bool类型,是否用线的形式表示均值,默认用点来表示
|
showcaps
|
bool类型,是否显示箱线图顶端和末端的两条线,默认显示
|
showmeans
|
是否显示均值,默认不显示
|
showbox
|
bool类型,
是否显示箱线图的箱体,默认显示
|
showfliers
|
bool类型,
是否显示异常值,默认显示
|
boxprops
|
设置箱体的属性,如边框颜色,填充色等
|
labels
|
为箱线图添加标签,类似于图例的作用
|
filerprops
|
设置异常值的属性,如异常点的形状、大小、填充色等
|
medianprops
|
设置中位数的属性,如线的类型、粗细等
|
meanprops
|
设置均值的属性,如点的大小、颜色等
|
capprops
|
设置箱线图顶端和末端线条的属性,如颜色、粗细等
|
whiskerprops
|
设置须的属性,如颜色、如粗细、线的类型等
|
乍一看,箱线图的参数特别多,但是基本使用,只需要把x输入即可,其他都是特殊情况下的定制。
如何看箱线图?以上图为例,最上方和最下方的两条线是上下限。箱体上下的两条箱线即对应四分位数(y轴看是对应2和7),中间黄色的线即为均值。
x = np.arange(10)
plt.boxplot(x,
sym='o',
vert=None, # 是否将箱线图垂直摆放
widths=0.8, # 设置箱线图宽度
patch_artist='g', # 是否填充箱体颜色
showmeans=True,
meanprops={'marker': 'o', 'markerfacecolor': 'red', 'markersize': 5})
plt.show()
如果要在一张图上画多个箱线图,输入的x是多维数据即可。图中meanprops的参数也可以类似地用在其他参数上。
x = np.arange(10)
y = np.arange(3, 12)
plt.boxplot([x, y],
sym='o',
vert=None, # 是否将箱线图垂直摆放
widths=0.8, # 设置箱线图宽度
patch_artist='g', # 是否填充箱体颜色
showmeans=True,
meanprops={'marker': 'o', 'markerfacecolor': 'red', 'markersize': 5})
plt.show()
三、 总结
作者认为,常用的图就这些,无论是在学习还是在工作上,这些只是基本的图形。如果需要美化,可以结合上一篇文章Python可视化——matplotlib.pyplot绘图的基本参数详解。以及通过更加丰富的色彩进行展示。当然数据才是最重要的,作图的目的是为了更加直观的看清楚数据的情况。
如有写错或者不明白的地方,可以在评论区或者私信作者,欢迎各位读者批评指正。创作不易,可以的话,点赞、关注、收藏!!!