快速入门指南
官网
官方网址:Matplotlib — Visualization with Python
官方教程:Tutorials — Matplotlib 3.9.2 documentation
官方指南:Using Matplotlib — Matplotlib 3.9.2 documentation
官方示例:Examples — Matplotlib 3.9.2 documentation
官方API说明:API Reference — Matplotlib 3.9.2 documentation
plot type
Matplotlib
支持很多种绘图类型:绘图类型 — Matplotlib 3.9.2 文档 --- Plot types — Matplotlib 3.9.2 documentation
基本概念
figure
:Matplotlib在figure上绘制您的数据,可以理解为画板,每个图都可以包含一个或者多个axes。
axes
:轴,理解为画布更合理,每个图都可以包含一个或多个轴,可以在轴上根据x-y坐标指定点。
创建带有figure和axes最简单的方式:
fig, ax = plt.subplots() # Create a figure containing a single Axes.
ax.plot([1, 2, 3, 4], [1, 4, 2, 3]) # Plot some data on the Axes.
plt.show() # Show the figure.
Figure的组成部分
Title
:Axes的标题Minor tick
:次要刻度Major tick label
:主要刻度标签ylabel
:Y轴标签Major tick
:主刻度y Axis
:Y轴x Axis
:X轴xlabel
:X轴标签Minor tick label
:次要刻度标签Line
:绘制线型图Markers
:散点图的点的形状和颜色Grid
:网格Legend
:图例- Axes:画板
Figure
Figure对所有axes有效,一组Artists(比如titles
,figure legends
,colorbars
等),以及嵌套subfigures。
通常,使用下面的方式创建一个figure:
fig = plt.figure() # 一个空的figure, 没有axes
fig, ax = plt.subplots() # 一个figure上有一个axes
fig, axs = plt.subplots(2, 2) # 一个figure上有2x2个axes, 网格方式存放
# 一个figure上, 一个axes在左边, 两个axes在右边
fig, axs = plt.subplot_mosaic([['left', 'right_top'], ['left', 'right_bottom']])
Axes
语义上,Axes是axis的复数(Plural of axis)。
Matplotlib 使用 Axes 来指代包含数据、x 轴x-axis和 y 轴y-axis、刻度ticks、标签labels、标题titile等的绘图区域。另一个经常使用的术语是“subplot”,它指的是与其他 Axes 对象位于网格中的 Axes。
Axes是一个Artist粘贴在Figure上,该Figure包含绘制数据的区域,通常包括两个Axis 对象。
Axis提供刻度(tick)和刻度标签(tick label),以便为Axes中的数据提供刻度比例scales。
每一个Axes也有一个title(set_title()
)、x-label(set_xlabel
)、y-label(set_ylabel()
)。
Axes
方法是绘图大部分内容(添加数据、控制轴比例axis scales和限制limits、添加标签labels等)的主要接口。
Axis
Axis用来设置scale、limits、ticks (the marks on the Axis) 、tick-labels (strings labeling the ticks)。
ticks的位置由Locator决定。
tick-labels由Formatter决定。
正确的Locator
和Formatter
的组合可以对刻度位置和标签进行非常精细的控制。
Figure、Axes、Axis、x-label、y-label的区别:
Artist
基本上,Figure上所有可见的东西(比如Figure、Axes、Axis)都是Artist。
包括Text对象、Line2D对象、Collection对象、Patch对象等。
当Figure渲染时,所有的Artist都作用到Canvas上。
大部分Artist绑定在Axes上,这些Artist不能被多个Axis共享,也不能从一个轴移动到另一个轴。
绘图函数输入数据类型
绘图函数需要 numpy.array
作为输入,或者可以传递给 numpy.asarray
的对象
大多数方法还将解析字符串可索引对象,如dict
、structured numpy array
或 pandas.DataFrame
。
Matplotlib 允许您提供 data
的key
作为参数并生成图,传递对应于 x 和 y 变量的字符串。
编码风格
隐式和显示创建
有三种方法可以使用Matplotlib:
- 显示创建Figure和Axes,并在此基础上调用方法,面向对象方式(the "object-oriented (OO) style")。本教程中示例代码主要使用这种方式。
- 依赖pyplot隐式创建和管理Figures和Axes,并使用pyplot函数进行绘图,类似MatLib。
- 此外,还可以在GUI程序中嵌套Matplotlib,比如Tkinter。
OO-Style
方式举例:
x = np.linspace(0, 2, 100) # Sample data.
# Note that even in the OO-style, we use `.pyplot.figure` to create the Figure.
fig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained')
ax.plot(x, x, label='linear') # Plot some data on the Axes.
ax.plot(x, x**2, label='quadratic') # Plot more data on the Axes...
ax.plot(x, x**3, label='cubic') # ... and some more.
ax.set_xlabel('x label') # Add an x-label to the Axes.
ax.set_ylabel('y label') # Add a y-label to the Axes.
ax.set_title("Simple Plot") # Add a title to the Axes.
ax.legend() # Add a legend.
pyplot-style
方式举例:
x = np.linspace(0, 2, 100) # Sample data.
plt.figure(figsize=(5, 2.7), layout='constrained')
plt.plot(x, x, label='linear') # Plot some data on the (implicit) Axes.
plt.plot(x, x**2, label='quadratic') # etc.
plt.plot(x, x**3, label='cubic')
plt.xlabel('x label')
plt.ylabel('y label')
plt.title("Simple Plot")
plt.legend()
Styling Artists
大多数绘图方法都有Artists的样式选项,也可以从Artists的setter访问。
下面的示例,手动设置plot的Artists的color、linewidth、linestyle:
fig, ax = plt.subplots(figsize=(5, 2.7))
x = np.arange(len(data1))
ax.plot(x, np.cumsum(data1), color='blue', linewidth=3, linestyle='--')
l, = ax.plot(x, np.cumsum(data2), color='orange', linewidth=2)
l.set_linestyle(':')
颜色
大部分Artist都可以有灵活的color,一些Artist会采用多种颜色,比如散点图Scatter,标记的边沿和内部可以是不同的颜色。
线宽、线的风格、标记大小
-
线宽通常以印刷点为单位 (1pt = 1/72英寸 = 0.035277777778cm,1英寸=2.54厘米),可用于描述有lines的Artist。
-
支持的线的风格:线型 — Matplotlib 3.9.2 文档 --- Linestyles — Matplotlib 3.9.2 documentation
-
Marker的大小取决于使用的方法。
plot
以磅pt(point)为单位,通常标记直径或者宽度。Scatter
将MakerSize指定为与标记的可视区域大致成正比。 -
Matplotlib提供的一组字符串代码的
MarkerStyle
可以参考:matplotlib.markers — Matplotlib 3.9.2 文档 --- matplotlib.markers — Matplotlib 3.9.2 documentation,用户也可以自己定义。
Labelling plots
Axes labels and text
set_xlabel
、set_ylabel
、set_title
用于在指定位置添加文本。也可以直接使用text
将文本添加到图中。
在文本中使用数学表达式
Matplotlib 接受任何文本表达式中的 TeX 方程表达式。 例如,要在标题中编写表达式 σi=15 , 你可以编写一个由美元符号包围的 TeX 表达式:
ax.set_title(r'$\sigma_i=15$')
Annotations注释
我们还可以通过将指向 xy 的箭头连接到 xytext 处的一段文本来注释图上的点。
Legends图例
我们通常希望使用 Axes.legend
识别线条或标记:
fig, ax = plt.subplots(figsize=(5, 2.7))
ax.plot(np.arange(len(data1)), data1, label='data1')
ax.plot(np.arange(len(data2)), data2, label='data2')
ax.plot(np.arange(len(data3)), data3, 'd', label='data3')
ax.legend()
Axis scales and ticks
每个 Axes 都有两个(或三个)Axis
对象,分别表示 x 轴和 y 轴。它们控制轴的比例scales、tick locators和tick formatters。
scales
scales设置从数据值到沿轴的间距的映射。这在两个方向上发生,并被组合成一个变换,这就是 Matplotlib 从数据坐标映射到轴、图形或屏幕坐标的方式。
除了线性刻度之外,Matplotlib 还提供非线性刻度,例如对数刻度。
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import FixedLocator, NullFormatter
# Fixing random state for reproducibility
np.random.seed(19680801)
# make up some data in the interval ]0, 1[
y = np.random.normal(loc=0.5, scale=0.4, size=1000)
y = y[(y > 0) & (y < 1)]
y.sort()
x = np.arange(len(y))
# plot with various axes scales
fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(6, 4))
print (axs)
# linear
ax = axs[0]
ax.plot(x, y)
ax.set_yscale('linear')
ax.set_title('linear')
ax.grid(True)
# log
ax = axs[1]
ax.plot(x, y)
ax.set_yscale('log')
ax.set_title('log')
ax.grid(True)
plt.show()
Tick locators and formatters
每个 Axis 都有一个tick locator和formatter,用于选择沿 Axis 对象放置刻度线的位置。一个简单的接口是 set_xticks
:
axs[1].set_xticks(np.arange(0, 100, 30), ['zero', '30', 'sixty', '90'])
axs[1].set_yticks([-1.5, 0, 1.5]) # note that we don't need to specify labels
不同的scale可以有不同的 locator和formatter,例如,上面的 log-scale 使用 LogLocator
和 LogFormatter
。
Plotting dates and strings
Matplotlib 可以处理绘制日期数组和字符串数组,以及浮点数。这些会根据需要获得特殊的 locators 和formatters。
对于日期:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.dates import ConciseDateFormatter
fig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained')
dates = np.arange(np.datetime64('2021-11-15'), np.datetime64('2021-12-25'), np.timedelta64(1, 'h'))
data = np.cumsum(np.random.randn(len(dates)))
ax.plot(dates, data)
ax.xaxis.set_major_formatter(ConciseDateFormatter(ax.xaxis.get_major_locator()))
plt.show()
对于字符串:
fig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained')
categories = ['turnips', 'rutabaga', 'cucumber', 'pumpkins']
ax.bar(categories, np.random.rand(len(categories)))
关于分类绘图的一个警告是,某些解析文本文件的方法会返回字符串列表,即使字符串都表示数字或日期。如果您传递 1000 个字符串,Matplotlib 会认为您指的是 1000 个类别,并将在您的绘图中添加 1000 个刻度!这种情况还是比较常见。
Additional Axis objects
在一个图表中绘制不同量级的数据可能需要额外的 y 轴。可以通过使用 twinx
添加一个不可见的 x 轴和一个位于右侧的 y 轴的新轴来创建这样的轴(类似于 twiny
)。
同样,也可以添加与主轴具有不同比例的secondary_xaxis
或secondary_yaxis
,以不同的比例或单位表示数据。有关更多示例,请参阅 Secondary Axis 。
import matplotlib.pyplot as plt
import numpy as np
# Create some mock data
t = np.arange(0.01, 10.0, 0.01)
data1 = np.exp(t)
data2 = np.sin(2 * np.pi * t)
fig, ax1 = plt.subplots()
color = 'tab:red'
ax1.set_xlabel('time (s)')
ax1.set_ylabel('exp', color=color)
ax1.plot(t, data1, color=color)
ax1.tick_params(axis='y', labelcolor=color)
ax2 = ax1.twinx() # instantiate a second Axes that shares the same x-axis
color = 'tab:blue'
ax2.set_ylabel('sin', color=color) # we already handled the x-label with ax1
ax2.plot(t, data2, color=color)
ax2.tick_params(axis='y', labelcolor=color)
fig.tight_layout() # otherwise the right y-label is slightly clipped
plt.show()
Color mapped data
通常,我们希望在绘图中拥有由颜色图中的颜色表示的第三个维度。Matplotlib 有许多绘图类型可以做到这一点。
Colormaps
这些都是从 ScalarMappable
对象派生的 Artist 示例。它们都可以将 vmin 和 vmax 之间的线性映射设置为 cmap 指定的颜色图。
Matplotlib 有许多颜色图可供选择(在 Matplotlib 中选择颜色图),您可以制作自己的颜色图(在 Matplotlib 中创建颜色图)或作为第三方包下载。
Matplotlib提供的Colormap:在 Matplotlib 中选择颜色图 — Matplotlib 3.9.2 文档 --- Choosing Colormaps in Matplotlib — Matplotlib 3.9.2 documentation
Normalizations
有时我们希望数据到颜色图的非线性映射。为此,我们向 ScalarMappable 提供 norm 参数,而不是 vmin 和 vmax。
颜色图归一化中显示了更多归一化。
Colorbars
NA
使用多个 Figures 和 Axes
可以通过多次调用 fig = plt.figure()
或 fig2, ax = plt.subplots()
来打开多个 Figure。
通过保留对象引用,您可以将 Artists 添加到任一个 Figure。
可以通过多种方式添加多个Axes,但最基本的是上面使用的 plt.subplots()
。
也可以使用 subplot_mosaic
实现更复杂的布局,其中 Axes 对象跨列或跨行。
fig, axd = plt.subplot_mosaic([['upleft', 'right'], ['lowleft', 'right']], layout='constrained')
axd['upleft'].set_title('upleft')
axd['lowleft'].set_title('lowleft')
axd['right'].set_title('right')
Matplotlib 具有相当复杂的轴排列工具:See Arranging multiple Axes in a Figure and Complex and semantic figure composition (subplot_mosaic).
常见问题
Why do I have so many ticks, and/or why are they out of order?
意外ticks行为的一个常见原因是传递字符串列表,而不是数字或日期时间对象。在读取CSV的文本文件时,这很容易发生,而不会引起通知。
Matplotlib 将字符串列表视为strings as categorical variables
,默认情况下为每个类别放置一个勾号,并按照提供它们的顺序绘制它们。
解决方案是将字符串列表转换为数字或日期时间对象(通常为 np.asarray(numeric_strings, dtype='float')
或 np.asarray(datetime_strings, dtype='datetime64[s]'))。
Save multiple plots to one pdf file
许多图像文件格式每个文件只能有一个图像,但某些格式支持多页文件。目前,Matplotlib 仅通过 backend_pdf 使用 pdf 或 pgf backends为 pdf 文件提供多页输出。
PdfPages
和 backend_pgf。PdfPages
类。
Make room for tick labels
默认情况下,Matplotlib 在subplots周围使用固定的百分比边距。这可能会导致Label重叠或在figure边界处被截断。
有多种方法可以解决此问题:
-
使用
Figure.subplots_adjust
/pyplot.subplots_adjust
手动调整子图参数。 -
使用以下自动布局机制之一:
-
自己根据绘图元素的大小计算出合适的值(以编程方式控制子图调整)
Draw multiple y-axis scales
一个常见的需求是为左轴和右 y 轴设置两个刻度,这可以使用 twinx()
实现(目前不支持两个以上的刻度,尽管它在愿望列表中)。
Generate images without having a window appear
只需不调用 show
,直接将图形保存为所需的格式即可:
import matplotlib.pyplot as plt
plt.plot([1, 2, 3])
plt.savefig('myfig.png')
Figures介绍
在查看 Matplotlib 可视化时,您几乎总是在查看放置在 Figure
上的 Artists
。
在下面的示例中,Figure是蓝色区域,并且通过add_subplot
向Figure
添加了Axes
的Aritist。
更复杂的可视化可以在Figure中添加多个Axes。Colorbars、Legends、Annotations以及Axes都可以添加多个Artists(例如 ax.plot
或 ax.imshow
)。
fig = plt.figure(figsize=(4, 2), facecolor='lightskyblue', layout='constrained')
fig.suptitle('A nice Matplotlib Figure')
ax = fig.add_subplot()
ax.set_title('Axes', loc='left', fontstyle='oblique', fontsize='medium')
Viewing Figures
Notebooks and IDEs
如果使用的是Notebooks and IDEs,例如 Jupyter,那么它们有一个后端,可以在执行代码单元时渲染 Matplotlib Figure。
Standalone scripts and interactive use
如果用户使用的是带有窗口系统的客户端,则可以使用许多后端将图形呈现到屏幕上,通常使用 Python Qt、Tk 或 Wx 工具包。
这些通常是在用户的 matplotlibrc 中选择的,或者通过在会话或脚本开始时调用 matplotlib.use('QtAgg')
来选择。
当从脚本或交互方式(例如从 IPython shell)运行时,在我们调用 plt.show()
之前,不会显示 Figure。Figure将出现在一个新的 GUI 窗口中,并且通常有一个工具栏,其中包含 Zoom、Pan 和其他用于与Figure交互的工具。
默认情况下,plt.show()
会阻止脚本或 shell 的进一步交互,直到 Figure 窗口关闭,但出于某些目的可以将其关闭。
Creating Figures
创建Figure的最常见方法是使用 pyplot 接口。pyplot 接口有两个用途:
- 一种是启动 Backend 并跟踪 GUI 窗口。另一个是 Axes 和 Artists 的全局状态,它允许使用简短的 API 来绘制图形。
fig = plt.figure(figsize=(2, 2), facecolor='lightskyblue', layout='constrained')
在上面的示例中,我们首先使用 pyplot,并创建 Figure 对象 fig
.作为返回值, fig
也被添加到 pyplot 的全局状态中,可以通过 gcf
访问。
用户在创建 Figure 时通常需要 Axes 或 Axes 网格,因此除了 Figure
之外,还有一些方便的API可以同时返回 Figure 和一些 Axe:
fig, axs = plt.subplots(2, 2, figsize=(4, 3), layout='constrained')
也可以使用 pyplot.subplot_mosaic
实现更复杂的网格:
fig, axs = plt.subplot_mosaic([['A', 'right'], ['B', 'right']], figsize=(4, 3), layout='constrained')
for ax_name, ax in axs.items():
ax.text(0.5, 0.5, ax_name, ha='center', va='center')
有时我们希望在Figure中有一个嵌套布局,其中包含两组或多组Axes,这些Axes不共享相同的子绘图网格。我们可以使用add_subfigure()
或subfigures
在父Figure中创建:
fig = plt.figure(layout='constrained', facecolor='lightskyblue')
fig.suptitle('Figure')
figL, figR = fig.subfigures(1, 2)
figL.set_facecolor('thistle')
axL = figL.subplots(2, 1, sharex=True)
axL[1].set_xlabel('x [m]')
figL.suptitle('Left subfigure')
figR.set_facecolor('paleturquoise')
axR = figR.subplots(1, 2, sharey=True)
axR[0].set_title('Axes 1')
figR.suptitle('Right subfigure')
Figure options
matplotlib.pyplot.figure(num=None, figsize=None, dpi=None, *, facecolor=None, edgecolor=None, frameon=True, FigureClass=<class 'matplotlib.figure.Figure'>, clear=False, **kwargs)
创建Figure时,有一些选项可以配置:
- figsize:屏幕上的图形大小由 figsize 和 dpi 设置。figsize 是图形的
(width, height)
,以英寸inches为单位。 - dpi:是图形每英寸将呈现多少像素。要使您的图形以您请求的物理尺寸显示在屏幕上,应将 dpi 设置为与您的图形系统相同的 dpi。
- facecolor、edgecolor、linewidth、frameon:以预期的方式更改图形的外观,如果设置为 False,则 frameon 会使图形透明。
- 用户可以使用 layout 参数为Figure指定布局引擎。目前 Matplotlib 提供 “constrained”、“compressed” 和 “tight” 布局引擎。这些功能会重新缩放 Figure 内的轴,以防止刻度标签重叠,并尝试对齐轴,并且可以在许多常见情况下节省对 Figure 上Artists的大量手动调整。
Adding Artists
Figure有很多将Artists添加到Figure或SubFigure的方法。最常见的有添加各种配置: (add_axes
, add_subplot
, subplots
, subplot_mosaic
)和 (subfigures
)。
Colorbars被添加到Axes或Axes组的级别,也可能有Figure-Level的Legend。
其它Artist包括figure-wide标签,比如 (suptitle
, supxlabel
, supylabel
) and text (text
)。
最后,可以使用 add_artist
直接添加低级 Artist,但通常需要注意使用适当的转换。通常,这些包括 Figure.transFigure
,它在每个方向上的范围从 0 到 1,表示当前 Figure 大小的分数,或者 Figure.dpi_scale_trans
以距离 Figure 左下角的英寸物理单位(有关详细信息,请参阅转换教程)。
Saving Figures
可以使用 savefig
方法将 Figures 保存到磁盘。比如fig.savefig('MyFigure.png', dpi=200)
会将 PNG 格式的Figure以每英寸 200 点的分辨率保存到磁盘上当前目录下的 MyFigure.png
文件中。
文件名可以包含文件系统上任何位置的相对或绝对路径。
支持多种类型的输出,包括 PNG、GIF、JPEG、TIFF 等光栅格式以及 PDF、EPS 和 SVG 等矢量格式。
默认情况下,保存的Figure的大小由Figure size(以英寸inches为单位)设置,对于栅格格式,则由 dpi 设置。如果未设置 dpi,则使用 Figure 的 dpi。请注意,如果Figure包含已栅格化的Artists,则 dpi*对于矢量格式(如 PDF)仍然有意义,指定的 DPI 将是栅格化对象的分辨率。
可以使用 savefig
的 bbox_inches
参数更改 Figure 的大小。这可以手动指定,同样以英寸为单位。最常见的用法是 bbox_inches='tight'
。此选项“收缩包装”,根据需要修剪或扩展图形的大小,使其紧密围绕Figure中的所有Artist,并使用一个可由 pad_inches
参数指定pad,默认为 0.1 英寸。
下图中的虚线框显示了如果在 savefig
中使用 bbox_inches='tight'
将保存的图形部分。
后端Backends
What is a backend?
Backends用于在屏幕上显示 Matplotlib 图形或写入文件。
Matplotlib 可能有许多不同的用例和输出格式:
- 从 Python shell 以交互方式使用 Matplotlib,并在键入命令时弹出绘图窗口。
- 运行 Jupyter 笔记本并绘制内联图以进行快速数据分析。
- 其他应用程序将 Matplotlib 嵌入到 PyQt 或 PyGObject 等图形用户界面中,以构建丰富的应用程序。
为了支持所有这些用例,Matplotlib 可以针对不同的输出,这些功能中的每一种都称为后端;
“前端”是面向用户的代码,即绘图代码,而“后端”在幕后完成所有艰苦的工作来制作图形。
有两种类型的后端:
- user interface backends用户界面后端:用于 PyQt/PySide、PyGObject、Tkinter、wxPython 或 macOS/Cocoa,也称为“交互式后端”
- hardcopy backends硬拷贝后端:用于制作图像文件PNG、SVG、PDF、PS,也称为“非交互式后端”。
Selecting a backend
有三种方法可以配置您的后端:
matplotlibrc
文件中的rcParams["backend"]
参数MPLBACKEND
环境变量matplotlib.use()
函数
The builtin backends
默认情况下,Matplotlib 应该自动选择一个默认的后端,该后端允许交互式工作和脚本绘图,输出到屏幕和/或文件,因此至少在最初,您无需担心后端。
Matplotlib Application Interfaces (APIs)
Matplotlib 有两个主要的应用程序界面,或使用库的样式:
- 一个显式的“Axes”接口,它使用 Figure 或 Axes 对象上的方法来创建其他 Artists,并逐步构建可视化效果。这也称为 “面向对象” 接口。
- 一个隐式的 “pyplot” 接口,用于跟踪最后创建的 Figure 和 Axes,并将 Artists 添加到它认为用户想要的对象中。
Native Matplotlib interfaces
The explicit "Axes" interface
Axes
接口是 Matplotlib 的实现方式,许多自定义和微调最终都在这个级别完成。
此接口的工作原理是实例化 Figure
类的实例,在该对象上使用subplots
方法创建一个或多个Axes
对象,然后在Axes上调用绘图方法。
比如:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.subplots()
ax.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])
我们称其为 “显式” 接口,因为每个对象都被显式引用,并用于生成下一个对象。保留对象的引用非常灵活,并允许我们在对象创建之后但在显示对象之前对其进行自定义。
The implicit "pyplot" interface
pyplot
模块隐藏了大多数 Axes
绘图方法,以提供与上述等效内容,其中 Figure 和 Axes 的创建是为用户完成的:
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])
本教程基本不使用这种方式。
Appendix: "Axes" interface with data structures#
大多数 Axes
方法允许另一个 API 寻址,方法是将数据对象传递给绘图方法并将参数指定为字符串
:
import matplotlib.pyplot as plt
data = {'xdat': [0, 1, 2, 3], 'ydat': [0, 0.2, 0.4, 0.1]}
fig, ax = plt.subplots(figsize=(3, 2))
ax.plot('xdat', 'ydat', data=data)
plt.show()
交互式Figures
在处理数据时,交互性可能非常宝贵。Matplotlib GUI 窗口中内置的平移/缩放和鼠标定位工具通常就足够了,但您也可以使用事件系统来构建自定义的数据探索工具。
Matplotlib 附带了绑定到多个 GUI 工具包(Qt、Tk、Wx、GTK、macOS、JavaScript)的后端
为了使图形能够响应鼠标、键盘和绘制事件,需要将 GUI 事件循环与交互式提示符集成。
pyplot
模块提供了用于显式创建图形的功能,其中包括交互式工具、工具栏、工具提示和键绑定:
pyplot.figure
:创建新的空Figure或选择现有的Figurepyplot.subplots
:创建一个新的Figure,并使用Axespyplot.gcf
:获取当前Figure,如果当前没有Figure,会创建一个新的Figurepyplot.gca
:获取当前Axes
,如果图窗上当前没有Axes,则会创建一个新Axes
pyplot
中的几乎所有函数都根据需要通过当前的 Figure
/ Axes
(或创建一个)。
交互模式
pyplot.ion
:启用交互模式
pyplot.ioff
:禁用交互模式
pyplot.isinteractive
:返回是否在每次绘图命令后更新绘图
pyplot.show
:显示所有打开的figures
pyplot.pause
:运行GUI事件循环
如果您处于非交互模式(或在非交互模式下创建图形),则需要显式调用 pyplot.show
来在屏幕上显示窗口。当前教程就是非交互模式。
默认UI
pyplot
创建的窗口有一个交互式工具栏,带有导航按钮和光标指向的数据值的读数。
交互式导航
所有Figure窗口都带有一个导航工具栏,可用于在数据集中使用。
Forward
和Back
用于在先前定义的视图之间来回导航。除非您已经使用平移和缩放按钮导航到其他位置,否则它们没有任何意义。Home
会将您带到数据的第一个默认视图。Pan/Zoom
平移和缩放:单击按钮激活平移和缩放,然后将鼠标放在轴上的某个位置。按住鼠标左键可平移图窗,将其拖动到新位置。当释放鼠标时,按下的点下的数据将移动到您释放的点。Zoom-to-Rectangle
缩放到矩形:当鼠标按照坐标轴上,然后按住鼠标左键拖动会定义一个矩形区域并放大,相反,按住鼠标右键拖动会缩小。Subplot-configuration
:使用此按钮可配置子图的外观。可以拉伸或压缩子图的左侧、右侧、顶部或底部,或者行之间的间距或列之间的间距。Save
:单击此按钮可启动文件保存对话框。可以使用以下扩展名保存文件:png
、ps
、eps
、svg
和pdf
。
Axes简介
Axes
是创建数据可视化的关键,将Axes放在Figure上后,可以使用很多方法将数据添加到Axes。Axis
通常是一对Artists,用于定义数据坐标系,并且包含用于添加注释(比如x-label、y-label、legends)的方法。
上图中,Axes使用ax = fig.subplots()
创建,Figure上的其它内容都是通过ax对象的方法创建,或者可以从该对象访问。
如果想更改x轴上的标签,调用ax.set_xlabel('new label')
方法。如果想绘制一些数据,调用ax.plot(x, y)
。
上图中,唯一不属于Axes的Artist是Figure本身,也就是axes.Axes
。
创建Axes
Axes使用Figure对象上的方法添加,或者可以使用pyplot
接口添加。
fig, axs = plt.subplots(ncols=2, nrows=2, figsize=(3.5, 2.5), layout="constrained")
还有其他方法可以将 Axes 添加到 Figure:
Figure.add_axes
:比如fig.add_axes([0, 0, 1, 1])
会创建一个填充整个图形的Axes。pyplot.subplots
和Figure.subplots
:添加网格状的Axes,注意:fig, ax = plt.subplots
添加的单个Axes。pyplot.subplot_mosaic
和Figure.subplot_mosaic
:添加一个名为Axes的网格并返回一个字典。比如fig, axs = plt.subplot_mosaic([['left', 'right'], ['bottom', 'bottom']])
, 其中axs['left'])
是左侧顶行的Axes,axs['botton']
是跨越底部两列的轴。
Axes绘制方法
大多数高级绘图方法都基于axes.Axes
类。请参阅 Plot types 以获取示例。
一个基本示例是 axes.Axes.plot
:
fig, ax = plt.subplots(figsize=(4, 3))
np.random.seed(19680801)
t = np.arange(100)
x = np.cumsum(np.random.randn(100))
lines = ax.plot(t, x)
plot返回的是lines Artists,这些lines可以人为操作。
下面是一个非常不完整的绘图方法列表,可以参考 Plot types 获取更完整的示例。
类别 | 支持的绘图类型 |
---|---|
Pairwise data成对数据 | plot、scatter、bar、step |
Array objects数组对象 | pcolormesh、contour、quiver、steamplot |
Statistical distribution统计分布 | hist、errorbar、hist2d、pie、boxplot、violinplot |
Irregularly gridded data不规则网格化数据 | tricontour、tripcolor |
Axes标签和注释
通常我们希望用 xlabel、ylabel 和 title 来标记 Axes,并且通常我们希望有一个图例来区分绘图元素。Axes
类具有许多用于创建这些注释的方法。
ax.set_xlabel('Time [s]')
ax.set_ylabel('Distance [km]')
ax.set_title('Random walk example')
ax.legend()
这些方法比较简单,也可以使用Text对象将文本添加到Axes,并进行注释Annotate,但这比较复杂。
Axes limits, scales, and ticking
每个 Axes 都有两个(或多个)Axis
对象,可以通过 xaxis
和 yaxis
属性访问这些对象。这些 Axis 上有大量的方法。
其他重要方法,比如设置Axes的范围 (set_xlim
、set_ylim
),或者更基本地设置Axes的比例。
例如:可以使Axis具有对数刻度:
fig, ax = plt.subplots(figsize=(4, 2.5), layout='constrained')
np.random.seed(19680801)
t = np.arange(200)
x = 2**np.cumsum(np.random.randn(200))
linesx = ax.plot(t, x)
ax.set_yscale('log')
ax.set_xlim([20, 180])
Axes 类还具有用于处理 Axis 刻度ticks及其标签Label的帮助程序。最直接的是 set_xticks
和 set_yticks
,它们手动设置ticks位置及其Lable(可选)。
Axes 刻度ticks和刻度标签tick labeling的许多方面都可以使用 tick_params
进行调整。例如,要标记axes的顶部而不是底部,请将刻度线设置为红色,并将刻度标签设置为绿色:
fig, ax = plt.subplots(figsize=(4, 2.5))
ax.plot(np.arange(10))
ax.tick_params(top=True, labeltop=True, color='red', axis='x', labelcolor='green')
Axes布局
有时在数据空间中设置绘图的纵横比很重要,我们可以用set_aspect
来做到这一点:
fig, axs = plt.subplots(ncols=2, figsize=(7, 2.5), layout='constrained')
np.random.seed(19680801)
t = np.arange(200)
x = np.cumsum(np.random.randn(200))
axs[0].plot(t, x)
axs[0].set_title('aspect="auto"')
axs[1].plot(t, x)
axs[1].set_aspect(3)
axs[1].set_title('aspect=3')
在一个 Figure 中排列多个 Axes
通常需要在一个Figure上有多个 Axes,组织成一个规则的网格。Matplotlib 有多种工具可用于处理Axes网格。
Matplotlib 使用 Axes 来指代包含数据、x 轴x-axis和 y 轴y-axis、刻度ticks、标签labels、标题titile等的绘图区域。另一个经常使用的术语是“subplot”,它指的是与其他 Axes 对象位于网格中的 Axes。
创建 Axes 的网格形状组合
subplots
:用于创建Figures和 Axes 网格的主要功能。它一次创建所有Axes并放置在Figure上,并返回一个对象数组,其中包含网格中Axes的句柄。subplot_mosaic
:一种创建Figures和Axes网格的简单方法,并且Axes可以跨行或列,增加了灵活性。Axes以带标签的字典而不是数组的形式返回。SubFigure
:有时,拥有不止一组不同的 Axes 网格是很自然的,在这种情况下,Matplotlib 有SubFigure
可以实现。
一次添加单个轴
Matplotlib可以一次添加一个 Axes。
add_axes
:在[left, bottom, width, height]
指定的位置以Figure宽度或高度的比例添加单个 Axes。subplot
或Figure.add_subplot
:在Figure上添加单个子图,具有从 1 开始的索引。可以通过指定网格单元格范围来跨越列和行。subplot2grid
:类似于pyplot.subplot
,但使用从 0 开始的索引和二维 python 切片来选择单元格。
示例:将3x2英寸的Axes添加到4x3英寸的Figure中,子图的位置由[left, bottom, width, height] (以数字归一化单位表示):
import matplotlib.pyplot as plt
import numpy as np
w, h = 4, 3
margin = 0.5
fig = plt.figure(figsize=(w, h), facecolor='lightblue') # facecolor: Figure的颜色
# width = 0.75, 4 * 0.75 = 3; heigh = (2/3) * 3 = 2
ax = fig.add_axes([margin / w, margin / h, (w - 2 * margin) / w, (h - 2 * margin) / h])
创建网格的高级方法
基本 2x2 网格
可以使用subplots
创建一个基本的 2×2 轴网格。它返回一个 Figure
实例和一个 Axes
对象数组。Axes 对象可用于访问将Artist放置在 Axes 上的方法。这里我们使用 Annotate
,但其他示例可以是 Plot
、pColorMesh
等。
import matplotlib.pyplot as plt
import numpy as np
# Grid为2x2
fig, axs = plt.subplots(ncols=2, nrows=2, figsize=(5.5, 3.5), layout="constrained")
# add an artist, in this case a nice label in the middle...
for row in range(2):
for col in range(2):
axs[row, col].annotate(f'axs[{row}, {col}]', (0.5, 0.5),
transform=axs[row, col].transAxes,
ha='center', va='center', fontsize=18,
color='darkgrey')
fig.suptitle('plt.subplots()')
也可以使用 subplot_mosaic
也可以实现相同的效果,但返回类型是字典而不是数组,用户可以在其中为键提供有用的含义。在这里,我们提供了两个列表,每个列表代表一行,列表中的每个元素都有一个代表列的键。
import matplotlib.pyplot as plt
import numpy as np
def annotate_axes(ax, text, fontsize=18):
ax.text(0.5, 0.5, text, transform=ax.transAxes,
ha="center", va="center", fontsize=fontsize, color="darkgrey")
fig, axd = plt.subplot_mosaic([['upper left', 'upper right'],
['lower left', 'lower right']],
figsize=(5.5, 3.5), layout="constrained")
for k, ax in axd.items():
annotate_axes(ax, f'axd[{k!r}]', fontsize=14)
fig.suptitle('plt.subplot_mosaic()')
固定纵横比轴的网格
固定纵横比轴通常用于images或maps。但是,它们对布局提出了挑战,因为对 Axes 的大小施加了两组约束 - 它们适合图中,并且它们具有固定的纵横比。默认情况下,这会导致 Axes 之间出现较大的间隙。
解决此问题的一种方法是将figure的纵横比更改为接近 Axes 的纵横比,但这需要反复试验。Matplotlib 还提供 layout='compressed'
,它将与简单的网格一起使用以减少 Axes 之间的间隙。
fig, axs = plt.subplots(2, 2, layout="compressed", figsize=(5.5, 3.5),
facecolor='lightblue')
for ax in axs.flat:
ax.set_aspect(1)
fig.suptitle('Fixed aspect Axes: compressed')
跨网格中的行或列
有时我们希望 Axes 跨越网格的行或列。实际上有多种方法可以完成此操作,但最方便的可能是通过重复其中一个键来使用 subplot_mosaic
:
fig, axd = plt.subplot_mosaic([['upper left', 'right'],
['lower left', 'right']],
figsize=(5.5, 3.5), layout="constrained")
for k, ax in axd.items():
annotate_axes(ax, f'axd[{k!r}]', fontsize=14)
fig.suptitle('plt.subplot_mosaic()')
fig, axd = plt.subplot_mosaic([['upper left', 'upper right'],
['lower', 'lower']],
figsize=(5.5, 3.5), layout="constrained")
for k, ax in axd.items():
annotate_axes(ax, f'axd[{k!r}]', fontsize=14)
fig.suptitle('plt.subplot_mosaic()')
网格中的可变宽度或高度
subplots
和和subplot_mosaic
都使用 gridspec_kw 关键字参数允许网格中的行具有不同的高度,并且允许列具有不同的宽度。
GridSpec
接受的间距参数可以传递给subplots
和subplot_mosaic
:
gs_kw = dict(width_ratios=[1.4, 1], height_ratios=[1, 2])
fig, axd = plt.subplot_mosaic([['upper left', 'right'],
['lower left', 'right']],
gridspec_kw=gs_kw, figsize=(5.5, 3.5),
layout="constrained")
for k, ax in axd.items():
annotate_axes(ax, f'axd[{k!r}]', fontsize=14)
fig.suptitle('plt.subplot_mosaic()')
嵌套轴布局
有时,可能需要两个或多个可能不需要彼此关联的 Axes 网格。实现此目的的最简单方法是使用 Figure.subfigures
。
请注意,SubFigures布局是独立的,因此每个subFigure中的 Axes 不一定对齐。
fig = plt.figure(layout="constrained")
subfigs = fig.subfigures(1, 2, wspace=0.07, width_ratios=[1.5, 1.])
axs0 = subfigs[0].subplots(2, 2)
subfigs[0].set_facecolor('lightblue')
subfigs[0].suptitle('subfigs[0]\nLeft side')
subfigs[0].supxlabel('xlabel for subfigs[0]')
axs1 = subfigs[1].subplots(3, 1)
subfigs[1].suptitle('subfigs[1]')
subfigs[1].supylabel('ylabel for subfigs[1]')
也可以使用 subplot_mosaic
嵌套 Axes 实现,此方法不使用SubFigures。
inner = [['innerA'],
['innerB']]
outer = [['upper left', inner],
['lower left', 'lower right']]
fig, axd = plt.subplot_mosaic(outer, layout="constrained")
for k, ax in axd.items():
annotate_axes(ax, f'axd[{k!r}]')
低级和高级网格方法
在内部,通过创建 GridSpec
和 SubplotSpec
的实例来控制 Axes 网格的排列。GridSpec 定义一个(可能不均匀的)单元格网格。对 GridSpec 进行索引将返回一个 SubplotSpec,该 SubplotSpec 涵盖一个或多个网格单元,可用于指定 Axes 的位置。
基本 2x2 网格
我们可以用与 add_gridspec
方式完成 2x2 网格:
fig = plt.figure(figsize=(5.5, 3.5), layout="constrained")
spec = fig.add_gridspec(ncols=2, nrows=2)
ax0 = fig.add_subplot(spec[0, 0])
annotate_axes(ax0, 'ax0')
ax1 = fig.add_subplot(spec[0, 1])
annotate_axes(ax1, 'ax1')
ax2 = fig.add_subplot(spec[1, 0])
annotate_axes(ax2, 'ax2')
ax3 = fig.add_subplot(spec[1, 1])
annotate_axes(ax3, 'ax3')
fig.suptitle('Manually added subplots using add_gridspec')
Axes跨网格中的行或网格
我们可以使用 NumPy slice 语法为 GridSpec 数组进行切片索引,新的 Axes 将跨越该 slice。这与fig, axd = plt.subplot_mosaic([['ax0', 'ax0'], ['ax1', 'ax2']], ...)
相同:
fig = plt.figure(figsize=(5.5, 3.5), layout="constrained")
spec = fig.add_gridspec(2, 2)
ax0 = fig.add_subplot(spec[0, :])
annotate_axes(ax0, 'ax0')
ax10 = fig.add_subplot(spec[1, 0])
annotate_axes(ax10, 'ax10')
ax11 = fig.add_subplot(spec[1, 1])
annotate_axes(ax11, 'ax11')
fig.suptitle('Manually added subplots, spanning a column')
手动调整 GridSpec 布局
当显式使用 GridSpec 时,您可以调整从 GridSpec 创建的subplots的布局参数。请注意,此选项与约束布局或Figure.tight_layout
不兼容。
fig = plt.figure(layout=None, facecolor='lightblue')
gs = fig.add_gridspec(nrows=3, ncols=3, left=0.05, right=0.75,
hspace=0.1, wspace=0.05)
ax0 = fig.add_subplot(gs[:-1, :])
annotate_axes(ax0, 'ax0')
ax1 = fig.add_subplot(gs[-1, :-1])
annotate_axes(ax1, 'ax1')
ax2 = fig.add_subplot(gs[-1, -1])
annotate_axes(ax2, 'ax2')
fig.suptitle('Manual gridspec with right=0.75')
使用 SubplotSpec 的嵌套布局
您可以使用 subgridspec
创建类似于subfigures
的嵌套布局。
fig = plt.figure(layout="constrained")
gs0 = fig.add_gridspec(1, 2)
gs00 = gs0[0].subgridspec(2, 2)
gs01 = gs0[1].subgridspec(3, 1)
for a in range(2):
for b in range(2):
ax = fig.add_subplot(gs00[a, b])
annotate_axes(ax, f'axLeft[{a}, {b}]', fontsize=10)
if a == 1 and b == 1:
ax.set_xlabel('xlabel')
for a in range(3):
ax = fig.add_subplot(gs01[a])
annotate_axes(ax, f'axRight[{a}, {b}]')
if a == 2:
ax.set_ylabel('ylabel')
fig.suptitle('nested gridspecs')
放置colorbars
Colorbars表示图像数据的定量范围。放置一个数字并非易事,因为需要为他们腾出空间。
自动放置colorbars
最简单的情况是为每个 Axes 附加一个颜色条。请注意,在此示例中,colorbars会从父 Axes 中窃取一些空间。
import matplotlib.pyplot as plt
import numpy as np
# Fixing random state for reproducibility
np.random.seed(19680801)
fig, axs = plt.subplots(1, 2, figsize = (7, 4))
cmaps = ['RdBu_r', 'viridis']
for col in range(2):
ax = axs[col]
pcm = ax.pcolormesh(np.random.random((20, 20)) * (col + 1), cmap=cmaps[col])
fig.colorbar(pcm, ax=ax)
被盗的空间可能导致同一subplots布局中的Axes大小不同,如果每个图上的 x 轴具有可比性,这通常是不希望的,如下所示:
fig, axs = plt.subplots(2, 1, figsize=(4, 5), sharex=True)
X = np.random.randn(20, 20)
axs[0].plot(np.sum(X, axis=0))
pcm = axs[1].pcolormesh(X)
fig.colorbar(pcm, ax=axs[1], shrink=0.6)
可以通过多种方式解决,例如,向其他 Axes 添加颜色条,然后将其删除。但是,最直接的方法是使用 constrained layout:
fig, axs = plt.subplots(2, 1, figsize=(4, 5), sharex=True, layout='constrained')
axs[0].plot(np.sum(X, axis=0))
pcm = axs[1].pcolormesh(X)
fig.colorbar(pcm, ax=axs[1], shrink=0.6)
使用此范例可以实现相对复杂的彩条布局。请注意,此示例在layout='constrained'
fig, axs = plt.subplots(3, 3, layout='constrained')
for ax in axs.flat:
pcm = ax.pcolormesh(np.random.random((20, 20)))
fig.colorbar(pcm, ax=axs[0, :2], shrink=0.6, location='bottom')
fig.colorbar(pcm, ax=[axs[0, 2]], location='bottom')
fig.colorbar(pcm, ax=axs[1:, :], location='right', shrink=0.6)
fig.colorbar(pcm, ax=[axs[2, 1]], location='left')
自动缩放Axis
Axis上的限制可以手动设置(例如 ax.set_xlim(xmin, xmax)
),或者 Matplotlib 可以根据Axis上已有的数据自动设置它们。这种自动缩放行为有许多选项。
我们将从一个简单的线图开始,显示自动缩放将axis限制扩展到数据限制 (-2π, 2π) 之外 5%。
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl
x = np.linspace(-2 * np.pi, 2 * np.pi, 100)
y = np.sinc(x)
fig, ax = plt.subplots()
ax.plot(x, y)
Margins 边距
数据限制周围的默认边距为 5%,这是基于下面三个值默认配置的:
rcParams["axes.xmargin"]
(default:0.05
)rcParams["axes.ymargin"]
(default:0.05
)rcParams["axes.zmargin"]
(default:0.05
)
可以使用 margins
覆盖 margin 大小以使其更小或更大:
fig, ax = plt.subplots()
ax.plot(x, y)
ax.margins(0.2, 0.2)
通常,边距可以在(-0.5, ∞)范围内,其中负边距将Axis限制设置为数据范围的子范围。使用单个数字作为外边距会影响两个轴,可以使用关键字参数 x
或 y
自定义单个外边距,但不能组合位置和关键字接口。
fig, ax = plt.subplots()
ax.plot(x, y)
ax.margins(y=-0.2)
粘性边缘
有一些元素 (Artist
s) 通常没有边距,例如使用 Axes.imshow
创建的图像。
xx, yy = np.meshgrid(x, x)
zz = np.sinc(np.sqrt((xx - 1)**2 + (yy - 1)**2))
fig, ax = plt.subplots(ncols=2, figsize=(12, 8))
ax[0].imshow(zz)
ax[0].set_title("default margins")
ax[1].imshow(zz)
ax[1].margins(0.2)
ax[1].set_title("margins(0.2)")
这种外边距的覆盖由 “sticky edges” 决定,这是 Artist
类的一个属性,可以禁止向轴限制添加外边距。可以通过更改 Axes 来禁用粘滞边缘的效果use_sticky_edges
。
fig, ax = plt.subplots(ncols=3, figsize=(16, 10))
ax[0].imshow(zz)
ax[0].margins(0.2)
ax[0].set_title("default use_sticky_edges\nmargins(0.2)")
ax[1].imshow(zz)
ax[1].margins(0.2)
ax[1].use_sticky_edges = False
ax[1].set_title("use_sticky_edges=False\nmargins(0.2)")
ax[2].imshow(zz)
ax[2].margins(-0.2)
ax[2].set_title("default use_sticky_edges\nmargins(-0.2)")
我们可以看到,将 use_sticky_edges
设置为 False 会渲染具有边距的图像。
控制自动缩放
默认情况下,每次向绘图添加新曲线时,都会重新计算限制:
fig, ax = plt.subplots(ncols=2, figsize=(12, 8))
ax[0].plot(x, y)
ax[0].set_title("Single curve")
ax[1].plot(x, y)
ax[1].plot(x * 2.0, y)
ax[1].set_title("Two curves")
但是,在某些情况下,您不希望自动将viewpoint调整为新数据。
禁用自动缩放的一种方法是手动设置轴限制。假设我们只想更详细地查看数据的一部分。即使我们向数据添加更多曲线,设置 xlim
也会保持不变。要重新计算新的limit,需要调用 Axes.autoscale
将手动切换该功能。
fig, ax = plt.subplots(ncols=2, figsize=(12, 8))
ax[0].plot(x, y)
ax[0].set_xlim(left=-1, right=1)
ax[0].plot(x + np.pi * 0.5, y)
ax[0].set_title("set_xlim(left=-1, right=1)\n")
ax[1].plot(x, y)
ax[1].set_xlim(left=-1, right=1)
ax[1].plot(x + np.pi * 0.5, y)
ax[1].autoscale()
ax[1].set_title("set_xlim(left=-1, right=1)\nautoscale()")
autoscale
函数的参数使我们能够精确控制自动缩放的过程。
- 参数
enable
:是否使能 - 参数
axis
: 为所选轴(或两者)设置自动缩放功能。 - 参数
tight
:将所选轴的边距设置为零。 - 要保留
enable
或tight
的设置,您可以将相反的设置为 None,这样就不应该修改它。但是,将enable
设置为 None 并将tight
设置为 True 会影响两个轴,而不管axis
参数如何。
fig, ax = plt.subplots()
ax.plot(x, y)
ax.margins(0.2, 0.2)
ax.autoscale(enable=None, axis="x", tight=True)
print(ax.margins())
Axis ticks
可以使用 set_xticks
等高级方法自定义tick和tick label,也可以直接在轴上设置locators和formatters 。
手动Location 和 格式Formats
自定义tick location和formats的最简单方法是使用 set_xticks
和 set_yticks
。这些可以用于 major ticks 或 minor ticks。
fig, axs = plt.subplots(2, 1, figsize=(5.4, 5.4), layout='constrained')
x = np.arange(100)
for nn, ax in enumerate(axs):
ax.plot(x, x)
if nn == 1:
ax.set_title('Manual ticks')
ax.set_yticks(np.arange(0, 100.1, 100/3)) # 设置Y轴ticks
xticks = np.arange(0.50, 101, 20)
xlabels = [f'\\${x:1.2f}' for x in xticks]
ax.set_xticks(xticks, labels=xlabels) # 设置X轴ticks
else:
ax.set_title('Automatic ticks')
请注意,labels
参数的个数必须与用于指定ticks的数组的成员个数相同。
默认情况下,set_xticks
和 set_yticks
作用于 Axis 的major ticks,但是可以添加minor ticks:
fig, axs = plt.subplots(2, 1, figsize=(5.4, 5.4), layout='constrained')
x = np.arange(100)
for nn, ax in enumerate(axs):
ax.plot(x, x)
if nn == 1:
ax.set_title('Manual ticks')
ax.set_yticks(np.arange(0, 100.1, 100/3))
ax.set_yticks(np.arange(0, 100.1, 100/30), minor=True)
else:
ax.set_title('Automatic ticks')
Locators 和 Formatters
手动设置Location和Formatter随着用户与 Axes 的交互而无法适应。在较低级别,Matplotlib 具有 Locators
,用于根据Axis的当前视图限制自动选择ticks,以及用于自动格式化tick label的 Formatters
。
Matplotlib 提供的定位器的完整列表列在 Tick locating中,格式化程序列在 Tick formatting 中。
def setup(ax, title):
"""Set up common parameters for the Axes in the example."""
# only show the bottom spine
ax.yaxis.set_major_locator(ticker.NullLocator())
ax.spines[['left', 'right', 'top']].set_visible(False)
ax.xaxis.set_ticks_position('bottom')
ax.tick_params(which='major', width=1.00, length=5)
ax.tick_params(which='minor', width=0.75, length=2.5)
ax.set_xlim(0, 5)
ax.set_ylim(0, 1)
ax.text(0.0, 0.2, title, transform=ax.transAxes,
fontsize=14, fontname='Monospace', color='tab:blue')
fig, axs = plt.subplots(8, 1, layout='constrained')
# Null Locator
setup(axs[0], title="NullLocator()")
axs[0].xaxis.set_major_locator(ticker.NullLocator())
axs[0].xaxis.set_minor_locator(ticker.NullLocator())
# Multiple Locator
setup(axs[1], title="MultipleLocator(0.5)")
axs[1].xaxis.set_major_locator(ticker.MultipleLocator(0.5))
axs[1].xaxis.set_minor_locator(ticker.MultipleLocator(0.1))
# Fixed Locator
setup(axs[2], title="FixedLocator([0, 1, 5])")
axs[2].xaxis.set_major_locator(ticker.FixedLocator([0, 1, 5]))
axs[2].xaxis.set_minor_locator(ticker.FixedLocator(np.linspace(0.2, 0.8, 4)))
# Linear Locator
setup(axs[3], title="LinearLocator(numticks=3)")
axs[3].xaxis.set_major_locator(ticker.LinearLocator(3))
axs[3].xaxis.set_minor_locator(ticker.LinearLocator(31))
# Index Locator
setup(axs[4], title="IndexLocator(base=0.5, offset=0.25)")
axs[4].plot(range(0, 5), [0]*5, color='white')
axs[4].xaxis.set_major_locator(ticker.IndexLocator(base=0.5, offset=0.25))
# Auto Locator
setup(axs[5], title="AutoLocator()")
axs[5].xaxis.set_major_locator(ticker.AutoLocator())
axs[5].xaxis.set_minor_locator(ticker.AutoMinorLocator())
# MaxN Locator
setup(axs[6], title="MaxNLocator(n=4)")
axs[6].xaxis.set_major_locator(ticker.MaxNLocator(4))
axs[6].xaxis.set_minor_locator(ticker.MaxNLocator(40))
# Log Locator
setup(axs[7], title="LogLocator(base=10, numticks=15)")
axs[7].set_xlim(10**3, 10**10)
axs[7].set_xscale('log')
axs[7].xaxis.set_major_locator(ticker.LogLocator(base=10, numticks=15))
plt.show()
同样,我们可以为每个Axis上的主要和Minor ticks指定 “Formatters”。
ticks format通过函数 set_major_formatter
或 set_minor_formatter
进行配置。它接受:
- 一个格式字符串,它隐式地创建一个
StrMethodFormatter
。 - 一个函数,隐式创建
FuncFormatter
。 Formatter
子类的实例。最常见的是:NullFormatter
:刻度没有标签StrMethodFormatter
:使用 string 的str.format
方法FormatStrFormatter
: 使用 % 样式FuncFormatter
:通过函数定义标签FixedFormatter
:显式设置标签字符串ScalarFormatter
:scalars的默认格式化程序:自动选择格式字符串PercentFormatter
:将标签格式设置为百分比
有关完整列表,请参阅 Tick formatting (刻度格式)。
def setup(ax, title):
"""Set up common parameters for the Axes in the example."""
# only show the bottom spine
ax.yaxis.set_major_locator(ticker.NullLocator())
ax.spines[['left', 'right', 'top']].set_visible(False)
# define tick positions
ax.xaxis.set_major_locator(ticker.MultipleLocator(1.00))
ax.xaxis.set_minor_locator(ticker.MultipleLocator(0.25))
ax.xaxis.set_ticks_position('bottom')
ax.tick_params(which='major', width=1.00, length=5)
ax.tick_params(which='minor', width=0.75, length=2.5, labelsize=10)
ax.set_xlim(0, 5)
ax.set_ylim(0, 1)
ax.text(0.0, 0.2, title, transform=ax.transAxes,
fontsize=14, fontname='Monospace', color='tab:blue')
fig = plt.figure(figsize=(8, 8), layout='constrained')
fig0, fig1, fig2 = fig.subfigures(3, height_ratios=[1.5, 1.5, 7.5])
fig0.suptitle('String Formatting', fontsize=16, x=0, ha='left')
ax0 = fig0.subplots()
setup(ax0, title="'{x} km'")
ax0.xaxis.set_major_formatter('{x} km')
fig1.suptitle('Function Formatting', fontsize=16, x=0, ha='left')
ax1 = fig1.subplots()
setup(ax1, title="def(x, pos): return str(x-5)")
ax1.xaxis.set_major_formatter(lambda x, pos: str(x-5))
fig2.suptitle('Formatter Object Formatting', fontsize=16, x=0, ha='left')
axs2 = fig2.subplots(7, 1)
setup(axs2[0], title="NullFormatter()")
axs2[0].xaxis.set_major_formatter(ticker.NullFormatter())
setup(axs2[1], title="StrMethodFormatter('{x:.3f}')")
axs2[1].xaxis.set_major_formatter(ticker.StrMethodFormatter("{x:.3f}"))
setup(axs2[2], title="FormatStrFormatter('#%d')")
axs2[2].xaxis.set_major_formatter(ticker.FormatStrFormatter("#%d"))
def fmt_two_digits(x, pos):
return f'[{x:.2f}]'
setup(axs2[3], title='FuncFormatter("[{:.2f}]".format)')
axs2[3].xaxis.set_major_formatter(ticker.FuncFormatter(fmt_two_digits))
setup(axs2[4], title="FixedFormatter(['A', 'B', 'C', 'D', 'E', 'F'])")
# FixedFormatter should only be used together with FixedLocator.
# Otherwise, one cannot be sure where the labels will end up.
positions = [0, 1, 2, 3, 4, 5]
labels = ['A', 'B', 'C', 'D', 'E', 'F']
axs2[4].xaxis.set_major_locator(ticker.FixedLocator(positions))
axs2[4].xaxis.set_major_formatter(ticker.FixedFormatter(labels))
setup(axs2[5], title="ScalarFormatter()")
axs2[5].xaxis.set_major_formatter(ticker.ScalarFormatter(useMathText=True))
setup(axs2[6], title="PercentFormatter(xmax=5)")
axs2[6].xaxis.set_major_formatter(ticker.PercentFormatter(xmax=5))
设置ticks styling(tick parameters)
通过在Axis上找到单个 Tick ,可以在较低级别控制 Tick
的外观。但是,通常最简单的方法是使用 tick_params
一次更改所有对象。
tick_params
方法可以更ticks的属性:
- length 长度
- direction 方向 (in or out of the frame)
- colors 颜色
- width and length 宽度和长度
- 以及刻度是在 Axes 的底部、顶部、左侧还是右侧绘制。
它还可以控制tick labels:
- labelsize (fontsize) 字体大小
- labelcolor (标签的颜色)
- labelrotation 标签旋转
- labelbottom, labeltop, labelleft, labelright
还有一个 pad 关键字参数,用于指定tick label与tick的距离。
最后,可以设置网格线型:
- grid_color
- grid_alpha
- grid_linewidth
- grid_linestyle
所有这些属性都可以限制为一个Axis,并且可以仅应用于 major tick 或 minor tick。
fig, axs = plt.subplots(1, 2, figsize=(6.4, 3.2), layout='constrained')
for nn, ax in enumerate(axs):
ax.plot(np.arange(100))
if nn == 1:
ax.grid('on')
ax.tick_params(right=True, left=False, axis='y', color='r', length=16,
grid_color='none')
ax.tick_params(axis='x', color='m', length=4, direction='in', width=4,
labelcolor='g', grid_color='b')
绘制日期dates和字符串strings
最基本的X轴为数字,但是Matplotlib也支持其它类型,可以是python列表。
如果数据类型存在“单位转换器unit converter”,Matplotlib 还具有转换其他数据类型的能力。Matplotlib 有两个内置转换器,一个用于日期,另一个用于字符串列表。
将转换器添加到 Matplotlib 的方法在 matplotlib.units
中描述。在这里,我们简要概述了内置的日期和字符串转换器。
日期转换
如果 x
和/或 y
是datetime
列表或 numpy.datetime64
数组,则 Matplotlib 有一个内置转换器,可以将日期时间转换为浮点数,并将tick locators 和 formatters 添加到适合日期的Axis上。
在以下示例中,x 轴获得了一个从 numpy.datetime64
转换为 float 的转换器converter,一个将ticks放在月初的定位符locator ,以及一个适当标记ticks的formatter:
import numpy as np
import matplotlib.dates as mdates
import matplotlib.units as munits
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(5.4, 2), layout='constrained')
time = np.arange('1980-01-01', '1980-06-25', dtype='datetime64[D]')
x = np.arange(len(time))
ax.plot(time, x)
请注意,如果我们尝试在 x 轴上绘制浮点数,它将以converter的 “纪元” 以来的天数为单位绘制,在本例中为 1970-01-01 (参见 Matplotlib 日期格式)。因此,当我们绘制值 0 时,ticks 从 1970-01-01 开始。
fig, ax = plt.subplots(figsize=(5.4, 2), layout='constrained')
time = np.arange('1980-01-01', '1980-06-25', dtype='datetime64[D]')
x = np.arange(len(time))
ax.plot(time, x)
# 0 gets labeled as 1970-01-01
ax.plot(0, 0, 'd')
ax.text(0, 0, ' Float x=0', rotation=45)
我们可以自定义 locator 和 formatter,在这里我们每隔一个月进行一次定位,并使用 "%b"
仅使用月份的 3 个字母名称进行格式设置格式:
fig, ax = plt.subplots(figsize=(5.4, 2), layout='constrained')
time = np.arange('1980-01-01', '1980-06-25', dtype='datetime64[D]')
x = np.arange(len(time))
ax.plot(time, x)
ax.xaxis.set_major_locator(mdates.MonthLocator(bymonth=np.arange(1, 13, 2)))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b'))
ax.set_xlabel('1980')
默认定位器是 AutoDateLocator
,默认格式化程序是 AutoDateFormatter
。还有一些 “简洁” Formatter和Locators,它们提供更紧凑的标签,并且可以通过 rcParams 进行设置。请注意,如何改用 “1980” 而不是年初多余的 “Jan” 标签。
plt.rcParams['date.converter'] = 'concise'
fig, ax = plt.subplots(figsize=(5.4, 2), layout='constrained')
time = np.arange('1980-01-01', '1980-06-25', dtype='datetime64[D]')
x = np.arange(len(time))
ax.plot(time, x)
字符串转换:categorical plots
有时我们想在Axis上标记类别,而不是数字。Matplotlib 允许使用 “categorical” converter。(见category
)
data = {'apple': 10, 'orange': 15, 'lemon': 5, 'lime': 20}
names = list(data.keys())
values = list(data.values())
fig, axs = plt.subplots(1, 3, figsize=(7, 3), sharey=True, layout='constrained')
axs[0].bar(names, values)
axs[1].scatter(names, values)
axs[2].plot(names, values)
fig.suptitle('Categorical Plotting')
请注意,categories
是按照它们第一次指定的顺序绘制的,并且随后以不同的顺序绘制不会影响原始顺序。
data = {'apple': 10, 'orange': 15, 'lemon': 5, 'lime': 20}
names = list(data.keys())
values = list(data.values())
fig, ax = plt.subplots(figsize=(5, 3), layout='constrained')
ax.bar(names, values)
# plot in a different order:
ax.scatter(['lemon', 'apple'], [7, 12])
# add a new category, "pear", and put the other categories in a different order:
ax.plot(['pear', 'orange', 'apple', 'lemon'], [13, 10, 7, 12], color='C1')
category converter
从类别映射到整数,从 0 开始。因此,也可以使用浮点数手动将数据添加到轴中。请注意,如果传入的浮点数没有与之关联的 “category”,则仍可以绘制数据点,但不会创建刻度。
在下文中,我们在 4.0 和 2.5 处绘制数据,但未在此处添加刻度,因为它们不是category。
fig, ax = plt.subplots(figsize=(5, 3), layout='constrained')
ax.bar(names, values)
# arguments for styling the labels below:
args = {'rotation': 70, 'color': 'C1',
'bbox': {'color': 'white', 'alpha': .7, 'boxstyle': 'round'}}
# 0 gets labeled as "apple"
ax.plot(0, 2, 'd', color='C1')
ax.text(0, 3, 'Float x=0', **args)
# 2 gets labeled as "lemon"
ax.plot(2, 2, 'd', color='C1')
ax.text(2, 3, 'Float x=2', **args)
# 4 doesn't get a label
ax.plot(4, 2, 'd', color='C1')
ax.text(4, 3, 'Float x=4', **args)
# 2.5 doesn't get a label
ax.plot(2.5, 2, 'd', color='C1')
ax.text(2.5, 3, 'Float x=2.5', **args)
category axes对于某些绘图类型很有用,但如果将数据作为字符串列表读入,则可能会导致混淆,即使它是浮点数或日期列表。读取逗号分隔值CSV文件时,有时会发生这种情况,categorical locator 和 formatter将在每个字符串值放置一个tick标记每个字符串值:
如果不需要,则只需在绘图之前将数据转换为浮点数:
fig, ax = plt.subplots(figsize=(5.4, 2.5), layout='constrained')
x = np.asarray(x, dtype='float') # array of float.
ax.plot(x, np.arange(100))
ax.set_xlabel('x is array of floats')
确定Axis上的Converter, Formattter, Locator
有时,能够调试 Matplotlib 用于转换传入数据的内容会很有帮助。我们可以通过查询轴上的 converter
属性来实现这一点。我们还可以使用 get_major_locator
和 get_major_formatter
查询Formattter和Locator。
请注意,默认情况下,Converter为 None。
fig, axs = plt.subplots(3, 1, figsize=(6.4, 7), layout='constrained')
x = np.arange(100)
ax = axs[0]
ax.plot(x, x)
label = f'Converter: {ax.xaxis.converter}\n '
label += f'Locator: {ax.xaxis.get_major_locator()}\n'
label += f'Formatter: {ax.xaxis.get_major_formatter()}\n'
ax.set_xlabel(label)
ax = axs[1]
time = np.arange('1980-01-01', '1980-06-25', dtype='datetime64[D]')
x = np.arange(len(time))
ax.plot(time, x)
label = f'Converter: {ax.xaxis.converter}\n '
label += f'Locator: {ax.xaxis.get_major_locator()}\n'
label += f'Formatter: {ax.xaxis.get_major_formatter()}\n'
ax.set_xlabel(label)
ax = axs[2]
data = {'apple': 10, 'orange': 15, 'lemon': 5, 'lime': 20}
names = list(data.keys())
values = list(data.values())
ax.plot(names, values)
label = f'Converter: {ax.xaxis.converter}\n '
label += f'Locator: {ax.xaxis.get_major_locator()}\n'
label += f'Formatter: {ax.xaxis.get_major_formatter()}\n'
ax.set_xlabel(label)
Legend指南
本指南使用了一些常用术语,为清楚起见,此处记录了这些术语:
- legend entry 图例条目:图例由一个或多个图例条目组成。一个条目由一个 key 和一个 label 组成。
- legend key 图例键:每个图例标签左侧的彩色/图案标记。
- legend label 图例标签:描述 key 表示的句柄的文本。
- legend handle 图例句柄:用于在图例中生成相应条目的原始对象。
控制图例条目
不带参数调用 legend()
会自动获取图例句柄及其关联的标签。此功能等效于:
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels)
get_legend_handles_labels()
函数返回 Axes 上存在的 handles/artists 列表,这些 handles/artists 可用于为生成的图例生成条目。
为了完全控制添加到图例中的内容,通常将适当的句柄直接传递给 legend()
:
fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend(handles=[line_up, line_down])
重命名图例条目
当标签不能直接在手柄上设置时,可以直接传递给 Axes.legend
:
fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend([line_up, line_down], ['Line Up', 'Line Down'])
创建专门用于添加到图例的artists(又名Proxy artists)
并非所有手柄都可以自动转换为图例条目,因此通常需要创建一个的艺术家。图例手柄不必存在于 Figure 或 Axes 上即可使用。
假设我们想创建一个图例,其中有一个数据条目,这些数据由红色表示:
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
fig, ax = plt.subplots()
red_patch = mpatches.Patch(color='red', label='The red data')
ax.legend(handles=[red_patch])
plt.show()
有许多受支持的图例句柄。我们可以创建一条带有标记的线条,而不是创建颜色块:
import matplotlib.lines as mlines
fig, ax = plt.subplots()
blue_line = mlines.Line2D([], [], color='blue', marker='*',
markersize=15, label='Blue stars')
ax.legend(handles=[blue_line])
plt.show()
图例位置
图例的位置可以通过关键字参数 loc 指定。
bbox_to_anchor
关键字为手动图例放置提供了很大程度的控制。例如,如果您希望 Axes 图例位于figure的右上角而不是 Axes 的角,只需指定角的位置和该位置的坐标系:
ax.legend(bbox_to_anchor=(1, 1), bbox_transform=fig.transFigure)
自定义图例放置的更多示例:
fig, ax_dict = plt.subplot_mosaic([['top', 'top'], ['bottom', 'BLANK']], empty_sentinel="BLANK")
ax_dict['top'].plot([1, 2, 3], label="test1")
ax_dict['top'].plot([3, 2, 1], label="test2")
# Place a legend above this subplot, expanding itself to
# fully use the given bounding box.
ax_dict['top'].legend(bbox_to_anchor=(0., 1.02, 1., .102), loc='lower left',
ncols=2, mode="expand", borderaxespad=0.)
ax_dict['bottom'].plot([1, 2, 3], label="test1")
ax_dict['bottom'].plot([3, 2, 1], label="test2")
# Place a legend to the right of this smaller subplot.
ax_dict['bottom'].legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
Figure图例
有时,相对于(sub)figure放置图例比放置单个 Axes 更有意义。通过使用constrained layout 并在 loc 关键字参数的开头指定 “outside”,图例绘制在(sub)figure的 Axes 之外。
fig, axs = plt.subplot_mosaic([['left', 'right']], layout='constrained')
axs['left'].plot([1, 2, 3], label="test1")
axs['left'].plot([3, 2, 1], label="test2")
axs['right'].plot([1, 2, 3], 'C2', label="test3")
axs['right'].plot([3, 2, 1], 'C3', label="test4")
# Place a legend to the right of this smaller subplot.
fig.legend(loc='outside upper right')
ucl = ['upper', 'center', 'lower']
lcr = ['left', 'center', 'right']
fig, ax = plt.subplots(figsize=(6, 4), layout='constrained', facecolor='0.7')
ax.plot([1, 2], [1, 2], label='TEST')
# Place a legend to the right of this smaller subplot.
for loc in [
'outside upper left',
'outside upper center',
'outside upper right',
'outside lower left',
'outside lower center',
'outside lower right']:
fig.legend(loc=loc, title=loc)
fig, ax = plt.subplots(figsize=(6, 4), layout='constrained', facecolor='0.7')
ax.plot([1, 2], [1, 2], label='test')
for loc in [
'outside left upper',
'outside right upper',
'outside left lower',
'outside right lower']:
fig.legend(loc=loc, title=loc)
同一Axes上的多个图例
有时,将图例条目拆分为多个图例会更清楚。
fig, ax = plt.subplots()
line1, = ax.plot([1, 2, 3], label="Line 1", linestyle='--')
line2, = ax.plot([3, 2, 1], label="Line 2", linewidth=4)
# Create a legend for the first line.
first_legend = ax.legend(handles=[line1], loc='upper right')
# Add the legend manually to the Axes.
ax.add_artist(first_legend)
# Create another legend for the second line.
ax.legend(handles=[line2], loc='lower right')
plt.show()
subplot_mosaic
对于更复杂的布局,例如跨越布局的多列/行或将 Figure 的某些区域留空的 Axes,可以使用gridspec.GridSpec
完成。
Figure.subplot_mosaic
旨在提供一个界面来直观地布置你的 Axes以简化这个过程。
这个接口支持命名你的 Axes。Figure.subplot_mosaic
返回一个字典,该字典以用于布局 Figure 的labels为键。通过返回带有名称的数据结构,可以更轻松地编写独立于 Figure 布局的绘图代码。
如果我们想要一个 2x2 的网格,我们可以使用 Figure.subplots
,它返回一个二维的axes.Axes
,我们可以索引以进行绘图的Axes。
import matplotlib.pyplot as plt
import numpy as np
# Helper function used for visualization in the following examples
def identify_axes(ax_dict, fontsize=48):
"""
Helper to identify the Axes in the examples below.
Draws the label in a large font in the center of the Axes.
Parameters
----------
ax_dict : dict[str, Axes]
Mapping between the title / label and the Axes.
fontsize : int, optional
How big the label should be.
"""
kw = dict(ha="center", va="center", fontsize=fontsize, color="darkgrey")
for k, ax in ax_dict.items():
ax.text(0.5, 0.5, k, transform=ax.transAxes, **kw)
np.random.seed(19680801)
hist_data = np.random.randn(1_500)
fig = plt.figure(layout="constrained")
ax_array = fig.subplots(2, 2, squeeze=False)
ax_array[0, 0].bar(["a", "b", "c"], [5, 7, 9])
ax_array[0, 1].plot([1, 2, 3])
ax_array[1, 0].hist(hist_data, bins="auto")
ax_array[1, 1].imshow([[1, 2], [2, 1]])
identify_axes(
{(j, k): a for j, r in enumerate(ax_array) for k, a in enumerate(r)},
)
使用 Figure.subplot_mosaic
我们可以生成相同的Axes,但为 Axes 提供语义名称。
fig = plt.figure(layout="constrained")
ax_dict = fig.subplot_mosaic(
[
["bar", "plot"],
["hist", "image"],
],
)
ax_dict["bar"].bar(["a", "b", "c"], [5, 7, 9])
ax_dict["plot"].plot([1, 2, 3])
ax_dict["hist"].hist(hist_data)
ax_dict["image"].imshow([[1, 2], [2, 1]])
identify_axes(ax_dict)
Figure.subplots
和 Figure.subplot_mosaic
之间的主要区别在于返回值。前者返回用于索引访问的数组,而后者返回将标签映射到axes.Axes
的实例。
字符串简写
通过将 Axes 标签限制为单个字符,我们可以将我们想要的 Axes “绘制”为 “ASCII art”。以下内容:
mosaic = """
AB
CD
"""
fig = plt.figure(layout="constrained")
ax_dict = fig.subplot_mosaic(mosaic)
identify_axes(ax_dict)
将给我们 4 个轴,布置在 2x2 网格中,并生成与上述相同的布局(但现在标签为 {“A”, “B”, “C”, “D”}
而不是 {“bar”, “plot”, “hist”, “image”}
)。
或者,可以使用更紧凑的字符串表示法:
mosaic = "AB;CD"
其中 “;”
用作行分隔符而不是换行符。
跨多行/多列的Axes
指定一个 Axes 应该跨越几行或几列, Figure.subplot_mosaic
可以实现,而 Figure.subplots
不能实现。
如果我们想重新排列这四个Axes,让 "C"
在底部是一个水平跨度,而 "D"
是一个在右边的垂直跨度,我们可以这样做:
axd = plt.figure(layout="constrained").subplot_mosaic(
"""
ABD
CCD
"""
)
identify_axes(axd)
如果我们不想用Axes填充 Figure 中的所有空格,我们可以将网格中的一些空格指定为空白:
axd = plt.figure(layout="constrained").subplot_mosaic(
"""
A.C
BBB
.D.
"""
)
identify_axes(axd)
如果更喜欢使用另一个字符(而不是句点 “.”)
来标记空格,我们可以使用 empty_sentinel 来指定要使用的字符:
axd = plt.figure(layout="constrained").subplot_mosaic(
"""
aX
Xb
""",
empty_sentinel="X",
)
identify_axes(axd)
在内部,我们使用的字母没有任何意义,任何 Unicode 代码点都是有效的:
axd = plt.figure(layout="constrained").subplot_mosaic(
"""αб
ℝ☢"""
)
identify_axes(axd)
控制mosaic创建
此功能构建在 gridspec
之上,您可以将关键字参数传递给底层gridspec.GridSpec
。
在这种情况下,如果想使用subplot_mosaic来指定排列,并设置行/列的相对宽度。可以使用gridspec.GridSpec
的 height_ratios 和 width_ratios 在 Figure.subplot_mosaic
调用时配置。
axd = plt.figure(layout="constrained").subplot_mosaic(
"""
.a.
bAc
.d.
""",
# set the height ratios between the rows
height_ratios=[1, 3.5, 1],
# set the width ratios between the columns
width_ratios=[1, 3.5, 1],
)
identify_axes(axd)
Constrained布局
使用Constrained layout使plots干净地适应Figure。
Constrained layout会自动调整subplots,以便tick labels、Legends和colorbars等修饰不会重叠,同时仍保留用户请求的逻辑布局。
Constrained layout (约束布局) 类似于 Tight layout (紧密布局),但要灵活得多。
通常需要在将任何 Axes 添加到Figure之前激活 Constrained layout。有两种方法:
-
使用
subplots
,figure
,subplot_mosaic
的相应参数,例如:plt.subplots(layout="constrained")
-
通过 rcParams 激活,例如:
plt.rcParams['figure.constrained_layout.use'] = True
Warning:调用 tight_layout
将关闭 Constrained Layout!
简单示例
使用默认的 Axes 布局时,axes title、axis label或tick labels有时会超出图窗区域,从而被剪切。
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors as mcolors
import matplotlib.gridspec as gridspec
plt.rcParams['savefig.facecolor'] = "0.8"
plt.rcParams['figure.figsize'] = 4.5, 4.
plt.rcParams['figure.max_open_warning'] = 50
def example_plot(ax, fontsize=12, hide_labels=False):
ax.plot([1, 2])
ax.locator_params(nbins=3)
if hide_labels:
ax.set_xticklabels([])
ax.set_yticklabels([])
else:
ax.set_xlabel('x-label', fontsize=fontsize)
ax.set_ylabel('y-label', fontsize=fontsize)
ax.set_title('Title', fontsize=fontsize)
fig, ax = plt.subplots(layout=None)
example_plot(ax, fontsize=24)
为防止这种情况,需要调整 Axes 的位置。对于subplots,可以通过使用 Figure.subplots_adjust
调整subplots参数来手动完成。但是,使用 layout=“constrained”
关键字参数指定您的图形将自动进行调整。
fig, ax = plt.subplots(layout="constrained")
example_plot(ax, fontsize=24)
当有多个subplots时,经常会看到不同 Axes 的标签相互重叠。
在对 plt.subplots
的调用中指定 layout=“constrained”
可以将布局被正确约束。
fig, axs = plt.subplots(2, 2, layout="constrained")
for ax in axs.flat:
example_plot(ax)
Colorbars
如果使用 Figure.colorbar
创建Colorbars,则需要为其腾出空间。Constrained layout 会自动执行此操作。请注意,如果指定 use_gridspec=True
,它将被忽略,因为此选项通过 tight_layout
改进布局。
Suptitle
Constrained layout (约束布局)也可以为 suptitle
腾出空间。
fig, axs = plt.subplots(2, 2, figsize=(4, 4), layout="constrained")
for ax in axs.flat:
im = ax.pcolormesh(arr, **pc_kwargs)
fig.colorbar(im, ax=axs, shrink=0.6)
fig.suptitle('Big Suptitle')
Legends
图例可以放置在其父轴之外。Constrained layout 旨在为 Axes.legend()
处理此问题。但是,Constrained layout 还不处理通过 Figure.legend()
创建的图例。
fig, ax = plt.subplots(layout="constrained")
ax.plot(np.arange(10), label='This is a plot')
ax.legend(loc='center left', bbox_to_anchor=(0.8, 0.5))
但是,这将从subplot布局中窃取空间:
fig, axs = plt.subplots(1, 2, figsize=(4, 2), layout="constrained")
axs[0].plot(np.arange(10))
axs[1].plot(np.arange(10), label='This is a plot')
axs[1].legend(loc='center left', bbox_to_anchor=(0.8, 0.5))
解决这种问题的更好方法是简单地使用 Figure.legend
提供的 legend 方法。
Padding and spacing内边距
Axes 之间的内边距在水平方向上由 w_pad 和 wspace 控制,垂直方向由 h_pad 和 hspace 控制。这些可以通过 set
进行编辑。w/h_pad 是Axes周围的最小间距,以英寸为单位:
fig, axs = plt.subplots(2, 2, layout="constrained")
for ax in axs.flat:
example_plot(ax, hide_labels=True)
fig.get_layout_engine().set(w_pad=4 / 72, h_pad=4 / 72, hspace=0, wspace=0)
subplots之间的间距由 wspace 和 hspace 进一步设置。这些被指定为整个subplot组大小的分数。如果这些值小于 w_pad 或 h_pad,则改用固定pading。请注意,在下面,边缘的间距与上面没有变化,但subplots之间的间距发生了变化。
fig, axs = plt.subplots(2, 2, layout="constrained")
for ax in axs.flat:
example_plot(ax, hide_labels=True)
fig.get_layout_engine().set(w_pad=4 / 72, h_pad=4 / 72, hspace=0.2, wspace=0.2)
如果有两个以上的列,则 wspace 在它们之间共享,因此此处 wspace 一分为二,每列之间的 wspace 为 0.1:
fig, axs = plt.subplots(2, 3, layout="constrained")
for ax in axs.flat:
example_plot(ax, hide_labels=True)
fig.get_layout_engine().set(w_pad=4 / 72, h_pad=4 / 72, hspace=0.2, wspace=0.2)
rcParams
可以在脚本或 matplotlibrc
文件中设置五个 rcParams参数。它们都有前缀 figure.constrained_layout
:
- use:是否使用约束布局。默认值为 False
- w_pad、h_pad:在 Axes 对象周围填充。表示英寸的浮点数。默认值为 3./72英寸(3 pts)
- wspace, hspace:subplots组之间的空间。Float 表示要分隔的子图宽度的一小部分。默认值为 0.02。
手动设置 Axes 位置
手动调用 set_position
将设置 Axes, constrained layout不再对其产生影响。
fig, axs = plt.subplots(1, 2, layout="constrained")
example_plot(axs[0], fontsize=12)
axs[1].set_position([0.2, 0.2, 0.4, 0.4])
固定纵横比Axes的网格:compresse布局
Constrained layout在 Axes 的 “原始” 位置网格上运行。但是,当轴具有固定的纵横比时,一侧通常会变短,并在缩短的方向上留下较大的间隙。在下图中,Axes是方形的,但Fgiure相当宽,因此存在水平间隙:
fig, axs = plt.subplots(2, 2, figsize=(5, 3),
sharex=True, sharey=True, layout="constrained")
for ax in axs.flat:
ax.imshow(arr)
fig.suptitle("fixed-aspect plots, layout='constrained'")
解决此问题的一种明显方法是使Figure大小更方正,但是,缩小间隙需要反复试验。对于简单的 Axes 网格,我们可以使用 layout="compressed"
来为我们完成这项工作:
fig, axs = plt.subplots(2, 2, figsize=(5, 3),
sharex=True, sharey=True, layout='compressed')
for ax in axs.flat:
ax.imshow(arr)
fig.suptitle("fixed-aspect plots, layout='compressed'")
手动关闭 Constrained 布局
Constrained layout通常会调整Figure每次绘制上的 Axes 位置。如果你想获取 constrained layout 提供的间距但不更新它,然后进行初始绘制,然后调用 fig.set_layout_engine('none')。
这对于tick labels可能更改长度的动画可能很有用。
限制
不兼容的功能
Constrained layout将与 pyplot.subplot
一起使用,但前提是每次调用的行数和列数相同。
所以下面的工作正常:
fig = plt.figure(layout="constrained")
ax1 = plt.subplot(2, 2, 1) # 2行2列
ax2 = plt.subplot(2, 2, 3) # 2行2列
# third Axes that spans both rows in second column:
ax3 = plt.subplot(2, 2, (2, 4)) # 2行2列
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
plt.suptitle('Homogenous nrows, ncols')
但以下情况会导致布局不佳:
fig = plt.figure(layout="constrained")
ax1 = plt.subplot(2, 2, 1)
ax2 = plt.subplot(2, 2, 3)
ax3 = plt.subplot(1, 2, 2)
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
plt.suptitle('Mixed nrows, ncols')
其他注意事项
- 约束布局仅考虑tick labels、axis labels、title和legends。因此,其他Artist可能会被剪切,也可能重叠。
- 它假定tick labels、axis labels和title所需的额外空间与 Axes 的原始位置无关。这通常是正确的,但在极少数情况下并非如此。
- 如果Artist使用的 Axes 坐标超出 Axes 边界,则在添加到 Axes 时将导致不寻常的布局。
Tight布局
如何使用tight布局将绘图清晰地融入Figure中。
tight_layout 会自动调整subplots参数,以便subplots适合figure区域。这是一项实验性功能,可能不适用于某些情况。它仅检查tick labels、axis labels和title的范围。
tight_layout 的替代方案是 constrained_layout。
简单示例
使用默认的 Axes 布局时,axes title, axis labels, 或 tick labels 有时会超出figure区域,从而被剪切。
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['savefig.facecolor'] = "0.8"
def example_plot(ax, fontsize=12):
ax.plot([1, 2])
ax.locator_params(nbins=3)
ax.set_xlabel('x-label', fontsize=fontsize)
ax.set_ylabel('y-label', fontsize=fontsize)
ax.set_title('Title', fontsize=fontsize)
plt.close('all')
fig, ax = plt.subplots()
example_plot(ax, fontsize=24)
为防止这种情况,需要调整 Axes 的位置。对于subplots,这可以通过使用 Figure.subplots_adjust
调整子图参数来手动完成。Figure.tight_layout
会自动执行此操作。
fig, ax = plt.subplots()
example_plot(ax, fontsize=24)
plt.tight_layout()
当有多个子图时,经常会看到不同 Axes 的标签相互重叠。
plt.close('all')
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)
tight_layout()
还将调整subplots之间的间距以最大程度地减少重叠。
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)
plt.tight_layout()
可以接受 pad、w_pad 和 h_pad 的关键字参数。这些用于控制Figure边框周围和subplots之间的额外填充,填充以 fontsize 的分数指定。
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)
plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)
即使subplots的大小不同,只要它们的网格规范兼容,也可以正常工作。在下面的示例中,ax1 和 ax2 是 2x2 网格的子图,而 ax3 是 1x2 网格的子图。
plt.close('all')
fig = plt.figure()
ax1 = plt.subplot(221)
ax2 = plt.subplot(223)
ax3 = plt.subplot(122)
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
plt.tight_layout()
注意事项
- 默认情况下,会考虑 Axes 上的所有Artist。要从布局计算中删除Artist,您可以调用
Artist.set_in_layout
。 - 假设Artist所需的额外空间独立于 Axes 的原始位置。这通常是正确的,但在极少数情况下并非如此。
个人示例
Bar
垂直柱状图
创建一个柱状图,并且在每个柱子的上方显示百分比:
代码实现:
import matplotlib.pyplot as plt
# 示例数据
categories = ['A', 'B', 'C', 'D']
values = [0.23, 0.45, 0.56, 0.78] # 这些值将被转换为百分数
# 创建一个figure和axes
fig, ax = plt.subplots()
# 绘制柱状图
bars = ax.bar(categories, values)
# 为每个柱子添加标签,将值转换为百分数
ax.bar_label(bars, labels=[f' {val*100:.2f}%' for val in values])
# 设置标题和标签
ax.set_title('Bar Chart with Percentage Labels')
ax.set_xlabel('Categories')
ax.set_ylabel('Values (%)')
# 显示图表
plt.show()
水平柱状图
创建一个水平柱状图,并且在柱子的底部显示百分比:
import matplotlib.pyplot as plt
import numpy as np
# 示例数据
categories = ['A', 'B', 'C', 'D']
values = np.random.rand(4) # 生成0到100之间的随机小数
# 创建一个figure和axes
fig, ax = plt.subplots()
# 绘制水平柱状图
bars = ax.barh(categories, values, color='skyblue')
ax.bar_label(bars, labels=[f' {val*100:.2f}%' for val in values])
# 设置标题和标签
ax.set_title('Horizontal Bar Chart with Percent Labels')
ax.set_xlabel('Percentage')
# 显示图表
plt.show()
柏拉图
红色的为累加百分比,柱状图为每个类型的值。
代码:
import matplotlib.pyplot as plt
import numpy as np
# 示例数据:分类和对应的值
categories = ['Category A', 'Category B', 'Category C', 'Category D', 'Category E']
values = [30, 20, 15, 10, 25]
# 计算累积和
cumulative_values = np.cumsum(values)
# 计算累积百分比
cumulative_percentages = cumulative_values / cumulative_values[-1] * 100
percentages = []
# 遍历列表,计算并打印每个元素的百分比
for number in values:
percentages.append((number / sum(values)))
# 创建图形和坐标轴
fig, ax1 = plt.subplots()
# 绘制柱状图
color = 'tab:blue'
ax1.set_xlabel('Categories')
ax1.set_ylabel('Values', color=color)
bars = ax1.bar(categories, values, color=color)
ax1.bar_label(bars, labels=[f' {val*100:.2f}%' for val in percentages])
ax1.tick_params(axis='y', labelcolor=color)
# 绘制累积百分比的折线图
ax2 = ax1.twinx() # 创建共享x轴的第二个y轴
color = 'tab:red'
ax2.set_ylabel('Cumulative Percentage (%)', color=color)
ax2.plot(categories, cumulative_percentages, color=color, marker='D', ms=7, linestyle='-')
ax2.tick_params(axis='y', labelcolor=color)
# 设置图表标题
fig.suptitle('Pareto Chart Example')
# 显示图形
plt.show()
改进:在柏拉图下方显示一个table
import matplotlib.pyplot as plt
import numpy as np
# 示例数据:分类和对应的值
categories = ['Category A', 'Category B', 'Category C', 'Category D', 'Category E']
values = [30, 20, 15, 10, 25]
cumulative_values = np.cumsum(values) # 计算累积和
cumulative_percentages = cumulative_values / cumulative_values[-1] * 100 # 计算累积百分比
percentages = []
for number in values: # 遍历列表,计算并打印每个元素的百分比
percentages.append((number / sum(values)))
# 创建图形和坐标轴
fig, ax1 = plt.subplots()
# 绘制柱状图
color = 'tab:blue'
ax1.set_ylabel('Values', color=color)
bars = ax1.bar(categories, values, color=color)
ax1.bar_label(bars, labels=[f' {val*100:.2f}%' for val in percentages])
ax1.tick_params(axis='y', labelcolor=color)
# 绘制累积百分比的折线图
ax2 = ax1.twinx() # 创建共享x轴的第二个y轴
color = 'tab:red'
ax2.set_ylabel('Cumulative Percentage (%)', color=color)
ax2.plot(categories, cumulative_percentages, color=color, marker='D', ms=7, linestyle='-')
ax2.tick_params(axis='y', labelcolor=color)
# 添加table
cell_text = [categories, values, percentages, cumulative_percentages]
columns = ["Type", "Values", "Percentages", "Cumulative"]
ax1.table(cellText=cell_text, rowLabels=columns, loc='bottom', cellLoc='center')
plt.xticks([])
plt.subplots_adjust(left=0.2, bottom=0.1)
fig.tight_layout()
# 设置图表标题
fig.suptitle('Pareto Chart Example')
plt.tight_layout()
# 显示图形
plt.show()
轴坐标
在 Matplotlib 中,轴坐标(也称为归一化坐标)是一种特殊的坐标系统,它用于相对于当前轴(Axes)的位置和大小来定位图形元素。轴坐标的范围是从 0 到 1,其中 (0, 0) 表示轴的左下角,(1, 1) 表示轴的右上角。这种坐标系统不依赖于数据的实际值或图形的物理尺寸,而是基于轴的可视化区域。
使用轴坐标可以方便地放置图形元素,如标题、图例、注释或自定义的图形(如矩形、圆形等),而无需担心数据范围或图形窗口大小的变化。这是因为轴坐标是相对于轴的可视化区域进行解释的,而不是相对于数据或图形窗口的像素尺寸。
在 Matplotlib 中,你可以通过传递 transform=ax.transAxes
参数给图形元素(如 Rectangle
、Text
等)来指定使用轴坐标。ax
是你的 Axes
对象,而 transAxes
是该轴对象的一个属性,表示轴坐标变换。
在table上绘制图形和线条
ax.table创建的时候,使用的是轴坐标系统,但是ax.table的get_window_extent()方法返回的是像素坐标,而不是轴坐标:
bbox = the_table.get_window_extent()
x0, y0 = bbox.x0, bbox.y0 # 获取左下角的坐标
width, height = bbox.width, bbox.height # 获取宽度和高度
下面讲解在ax.table上绘制各种图形时的坐标系统:
-
Rectangle:绘制矩形,使用的是轴坐标系统
# : +------------------+ # : | | # : height | # : | | # : (xy)---- width -----+ class matplotlib.patches.Rectangle(xy, width, height, *, angle=0.0, rotation_point='xy', **kwargs)
-
axhline:绘制水平直线,使用的是轴坐标系统
''' y: 水平线的数据坐标中的y位置, 使用的是像素坐标系 xmin: 应介于0和1之间,0表示绘图的最左侧,1表示绘图的最右侧, 使用的是轴坐标系。 xmax: 应介于0和1之间,0表示绘图的最左侧,1表示绘图的最右侧, 使用的是轴坐标系。 ''' Axes.axhline(y=0, xmin=0, xmax=1, **kwargs)
-
axvline:绘制垂直线,使用的是轴坐标系统
''' x: 垂直线的数据坐标中的x位置, 使用的是像素坐标系 ymin: 应介于0和1之间,0是绘图的底部,1是绘图的顶部, 使用的是轴坐标系。 ymax: 应介于0和1之间,0是绘图的底部,1是绘图的顶部, 使用的是轴坐标系。 ''' Axes.axvline(x=0, ymin=0, ymax=1, **kwargs)
-
Ellipse:绘制椭圆,使用的是像素坐标系统
# xy: 椭圆中心的 xy 坐标 # width: 长轴的总长度 # height: 短轴的总长度 class matplotlib.patches.Ellipse(xy, width, height, *, angle=0, **kwargs)
以下是一个举例,创建一个table,然后在上面绘制水平直线、垂直直线、矩形、椭圆形:
实现代码:
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.patches import Ellipse
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
cell_width_px = 0
cell_height_px = 0
width_px = 0
height_px = 0
# 对于像素坐标系统,需要计算每个Cell的宽度和高度
def calculate_cell_size(fig, num_rows, num_cols):
global width_px
global height_px
global cell_width_px
global cell_height_px
# 绘制椭圆图形(这一步是必需的,以便FigureCanvas可以捕获渲染后的图形)
fig.canvas.draw()
# 获取FigureCanvas对象(这里我们假设使用的是Agg后端,但你可以根据你的后端进行调整)
canvas = FigureCanvas(fig)
# 获取图形的宽度和高度(以像素为单位)
width_px, height_px = canvas.get_width_height()
# 估算每个单元格的像素宽度和高度, 减去边距、标签等
cell_width_px = width_px / num_cols - 16 # 16只是人为估计出来的误差
cell_height_px = height_px / num_rows + 19 # 19只是人为估计出来的误差
print(f"Estimated width in pixels: {width_px}")
print(f"Estimated height in pixels: {height_px}")
print(f"Estimated cell width in pixels: {cell_width_px}")
print(f"Estimated cell height in pixels: {cell_height_px}")
# x0, y0, x1, y1代表的是cell的位置
# : +------------------+
# : | |
# : height |
# : | |
# : (xy)---- width -----+
def draw_rectangle(ax, rows, columns, xy, width, heights):
# 由于创建表时已经设置了轴坐标范围为(0, 0)->(1, 1), 因此计算单个cell的宽和高就很方便
cell_width = 1 / columns
cell_height = 1 / rows
# 由于表格中央被我们当作坐标原点, 但是极坐标的坐标原点默认为左下角, 因此需要添加一个偏移
start_x = (xy[1] + columns / 2 )* cell_width
start_y = (xy[0] + rows / 2) * cell_height
rect_width = width * cell_width
rect_height = heights * cell_height
print (start_x, start_y, rect_width, rect_height)
rect = Rectangle((start_x, start_y), rect_width, rect_height, linewidth=1.5,
edgecolor='blue', facecolor='none', transform=ax.transAxes)
ax.add_patch(rect)
# 绘制椭圆形
# xy: 椭圆原点(x, y)
# width: 水平轴直径
# height: 垂直轴执行
def draw_ellipse(ax, xy, width, height):
ellipse_width = cell_width_px * width # 水平轴
ellipse_height = cell_height_px * height # 垂直轴
x1 = xy[0] * cell_width_px
y1 = xy[1] * cell_height_px
ellipse = Ellipse((x1, y1), ellipse_width, ellipse_height, edgecolor='red', facecolor='none')
ax.add_patch(ellipse)
# 在轴上添加一个水平线: matplotlib.pyplot.axhline(y=0, xmin=0, xmax=1, **kwargs)
# '''
# : +--------------------+
# : | |
# (x0, y0) +----------- y1 -----+
# : | |
# : +--------------------+
# '''
def draw_axhline(ax, columns, x0, y0, y1):
cell_width = 1 / columns # 创建表时已经设置了轴坐标范围为(0, 0)->(1, 1)
y = x0 * cell_height_px # 使用的是数据(像素)坐标系
x_min = (y0 + columns / 2) * cell_width # 使用的是轴坐标系
x_max = (y1 + columns / 2) * cell_width # 使用的是轴坐标系
print (y, x_min, x_max)
ax.axhline(y, x_min, x_max, linewidth=1.5, color='red')
# 在轴上添加一条垂直线: Axes.axvline(x=0, ymin=0, ymax=1, **kwargs)
# '''
# : y1-------------------+
# : | |
# : |--------------------+
# : | |
# :(x0, y0) +--------------------+
# '''
def draw_axvline(ax, rows, y0, x0, x1):
cell_height = 1 / rows # 创建表时已经设置了轴坐标范围为(0, 0)->(1, 1)
x = y0 * cell_width_px # 使用的是数据(像素)坐标系
y_min = (x0 + rows / 2) * cell_height # 使用的是轴坐标系
y_max = (x1 + rows / 2) * cell_height # 使用的是轴坐标系
print (x, y_min, y_max)
ax.axvline(x, y_min, y_max, linewidth=2, color='cyan')
if __name__ == '__main__':
rows = 8
columns = 10
cell_text = [[1 for x in range(columns)] for y in range(rows)]
fig, ax = plt.subplots()
the_table = ax.table(
cellText=cell_text,
loc='center', cellLoc='center',
bbox=[0, 0, 1, 1], # 为了方便, 将轴坐标范围设置为[0, 0]->[1, 1]
edges = 'closed',
)
calculate_cell_size(fig, rows, columns)
# 将坐标原点设置到table的中央
ax.set_xlim(-height_px/2, height_px/2) # 设置坐标轴原点
ax.set_ylim(-width_px/2, width_px/2) # 设置坐标轴原点
# 绘图
draw_rectangle(ax, rows, columns, (1, 1), 2, 2)
draw_ellipse(ax, (1, 1), 6, 6)
draw_axhline(ax, columns, -1, 1, 3)
draw_axvline(ax, rows, -1, 1, 3)
plt.show()
实现效果:
标签:plot,plt,Python,Axes,Matplotlib,set,fig,ax,绘制 From: https://www.cnblogs.com/mrlayfolk/p/18403483