Python数据分析基础03: 数据可视化 --- matplotlib 详细教程

原文链接:https://xiets.blog.csdn.net/article/details/130955982

版权声明:原创文章禁止转载

专栏目录:Python 专栏(总目录)

Matplotlib 是一个用于在 Python 中创建静态、动画和交互式可视化的综合库。Matplotlib 使容易的事情变得容易,使困难的事情成为可能。Matplotlib 以各种硬拷贝格式和跨平台的交互式环境生成达到出版质量的统计图。Matplotlib 可以用于 Python 脚本、Python/IPython Shell、Web应用程序 和 各种图形用户界面工具包。

Matplotlib 官方链接:

使用 pip 安装:

pip install matplotlib

使用 conda 安装:

conda install -c conda-forge matplotlib

1. Matplotlib 图表组成元素

Matplotlib 图表是一个 Figure 实例,包含了若干 plot 元素,通过调用函数控制图表的显示。

1.1 控制图表组成元素的函数

Matplotlib 绘图主要使用的模块是 matplotlib.pyplot,导入模块,一般取别名为 plt,控制图表组成元素的常用函数:

函数描述
plt.plot()将两个数组组成的坐标绘制成 线条 或 标记
plt.title()添加标题
plt.xlabel(), plt.ylabel()添加 X/Y 轴的标签(名称)
plt.xlim(), plt.ylim()设置/获取 X/Y 轴坐标限制范围
plt.xscale(), plt.yscale()设置 X/Y 轴刻度的缩放类型 (一般是线性的)
plt.xticks(), plt.yticks()设置/获取 X/Y 轴的当前刻度位置和标签
plt.grid()是否显示网格线
plt.axhline(), plt.axvline()添加水平/垂直的参考线
plt.axhspan(), plt.axvspan()添加水平/垂直的参考区域
plt.text(), plt.arrow(), plt.annotate()添加 文本、箭头、文本+箭头
plt.legend()显示绘制图形时添加的文本标签图例
plt.show()显示绘图(交互式模式下函数阻塞,非交互式模式下函数不阻塞)
plt.draw()重绘当前绘图窗口(可以中途就绘制图形而不需要等到 show() 后才能看到图形,交互式模式下一般很少用到)
plt.pause()短暂暂停以运行 GUI 事件循环,调用 draw() 后需要再调用 pause() 才能更新窗口(只需要极短暂暂停,更新窗口是在暂停执行前)
plt.cla()清除当前绘图区域(axes)
plt.clf()清除当前绘图窗口(figure)
plt.close()关闭一个绘图窗口(figure)

控制图表组成元素的函数原型:

import matplotlib.pyplot as plt

# 将数组 X 和 Y 组成的坐标绘制成 线条 或 标记
# 
# scalex 和 scaley 表示是否缩放坐标轴, 如果为 True 则把要显示的范围缩放到画布内
#
plt.plot(*args, scalex=True, scaley=True, data=None, **kwargs)

# 为轴设置标题, 可以设置左中右三个标题
#
# loc: 标题位置 ("center", "left", "right")
# pad: 标题与轴顶部的偏移量, 以磅为单位, 默认值为 rcParams["axes.titlepad"] == 6.0
# y:   浮点数, 标题的垂直轴位置 (1.0 表示为顶部) 默认值为 rcParams["axes.titley"] == None
#
plt.title(label, fontdict=None, loc=None, pad=None, *, y=None, **kwargs)

# 设置/获取 X/Y 轴坐标限制范围
#
# labelpad: 轴边界框的点间距, 包括刻度和刻度标签。如果为 None, 则保留先前的值。默认值为 rcParams["axes.labelpad"] == 4.0
#
# loc: 标签的位置, xlabel.loc 值可为 ("left", "center", "right"}, 默认值为 rcParams["xaxis.labellocation"] == "center"
#                ylabel.loc 值可为 ("bottom", "center", "top"}, 默认值为 rcParams["yaxis.labellocation"] == "center"
#
plt.xlabel(xlabel, fontdict=None, labelpad=None, *, loc=None, **kwargs)
plt.ylabel(ylabel, fontdict=None, labelpad=None, *, loc=None, **kwargs)

# 设置/获取 X/Y 轴坐标限制范围
#
# 使用示例:
#   xlim((left, right))     # set the xlim to left, right
#   xlim(left, right)       # set the xlim to left, right
#   xlim(right=3)           # adjust the right leaving left unchanged
#   xlim(left=1)            # adjust the left leaving right unchanged
#
# 返回: 新的 X/Y 轴坐标限制范围
#
plt.xlim(*args, **kwargs)
plt.ylim(*args, **kwargs)

# 设置 X/Y 轴刻度的缩放类型 (一般是线性的)
# 
# value 可取值为 "linear", "log", "symlog", "logit", ... 等
#
plt.xscale(value, **kwargs)
plt.yscale(value, **kwargs)

# 设置/获取 X/Y 轴的当前刻度位置和标签
#
# ticks:  需要设置标签的 刻度位置 数组
# labels: 在 ticks 数组元素 (刻度值) 对应位置显示的标签名称
# minor:  False 表示主要刻度/标签 (优先显示此函数设置的刻度/标签), 
#         True 表示次要刻度/标签 (优先显示原本的刻度/标签)
# kwargs: 控制文本标签的外观
#
plt.xticks(ticks=None, labels=None, *, minor=False, **kwargs)
plt.yticks(ticks=None, labels=None, *, minor=False, **kwargs)

# 配置网格线的显示
#
# visible: 是否显示
# which:   需要显示的刻度类型, 值可为: 'major', 'minor', 'both'
# axis:    需要显示的轴, 值可为: 'both', 'x', 'y'
# kwargs:  网格线的样式配置, 如: linestyle, linewidth, color 等
#          linestyle 线样式值可为: '-', '--', '-.', ':', '' ... 等
#
plt.grid(visible=None, which='major', axis='both', **kwargs)

# 添加水平/垂直的参考线
#
# y:          水平参考线的位置 (Y轴坐标)
# xmin, xmax: 水平参考线的左右两端点相对于画布的位置 (X轴起点和终点坐标), 值范围 [0.0, 1.0], 0 表示最左端, 1 表示最右端
#
# x:          垂直参考线的位置 (X轴坐标)
# ymin, ymax: 水平参考线的上下两端点相对于画布的位置 (Y轴起点和终点坐标), 值范围 [0.0, 1.0], 0 表示最底端, 1 表示最顶端
#
# kwargs:     参考线的样式配置, 如: linestyle, linewidth, color 等
#             linestyle 线样式值可为: '-', '--', '-.', ':', '' ... 等
#
plt.axhline(y=0, xmin=0, xmax=1, **kwargs)
plt.axvline(x=0, ymin=0, ymax=1, **kwargs)

# 添加一个水平/垂直跨度 (矩形)
#
# ymin, ymax: 水平矩形上下边坐标跨度 (Y轴坐标跨度)
# xmin, xmax: 水平矩形左右边相对于画布的位置, 值范围 [0.0, 1.0], 0 表示最左端, 1 表示最右端
#
# xmin, xmax: 垂直矩形左右两边坐标跨度 (X轴坐标跨度)
# ymin, ymax: 垂直矩形上下边相对于画布的位置, 值范围 [0.0, 1.0], 0 表示最底端, 1 表示最顶端
#
# kwargs:     矩形的样式配置, 如: linestyle, linewidth, color 等
#             linestyle 线样式值可为: '-', '--', '-.', ':', '' ... 等
#
plt.axhspan(ymin, ymax, xmin=0, xmax=1, **kwargs)
plt.axvspan(xmin, xmax, ymin=0, ymax=1, **kwargs)

# 添加文本
#
# x, y:     文本显示的坐标位置 (文本左下角坐标)
# s:        需要显示的文本
# fontdict: 覆盖默认文本属性的字典 (覆盖 rcParams 中的文本属性)
# kwargs:   文本的其他样式等属性
#
plt.text(x, y, s, fontdict=None, **kwargs)

# 添加箭头, 从 坐标 (x, y) 到 (x+dx, y+dy) 的箭头
#
# kwargs 表示箭头样式, 部分样式:
#       head_width: 头部宽度
#       head_length: 头部长度
#       shape: 形状, 值可为 绘制左半边('full'), 绘制右半边('left'), 全箭头('right')
#       linestyle: 线样式, 值可为 '-', '--', '-.', ':', '', ... 等
#       linewidth: 线宽
#
plt.arrow(x, y, dx, dy, **kwargs)

# 添加可带箭头的文本提示
#
# text:       需要显示的文本
# xy:         箭头指向的坐标, 类型为 (float, float)
# xytext:     放置文本的坐标, 类型为 (float, float)
# arrowprops: 箭头属性, 字典类型, 如: arrowprops={"arrowstyle": "->"}
#
plt.annotate(text, xy, xytext=None, xycoords='data', textcoords=None, arrowprops=None, annotation_clip=None, **kwargs)

