matplotlib学习笔记

阅读量: searchstar Created: 2023-10-18 19:28:00 Updated: 2026-08-01 23:30:23
Categories: Tags:

如果要用plt.show()的话,需要额外安装一些依赖:

# https://stackoverflow.com/a/77644828/13688160
pip3 install PyQt6

pyplot

import matplotlib.pyplot as plt

yscale: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.yscale.html

非阻塞显示图片:plt.show(block=False)

开始画下一张:plt.figure()

散点图 plt.scatter

交互式散点图:https://mpld3.github.io/examples/scatter_tooltip.html

marker

完整列表:https://matplotlib.org/stable/api/markers_api.html

常用:

o: 圆圈

s: square, 正方形

D: diamond, 菱形

^: 上三角

v: 下三角

<: 左三角

>: 右三角

默认是圆角的。如果不想要圆角效果,可以设置linewidth=0

legend

要用Line2D画: https://stackoverflow.com/questions/47391702/how-to-make-a-colored-markers-legend-from-scratch

调整宽度用legend的参数handlelength:

https://stackoverflow.com/questions/66809947/matplotlib-change-length-of-legend-lines

https://stackoverflow.com/questions/20048352/how-to-adjust-the-size-of-matplotlib-legend-box

折线图 plt.plot

plt.plot(y)的横坐标是从0开始的数组下标。

常用参数:

linestyle: '-' or 'solid', '--' or 'dashed', '-.' or 'dashdot', ':' or 'dotted'。完整列表:https://matplotlib.org/stable/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D.set_linestyle

marker

一般可以用marker, markersize, markerfacecolor, markevery

但是如果要手动指定哪些数据点需要marker,还是得用scatter。需要加上参数zorder=2手动把层级顺序调成跟线条一样,不然会出现后画的marker在先画的线条下面。

'plt.ylabel'

其他参数传给了Text。常用的:

可以微调高度

plt.text

Positional, required:

Optional:

The default transform specifies that text is in data coords.

transform=ax.transAxes: in axis coords. (0, 0) is lower-left and (1, 1) is upper-right.

其他参数:

savefig

Positional, required:

Optional:

PDF可用metadata: https://matplotlib.org/stable/api/backend_pdf_api.html#matplotlib.backends.backend_pdf.PdfPages

metadata={'CreationDate': None}: 在PDF中不保存CreationDate,从而使得数据相同时生成的PDF也相同。

参考:

PDF file generation is not deterministic - results in different outputs on the same input

https://matplotlib.org/2.1.1/users/whats_new.html#reproducible-ps-pdf-and-svg-output

Figure

Figure.get_layout_engine()

一般这样用:

fig.get_layout_engine().set(...)

文档:https://matplotlib.org/stable/api/layout_engine_api.html#matplotlib.layout_engine.ConstrainedLayoutEngine.set

常用参数:

图片上下边缘的padding。默认0.04167

图片左右边缘的padding。默认0.04167

Fraction of the figure to dedicate to space between the axes. These are evenly spread between the gaps between the Axes. A value of 0.2 for a three-column layout would have a space of 0.1 of the figure width between each column.

hspace是纵向间距。wspace是横向间距。

Rectangle in figure coordinates to perform constrained layout in (left, bottom, width, height), each from 0-1.

plt.legend

The location of the legend.

+--------------+--------------+---------------+
| 'upper left' |'upper center'| 'upper right' |
+--------------+--------------+---------------+
|'center left' |   'center'   |'center right' |
+--------------+--------------+---------------+
| 'lower left' |'lower center'| 'lower right' |
+--------------+--------------+---------------+

如果用了constrained layout,可以加outside前缀,比如outside upper center可以把legend放到图表的上面的中间。

Whether the legend should be drawn on a patch (frame).

The length of the legend handles, in font-size units.

The pad between the legend handle and text, in font-size units.

The spacing between columns, in font-size units.

The vertical space between the legend entries, in font-size units.

The fractional whitespace inside the legend border, in font-size units.

The pad between the Axes and legend border, in font-size units.

增加线宽

legend = plt.legend()
for line in legend.get_lines():
    line.set_linewidth(1.0)

来源:https://stackoverflow.com/a/48296983/13688160

Axes

ax = plt.gca()

文档:https://matplotlib.org/stable/api/axes_api.html

来源:https://stackoverflow.com/questions/15067668/how-to-get-a-matplotlib-axes-instance

tick_params

ax.tick_params(axis='y', which='major', labelsize=8)

set_title

Positional, required: label

Optional: fontdict

set_xticks

Positional, required: ticks

Optional: labels (list-like)

tick_params调labelsize。

set_xlabel

plt.xlabel一样。

Positional, required: xlabel

Optional: labelpad, fontsize

比方说如果xlabel超过了右边界,可以设置loc='right'来让它与右边界对齐,就不会超过右边界了。

