matploblib库是一个用于数据可视化和绘图的python库。它提供了大量的函数和类,可以帮助用户轻松地创建各种类型地图表,包括直方图,箱形图、散点图、饼图、条形图和密度图等。使用matplotlib的过程中,遇到的难点并不在于绘制各类的图形,因为每种图形都有其对应的API。难点在于对绘制的图形进行调整,这些调整包括:
进行这些调整需要对matplotlib的绘图机制和其中的主要元素有个整体的了解。在此首先整体介绍matplotlib绘制的图形中的主要元素,然后重点介绍其中第一个重要的元素:画布。
下面绘制一个简单的图形来演示matplotlib绘图时主要的元素。
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
%matplotlib inline
x=np.array(np.pi*2 * np.linspace(0,1,20))
y1=np.sin(x)
fig=plt.figure()
fig.set_size_inches(10,4)
fig.set_facecolor('yellow')
fig.suptitle('whole figure caption')
fig.subplots_adjust(wspace=0.3)
ax1=fig.add_subplot(1,2,1)
ax1.set_title("fig1 title")
ax1.set_xlabel("fig1 x-axis")
ax1.set_ylabel("fig1 y-axis")
ax1.plot(x,y1)
ax2=fig.add_subplot(1,2,2)
ax2.set_title("fig2 title")
ax2.set_xlabel("fig2 x-axis")
ax2.set_ylabel("fig2 y-axis")
ax2.plot(x,y1)
y2=np.cos(x)
ax2.plot(x,y2)
ax2.legend(['sin','cos'])
fig.show()
上例中,我们绘制了2个子图。
主要的元素包括,图形的大小,图形的标题(主标题和子图标题),坐标轴(轴标签和可读),图例,子图中曲线 (这里可以根据情况换成其它图形,比如柱状图,散点图等)。
上面的示例代码不用太关心,这里只是为了现实matplot的主要元素。后续将介绍各个组要元素的常用属性,最终的目的是能够灵活绘制符合显示要求的图形,而不仅仅只是绘制图形。
本节介绍的主要元素是画布。
画布是其它所有的元素的载体,可以说是最重要,也是最容易被忽视的元素。绘制图形之前,第一件事即是创建画布。
创建画布之后,一般主要用到的属性是调整画布的大小和颜色。
matplotlib画布的大小通过设置英寸和dpi来实现,dpi表示一英寸有多少像素。
比如以下示例
import numpy as np
import matplotlib
# matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure(figsize=[6,3],dpi=100)
fig.suptitle("caption")
x = np.linspace(0,1,20)
y = np.sin(x * 2 * np.pi)
plt.plot(x, y)
plt.show()
修改dpi=200,图形明显变大和清晰。
fig = plt.figure(figsize=[6,3],dpi=200)
除了大小,设置画布的颜色也是比较常用的。
颜色主要有两种,背景色和边框颜色(默认的边框宽度是0,随意要设置边框颜色,同时设置边框的宽度)。
比如:下面示例设置了背景色为橙色,边框宽度为10,颜色为黄色。
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure(figsize=[6,3],edgecolor="orange",linewidth=10,facecolor="yellow")
fig.suptitle("caption")
x = np.linspace(0,1,20)
y = np.sin(x * 2 * np.pi)
plt.plot(x, y)
plt.show()
除了属性,画布还有几个方法也是经常使用的。
上面的示例中已经包含了也就是suptitle()方法。
添加子图用add_subplot()方法,这个方法的参数一般三个数字xyz,x表示有几行,y表示有几列,z表示是第一个子图。
比如,一行两列3个图。
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure()
fig.add_subplot(121)
fig.add_subplot(122)
两行一列2个图:
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure()
fig.add_subplot(211)
fig.add_subplot(212)
两个两列4个图:
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure()
fig.add_subplot(221)
fig.add_subplot(222)
fig.add_subplot(223)
fig.add_subplot(224)
画布还有个重要的功能就是把显示的图像保存下来,即savefig()方法。
可以把绘制的图形保存到磁盘,用于分享或者制作报告。
fig.savefig("/home/user/pp.png")
画布让我们可以整体上设置图形的质量和排版,分享和作图过程中虽然不用过多考虑它,但是最终如果要出报告和文档,画布的设置就变得重要了。
画布是绘图的第一步,接下来这个系列会逐步介绍matplotlib的其它主要元素。
使用matplotlib对分析结果可视化时,比较各类分析结果是常见的场景。在这类场景之下,将多个分析结果绘制在一张图上,可以帮助用户方便地组合和分析多个数组集,提高数据可视化地效果和准确性。本节介绍matplotlib绘制子图地常用方法和技巧。
添加子图主要有两种方式:
一种是函数式风格(也就是上一节中画布中介绍的方式)
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
x = np.linspace(0,1,20)
y1 = np.cos(2 * np.pi * x)
y2 = np.sin(2 * np.pi * x)
fig= plt.figure(figsize=[6,4])
fig.add_subplot(211)
plt.plot(x,y1)
fig.add_subplot(212)
plt.plot(x,y2)
另一种风格是面向对象的风格(使用Axes对象)
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
x = np.linspace(0,1,20)
y1 = np.cos(2 * np.pi * x)
y2 = np.sin(2 * np.pi * x)
fig, ax = plt.subplots(1,2)
ax[0].plot(x,y1)
ax[1].plot(x,y2)
子图的布局是按照行列设置的,设置之后,相应的位置可以添加子图。
x = np.array(range(1,10))
rows, cols = 2,2
fig, ax = plt.subplots(rows, cols)
for i in range(rows):
for j in range(cols):
y = np.random.randint(1,100,9)
ax[i,j].plot(x,y)
子图按照网格布局时,以上4个子图的Y轴刻度不一样,这样不利于比较。
x = np.array(range(1,10))
rows, cols = 2,2
fig, ax = plt.subplots(rows, cols,sharey='all')
for i in range(rows):
for j in range(cols):
y = np.random.randint(1,100,9)
ax[i,j].plot(x,y)
设置sharey='all'之后,Y轴刻度保持一致,这样比较曲线才有意义。上面的示例中X刻度是一致的,如果不一致,可以用sharex属性来设置。
3.1 不规则的网格
除了规则的网格布局,还可以通过GridSpec设置不规则的网格。
比如:
rows, cols = 3,3
grid = plt.GridSpec(rows, cols)
plt.subplot(grid[0,:2]) # 横向占两个单位0和1,竖直占1个单位0
plt.subplot(grid[0, 2]) # 横向占一个单位2,竖直占1个单位0
plt.subplot(grid[1,:2]) # 横向占一个单位0,竖直占1个单位1
plt.subplot(grid[1, 2]) # 横向占两个个单位1和2,竖直占1个单位1
plt.subplot(grid[2,:]) # 横向占三个单位0,1和2,竖直占1个单位2
上图设置了3行3列的网格,但是每个图形占用几个网格都是可以调整的。
除了网格,还可以通过相对定位的方式来绘制多个子图。
fig = plt.figure()
fig.add_axes([0.1,0.1,1, 1])
fig.add_axes([0.2,0.2,0.2, 0.2])
fig.add_axes([0.7,0.7,0.3, 0.15])
上面按相对位置添加子图的函数add_axes的参数是一个4元列表。这个列表4个元素的含义:
注意:这里4个值都是比例。
matplotlib中每个子图可以有自己的标签,大小,位置和样式,可以方便地组合成一个复杂地图形。我们一般在下来场景中使用子图:
matplotlib的坐标中是用于在绘图中表示数据的位置的工具。坐标轴是图像中的水平和垂直线,它们通常表示为x轴和y轴。坐标的作用是帮助观察者了解图中数据的位置和大小,通常有数字或标签,以指示特定的值在图像中的位置。
matplitlib绘制图形时,会自动根据X,Y轴的数值,自动确定其范围,确保能够涵盖所有的数值。
比如:
fig,ax = plt.subplots(2,1)
x = np.linspace(1,10,10)
y = np.random.randint(0,10,10)
ax[0].plot(x,y)
x = np.linspace(1,100,10)
y = np.random.randint(0,100,10)
ax[1].plot(x,y)
可以看出,图形中X轴,Y轴的范围是根据x,y列表中数值的最大值来生成的。有时候,为了看图的局部位置,可以主动设置X轴,Y轴的范围,而不是依靠自动生成。
比如:
fig, ax = plt.subplots(2,1)
x = np.array(range(0,8))
y = np.random.randint(1,100,8)
ax[0].set_xlim(3,6)
ax[0].plot(x,y)
y = np.random.randint(100,200,8)
ax[1].set_ylim(140,180)
ax[1].plot(x,y)
上面的示例设置第一个图的X轴范围,第二个图设置Y轴范围。
如果要把Y轴不同范围的两条曲线放在一起比较,就要用到双坐标轴。
如:
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
x = np.linspace(1,10,10)
y1 = np.random.randint(1,50,10)
y2 = np.random.randint(50,100,10)
ax.plot(x, y1, c='y')
ax.plot(x, y2, c='b')
上图中,黄色线条在0~50之间,蓝色线条在50~100之间。虽然放在一个图中比较,看着却如两个子图。这时,我们可以用两个不同的Y轴,从而能够让两条曲线更好的比较。
fig = plt.figure()
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax_twinx = ax.twinx()
x = np.linspace(1,10,10)
y1 = np.random.randint(1,50,10)
y2 = np.random.randint(51,100,10)
ax.plot(x, y1, c='g')
ax.plot(x, y2, c='b')
左边是绿线对应的Y轴,右边时蓝线对应的Y轴。
关于轴标轴的设置,还有一个比较常用的设置是反转坐标轴。坐标轴的默认顺序是从小到大,但是,对于一些特殊的图表类型(如果散点图、条形图、直方图等),可以通过反转坐标轴来更好地展示数据点地分布情况。
fig = plt.figure()
x = np.linspace(1,10,10)
y = np.random.randint(1,100,10)
ax1 = fig.add_subplot(211)
ax1.plot(x,y)
ax2 = fig.add_subplot(212)
ax2.invert_xaxis()
ax2.plot(x,y)
fig = plt.figure()
x = np.linspace(1,10,10)
y = np.random.randint(1,100,10)
ax1 = fig.add_subplot(211)
ax1.plot(x,y)
ax2 = fig.add_subplot(212)
ax2.invert_yaxis()
ax2.plot(x,y)
上例两个子图的Y轴顺序是相反的。
这里介绍的主要轴标轴在展示分析结果的不同场景中常用的设置方法,其它关于坐标轴字体,颜色等可以查阅官方文档。
matplotlib中刻度是用于在绘图中表示数据大小的工具。刻度是坐标轴上的数字或标签,用于指示数据的大小或值,通常以整数或小数表示,具体取决于坐标轴的类型和限制。
默认的绘制时,坐标轴只有默认的主要刻度,如下所示:
from matplotlib.ticker import MultipleLocator
x = np.linspace(1, 50 ,50)
y = np.random.randint(100,200, 50)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
w=ax.get_xaxis()
w.set_major_locator(MultipleLocator(20))
w.set_minor_locator(MultipleLocator(2))
v=ax.get_yaxis()
v.set_major_locator(MultipleLocator(50))
v.set_minor_locator(MultipleLocator(10))
ax.plot(x,y)
在上面示例中:
设置了X受的主要刻度间隔为20,次要刻度间隔2,也就是每2个主要刻度之间有10个次要刻度。
设置了Y轴的主要刻度间隔为50,次要刻度间隔10,也就是每2个主要刻度之间有5个次要刻度。
次要刻度就是上面图中主要刻度之间稍微短点的线。
刻度的样式非常灵活,常见的有以下几种设置。
隐藏刻度,只保留图形,这在做某些示意图时可能会用到。
x=np.linspace(1,100,100)
y=np.random.randint(0,200,100)
fig = plt.figure()
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
xaxis=ax.get_xaxis()
yaxis=ax.get_yaxis()
xaxis.set_major_locator(plt.NullLocator())
yaxis.set_major_locator(plt.NullLocator())
ax.plot(x,y)
密度时指刻度的间隔,如果图比较小,可以设置间隔大一些,反之则设置小一些。
from matplotlib.ticker import MultipleLocator
x = np.linspace(1,100,100)
y = np.random.randint(100,200,100)
rows, cols = 2, 2
grid = plt.GridSpec(rows, cols)
ax = plt.subplot(grid[0,0])
ax.plot(x, y)
ax.xaxis.set_major_locator(MultipleLocator(20))
ax.yaxis.set_major_locator(MultipleLocator(50))
ax = plt.subplot(grid[1,:])
ax.plot(x, y)
ax.xaxis.set_major_locator(MultipleLocator(10))
ax.yaxis.set_major_locator(MultipleLocator(20))
上例中,根据图形的大小,我们设置了刻度的不同密度。
为了突出默写刻度值,有时候会需要修改那些刻度值的颜色和大小。
x = np.linspace(1,100,100)
y = np.random.randint(100,200,100)
fig = plt.figure()
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax.xaxis.set_major_locator(MultipleLocator(10))
obj = ax.get_xticklabels()[2]
obj.set_size(20)
obj.set_color("pink")
ax.plot(x,y,c="y")
上面例子中,X轴刻度10被放大并且改成红色。
刻度的旋转一般在刻度内容比较长的情况下,比如下面的示例:
x=np.array([
"2023-01-01",
"2023-02-01",
"2023-03-01",
"2023-04-01",
"2023-05-01",
"2023-06-01",
"2023-07-01",
"2023-08-01",
"2023-09-01",
"2023-10-01",
"2023-11-01",
"2023-12-01",
])
y = np.random.randint(100,200,12)
fig = plt.figure()
ax = fig.add_axes([0.1, 0.1,0.8,0.8])
ax.plot(x,y, color="r")
由于X轴的刻度是日期,因为太长,所以会挤在一起,显示不清。这时可以调整X轴的刻度的角度,避免重合在一起。
x=np.array([
"2023-01-01",
"2023-02-01",
"2023-03-01",
"2023-04-01",
"2023-05-01",
"2023-06-01",
"2023-07-01",
"2023-08-01",
"2023-09-01",
"2023-10-01",
"2023-11-01",
"2023-12-01",
])
y = np.random.randint(100, 200, 12)
fig = plt.figure()
ax = fig.add_axes([0.1, 0.1,0.8,0.8])
plt.xticks(rotation=60)
ax.plot(x,y, color="r")
matplotlib的刻度还支持latex格式,可以显示一些特殊的字符,比如圆周率pi。
直接显示时:
x = np.array([0, np.pi/6, np.pi/4, np.pi/3, np.pi/2])
x = np.round(x,2)
y = np.sin(x)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
plt.xticks(labels=x, ticks=x)
ax.plot(x,y)
X轴的刻度显示实际的值。
调整为latex格式显示:(调整plt.xticks()这个函数)
x = np.array([0, np.pi/6, np.pi/4, np.pi/3, np.pi/2])
y = np.sin(x)
fig = plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
plt.xticks(labels=["0","$\pi/6$","$\pi/4","$\pi/3$","$\pi/2$"], ticks=x)
ax.plot(x,y)
X轴的刻度中显示圆周率pi,更易于阅读和理解。
与之前介绍的画布,子图和坐标轴相比,刻度时设置最多也是最复杂的一个容器。刻度的主要作用是帮助数组可视化更加清晰和易于理解,基于此,本节介绍了: