Fari

matplotlib.pyplot 一些基本概念

默认的figure和axes

首先明确概念,figure可以看作整个窗口,而axes只是其中的一个chart组件,figure中除了axes外,还有标题、按钮等组件

如果直接使用 plt.plot([1,2,3]),则会自动创建一个 figure,并且自动向该figure中添加一个 axes,画图就是在该axes中画

plt.plot([1,2,3]) # 直接调用plt.plot()会先自动创建一个figure和axes

plt.plot()会自动在最后一个激活的figure和最后一个激活的axes中画图,所以上述代码和下面的代码等价:

fig = plt.figure()plt.plot([1,2,3]) # 如果已经有figure,则会自动在最后一个figure中画图

上面这个代码其实和下面这个代码是一样的:

fig = plt.figure()fig.gca().plot([1,2,3]) # figure.gca() 即获取当前的(最后一个) axes,如果没有则自动创建一个# 也等价于plt.gcf().gca().plot([1,2,3]) # plt.gcf() 即获取当前的(最后一个)figure

同理也等价于下面代码:

fig, (ax1, ax2) = plt.subplots(1,2)ax2.plot([1,2,3]) # 是自动在最后一个figure中最后一个axes中画

figure.canvas.draw()

需要注意的是,上述代码,不管是调用 plot() 还是调用 scatter() 等,并没有真正在axes上画图,它只是相当于一个蓝图,真正的渲染得靠 fig.canvas.draw() 方法,在调用 plt.show() 时会自动调用该方法:

fig, ax = plt.subplots()ax.plot([1,2,3])plt.show() # 内部会先自动调用 fig.canvas.draw() 方法

plt.cla、plt.clf

plt.cla() 方法用于clean最后一个axes

fig, (ax1, ax2) = plt.subplots(1,2)ax1.plot([1,2])ax2.plot([2,1])plt.cla() # 只会清理最后一个axes(即ax2)plt.show()

同理,plt.clf() 则会将最后一个figure整个清理掉

如果不清理多次调用 ax.plot() 会怎样呢?

如前文所说,ax.plot() 并非真正渲染,只是创建一个蓝图,则多次调用 ax.plot() 方法会在同一个ax中添加多个折线或散点等,最后调用 draw() 方法一起在同一个ax上渲染

x = [1,2,3]y1 = [4,2,6]y2 = [8,3,5]plt.plot(x, y1)plt.plot(x, y2)plt.show()

plt中,如果创建的figure超过20个,则会出现警告,此时就可以考虑是不是代码有问题,明明只创建一个figure即可,然后每次调用 cla() 或 clf() 或 ax.clear() 后进行重绘。

动态更新数据

fig, ax = plt.subplots()ax.plot([], [])dynamic_data = []for i in range(100):  dynamic_data.append(i)  ax.lines[0].set_data(range(len(dynamic_data)), dynamic_data)  ax.relim() # 让x y 轴的上下限重置  ax.autoscale() # 让画面自动缩放以渲染全部数据  plt.draw()  # 此时就可以将figure保存成图片或者转成字符串等格式进行使用plt.show()

figuresize 指的什么

matplotlib中无法直接根据像素值大小设定figure大小,只能根据 英寸 大小设置

fig = plt.figure(figuresize=(2, 1)) # 创建一个宽2 inch,高1 inch的figure

如何根据像素大小设置figure大小呢,前提是你得知道你的显示器的dpi,即一英寸中有多少个像素,这个网站可以检测dpi:https://www.infobyip.com/detectmonitordpi.php,然后你就可以使用期望像素长度除以dpi,设置figure大小了

# 例如我的显示器dpi为96,我希望设置一个 宽高为 1280*960 像素的figurefig = plt.figure(figuresize=(1280/96, 960/96), dpi=96)

如何自定义显示方式

x = [1,2,3]y = [4,2,6]plt.plot(x, y)plt.xticks(rotation=25)  # 让轴的label旋转一定角度显示plt.gca().xaxis.set_major_formatter((lambda val, pos: f"{val=}, {pos=}"))  # 添加轴显示的映射关系plt.show()

通过查看源码可知,上述的 plt.xticks(rotation=25) 其实调用的是下面的代码:

for l in plt.gcf().gca().get_xticklabels():    # 这里遍历的是每个index的位置,由于plt会自动补充一些位置点,所以实际的比x中的元素要多    l.update({"rotation":25})

其他可设置的属性见 https://matplotlib.org/stable/api/text_api.html,例如 l.update({"rotation":25, "fontsize":"x-small"})

另外还有很多其他的方式,更简单的:

plt.gcf().gca().xaxis.set_tick_params(rotation=20, labelsize=7)