set_xlim, set_ylim

设置Y轴最小值:

ax.set_ylim(bottom=0)

来源:https://stackoverflow.com/a/22642641/13688160

set_yscale

内置scale:https://matplotlib.org/stable/api/scale_api.html#builtin-scales

常用:linear, log

例子:

ax.set_yscale('log')
# 对数坐标有时候副刻度会显示label,看着很挤,可以强制不显示副刻度的label
ax_sa.tick_params(axis='y', which='minor', labelleft=False)

annotate 画箭头

The point (x, y) to annotate. The coordinate system is determined by xycoords.

The position (x, y) to place the text at. The coordinate system is determined by textcoords.

完整列表见文档。这里放常用的。

Value Description
data Use the coordinate system of the object being annotated (default)
figure fraction Fraction of figure from lower left
subfigure fraction Fraction of subfigure from lower left
axes fraction Fraction of axes from lower left

https://matplotlib.org/stable/api/_as_gen/matplotlib.patches.FancyArrowPatch.html#matplotlib.patches.FancyArrowPatch

Key Description
arrowstyle 默认simple,一般填 ->,这样能用的选项更多
relpos 起点相对文本框位置。默认(0.5, 0.5),即文本框中心
shrinkA 箭头起点收缩的距离。Default is 2 points
shrinkB 箭头终点收缩的距离。Default is 2 points
linewidth 调节箭头线宽

其他参数传给了Text。常用的:

常用值:bold

参考:https://stackoverflow.com/questions/36162414/how-to-add-bold-annotated-text-to-a-plot

ticklabel_format

比如把tick设置成

ax.ticklabel_format(style='sci', scilimits=(4, 4), useMathText=True)

tick formatter

文档:https://matplotlib.org/stable/gallery/ticks/tick-formatters.html

例子:

ax1.xaxis.set_major_formatter(lambda x, pos: str(x-5))

指定指数

比如指定指数为1e-9:

from matplotlib.ticker import ScalarFormatter
y_formatter = ScalarFormatter()
y_formatter.set_powerlimits((-9, -9))
ax.yaxis.set_major_formatter(y_formatter)

官方文档:https://matplotlib.org/stable/api/ticker_api.html#matplotlib.ticker.ScalarFormatter.set_powerlimits

来源:https://stackoverflow.com/a/77442842/13688160

设置fontsize:

ax.yaxis.get_offset_text().set_fontsize(8)

来源:https://stackoverflow.com/a/34228384/13688160

set_label_coords

例子:

ax.xaxis.set_label_coords(0.1, -0.19)

grid

官方文档:https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.grid.html

让参考线在柱状图的柱子后面:

# https://stackoverflow.com/a/68344604
ax.set_axisbelow(True)

给y轴画参考线:

ax.grid(axis='y')

colorbar

https://matplotlib.org/stable/users/explain/colors/colormapnorms.html

例子:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm, colors

ax = plt.gca()
cmap = plt.get_cmap('coolwarm')

# need to normalize because color maps are defined in [0, 1]
norm = colors.TwoSlopeNorm(1, vmin=0, vmax=5)

norm_cmap = cm.ScalarMappable(norm=norm, cmap=cmap)

for i in np.linspace(0, 5, 100):
    plt.scatter(i, i, color=norm_cmap.to_rgba(i))
cb = plt.colorbar(norm_cmap, ax=ax, ticks=[0, 0.5, 1, 2, 3, 4, 5])
cb.ax.tick_params(labelsize=8)
plt.show()

参考:

https://stackoverflow.com/questions/73510185/how-to-add-colorbar-in-matplotlib

https://stackoverflow.com/questions/29074820/how-do-i-change-the-font-size-of-ticks-of-matplotlib-pyplot-colorbar-colorbarbas

翻转坐标轴

https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.invert_yaxis.html

子图

一行多列

from matplotlib import gridspec

# https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure
fig = plt.figure(dpi=300, figsize=(xx, xx), constrained_layout=True)
fig_sa_max.get_layout_engine().set(
    # 上下的padding
    h_pad=0.01,
    # 左右的padding
    w_pad=0.01,
    # 左,下,宽,高。一般上面预留出来放legend。
    rect=(0, 0, 1, 0.74),
)
# 1行2列
gs = gridspec.GridSpec(1, 2, figure=fig)
for col in range(2):
    ax = plt.subplot(gs[0, col])
    ...
fig.legend(
    loc='upper center',
    # 精确定位
    bbox_to_anchor=(0.53, 1.04),
    ...
)
fig.savefig(pdf_path, metadata={'CreationDate': None})

多行多列

from matplotlib import gridspec