# 显示绘制图形时添加的文本标签图例, 
#
# 如 plt.plot(x, y, label="Test Line") 绘图时 label 参数标志的图例
# 可通过 args/kwargs 参数配置图例显示的位置和样式
#
plt.legend(*args, **kwargs)

# 显示绘图
#
# block: 是否等待所有图形关闭后再返回。
#        如果为 True 则阻塞并运行 GUI 主循环, 直到所有图形窗口都关闭。
#        如果为 False 则显示所有图形窗口并立即返回 (不阻塞)。
#        在非交互模式下默认为 True, 在交互模式下默认为 False。
#
# 交互式模式开启和关闭:
#       plt.ion()               开启交互式模式, 开启后 plt.show() 方法不阻塞
#       plt.ioff()              关闭交互式模式, 关闭后 plt.show() 方法阻塞 (默认)
#       plt.isinteractive()     交互式模式是否开启
#
plt.show(*, block=None)

# 重绘当前绘图窗口(figure), 可以中途就显示绘制的图形而不需要等到 show() 后才能看到图形, 交互式模式下一般很少用到。
# 结合 pause(), cla() 或 clf() 函数可以简单实现动画。
plt.draw()

# 运行 GUI 事件循环指定秒数, 如果有活动的窗口(figure), 在暂停前将更新并显示。
# 调用 draw() 后, 需要调用 pause() 才能触发更新窗口。
plt.pause(interval)

# 清除当前绘图区域 (axes)
plt.cla()

# 清除当前绘图窗口 (figure)
plt.clf()

# 关闭一个绘图窗口 (figure)
#
# fig: None or int(a figure number) or str(a figure name) or Figure, fig=None 表示当前窗口
#
plt.close(fig=None)

1.2 中文显示问题

中文显示问题: https://matplotlib.org/stable/tutorials/text/text_props.html#text-with-non-latin-glyphs

Matplotlib 默认不支持 CJK (中日韩) 字符,需要手动设置字体:

matplotlib.rcParams["font.family"] = ["Kai"]        # 设置字体, 可以添加多个, 绘制文本时依次查找支持当前字符的字体
matplotlib.rcParams["axes.unicode_minus"] = False   # 处理设置了中文字体后负号显示异常问题

如果不希望修改 ASCII 字符显示的字体,可以使用 append() 方法把中文字体添加到列表尾部:

matplotlib.rcParams["font.family"].append("Kai")

对于 系统可用的字体文件,可以使用 matplotlib 模块执行下面代码查看:

import matplotlib.font_manager

fonts = matplotlib.font_manager.findSystemFonts()

for font in fonts:
    print(font)     # 字体文件路径 (.ttf, .ttc 等字体文件), 使用时只需要使用字体文件名的名称(可以不包括后缀)

在 Mac/Linux 系统上,可以使用 fc-list :lang=zhfc-list :lang=zh family 命令查看本机 支持中文的字体

也可以使用网上下载的字体文件,一些开源字体:

1.3 简单绘图示例

import numpy as np
import matplotlib
import matplotlib.pyplot as plt

# 处理中文问题
matplotlib.rcParams["font.family"].append("Kai")
matplotlib.rcParams["axes.unicode_minus"] = False

# 标题
plt.title("正弦曲线", pad=10)

# X/Y 轴标签名称, Y 轴标签默认为垂直方向, rotation="horizontal" 表示和 X 轴一样改为水平方向
plt.xlabel("X", loc="right")
plt.ylabel("Y", loc="top", rotation="horizontal")

# 正弦曲线
x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x)

# 根据数组 x 和 y 各元素组成的坐标点绘制连续的曲线
plt.plot(x, y, label=r"sin(x)")

# 显示网格
plt.grid(True, linestyle=":", linewidth=0.5)

# 添加注释 (文字 + 箭头)
d = np.pi / 2
plt.annotate("最高点", (d, np.sin(d)), (1.2, 0.6), arrowprops={"arrowstyle": "->"})

# 设置子 X 轴坐标 (如果没设置, 则默认为普通数字坐标)
pi = np.pi
plt.xticks([0, pi/2, pi, 3*pi/2, 2*np.pi], ["0", "π/2", "π", "3π/2", "2π"])

# 添加垂直矩形区域, 颜色格式为: #RGBA
plt.axvspan(4.2, 5.2, 0.5, 0.75, color="#FF00002F")

# 显示绘图时添加的图例 (plot 方法中的 label 参数)
plt.legend()

# 显示图形
plt.show()

结果展示:

sin.webp

1.4 保存图片: savefig()

savefig() 函数可以将当前画布保存为本地图片。

函数说明:

# 函数原型
matplotlib.pyplot.savefig(*args, **kwargs)

# 函数用法
savefig(fname, *, dpi='figure', format=None, metadata=None,
        bbox_inches=None, pad_inches=0.1,
        facecolor='auto', edgecolor='auto',
        backend=None, **kwargs)

# 参数说明
#   fname       保存的文件路径, 或 Python 文件对象
#   dpi         保存的分辨率, 每英寸点数, float 或 'figure', 默认值为 rcParams["savefig.dpi"] == 'figure'
#               如果是默认值 'figure', 则 dpi 使用 rcParams["figure.dpi"] == 100
#   format      保存格式, 如 'png', 'pdf', 'svg' ... 等, 如果为 None 则默认从 fname 的扩展名中读取。
#   metadata    要存储在图片元数据中的键值对, dict 类型。
#
#   bbox_inches str 或 Bbox, 以英寸为单位的边界框: 仅保存图形的给定部分。默认值为 rcParams["savefig.bbox"] == None。
#   pad_inches  float, 当 bbox_inches 为 'tight' 时, 图形周围的填充量。默认值为 rcParams["savefig.pad_inches"] == 0.1。
#   facecolor   color 或 'auto', 人物的面色。如果是 'auto', 则使用当前图形的面色。默认值为 rcParams["savefig.facecolor"] == 'auto'。
#   edgecolor   color 或 'auto', 图的边缘颜色。如果为 'auto', 则使用当前图形边缘颜色。默认值为 rcParams["savefig.edgecolor"] == 'auto'。

保存图片示例:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi, 100)

plt.plot(x, np.sin(x))

# 保存图片
plt.savefig("demo.png")

# 如果需要显示图片, 则 savefig() 必须在 show() 的前面
# plt.show()

2. Matplotlib 绘图函数

Matplotlib 常用的绘图函数主要在 matplotlib.pyplot 模块中。

2.1 点线图: plot()

plot() 函数用于将数组 X 和 Y 组成的坐标绘制成 线条 或 标记。

函数说明:

# 函数原型
matplotlib.pyplot.plot(*args, scalex=True, scaley=True, data=None, **kwargs)

# 一般用法 (可以同时绘制多组数据)
plot([x], y, [fmt], *, data=None, **kwargs)
plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)

# 参数说明:
#
#   x, y            拥有相同长度的数字一维数组, 组成一序列坐标点。x 值可选, 默认为 range(len(y))
#   fmt             定义图形的基本格式 (如 颜色、标记 和 线型) 的便捷方式, 可选参数。
#
#   scalex, scaley  是否缩放X/Y坐标轴, 默认为 True 表示把要显示的范围缩放到画布内
#   kwargs          Line2D 属性, 可选参数。用于指定 线标签、线宽、抗锯齿、标记颜色 等属性。

可以通过 fmt 格式字符串参数便携定义图形的基本格式,也可以使用 Line2D 的属性作为关键字参数来更好地控制外观。线属性和 fmt 可以混用(优先使用关键字参数)。

fmt 格式字符串参数是由 颜色、标记、线型 组成:

fmt = "[marker][line][color]"

它们中的每一个组成部分都是可选的。例外:如果有 line,但没有 marker,数据将是一条没有标记的线。默认情况下是使用默认颜色的一条连续实线。

marker 的取值:

'.'         点标记
','         像素标记
'o'         圆圈标记
'v'         triangle_down 标记
'^'         triangle_up 标记
'<'         triangle_left 标记
'>'         triangle_right 标记
'1'         tri_down 标记
'2'         tri_up 标记
'3'         tri_left 标记
'4'         tri_right 标记
'8'         八角形标记
's'         方形标记
'p'         五边形标记
'P'         加(填充)标记
'*'         星标
'h'         hexagon1 标记
'H'         hexagon2 标记
'+'         加号标记
'x'         x 标记
'X'         x (填充) 标记
'D'         钻石标记
'd'         薄钻石标记
'|'         线标记
'_'         线标记

line 的取值:

'-'         实线
'--'        虚线
'-.'        点划线
':'         点状虚线

color 的取值:

'b'         蓝色
'g'         绿色
'r'         红色的
'c'         青色
'm'         品红
'y'         黄色
'k'         黑色的
'w'         白色的

fmt 取值示例:

fmt = "b"           # 具有默认形状的蓝色标记
fmt = "or"          # 红色圆圈
fmt = "-g"          # 绿色实线
fmt = "--"          # 默认颜色的虚线
fmt = "^k:"         # 黑色 triangle_up 标记由虚线连接

plot() 绘图代码示例:

