Matplotlib 绘图

Matplotlib 作为 Python 界相当知名的绘图库,其功能非常之多。为了防止自己哪天忘了,特将网上的零散教程收集起来,方便自查。

Matplotlib基本概念图

绘图前的设置

rcParam 设置

  • 中文支持和 Unicode 负号问题
    这个问题对于图里同时有中英文字体的场景来说非常重要。目前我的解决方案是把字体设置为 “STSong”(如果没有这个字体的话去网上下载一个)。省去了设置 matplotlib.rcParams[‘axes.unicode_minus’]=False ,同时显示效果还不错。
import matplotlib.pyplot as plt
plt.rcParams["font.family"] = "STSong"
  • Ticker 朝里
plt.rcParams['xtick.direction'] = "in"
plt.rcParams['ytick.direction'] = "in"
  • 显示子 ticker
plt.rcParams["xtick.minor.visible"] = True
plt.rcParams["ytick.minor.visible"] = True

Latex 字体问题

  1. 选用 stix 字体使其样式与常规公式一致
plt.rcParams["mathtext.fontset"] = "stix"
  1. 如果觉得 \frac{}{} 输出的分式太小,可以用 \dfrac{}{}。详见 Matplotlib 官方 Demo

  2. Python 对字符串的解析问题,这一问题应该在高版本python中会得到解决。比如

>>> A = "\frac{1}{2}"   # '\f' 被当成换页符了
>>> A
'\x0crac{1}{2}'
>>> print(A)

rac{{1}}{{2}}
>>> A = "\\frac{1}{2}"  # 将 '\f' 换为 '\\f' 
>>> print(A)
\frac{1}{2}
>>> A = "\\frac{{{}}}{{{}}}".format(1, 2)  # 用三引号实现想要的latex输出
>>> print(A)
\frac{1}{2}

基本绘图

以不同单位设置 Figure 的大小

这里总结一下官方文档的说法。
首先,matplotlib 默认的 Figure 的大小是以 inch 计算的,默认的 dpi=100 。如果想将图片以厘米输出,可以将长度乘上从厘米到 inch 的转换系数,就如官方给出的下面代码(效果图):

import matplotlib.pyplot as plt
text_kwargs = dict(ha='center', va='center', fontsize=28, color='C1')
cm = 1/2.54  # 厘米到 inch 的转换系数
plt.subplots(figsize=(15*cm, 5*cm))
plt.text(0.5, 0.5, '15cm x 5cm', **text_kwargs)
plt.show()

如果想要指定像素输出的话,其实只需要在定义 Figure 时修改 figsizedpi 两个选项即可。比如:输出一张 800x600 像素的图,且 dpi=200,则

fig = plt.figure(figsize=(4, 3), dpi=200)  # 图像的像素大小为 figsize 乘以 dpi

多列/行子图布局绘图

  1. plt.title() 会为当前正在绘制的子图添加标题,等价于 plt.gca().set_title() 。如果需要为整张图添加一个总标题,使用 plt.suptitle() ,或者像这样
fig, ax = plt.subplots(figsize=(2, 2), facecolor='lightskyblue', layout='constrained')
fig.suptitle('Figure')   # 设置总标题
ax.set_title('Axes', loc='left', fontstyle='oblique', fontsize='medium')  # 为Axes设置标题

在这里插入图片描述
2. 如果只需要等大的子图,使用 plt.subplots() ,或者采用如下的OOP写法:

fig = plt.figure()

# >> 添加2行3列,指向第一个子图的 `Axes` 
fig.add_subplot(2, 3, 1)

# >> 只添加1行2列,并把所有子图 `Axes` 的列表都作为返回值
ax1, ax2 = fig.subplots(1, 2)
  1. 如果需要不等大的子图,使用 GridSpec 划分空间。Figure 对象也支持 add_gridspec 方法。
    如果需要将 GridSpec 划分出的网格做出进一步细分,则需要使用 GridSpecFromSubplotSpec 函数,或者对 GridSpec 下标对应的 SubplotSpec 对象使用 subgridspec 方法。
    下面是参照 Matplotlib 的 Examples 写的示例代码,并给出中文注释和效果图。
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from matplotlib.gridspec import (
    GridSpec, GridSpecFromSubplotSpec
)

def format_axes(fig: Figure) -> None:
    for i, ax in enumerate(fig.axes):
        ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center")
        ax.tick_params(labelbottom=False, labelleft=False)