fig = plt.figure(dpi=300, figsize=(xx, xx), constrained_layout=True)
# 2行3列
gs = gridspec.GridSpec(2, 3, figure=fig)
# https://matplotlib.org/stable/api/layout_engine_api.html#matplotlib.layout_engine.ConstrainedLayoutEngine.set
fig.get_layout_engine().set(
    # 左右的padding
    w_pad=0.01,
    # 子图纵向间距,可以用来放子图title。
    hspace=0.13,
    # 左,下,宽,高。一般下面预留出来放子图title。上面预留出来放legend。
    rect=(0, 0.05, 1, 0.85),
)
for row in range(2):
    for col in range(3):
        ax = plt.subplot(gs[row, col])
        ...
    # 放title一般用fig.text
    fig.text(x, y, title, ...)
fig.legend(
    loc='upper center',
    # 精确定位
    bbox_to_anchor=(0.54, 1.0),
    # 跟图片上沿的距离
    borderaxespad=0.01,
    ...
)
...
fig.savefig(pdf_path, metadata={'CreationDate': None})

嵌套子图

如果是嵌套的子图,比如外面是2行2列,每个子图又是3个小子图,可以用GridSpecFromSubplotSpec。如果要求子图坐标轴对齐的话,就不能用constrained_layout了。这里我们手动配置layout。

fig = plt.figure(dpi=300, figsize=(7, 2.8))
# 外面是2行2列的大子图
# https://matplotlib.org/stable/api/_as_gen/matplotlib.gridspec.GridSpec.html
outer_grid = gridspec.GridSpec(2, 2, figure=fig,
    # 左边距
    left=0.06,
    # 下边距
    bottom=0.12,
    # 右边距
    right=0.998,
    # 上边距
    top=0.93,
    # 子图横向距离
    wspace=0.2,
    # 子图纵向距离
    hspace=0.4,
)
for row in range(2):
    for col in range(2):
        # 每个子图又分为1行3列的小子图
        inner_grid = gridspec.GridSpecFromSubplotSpec(1, 3, subplot_spec=outer_grid[row, col], wspace=0.4)
        for i in range(3):
            ax = fig.add_subplot(inner_grid[i])
            ...
        # 给每个大子图加title可以这样加
        bbox = outer_grid[row, col].get_position(fig)
        fig.text(bbox.x0 + bbox.width/2, bbox.y0 - 0.07, title, ha='center', va='top')
...
fig.legend(
    loc='upper center',
    # 精确定位
    bbox_to_anchor=(0.5, 1.02),
    ...
)
fig.savefig(pdf_path, metadata={'CreationDate': None})

调整坐标轴label与tick label之间的空隙

labelpad

官方文档:https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.xlabel.html

设置tick的个数

比如让y轴有4个tick:

plt.locator_params(axis='y', nbins=4)

来源:https://stackoverflow.com/a/13418954/13688160

很坑的是,log scale用这种方式无效,需要手动设置ticks:

plt.yscale('log')
# 设置成log scale似乎会清空ticks,所以要把设置ticks放后面
plt.yticks([1e5, 1e6, 1e7], fontsize=8)
# plt.yticks似乎会消除minor ticks,所以还得把它们补上
# 其中numticks比较玄学,似乎大于3就行。这里直接设置成一个大数,就肯定不会有问题了。
ax.yaxis.set_minor_locator(LogLocator(base=10, subs=np.arange(2, 10) * 0.1, numticks=233))

设置tick和坐标轴的间距

来源:https://stackoverflow.com/questions/2969867/how-do-i-add-space-between-the-ticklabels-and-the-axes

ax.tick_params(axis='y', which='major', pad=0.1)

双Y轴

# 手动控制颜色,不然两个ax上画出的线会出现相同颜色
color_list = plt.rcParams['axes.prop_cycle'].by_key()['color']
color_index = 0

ax1 = plt.gca()
ax1.set_ylabel('ylabel1', fontsize=8)
ax1.plot(x, y, label='legend1', color=color_list[color_index])
color_index += 1

ax2 = ax1.twinx()
ax2.set_ylabel('ylabel2', fontsize=8)
ax2.plot(x, y, label='legend2', color=color_list[color_index])
color_index += 1

lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, fontsize=8)

plt.show()

疑难杂症

Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.

sudo apt install python3-tk

来源:https://stackoverflow.com/questions/56656777/userwarning-matplotlib-is-currently-using-agg-which-is-a-non-gui-backend-so

在安装了ttf-mscorefonts-installer的情况下matplotlib找不到Times New Roman

sudo apt install msttcorefonts -qq
rm ~/.cache/matplotlib -rf

参考:https://stackoverflow.com/questions/42097053/matplotlib-cannot-find-basic-fonts

已知的问题

plt.legend顺序似乎只能是按列的,要改成按行只能手动reorder: https://stackoverflow.com/questions/29639973/custom-legend-in-pandas-bar-plot-matplotlib