import numpy as np
import matplotlib.pyplot as plt

plt.title("plot()")

x = np.linspace(0, 2 * np.pi, 20)

# 星标点 (没有连线)
plt.plot(x, np.sin(x), "*", label="sin(x)")

# 圆点,青色,虚线连接, 线宽为1, 标记的大小为8
plt.plot(x, np.cos(x), "o--c", linewidth=1, markersize=8, label="cos(x)")

# 连续的实现, 指定颜色, 颜色格式: "#RGBA"
plt.plot(x, np.log(x), color="#FF00007F", label="log(x)")

plt.legend()
plt.show()

结果展示:

plot.webp

2.2 柱状图: bar()

bar() 函数用于绘制柱状图(在 X 轴上绘制定性数据的分布特征)。

函数说明:

# 函数原型:
matplotlib.pyplot.bar(x, height, width=0.8, bottom=None, *, align='center', data=None, **kwargs)

# 参数说明:
#   x           浮点数或数组, 柱状图每个柱状在 X 轴上的显示位置
#   height      浮点数或数组, 柱状图每个柱状的显示高度
#   width       浮点数, 单个柱状的宽度
#   bottom      浮点数或数组, 柱状底部的 Y 坐标, 默认为 0
#   align       对齐方式, 可取值为 'center'(默认), 'edge'
#
# kwargs 部分参数:
#   color       颜色或颜色列表, 条形面的颜色 (可以为每条柱状绘制不同的颜色)
#   edgecolor   颜色或颜色列表, 条形边缘的颜色
#   linewidth   浮点数或数组, 条边的宽度。如果为 0, 则不绘制边缘。
#   tick_label  条形的刻度标签。默认值使用默认数字标签。

柱状图 bar() 代码示例:

import matplotlib.pyplot as plt

plt.title("bar()")

x = [1, 2, 3, 4, 5, 6, 7, 8]        # 柱状图显示的位置
y = [8, 7, 9, 3, 12, 5, 10, 6]      # 柱状图每个位置的显示高度

# 绘制柱状图, 颜色可以不设置、设置一个或多个 (如果有多个颜色, 则按顺序依次使用)
plt.bar(x, y,
        color=["#FF00007F", "#00FF007F", "#0000FF7F"],
        tick_label=["A", "B", "C", "D", "E", "F", "G", "H"])

# tick 也可以另外再设置
# plt.xticks(x, ["A", "B", "C", "D", "E", "F", "G", "H"])

plt.xlabel("Number")
plt.ylabel("HEIGHT")

plt.show()

结果展示:

bar.webp

堆积柱状图:

import matplotlib.pyplot as plt

"""
堆积柱状图的实现原理: 绘制两组柱状图, 在第一组绘制后的顶边作为第二组的底边继续绘制
"""

plt.title("bar()")

x = [1, 2, 3, 4, 5, 6, 7, 8]

y1 = [8, 7, 9, 3, 12, 5, 3, 6]
y2 = [3, 2, 4, 5, 2, 6, 3, 4]

# 绘制第一组柱状图, 柱状的底边坐标为0
plt.bar(x, y1, label="ONE")

# 绘制第二组柱状图, 柱状的底边坐标以 y1 作为底边坐标
plt.bar(x, y2, bottom=y1, label="TWO")

plt.xticks(x, ["A", "B", "C", "D", "E", "F", "G", "H"])

plt.xlabel("Number")
plt.ylabel("HEIGHT")

plt.legend()
plt.show()

结果展示:

bar2.webp

并列柱状图:

import numpy as np
import matplotlib.pyplot as plt

plt.title("bar()")

x = np.array([1, 2, 3, 4, 5, 6, 7, 8])

y1 = np.array([8, 7, 9, 3, 12, 5, 3, 6])
y2 = np.array([3, 2, 4, 5, 2, 6, 3, 4])

# 绘制柱第一组状图: 宽度为 0.4, 集体往左偏移 0.2
plt.bar(x - 0.2, y1, width=0.4, label="ONE")

# 绘制柱第而组状图: 宽度为 0.4, 集体往右偏移 0.2
plt.bar(x + 0.2, y2, width=0.4, label="TWO")

plt.xticks(x, ["A", "B", "C", "D", "E", "F", "G", "H"])

plt.xlabel("Number")
plt.ylabel("HEIGHT")

plt.legend()
plt.show()

结果展示:

bar3.webp

2.3 条形图: barh()

barh() 函数用于绘制条形图(在 Y 轴上绘制定性数据的分布特征,也就是水平柱状图)。条形图和柱状图的绘制方法类似,只不过条形图是水平绘制,而柱状图是垂直绘制。

函数说明:

# 函数原型
matplotlib.pyplot.barh(y, width, height=0.8, left=None, *, align='center', data=None, **kwargs)

# 参数说明
#   y           浮点数或数组, 条形图每个条形在 X 轴上的显示位置
#   width       浮点数或数组, 条形图每个条形的显示宽度 (长度)
#   left        浮点数或数组, 条形左边的 X 坐标, 默认为 0
#   align       对齐方式, 可取值为 'center'(默认), 'edge'
#
# kwargs 部分参数:
#   color       颜色或颜色列表, 条形面的颜色 (可以为每条柱状绘制不同的颜色)
#   edgecolor   颜色或颜色列表, 条形边缘的颜色
#   linewidth   浮点数或数组, 条边的宽度。如果为 0, 则不绘制边缘。
#   tick_label  条形的刻度标签。默认值使用默认数字标签。

条形图 barh() 代码示例:

import matplotlib.pyplot as plt

plt.title("barh()")

y = [1, 2, 3, 4, 5, 6, 7, 8]        # 条形图显示的位置
x = [8, 7, 9, 3, 12, 5, 10, 6]      # 条形图每个位置的显示宽度 (长度)

plt.barh(y, x,
         color=["#FF00007F", "#00FF007F", "#0000FF7F"],
         tick_label=["A", "B", "C", "D", "E", "F", "G", "H"])

plt.xlabel("WIDTH")
plt.ylabel("Number")

plt.show()

结果展示:

barh.webp

条形图的堆积图和并列图的绘制原理与柱状图一样。

2.4 直方图: hist()

hist() 函数用于绘制直方图(在 X 轴上绘制定量数据的分布特征)。

函数说明:

# 函数原型
matplotlib.pyplot.hist(x, bins=None, range=None, density=False, weights=None, 
                       cumulative=False, bottom=None, histtype='bar', align='mid', 
                       orientation='vertical', rwidth=None, log=False, color=None, 
                       label=None, stacked=False, *, data=None, **kwargs)

# 参数说明
#   x       数组, 需要展示的数据
#
#   bins    int/序列/str, 用于描述所有 bin 的范围和每一个 bin 的宽度, 一个 bin 表示一个半开的数值区间。
#           默认值为 rcParams["hist.bins"] == 10。
#
#           如果是整数, 则它定义范围内等宽 bin 的数量, 相当于 x.min() 与 x.max() 之间使用此整数等分。
#
#           如果是序列, 则定义 bin 边缘, 包括第一个 bin 的左边缘和最后一个 bin 的右边缘; 在这种情况下, bin 的间距可能不相等。
#           除了最后一个 bin, 其他 bin 都是半开区间 (包头不包尾), 
#           例如: bins = [1, 2, 3, 4], 则包括 3 个 bin 区间: [1, 2), [2, 3), [3, 4]
#
#           如果bins是一个字符串, 它是以下分箱策略之一: 'auto'、'fd'、'doane'、'scott'、'stone'、'rice'、'sturges' 或 'sqrt'。
#
#   range   元祖 或 None, bins 的数值显示范围 (相当于X轴的坐标范围),
#           如果 bins 是序列, 则 range 无效。
#           如果未提供, 则默认为 (x.min(), x.max())。
#
#   density 布尔值, 如果 True, 则绘制并返回一个概率密度: 每个 bin 将显示 bin 的原始计数除以计数总数和 bin 宽度, 从而使直方图下的面积积分为 1。
#
#   weights 数组 或 None。如果是数组则为与 x 形状相同的权重数组。
#           比如 x[0] 的权重为 2, 则 x[0] 在统计时将被当成 2 份 (默认情况下数组中的每一个元素都当做 1 份统计)。
#           如果 density 为 True, 则权重被归一化, 因此密度在该范围内的积分保持为 1。
#
#   cumulative      bool 或 -1  
#
#   bottom          数组/标量/None, 每一个 bin 的底部位置。
#
#   histtype        直方图的类型, 可取值:
#                       'bar'           (默认) 传统的条形直方图。如果给出多个数据, 则条形图并排排列。
#                       'barstacked'    一种条形直方图, 其中多个数据堆叠在一起。
#                       'step',         生成默认未填充的线图。
#                       'stepfilled'    生成默认填充的线图。
#
#   align           直方图条的水平对齐方式, 可取值:
#                       'left'          条形图位于 bin 左侧边缘的中心。
#                       'mid'           条在 bin 边缘之间居中 (默认)。
#                       'right'         条形图位于右侧 bin 边缘的中心。
#
#   orientation     方向, 可取值: 'vertical'(默认), 'horizontal'。
#                   如果 'horizontal', barh 将用于条形直方图, bottom 将是左边缘。
#
#   rwidth          float/None, default: None。Bars 的相对宽度, 作为 bin 宽度的一部分。如果 None, 自动计算宽度。
#                   如果 histt​​ype 是 'step' 或 'stepfilled' 则忽略。
#
#   log             bool, 如果 True, 直方图轴将设置为对数刻度。
#
#   color           颜色 或 颜色序列, 每个数据集一个。默认 (None) 使用标准线条颜色序列。
#
#   label           字符串或字符串序列以匹配多个数据集。
#
#   stacked         bool, 默认为 False。
#                   如果为 True, 多个数据堆叠在彼此的顶部。
#                   如果为 False, 如果 histtype 为 'bar', 多个数据并排排列; 如果 histtype 为 'step', 则多个数据堆叠在彼此的顶部。
#
#   data            indexable object, optional.
#
#   **kwargs        Patch特性