# 创建 Figure 对象
fig: Figure = plt.figure()

# 将 Figure 分成 1 行 2 列
gs0 = GridSpec(1, 2, figure=fig)

# 将左侧(即 gs0[0])分为 3 行 3 列
gs00 = GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[0])
# 分配左侧子区域
ax1 = fig.add_subplot(gs00[:2, :])
ax2 = fig.add_subplot(gs00[2, 0])
ax3 = fig.add_subplot(gs00[2, 1:])

# 将右侧(即 gs0[1])分为 3 行 3 列
# 与使用 `GridSpecFromSubplotSpec` 函数效果一致,但更为方便
gs01 = gs0[1].subgridspec(3, 3)
# 分配右侧子区域
ax4 = fig.add_subplot(gs01[:, :2])
ax5 = fig.add_subplot(gs01[:2, 2])
ax6 = fig.add_subplot(gs01[2, 2])

plt.suptitle("GridSpec Inside GridSpec")
format_axes(fig)

plt.show()

GridSpec Inside GridSpec

绘制水平条形图

关于绘制条形图的细节,可以参考CSDN用户 超爱太阳雨 的帖子

fig, ax = plt.subplots(
    figsize=(8, 4)
)
MLUs_label = ["CPU", "GPU"]
MLUs_data = [30.27, 320.94]

# 绘制条形图对象
MLUs_barh = ax.barh(
    range(len(MLUs_label)), MLUs_data,
    color='#6699CC'
)
# 这里在每个条形图对象旁边把数值标注出来
for rect in MLUs_barh:
    ax.text(
        rect.get_width(), rect.get_y() + rect.get_height()/2,  # 文本位置
        f"{w:.2f}",            # 文本格式
        ha='left',va='center'  # 文本左对齐 + 居中对齐
    )

# 把 y 轴的 tick 设置为 MLUs_label 
ax.set_yticks(range(len(MLUs_label)))
ax.set_yticklabels(MLUs_label)

# 设置 x 轴
ax.set_xlim([0, 400])
ax.set_xlabel("Million lattices per second")

# 隐藏右侧和顶部边框
ax.spines["right"].set_color("none")
ax.spines["top"].set_color("none")

横向条形图

设置label和ticker

ticker设置

如果需要调整 ticker 的设置,可以使用 plt.tick_param() 或者 Axes 对象 axax.tick_param() 进行设置。
如果需要具体配置 ticker 的格式,则可以使用 matplotlib.tickerticker API 进行设置。

进阶绘图

局部放大图

局部放大图(网上案例)
上图来自知乎专栏 【Matplotlib】 局部放大图 。绘图思路为:

  1. 在父坐标系中画图
  2. 使用 mpl_toolkits.axes_grid1.inset_locator.inset_axes 插入子图。随后在子图中画对应内容,控制显示区间。【inset_axes也是Axes对象中的一个方法】
  3. 使用 mpl_toolkits.axes_grid1.inset_locator.mark_inset 画出父坐标系与子坐标系的连接线。

图例组合

可参照此网页的做法

import numpy as np
import matplotlib.pyplot as plt
x=np.arange(0,10,1)
y=x**2
fig, ax = plt.subplots(1,1)

blue_dot = ax.scatter(x[:5],y[:5], s=100, color='b')

red_dot = ax.scatter(x[5:],y[5:], s=200, color='r')
black_cross = ax.scatter(x[5:],y[5:], s=400, marker='+', color='k')

# 将红色圆与黑色十字交叉组合为一个图例
lgnd = ax.legend(
    [blue_dot, (red_dot, black_cross)],
    ["Blue Circle", "Red Circle and Black Cross"]
)

图例组示意图

导出视频

注: matplotlib 的导出视频功能需要本机安装有 ffmpeg 之类的视频编码器,而matplotlib 在找不到 ffpmeg 时会使用 Pillow 生成视频。如果 matplotlib 找不到 ffmpeg 的位置,可以在 rcParams 中添加
matplotlib.rcParams["animation.ffmpeg_path"] = "在此用字符串写 ffmpeg 的绝对位置"

关于使用matplotlib制作动画,可参考 Animations using Matplotlib 这一官方教程。需要提醒的是 matplotlib.animation.FuncAnimation 在 3.7 版本中被弃用。

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值