本文主要介绍折线图、散点图、面积图和填充图
plt.plot是matplotlib最基础的接口,matplotlib作者也将这个接口设计得足够简单,以至于只需要输入一个参数(数组,列表型数据),就能够绘制好一张图。
与此同时,由于折线图(plt.plot)和散点图(plt.scatter)都可以对数据点进行不同形状的标记,使用起来容易将其混淆,因此本文将这两类绘图对象放在一起介绍,方便读者进行对比。
最后,将表现趋势的面积图和填充图也一并放在本文。
本文所用到的库包括
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
相比Excel,matplotlib折线图绘制更显优雅,即使是折线连接,看起来也较为圆润,且默认绘制的折线图仅含有曲线,没有数据标记,对于趋势的可视化而言,个人认为这是恰到好处的。
接口只传入一个参数时,横轴默认按照0,1,2,3……逐一递增的形式赋值。如图,因y有100个点。因此,曲线最后一个点的横坐标对应的数值为99
x=np.linspace(0,10,100)
y=np.sin(x)
plt.plot(y)
当传入的参数为两个向量的时候,则分别将其映射到x,y坐标,并用实线将其逐点相连。
x=np.linspace(0,10,100)
y=np.sin(x)
plt.plot(x,y)
当传入的列表型参数为大于2的偶数序列时,则两两分别划定为一个序列,如图,x,y1 和 x,y2分别为两个数据序列。
x=np.linspace(0,10,100)
y1=np.sin(x)
y2=np.cos(x)
plt.plot(x,y1,x,y2)
下图中,log函数对应的曲线展示了不同接口参数对线型的修饰;sin函数对应的曲线展示了不同参数接口对标记的修饰。
x=np.linspace(1,10,20)
y1=np.log(x)
y2=np.sin(x)
# line 的设置
plt.plot(x,y1,
color='red', # 线条颜色
linestyle='--', # 线型
dash_capstyle='round', # 每个虚线小段的形状,round为圆角矩形
alpha=0.9, # 透明度
linewidth=8) # 线宽
# marker 的设置
plt.plot(x,y2,
marker='^',
markersize=15,
markeredgecolor='blue',
markeredgewidth=2,
markerfacecolor='pink',
fillstyle='right', # 支持的填充方向为'full', 'left', 'right', 'bottom', 'top', 'none'
)
matplotlib中所有涉及到参数线型的修饰,均通过linestyle参数实现,其可以缩写为ls,定义的线型一个有四类,分别是 实线,虚线,点阵,点划线,下图展示了四类线型的变化规律。
plt.figure(figsize=(6,3))
x=np.linspace(1,10,15)
y=np.ones(15)
linestyles=['-','--',':','-.']
for i,ls in enumerate(linestyles):
plt.plot(x,y+i,linestyle=ls,lw=4)
plt.axis('off')
相比于简单的线型,matplotlib中的标记不可谓不丰富,同理,所有接口中凡是带有参数marker或者markers的,均可以传入本例中给到的符号样例,从而实现对图像标记的修饰。
plt.figure(figsize=(6,8))
x=np.linspace(1,10,15)
y=np.ones(15)
markers='.,ov^<>1234sp*hH+xDd|'
for i,marker in enumerate(markers):
plt.plot(x,y+i,marker=marker,markersize=10)
plt.text(0.4,y[0]+i,marker,size=20,va='center')
plt.axis('off')
散点图,乍一看就是不带曲线的折线图,这么理解其实是不对的。以下是我的一些个人理解:
折线图的优势在于看趋势,同时,可以实现不同序列的数据在同一尺度下的对比。
比如我们可以看到任一数据在本序列的绝对位置及本序列中所有数据的变化趋势,同时可以看到在某一方向上,不同序列的表现,前者非常适用于时间序列的展示分析,后者适用于是否存显著性差异的对比分析。
散点图的优势在于将多维度的数据以不同的形式映射到一张二维的图像上
比如特征1和特征2可以分别映射成坐标,而特征3可以映射成标记的颜色,特征4映射成标记的形状,特征5映射成标记的大小,特征6映射成标记轮廓线的粗细等等。特征1,2,5的组合,就是我们常用的气泡图。散点图,是特征展示的集大成者,是有态度,有深度的图。正因为如此,驾驭的好事半功倍,驾驭不好就容易让人眼花缭乱。
散点图的基础接口非常简单,只需要传入两个参数,就能实现基础图的绘制。
x=np.linspace(0,10,100)
y=np.sin(x)
plt.scatter(x,y)
对散点图的修饰,主要体现在对其标记的修饰。标记的特征包括标记符号marker,大小s,填充色c,轮廓线线宽linewidths,轮廓线颜色edgecolors。
需要注意的是:
1 这里大小等修饰参数,均可以传入一个标量(表示所有标记该属性的设置相同),或者一个与x,y等长度的向量(对每个标记分别修饰)。
2 若轮廓线颜色传入的为RGB元组的列表,其列表长度需与x,y等长度,列表中每一个元素为RGB元组(或列表),该为一个长度为3的元组,每个数值分别代表RGB通道的浮点数数值(最小为0.0,最大为1.0),如(1.0,0.0,0.0)代表红色。在后面的章节中,大家将看到matplolib中大多数的颜色传参均以两种形式传入,一种为十六进制颜色,如 F0F8FF,另一种便是RGB元组。
N = 25
np.random.seed(121)
x = np.linspace(0, 10, N)
y = np.sin(x)
s = np.linspace(100, 500, N) # marker大小随x增大线性递增
c = np.linspace(0, 10, N) # marker填充颜色在色板按顺序遍历
linewidths = np.linspace(0, 10, N) # marker轮廓线宽随x增大线性增大
edgecolors = np.random.uniform(size=(N, 3)) # marker轮廓颜色,随机生成N组 RGB元组
plt.scatter(x=x,
y=y,
marker='s', # marker形状
s=s, # marker大小
c=c, # marker颜色
linewidths=linewidths, # marker轮廓线线宽
cmap=plt.cm.autumn, # marker颜色色板
edgecolors=edgecolors, # marker轮廓颜色,RGB元组构成的列表 (N,3)
)
鉴于人眼对连成块的色彩块既具有敏感性,面积图用来表达一种强烈的堆积递增效应,如下图中的y5序列,强烈的表达了该趋势在初始状态下原高于其他序列;若该图表达的是某种力(或能量)在时间序列下的累积作用,则图面积大小将显著地表达出y5的累积能力远大于其他序列。
N=10
np.random.seed(123)
x=np.linspace(1,10,N)
y=np.log(x)
y_reverse_x=np.linspace(10,0,N)
plt.stackplot(x,
[y,y,y,y,y_reverse_x], # 面积图是在前一个序列数据基础上,逐层向上累加而构成的图
labels=('y1','y2','y3','y4','y5'),
colors=np.random.uniform(size=(N,3)), # 每个系列的颜色,此处传入的是N个RGB元组
)
plt.legend()
面积图的堆积基面baseline默认是0轴(zero)开始的,当将其设置为sym时,表示各序列在任一位置,均实现以0轴上下对称。
N=10
x=np.linspace(0,10,N)
y=x
plt.stackplot(x,
[y,y,y,y],
baseline='sym', #'sym:以y=0轴对称'
)
plt.grid()
当baseline设置为wiggle,表示所有序列的斜率平方和最小。
N=10
x=np.linspace(0,10,N)
y1=x
y2=3*x
y3=4*x
y4=12*x
plt.stackplot(x,
[y1,y2,y3,y4],
baseline='wiggle', #'wiggle':最小的斜率平方和
)
plt.grid()
与面积图plt.stackplot相类似的一个颜色块接口为plt.fill_between及plt.fill_betweenx,默认参数下,将y坐标至0轴的区域用某种颜色进行填充。
下图通过plt.fill_between接口复现了上文中的面积图。
N=10
np.random.seed(123)
x=np.linspace(1,10,N)
y=np.log(x)
y_reverse_x=np.linspace(10,0,N)
plt.fill_between(x,y1=y_reverse_x+4*y)
for i in range(4):
plt.fill_between(x,y1=(4-i)*y)
同时,填充图还支持限定条件下的区域填充,如下图,对符合y2>y1且同时符合y2>0的区域进行了y方向上的填充。
N=100
x=np.linspace(-1*np.pi,1*np.pi,N)
y1=np.sin(x)
y2=np.cos(x)
plt.plot(x,y1)
plt.plot(x,y2)
plt.fill_between(x,y1=y1,y2=y2,where=(y2>y1) & (y2>0),color='skyblue')
综上,折线图和散点图侧重从线条、标记来表达序列本身及与其他序列的趋势关系;面积图和填充图侧重从色块面积来表达序列本身及与其他序列的趋势关系。
希望对你有所启发和帮助!