hist() 绘制直方图示例:

import numpy as np
import matplotlib.pyplot as plt

plt.title("hist()")

# 创建一个符号标志正态分布的一维随机数组
x = np.random.standard_normal(100)

# 绘制直方图,
# 从 x.min() 到 x.max() 之间把区间等分为 10 份 (X轴), 统计 数组x 中的数据在每一份区间内的数量 (Y轴)
plt.hist(x, bins=10, alpha=0.5)

plt.xlabel("X")
plt.ylabel("Count")

plt.show()

结果展示:

hist.webp

2.5 饼图: pie()

pie() 函数用于绘制饼图(绘制定性数据的不同类别的百分比)。

函数说明:

# 函数原型
matplotlib.pyplot.pie(x, explode=None, labels=None, colors=None, autopct=None, pctdistance=0.6, 
                      shadow=False, labeldistance=1.1, startangle=0, radius=1, 
                      counterclock=True, wedgeprops=None, textprops=None, center=(0, 0), 
                      frame=False, rotatelabels=False, *, normalize=True, data=None)

# 参数说明
#   x           数组, 组成饼图的每一块楔形的占比大小 (楔形尺寸)
#
#   explode     数组, 如果不为 None, 则是一个与 x 相同大小的数组, 表示 x 中对应楔形 (子饼块 ) 的偏移半径分数。
#
#   labels      列表 或 None, 为每个楔形提供标签的字符串序列。
#
#   colors      颜色数组 或 None, 饼图将循环使用的数组中的颜色。如果 None, 将使用当前活动循环中的颜色。
#
#   autopct     None 或 str 或 可调用对象, 用于显示在楔形内的标签。如果是字符串则使用 fmt % pct 格式化。
#
#   pctdistance float, 每个饼图的中心与 autopct 生成的文本的开头之间的比率。如果 autopct 为 None 则忽略。
#
#   shadow      bool, 在馅饼下面画一个阴影。
#
#   normalize   bool, 当为 True 时, 总是通过标准化 x 来制作一个完整的饼图。
#
#   labeldistance   float 或 None, 绘制饼图标签的径向距离。如果为 None, 则不会绘制标签, 而是存储标签以供使用 legend()。
#
#   startangle  float, 默认为 0。饼图起点角度 (从 x 轴逆时针旋转的角度)。
#
#   radius      float, 默认: 1。饼的半径。
#
#   counterclock    bool, 默认为 True。指定分数方向, 顺时针或逆时针。
#
#   wedgeprops  dict, 默认为 None。传递给制作饼图的楔形的属性。
#
#   textprops   dict, 默认为 None。传递给文本对象的参数字典。
#
#   center      (float, float), 默认: (0, 0)。图表中心的坐标。
#
#   frame       bool, 是否显示坐标边框。
#
#   rotatelabels    bool, 默认为 False。如果为 True, 则将每个标签旋转到相应切片的角度。
#
#   dataindexable   object, optional。

pie() 绘制饼图示例:

import matplotlib.pyplot as plt

plt.title("pie()")

x = [0.1, 0.2, 0.3, 0.4]
labels = ["A", "B", "C", "D"]

plt.pie(x, labels=labels, autopct="%3.2f%%", startangle=0)

plt.legend()
plt.show()

结果展示:

pie.webp

带分裂块的饼图:

import matplotlib.pyplot as plt

plt.title("pie()")

x = [0.1, 0.2, 0.3, 0.4]
labels = ["A", "B", "C", "D"]

# 第一块楔形分裂出0.1
explode = [0.1, 0, 0, 0]

plt.pie(x, labels=labels, autopct="%3.2f%%", explode=explode)

plt.show()

结果展示:

pie2.webp

内嵌环形的饼图:

import matplotlib.pyplot as plt

plt.title("pie()")

x1 = [0.1, 0.2, 0.3, 0.4]
labels1 = ["A", "B", "C", "D"]

# 返回 楔形列表, 标签文本列表, autotext列表
wedge1, text1, autotext1 = plt.pie(
    x1,
    autopct="%3.0f%%",                              # autotext 的显示格式
    radius=0.6,                                     # 半径
    pctdistance=0.75,                               # 每个饼图的中心与 autotext 文本的开头之间的比率
    textprops={"color": "w"},                       # 标签 和 autotext 为白色
    wedgeprops={"width": 0.3, "edgecolor": "w"}     # 每个饼图的边缘宽度和颜色
)

x2 = [0.2, 0.35, 0.15, 0.3]
labels2 = ["H", "I", "J", "K"]
wedge2, text2, autopct2 = plt.pie(
    x2,
    autopct="%3.0f%%",
    radius=0.9,
    pctdistance=0.85,
    textprops={"color": "w"},
    wedgeprops={"width": 0.3, "edgecolor": "w"}
)

# 已显示的所有楔形列表
wedges = []
wedges.extend(wedge1)
wedges.extend(wedge2)

# 已显示的所有楔形列表对应的标签名称
labels = []
labels.extend(labels1)
labels.extend(labels1)

# 显示图例
plt.legend(
    wedges, labels,             # 图例中 楔形 对应的 标签
    title="LEGEND",             # 图例的标题
    loc="center",               # 图例的位置
    bbox_to_anchor=(0.9, 0.5)   # 图例锚点坐标, 有此参数则 loc 是图例的锚点位置
)

# 需要显示图例, X轴右边扩大范围
plt.xlim(-1, 1.5)

plt.show()

结果展示:

pie3.webp

2.6 极线图: polar()

polar() 用于绘制极线图(在极坐标轴上绘制折线图)。

函数说明:

# 函数原型, 支持多个 theta, r 参数, 格式字符串, 如 plot()
matplotlib.pyplot.polar(theta, r, **kwargs)

# 参数说明:
#   theta       弧度数组
#   r           theta 数组中每一个弧度元素对应的 半径
#   **kwargs    其他关键字参数

polar() 绘制极线图示例:

import numpy as np
import matplotlib.pyplot as plt

size = 12

theta = np.linspace(0, 2*np.pi, size, endpoint=False)
r = np.random.rand(size) * 30

plt.polar(theta, r, "ro")

plt.show()

结果展示:

polar.webp

2.7 散点图: scatter()

scatter() 函数用于绘制散点图(气泡图),具有不同标记大小和颜色的 y 与 x 的散点图。二维数据借助气泡大小展示三维数据。

函数说明:

# 函数原型:
matplotlib.pyplot.scatter(x, y, s=None, c=None, marker=None, cmap=None, norm=None, 
                          vmin=None, vmax=None, alpha=None, linewidths=None, *, 
                          edgecolors=None, plotnonfinite=False, data=None, **kwargs)

# 参数说明:
#   x, y        组成坐标的长度相同的数组
#
#   s           float 或 float数组, 对应 (x, y) 坐标点标记的大小。
#               以 points**2 为单位的标记大小。默认值为 rcParams['lines.markersize'] ** 2。
#
#   c           颜色或颜色数组
#
#   marker      标记的样式(MarkerStyle), 默认值为 rcParams["scatter.marker"] == 'o'。
#
#   **kwargs    其他关键字参数。

scatter() 绘制散点图示例:

import numpy as np
import matplotlib.pyplot as plt

plt.title("scatter()")

x = np.random.randn(100)
y = np.random.randn(100)

plt.scatter(x, y,                           # 气泡坐标
            s=np.power(5*x + 10*y, 2),      # 气泡大小
            c=np.random.rand(100),          # 气泡颜色
            alpha=0.5)                      # 整体透明度

plt.show()

结果展示:

scatter.webp

2.8 棉棒图: stem()

stem() 函数用于绘制棉棒图(绘制离散有序数据)。

函数说明:

# 函数原型
matplotlib.pyplot.stem(*args, linefmt=None, markerfmt=None, basefmt=None, bottom=0, label=None, 
                       use_line_collection=<deprecated parameter>, orientation='vertical', data=None)

# 函数用法
stem([locs,] heads, linefmt=None, markerfmt=None, basefmt=None)

# 参数说明:
#   locs        如果是垂直茎图, 茎的 x 位置。如果是水平茎图, 茎的 y 位置。
#   heads       如果是垂直茎图, 茎头的 y 值。如果是水平茎图, 茎头的 x 值。
#
#   linefmt     垂直线的颜色和线条样式的字符串
#   markerfmt   茎头处标记的颜色和形状的字符串
#   basefmt     基线属性的格式字符串
#
#   orientation 方向, 默认为 'vertical'。
#   bottom      float, 基线的 y/x 的位置, 默认为 0。
#
#   label       用于图例中显示的标签

stem() 绘制棉棒图示例:

import numpy as np
import matplotlib.pyplot as plt

plt.title("stem()")

x = np.linspace(0, 10, 11)
y = np.random.randn(11)

plt.stem(x,                         # 茎的位置 (X轴位置)
         y,                         # 茎头的位置 (Y轴位置), (x, y) 表示原点所在坐标
         linefmt="r-.",             # 垂直线样式
         markerfmt="go",            # 茎头样式
         basefmt="y-",              # 基线样式
         orientation="vertical")    # 方向: horizontal|vertical

plt.show()

结果展示:

stem.webp

2.9 箱线图: boxplot()

boxplot() 函数用于绘制箱线图。

箱形图(Box-plot)又称为盒须图、盒式图或箱线图,是一种用作显示一组数据分散情况资料的统计图。

箱线图模型:

   o        <----- 异常值

  ---       <----- 上边缘
   |
   |
+-----+     <----- 上四分位数
|     |
|-----|     <----- 中位数
|     |
+-----+     <----- 下四分位数
   |
   |
  ---       <----- 下边缘


   o        <----- 异常值

函数说明:

# 函数原型
matplotlib.pyplot.boxplot(x, notch=None, sym=None, vert=None, whis=None, positions=None, 
                          widths=None, patch_artist=None, bootstrap=None, usermedians=None, 
                          conf_intervals=None, meanline=None, showmeans=None, showcaps=None, 
                          showbox=None, showfliers=None, boxprops=None, labels=None, 
                          flierprops=None, medianprops=None, meanprops=None, capprops=None, 
                          whiskerprops=None, manage_ticks=True, autorange=False, zorder=None, 
                          capwidths=None, *, data=None)

boxplot() 绘制箱线图示例:

import numpy as np
import matplotlib.pyplot as plt

plt.title("boxplot()")

x = np.random.randn(1000)
plt.boxplot(x)

plt.grid(True, axis="y", linestyle=":", linewidth=1, color="gray", alpha=0.5)
plt.show()

结果展示:

boxplot.webp

2.10 误差棒图: errorbar()

errorbar() 函数用于绘制误差棒图(绘制 X 或 Y 轴方向的误差范围)。

函数说明:

# 函数原型
matplotlib.pyplot.errorbar(x, y, yerr=None, xerr=None, fmt='', ecolor=None, elinewidth=None, 
                           capsize=None, barsabove=False, lolims=False, uplims=False, xlolims=False, 
                           xuplims=False, errorevery=1, capthick=None, *, data=None, **kwargs)

# 参数说明:
#   x, y            浮点数或数组, 数据的坐标位置
#   yerr, xerr      浮点数或数组, 误差条大小
#
#   fmt             数据点/数据线的格式, 参考 plot()
#   ecolor          误差线的颜色
#   elinewidth      误差线的线宽
#   capsize         误差线上限的长度 (以磅为单位)

errorbar() 绘制误差棒图示例:

import numpy as np
import matplotlib.pyplot as plt

plt.title("errorbar()")

x = np.linspace(1, 5, 5)
y = np.power(x, 2)

plt.errorbar(x, y, fmt="bo:", yerr=2, xerr=0.1, alpha=0.6)
plt.show()

结果展示:

errorbar.webp

2.11 堆积折线图: stackplot()

stackplot() 用于绘制堆积折线图。堆积折线图通过绘制多组拥有相同 X 坐标的数据集的折线图按垂直方向堆叠而成。

函数说明:

# 函数原型
matplotlib.pyplot.stackplot(x, *args, labels=(), colors=None, baseline='zero', data=None, **kwargs)

# 参数说明:
#   x           (N,) array-like, 多组数据的共同 X 坐标
#   y           (M, N) array-like, 需要堆叠的数据的 Y 坐标
#   labels      list of str, optional, 分配给每个数据系列的一系列标签。
#   colors      list of color, optional, 要循环并用于为堆叠区域着色的一系列颜色。
#   baseline    用于计算基线的方法, 可取值为: 'zero', 'sym', 'wiggle', 'weighted_wiggle'

stackplot() 绘制堆积折线图示例:

import matplotlib.pyplot as plt

plt.title("stackplot()")

# X轴坐标
x = [1, 2, 3, 4, 5]

# Y轴坐标
y1 = [0, 2, 1, 3, 4]
y2 = [1, 3, 2, 4, 5]
y3 = [2, 4, 3, 5, 6]

# 三组数据对应的标签和颜色
labels = ["R", "G", "B"]
colors = ["#FF00007F", "#00FF007F", "#0000FF7F"]

# 绘制堆积折线, 先绘制y1, 然后y2在y1基础上堆积(y1+y2), y3在堆积后的y2基础上再堆积(y1+y2+y3)
plt.stackplot(x, y1, y2, y3, labels=labels, colors=colors)

plt.xlim(min(x), max(x))

plt.legend(loc="upper left")
plt.show()

结果展示:

stackplot.webp

2.12 间断条形图: broken_barh()

broken_barh() 用于绘制间断条形图。

函数说明:

# 函数原型
matplotlib.pyplot.broken_barh(xranges, yrange, *, data=None, **kwargs)

# 参数说明:
#   xranges     元祖序列, 元素为 (xmin, xwidth) 的序列, 矩形的 x 位置和延伸。
#   yrange      元祖(ymin, yheight), 所有矩形的 y 位置和扩展。

broken_barh() 绘制间断条形图示例:

import matplotlib.pyplot as plt

plt.title("broken_barh()")

xranges1 = [(1, 5), (8, 7), (18, 3), (25, 8)]
yrange1 = (5, 3)
plt.broken_barh(xranges1, yrange1, facecolors="#1F78B47F")

xranges2 = [(3, 4), (9, 8), (20, 4), (26, 6)]
yrange2 = (9, 3)
plt.broken_barh(xranges2, yrange2, facecolors=("#FF0000", "#00FF00", "#0000FF"), alpha=0.5)

plt.ylim(0, 18)

plt.show()

结果展示:

broken_barh.webp

2.13 阶梯图: step()

step() 用于绘制阶梯图。

函数说明:

# 函数原型
matplotlib.pyplot.step(x, y, *args, where='pre', data=None, **kwargs)

# 函数用法
step(x, y, [fmt], *, data=None, where='pre', **kwargs)
step(x, y, [fmt], x2, y2, [fmt2], ..., *, where='pre', **kwargs)

# 参数说明:
#   x, y        绘制的坐标
#   fmt         线型的格式字符串, 参考 plot()
#   where       应放置步骤的位置, 可取值:
#                   'pre',      y 值从每个 x 位置一直向左连续, 即台阶的右边点是坐标
#                   'post'      y 值从每个 x 位置一直向右连续, 即台阶的左边点是坐标
#                   'mid'       台阶的中间点是坐标
#
#   color       线型颜色
#   linestyle   线型类型
#   linewidth   线型宽度

step() 绘制阶梯图示例:

import matplotlib.pyplot as plt

plt.title("step()")

x = [0, 1, 2, 3, 4]
y = [3, 2, 4, 1, 2]

plt.step(x, y, where="pre", color="#0000FF7F", linestyle="-", linewidth=1)

plt.show()

结果展示:

step.webp

3. 绘图窗口和画布

一个绘图窗口可以划分为多个子区域(画布),每个子区域绘制不同的图形。

3.1 FigureAxes

Figure 表示一个 绘图窗口,Axes 表示绘图窗口下的一个 画布(绘图区域)。程序中可以创建多个 绘图窗口(Figure),一个 绘图窗口(Figure) 下可以有多个 画布(Axes)。

matplotlib.pyplot 模块中 FigureAxes 的相关函数:

# 创建新的 绘图窗口, 或者 激活现有的绘图窗口。
# 
# num:         int/str, 画布的唯一标识符。
#              如果是 num 是数字, 则系统窗口标题为 "Figure num"。
#              如果是 num 是 None, 则默认从 1 开始编号 (num = 1, 2, 3, ...), 系统窗口标题为 "Figure num"。
#              如果是 num 是 str, 则直接使用此字符串作为系统窗口标题。
#              如果具有该标识符的绘图窗口已经存在, 则激活该窗口并返回。
#
# figsize:     (float, float), 画布尺寸 (inch), 默认为 rcParams["figure.figsize"] == [6.4, 4.8]
# dpi:         float, 画布分辨率, 默认为 rcParams["figure.dpi"] == 100.0
# facecolor:   背景颜色, 默认为 rcParams["figure.facecolor"] == 'white
# edgecolor:   边框颜色, 默认为 rcParams["figure.edgecolor"] == 'white'
# frameon:     如果为 False, 则禁止绘制图框。
# FigureClass: Figure 的子类, 如果设置, 将创建这个子类的一个实例, 而不是一个普通的 Figure。
# clear:       如果为 True 并且该图形已经存在, 则将其清除。
# layout:      用于定位绘图元素以避免重叠 Axes 装饰 (标签、刻度等) 的布局机制。可取值为 'constrained', 'tight', LayoutEngine, None。
# **kwargs:    其他关键字参数
#
# return       返回 绘图窗口(Figure)
#
plt.figure(num=None, figsize=None, dpi=None, *, facecolor=None, edgecolor=None, frameon=True, 
           FigureClass=matplotlib.figure.Figure, clear=False, **kwargs) -> Figure


# 获取当前 绘图窗口(Figure), 如果 pyplot 图形堆栈上当前没有 Figure 则使用 plt.figure() 创建。
# 可以调用 plt.get_fignums() pyplot 图形堆栈上的所有 Figure。
plt.gcf() -> Figure


# 获取当前 画布(Axes), 如果当前 绘图窗口(Figure) 中没有 画布, 则调用 figure.add_subplot() 函数添加一个新的画布。
# figure.axes 画布列表中存放了 绘图窗口 的所有 画布。
plt.gca() -> Axes


# 重绘当前绘图窗口(Figure), 可以中途就显示绘制的图形而不需要等到 show() 后才能看到图形, 交互式模式下一般很少用到。
# 结合 pause(), cla() 或 clf() 函数可以简单实现动画。
plt.draw()


# 运行 GUI 事件循环指定秒数, 如果有活动的窗口(Figure), 在暂停前将更新并显示。
# 调用 draw() 后, 需要调用 pause() 才能触发更新窗口。
plt.pause(interval)


# 清除当前 画布(Axes)
plt.cla()


# 清除当前 绘图窗口(Figure)
plt.clf()


# 关闭一个 绘图窗口 (figure)
# fig: None or int(a figure number) or str(a figure name) or Figure, fig=None 表示当前窗口
plt.close(fig=None)

使用 plt 模块操作 绘图窗口(Figure) 和 画布(Axes) 的函数, 是对当前 FigureAxes 操作,如果没有对应的对象,一般会自动创建。

标题 可分为 系统窗口标题、绘图窗口标题、画布标题,三者通过不同方法设置:

# 系统窗口标题: num 参数用于显示系统窗口标题
plt.figure(num=None, ...)

# 绘图窗口标题:
figure.suptitle(title, ...)

# 画布标题: plt.title() 相当于 plt.gca().set_title(title, ...)
axes.set_title(title, ...)

代码示例:

import numpy as np
import matplotlib.pyplot as plt

# 创建绘图窗口
curr_fig = plt.figure("系统窗口标题")

# curr_fig == plt.gcf()

# 绘图窗口标题
curr_fig.suptitle("Figure Title")

# 当前画布
curr_axes = plt.gca()
curr_axes.set_title("Axes Title")
curr_axes.grid(True, linestyle=":")

# 在当前画布上绘图, plt.plot() 相当于 plt.gca().plot()
x = np.linspace(0, 2*np.pi, 100)
curr_axes.plot(x, np.sin(x))

plt.show()

结果展示:

figure_axes.webp

3.2 创建/设置子区域: subplot()

subplot() 函数用于 创建设置(存在则设置,不存在则创建)当前 绘图窗口(Figure) 的 子区域画布(Axes)。

函数用法:

# 把绘图窗口分为 nrows 行 ncols 列一共 nrows*ncols 个网格子区域, 每个子区域有一个单独的画布(Axes), 
# 当前在 index 位置 (从1开始) 的子区域画布中操作绘图。
plt.subplot(nrows: int, ncols: int, index: int, **kwargs)

# 如果 pos = 231, 则把绘图窗口分为 2 行 3 列一共 6 个网格子区域, 每个子区域有一个单独的画布(Axes),
# 当前在第 1 个网格子区域操作绘图。
plt.subplot(pos: int, **kwargs)

subplot() 函数使用示例:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi, 200)

# 把绘图窗口划分为 2x2 个网格, 当前绘图操作设置在第 1 个网格/画布 (之后的 plt 相关绘制函数只在当前网格/画布内有效)
plt.subplot(2, 2, 1)
plt.title("sin(x)")
plt.plot(x, np.sin(x))
plt.xticks([0, np.pi/2, np.pi, 3*np.pi/2, 2*np.pi], ["0", "π/2", "π", "3π/2", "2π"])

# 把绘图窗口划分为 2x2 个网格, 当前绘图操作设置在第 4 个网格/画布
plt.subplot(224)
plt.title("cos(x)")
plt.plot(x, np.cos(x))

plt.show()

结果展示:

subplot.webp

多次调用 subplot() 方法时,划分的行列数量可以不同:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi, 200)

# 把画布划分为 2x2 个网格, 当前在第 1 个网格子区域绘图
plt.subplot(221)
plt.plot(x, np.sin(x), label="sin(x)")
plt.legend()

# 把画布划分为 2x2 个网格, 当前在第 2 个网格子区域绘图
plt.subplot(222)
plt.plot(x, np.cos(x), label="cos(x)")
plt.legend()

# 把画布划分为 2x1 个网格, 当前在第 2 个网格子区域绘图
plt.subplot(212)
plt.plot(x, np.log(x), label="log(x)")
plt.legend()

plt.show()

结果展示:

subplot2.webp

3.3 创建绘图窗口和子区域: subplots()

subplots() 函数用于创建 绘图窗口(Figure) 和 子区域/画布(Axes)。

函数说明:

# 创建 绘图窗口 和 子区域, 返回 窗口对象, 子区域数组
plt.subplots(nrows=1, ncols=1, *, sharex=False, sharey=False, squeeze=True, 
             width_ratios=None, height_ratios=None, subplot_kw=None, 
             gridspec_kw=None, **fig_kw) -> Figure, Axes

# 参数说明:
#   nrows, ncols        子区域网格的行/列数
#   sharex, sharey      控制 X/Y 轴之间的属性共享
#
#   figsize             (float, float), 窗口的尺寸, 默认为 rcParams["figure.figsize"] = [6.4, 4.8]
#   dpi                 float, 窗口的分辨率(dots/inch), 默认为 rcParams["figure.dpi"] == 100.0
#
#   facecolor           背景颜色
#   edgecolor           边框颜色
#
#   **fig_kw            更多参数参考 pyplot.figure 的属性

subplots() 函数使用示例:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi, 200)

# 创建画布, 把绘图窗口划分为 2x2 的网格
fig, axs = plt.subplots(2, 2)

# 在坐标为 (0, 0) 的网格内绘图 (相关方法与 plt 中的绘图方法类似)
axs[0, 0].plot(x, np.sin(x))
axs[0, 0].set(title="sin(x)", xticks=[], yticks=[])

# 隐藏坐标为 (0, 1) 的网格画布的坐标轴刻度
axs[0, 1].get_xaxis().set_visible(False)
axs[0, 1].get_yaxis().set_visible(False)

# 隐藏坐标为 (0, 1) 的网格画布的边框
axs[0, 1].spines["top"].set_visible(False)
axs[0, 1].spines["right"].set_visible(False)
axs[0, 1].spines["bottom"].set_visible(False)
axs[0, 1].spines["left"].set_visible(False)

# 在坐标为 (1, 1) 的网格画布内绘图
axs[1, 1].plot(x, np.cos(x))
axs[1, 1].set_title("cos(x)")

# 设置绘图窗口的标题
fig.suptitle("fig title")

# 保存图片时可以调用绘图窗口 fig 的保存方法, 也可以调用 plt 的保存方法
# fig.savefig("demo.png")
# plt.savefig("demo.png")

plt.show()

结果展示:

subplots.webp

3.4 子区域共享坐标轴

默认情况子区域的坐标轴体系是独立的,其中一个缩放不会影响其他的子区域。

子区域之间的坐标轴可以为共享(刻度相同,并且缩放时跟着缩放):

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi, 200)

# 创建绘图窗口, 把窗口划分为 2x1 的网格, 共享 X 轴坐标
# 只有一行或一列的, 返回的子区域数组是一维的
fig, axs = plt.subplots(2, 1, sharex=True)

axs[0].plot(x, np.sin(x), label="sin(x)")
axs[0].legend()

axs[1].plot(x, np.cos(x), label="cos(x)")
axs[1].legend()

fig.suptitle("sharex")
plt.show()

结果展示:

subplots_sharex.webp

缩放其中一个图形时,另一个图形的 X 轴坐标也将跟着缩放。

3.5 移动坐标轴刻度 和 隐藏边框

Axes 表示一个子区域的画布。通过 Axes 对象的方法,可以实现对画布的操作(绘图、设置元素显示状态等)。Spine 表示画布中的边框,调用其相关函数可以实现对边框状态的操作。

“移动”坐标轴脊 和 隐藏边框:

import numpy as np
import matplotlib.pyplot as plt

# 获取当前 画布 (没有则自动新创建一个)
axs = plt.gca()

# 设置画布的标题
axs.set_title("sin(x)", loc="right")

# 也可以调用 plt.axes() 新创建一个 画布
# axs = plt.axes()

# 也可调用 plt.subplots() 创建画布, axs 是 Axes 的实例, 表示一个画布或画布的一个子区域。
# 没有指定行列, 默认为 1行 1列, 返回一个画布实例(非数组)。
# 通过 plt.subplots() 方法创建的画布, 设置全局标题需调用 fig.suptitle() 方法。
# fig, axs = plt.subplots()
# fig.suptitle("sin(x)")

axs.grid(True, linestyle=":", linewidth=1, color="gray", alpha=0.5)

# 隐藏 上边框 和 右边框
axs.spines["top"].set_visible(False)
axs.spines["right"].set_visible(False)

# 左边框 和 右边框 移动到中间 (包括刻度)
axs.spines["left"].set_position("center")
axs.spines["bottom"].set_position("center")

x = np.linspace(-2*np.pi, 2*np.pi, 200)
axs.plot(x, np.sin(x))

plt.show()

# 刻度其他操作:
#
# 隐藏坐标轴刻度:
#       axs.get_xaxis().set_visible(False)
#       axs.get_yaxis().set_visible(False)
#
# 修改刻度的位置:
#       axs.xaxis.tick_bottom()         # X轴刻度在下边 (默认)
#       axs.xaxis.tick_top()            # X轴刻度在上边
#       axs.yaxis.tick_left()           # Y轴刻度在左边 (默认)
#       axs.yaxis.tick_right()          # Y轴刻度在右边
#

# 边框其他操作:
#
# 隐藏边框:
#       axs.spines["top"].set_visible(False)
#       axs.spines["right"].set_visible(False)
#       axs.spines["bottom"].set_visible(False)
#       axs.spines["left"].set_visible(False)
#
# 修改边框颜色:
#       axs.spines["top"].set_color("none")         # 透明色
#       axs.spines["right"].set_color("red")
#       axs.spines["bottom"].set_color("y")
#       axs.spines["left"].set_color("#00FF007F")

# 隐藏/显示 轴线 + 刻度 + 刻度标签 + 网格 + 轴标签
#       axs.set_axis_off()
#       axs.set_axis_on()

结果展示:

axes.webp

设置边框位置函数: set_position(position)

# 函数原型
matplotlib.spines.Spine.set_position(position)

# 参数说明:
#   position 参数可以是一个二元组 (position type, amount)
#   position 可取值:
#       ('outward', dots)   将脊椎从数据区域向外放置指定的点数,(负值将脊椎向内放置)。
#       ('axes', ratio)     将脊椎放置在指定的 Axes 坐标的比例 (0 到 1) 处。
#       ('data', value)     将脊椎放置在指定数据X/Y坐标值处。
#
#   position 默认值为: 
#       ('outward', 0.0)
#
#   position 可以传递一个字符串:
#       'center'            等价于 ('axes', 0.5)
#       'zero'              等价于 ('data', 0.0)

3.6 坐标轴反转

默认情况下,X 轴坐标从左到右,Y 轴坐标从下到上(坐标原点在左下角)。

反转 Y 轴坐标,使坐标原点在左上角:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)


curr_axs = plt.gca()                # 获取当前 画布

# curr_axs.invert_xaxis()           # X轴反转
curr_axs.invert_yaxis()             # Y轴反转

curr_axs.xaxis.tick_top()           # X轴刻度在上边

plt.plot(x, np.power(x, 2))

plt.show()

结果展示:

invert_yaxis.webp

4. Matplotlib 配置

Matplotlib 对画布元素控制、绘图默认参数、一些函数的默认参数均保存在 matplotlib.rcParams 字典对象中,可以修改对应参数的默认值。

默认值和样式: matplotlib.rcParams

matplotlib.rcParams == plt.rcParams

5. 绘制几何图形: matplotlib.patches

matplotlib.patches 模块中定义了很多几何形状:

patches.webp

绘制几何图形,只需要创建对应的图像对象,然后调用画布(轴)的添加方法(如 axes.add_patch() )添加画布(轴)中。

Axes 中的添加形状的相关方法:

方法描述
add_artist()添加 Artist(所有形状的基类)
add_child_axes()给 Axes 添加 子Axes,其他版本 inset_axes()
add_collection()添加 Collection 集合
add_container()添加 Container 容器
add_image()添加 AxesImage 图片
add_line()添加 Line2D 线段
add_patch()添加 Patch
add_table()添加 Table

绘图示例参考: Reference for Matplotlib artists

绘制几何图形示例:

import matplotlib.pyplot as plt
from matplotlib import axes
from matplotlib import lines
from matplotlib import patches


def main():
    fig, axs = plt.subplots(2, 2, figsize=(6, 6), dpi=100.0)
    fig.suptitle("Draw Artist ")

    draw_line(axs[0, 0])
    draw_rectangle(axs[0, 1])
    draw_circle(axs[1, 0])
    draw_arc(axs[1, 1])

    plt.show()


def draw_line(ax: axes.Axes):
    """
    绘制折线
    """
    x = [0, 1, 2, 4]
    y = [3, 4, 2, 3]
    line = lines.Line2D(x, y,
                        linestyle="-", linewidth=1, color="#FF0000", label="Line2D")
    ax.add_line(line)
    ax.set_xlim(0, 5)
    ax.set_ylim(0, 5)
    ax.legend()


def draw_rectangle(ax: axes.Axes):
    """
    绘制矩形
    """
    xy = (1, 1)
    width = 3
    height = 2
    rect = patches.Rectangle(xy, width, height,
                             linestyle="--", linewidth=1, edgecolor="#FF0000",
                             facecolor="#CCCCCC",
                             label="Rectangle")
    ax.add_patch(rect)
    ax.set_xlim(0, 5)
    ax.set_ylim(0, 5)
    ax.legend()


def draw_circle(ax: axes.Axes):
    """
    绘制圆
    """
    xy = (0, 0)
    radius = 1
    circle = patches.Circle(xy, radius,
                            linestyle="-.", linewidth=1, edgecolor="#FF0000",
                            facecolor="#CCCCCC",
                            label="Circle")
    ax.add_patch(circle)
    ax.set_xlim(-2, 2)
    ax.set_ylim(-2, 2)
    ax.legend()


def draw_arc(ax: axes.Axes):
    """
    绘制圆弧
    """
    xy = (0, 0)
    width = 3
    height = 3
    circle = patches.Arc(xy, width, height,
                         angle=0, theta1=90, theta2=360,
                         label="Arc")
    ax.add_patch(circle)
    ax.set_xlim(-2, 2)
    ax.set_ylim(-2, 2)
    ax.legend()


if __name__ == "__main__":
    main()

结果展示:

draw_artist.webp

6. 绘制动画: matplotlib.animation

matplotlib.animation 模块用于绘制动画,模块中的 FuncAnimation 类用于通过重复调用 func 函数来制作动画。

FuncAnimation 类的构造方法:

# 构造方法
class matplotlib.animation.FuncAnimation(
    fig, func, frames=None, init_func=None, fargs=None, save_count=None, *, 
    cache_frame_data=True, **kwargs
)

# 参数说明:
#   fig         Figure, 用于获取所需事件的画布对象, 例如绘制或调整大小。
#
#   func        在每一帧调用的函数。第一个参数将是 frames 中的下一个值。任何额外的参数都可以通过 fargs 参数提供。
#               函数签名为: def func(frame, *fargs) -> iterable_of_artists
#
#   frames      传递给 func 函数的动画每一帧的数据源。值类型为 可迭代对象/int/生成器函数/None。
#               如果是可迭代对象, 则直接使用提供的值序列。如果 iterable 有长度, 它将覆盖 save_count kwarg。
#               如果是整数, 则相当于通过 range(frames)。
#               如果是生成器函数, 则必须具有签名: def gen_function() -> obj
#
#   init_func   可调用对象, 用于绘制清晰框架的函数。如果未给出, 将使用从帧序列中的第一项绘制的结果。
#               此函数将在第一帧之前调用一次。
#               此函数的签名为: def init_func() -> iterable_of_artists
#
#   fargs       元祖/None, 传递给对 func 函数的每次调用的附加参数。
#
#   save_count  int, 默认为 100, 从帧到缓存的值数量的后备。 
#               这仅在无法从 frames 推断出帧数时使用, 即当它是没有长度的迭代器或生成器时。
#
#   interval    int, 默认为 200, 每帧之间的间隔时间 (以毫秒为单位)。
#
#   repeat          是否重复, 默认为 True。
#   repeat_delay    int, 默认为 0, 如果 repeat 为 True, 则连续动画运行之间的间隔 (以毫秒为单位)。
#
#   blit            bool, 默认为 False, blitting 是否用于优化绘图。
#
#   cache_frame_data    bool, 默认为 True, 帧数据是否被缓存。当帧包含大型对象时, 禁用缓存可能会有所帮助。

FuncAnimation 类的其他方法:

# 返回一个新的帧信息序列。
new_frame_seq()     

# 返回保存/缓存的帧信息的新序列。            
new_saved_frame_seq()

# 暂停动画。
pause()

# 恢复动画。
resume()

# 通过绘制每一帧将动画保存为 视频 或 动画。
# 使用 ffmpeg 保存为视频文件 (ffmpeg 需可用),
# 或者使用 Pillow 保存为动画图片(GIF)。
save(filename[, writer, fps, dpi, codec, ...])

# 将动画转换为 HTML5<video> 标签。
to_html5_video([embed_limit])

# 生成动画的 HTML 表示。
to_jshtml([fps, embed_frames, default_mode])

FuncAnimation 动画实例:

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation

# 创建画布
fig, ax = plt.subplots()

# X轴的数据序列
x = np.linspace(0, 2*np.pi, 100)

# 第一个图形
x1data, y1data = [], []
# 先绘制空图形, 返回绘制后的图像对象
line1 = ax.plot([], [], "r-")[0]

# 第二个图形
x2data, y2data = [], []
# 先绘制空图形, 返回绘制后的图像对象
line2 = ax.plot([], [], "r--")[0]


def init_func():
    """
    初始化函数, 动画开始 (包括重复的开始) 前会先调用一次 (首次开始前调用两次)
    返回 可迭代对象(元素为几何图形/Artist)
    """
    # 设置画布
    fig.suptitle("FuncAnimation")
    ax.set_xlim(0, 2*np.pi)
    ax.set_ylim(-1, 1)
    ax.set_xlabel("X", loc="right")
    ax.set_ylabel("Y", loc="top", rotation="horizontal")
    ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2, 2*np.pi], ["0", "π/2", "π", "3π/2", "2π"])
    ax.grid(True, linestyle=":")

    # 清空图形内容
    x1data.clear()
    y1data.clear()
    line1.set_data(x1data, y1data)

    x2data.clear()
    y2data.clear()
    line2.set_data(x2data, y2data)

    # 返回可迭代对象, 元素为几何形状用于绘制图形, 可以返回多个
    return [line1, line2]


def update_func(frame, *fargs):
    """
    每一帧调用一次
    返回 可迭代对象(元素为几何图形/Artist)
    """
    # 获取出当前帧 X 轴坐标值
    curr_x = x[frame]

    # 计算第一个图形的坐标点, 把值添加到坐标点列表中
    x1data.append(curr_x)
    y1data.append(np.sin(curr_x))
    # 重新设置图形的坐标序列
    line1.set_data(x1data, y1data)

    # 计算第二个图形的坐标点, 把值添加到坐标点列表中
    x2data.append(curr_x)
    y2data.append(np.cos(curr_x))
    # 重新设置图形的坐标序列
    line2.set_data(x2data, y2data)

    # 返回可迭代对象, 元素为几何形状用于绘制图形, 可以返回多个
    return [line1, line2]


# 创建动画器
anim = animation.FuncAnimation(fig,                     # 画布
                               update_func,             # 帧更新函数, 每一帧调用一次
                               frames=x.size,           # 帧数据, [0, 1, 2, ..., x.size) 之间逐个元素传递给 update_func 函数
                               init_func=init_func,     # 初始化函数, 每个周期开始前调用
                               interval=50,             # 每帧之间的间隔时间, 单位: 毫秒
                               repeat=True,             # 重复动画
                               fargs=(),                # 传递给 update_func 函数的第二个(包括)之后的参数
                               blit=True)

# 把动画保存为 GIF 动画 (使用 Pillow 编码保存, 如果动画是重复的, 只保一个周期)
anim.save("anim.gif", writer="pillow")

# 如果需要保存为视频文件, 需要确保 ffmpeg 可用 (默认使用 ffmpeg 编码, ffmpeg 不可用时自动改用 pillow)
# anim.save("anim.mp4", writer="ffmpeg")

# 显示动画
plt.show()

结果展示:

anim.gif

7. 图片读取与显示

matplotlib.pyplot 模块读取显示保存图片的函数:imread()imshow()imsave()

由于历史原因而存在 imread() 函数,建议使用 PIL.Image.open 加载图像。

函数说明:

# 读取图片
#
# fname     str 或 文件对象。要读取的图像文件: 以读取二进制模式打开的文件名、URL 或 类似文件的对象。
#           不推荐使用 URL, 打开 URL 请使用 Pillow, 例如: np.array(PIL.Image.open(urllib.request.urlopen(url)))
#
# format    用于读取数据的图像文件格式, 如 "png"。如果为 None, 则使用 fname 后缀名或自动检测格式。
#
# return    返回图片解码后生成的图像数据 (numpy.array)。
#           返回的数组根据图片格式具有不同的形状:
#               (M, N) 用于灰度图像。
#               (M, N, 3) 用于 RGB 图像。
#               (M, N, 4) 用于 RGBA 图像。
#           PNG 图像以浮点数组 (0-1) 的形式返回。所有其他格式都作为 int 数组返回, 位深由文件的内容决定。
#
plt.imread(fname, format=None)


# 显示图片
#
#   X       已解码的图片数据数组 或 PIL图像
#
#   return  返回一个表示画布中图片的图形对象 (matplotlib.image.AxesImage)
#
plt.imshow(X, cmap=None, norm=None, *, aspect=None, interpolation=None, alpha=None, 
           vmin=None, vmax=None, origin=None, extent=None, interpolation_stage=None, 
           filternorm=True, filterrad=4.0, resample=None, url=None, data=None, **kwargs)


# 保存图片
#
#   fname       str 或 path-like 或 file-like, 文件保存位置。
#   arr         图像数据数组, 形状可以是 MxN (灰度)、MxNx3 (RGB) 或 MxNx4 (RGBA)。
#
#   format      格式, 例如 'png', 'pdf', 'svg'。默认从 fname 文件名后缀中获取。
#   metadata    dict, 图片元数据。
#   pil_kwargs  dict, 传递给 PIL.Image.Image.save 的参数。
#
plt.imsave(fname, arr, **kwargs)

读取图片并显示:

from matplotlib import pyplot as plt

plt.title("Image")

# 读取图片, 也可以使用 img = PIL.Image.open("demo.png") 加载图片
img = plt.imread("demo.png")

# 把图片绘制到画布上
plt.imshow(img)

# 显示画布
plt.show()

结果展示:

imread.webp

把图片显示为圆形:

from matplotlib import pyplot as plt
from matplotlib import patches

# 读取图片
img = plt.imread("demo.png")

# 把图片绘制到画布上 (返回画布上的图形对象)
axes_image = plt.imshow(img)

# 图片的宽高
img_width = img.shape[0]
img_height = img.shape[1]
# 圆心和半径
circle_center = (img_width / 2, img_height / 2)
radius = min(img_width, img_height) / 2

# 创建一个圆
circle = patches.Circle(circle_center, radius, transform=plt.gca().transData)
# 在绘制图片后返回的图形对象上裁剪出圆
axes_image.set_clip_path(circle)

# 隐藏当前画布的 轴线 + 刻度 + 刻度标签 + 网格 + 轴标签
plt.gca().set_axis_off()

# 显示画布
plt.show()

结果展示:

imshow.webp

读取图片,交换图片的列 (竖直方向上翻转),保存图片:

import numpy as np
from matplotlib import pyplot as plt

# 读取图片
img = plt.imread("demo.png")

# 读取的 img 是只读的, 转换为普通的 ndarray
img = np.array(img)

# 交换图片的列 (竖直方向上翻转)
for r in range(img.shape[0]):
    for c in range(img.shape[1] // 2):
        for rgba in range(img.shape[2]):
            t = img[r][c][rgba]
            img[r][c][rgba] = img[r][img.shape[1] - 1 - c][rgba]
            img[r][img.shape[1] - 1 - c][rgba] = t

# 保存图片
plt.imsave("demo.webp", img)

保存的图片: demo.webp

save.webp

8. 使用 TeX 渲染数学公式

Matplotlib 支持使用 TeXLaTeX 渲染公式。TeX 是 Matplotlib 自带支持的,参考:使用 TeX 渲染数学方程

使用 LaTeX 需确保本地已安装支持,参考:使用 LaTeX 进行文本渲染

代码示例:

import matplotlib.pyplot as plt

plt.text(0.2, 0.2, r"$\sqrt{b^2 - 4ac}$", fontsize=16)
plt.text(0.3, 0.5, r"$\alpha, \beta$", fontsize=16)
plt.text(0.7, 0.5, r"$\sum_{n=0}^\infty\frac{-e^{i\pi}}{2^n}$", fontsize=16)
plt.text(0.3, 0.8, r"$\frac{\partial \phi}{\partial t} + U|\nabla \phi| = 0$", fontsize=16)

plt.show()

结果展示:

tex.webp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谢TS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值