Matplotlib嵌套PyQt5子图设置
一.创建子图的方式:
# 示例1:
self.figure, self.axes = plt.subplots(2, 2) # plt.subplots(2, 2)创建一个包含 2 行 2 列的子图网格,返回一个 Figure 对象和一个 axes 数组
# 示例2:add_subplot()的标准网格形式
self.fig = plt.figure()
self.ax1 = self.fig.add_subplot(2, 2, 1) # 2x2 网格中的第一个位置
self.ax2 = self.fig.add_subplot(2, 2, 2) # 2x2 网格中的第二个位置
self.ax3 = self.fig.add_subplot(2, 2, 3) # 2x2 网格中的第三个位置
self.ax4 = self.fig.add_subplot(2, 2, 4) # 2x2 网格中的第四个位置
# 示例3:add_subplot(),通过位置的列表或元组
self.fig = plt.figure()
self.ax1 = self.fig.add_subplot(221) # 等价于 fig.add_subplot(2, 2, 1)
self.ax2 = self.fig.add_subplot(222) # 等价于 fig.add_subplot(2, 2, 2)
self.ax3 = self.fig.add_subplot(223) # 等价于 fig.add_subplot(2, 2, 3)
self.ax4 = self.fig.add_subplot(224) # 等价于 fig.add_subplot(2, 2, 4)
# 示例4:add_subplot(),通过GridSpec对象
import matplotlib.gridspec as gridspec
self.fig = plt.figure()
gs = gridspec.GridSpec(2, 2)
self.ax1 = self.fig.add_subplot(gs[0, 0]) # 第一行第一列
self.ax2 = self.fig.add_subplot(gs[0, 1]) # 第一行第二列
self.ax3 = self.fig.add_subplot(gs[1, 0]) # 第二行第一列
self.ax4 = self.fig.add_subplot(gs[1, 1]) # 第二行第二列
1.subplots()
:
subplots()
是 matplotlib.pyplot
模块的一个函数,它用于创建一个图形对象,并在其中同时创建多个子图。这个方法返回一个 Figure
对象和一个包含所有子图的 Axes
对象的数组
参数:
nrows
(int): 子图的行数。ncols
(int): 子图的列数。figsize
(tuple): 图形的宽度和高度。sharex
(bool 或 str): 是否共享 x 轴。sharey
(bool 或 str): 是否共享 y 轴。subplot_kw
(dict): 传递给每个子图的参数。gridspec_kw
(dict): 传递给GridSpec
的参数。
返回:
fig
(Figure): 图形对象。axes
(ndarray of Axes):Axes
对象的数组。
2.add_subplot()
:
add_subplot()
方法是 Figure
类的一部分,它用于在一个图形对象上添加子图。每个子图都是一个 Axes
对象,提供了绘制图形的功能
参数:
nrows
(int): 子图的行数。ncols
(int): 子图的列数。index
(int): 子图的索引,从左到右,从上到下的顺序。
返回:
- 返回一个
Axes
对象
二.设置子图:
统一设置子图示例:
for ax in self.axes.flat:
# for ax in self.axes.flatten():
ax.set_facecolor('lightblue')
self.ax.flatten()和self.ax.flat这两种方法都自动迭代self.axs数组中的所有Axes对象,self.axs.flat提供一个迭代器,而self.axs.flatten()返回一个一维数组。推荐使用self.axes.flat
单独设置子图示例:
self.axs[0, 0].set_facecolor('lightblue')
self.axs[0, 1].set_facecolor('gray')
self.axs[1, 0].set_facecolor('lightpink')
self.axs[1, 1].set_facecolor('green')
三.调整子图间距:
self.figure.tight_layout()
用于自动调整子图参数,以便子图更好地适应图形区域。这在某些情况下是有用的,特别是当子图或图形标签重叠时。然而,不是每次都必须使用。
什么时候需要用?
- 子图重叠或者空间不足:间距太小导致标签、标题或轴标签重叠时,
tight_layout()
可以自动调整子图的布局,以避免这些重叠问题 - 动态调整布局:如果图形是动态生成的,子图内容可能会变化,
tight_layout()
可以确保每次生成图形时子图都能良好地适应图形区域
什么时候不需要?
- 手动调整间距:已经使用
GridSpec
或其他方法手动调整了子图之间的间距,并且布局已经不需要再更改时 - 固定布局:图形布局固定且不会因为内容变化而需要调整时
四.示例代码
plt_embed_pyqt5.py:
import sys
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.gridspec import GridSpec
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLineEdit, QLabel, QHBoxLayout
# 让图片可以显示中文
plt.rcParams['font.sans-serif'] = 'SimHei'
# 让图片可以显示负号
plt.rcParams['axes.unicode_minus'] = False
class MatplotlibWidget(QWidget):
def __init__(self, parent=None):
super(MatplotlibWidget, self).__init__(parent)
# 创建一个垂直布局
main_layout = QVBoxLayout(self)
# 创建一个 Matplotlib 图形对象
self.figure = plt.figure(figsize=(10, 8))
self.canvas = FigureCanvas(self.figure)
main_layout.addWidget(self.canvas)
# 调用绘制函数
self.draw_picture1()
def draw_picture1(self):
# 使用gridspec_kw,手动调整子图间距
self.axes = self.figure.subplots(2, 2, gridspec_kw={'wspace':0.4, 'hspace':0.4})
# 绘制第一个子图:折线图
self.axes[0, 0].plot([1, 2, 3], [4, 5, 6])
self.axes[0, 0].set_title('折线图')
# 绘制第二个子图:条形图
self.axes[0, 1].bar(['A', 'B', 'C'], [7, 8, 9])
self.axes[0, 1].set_title('条形图')
# 绘制第三个子图:散点图
self.axes[1, 0].scatter([1, 2, 3], [4, 5, 6])
self.axes[1, 0].set_title('散点图')
# 绘制第四个子图:饼图
sizes = [15, 30, 45, 10]
labels = ['A', 'B', 'C', 'D']
self.axes[1, 1].pie(sizes, labels=labels, autopct='%1.1f%%')
self.axes[1, 1].set_title('饼图')
# 绘制图形
self.canvas.draw()
def draw_picture2(self):
# 使用 GridSpec 分成四等份,手动调整子图间距
gs = GridSpec(2, 2, figure=self.figure, wspace=0.4, hspace=0.4)
# 创建子图数组
self.axes = [
self.figure.add_subplot(gs[0, 0]),
self.figure.add_subplot(gs[0, 1]),
self.figure.add_subplot(gs[1, 0]),
self.figure.add_subplot(gs[1, 1])
]
# 绘制第一个子图:折线图
self.axes[0].plot([1, 2, 3], [4, 5, 6])
self.axes[0].set_title('折线图')
# 绘制第二个子图:条形图
self.axes[1].bar(['A', 'B', 'C'], [7, 8, 9])
self.axes[1].set_title('条形图')
# 绘制第三个子图:散点图
self.axes[2].scatter([1, 2, 3], [4, 5, 6])
self.axes[2].set_title('散点图')
# 绘制第四个子图:饼图
sizes = [15, 30, 45, 10]
labels = ['A', 'B', 'C', 'D']
self.axes[3].pie(sizes, labels=labels, autopct='%1.1f%%')
self.axes[3].set_title('饼图')
# 绘制图形
self.canvas.draw()
def draw_picture3(self):
# 不手动调整间距时,用self.figure.tight_layout()自动调整子图参数避免子图重叠
self.axes = self.figure.subplots(2, 2)
# 绘制第一个子图:折线图
self.axes[0, 0].plot([1, 2, 3], [4, 5, 6])
self.axes[0, 0].set_title('折线图')
# 绘制第二个子图:条形图
self.axes[0, 1].bar(['A', 'B', 'C'], [7, 8, 9])
self.axes[0, 1].set_title('条形图')
# 绘制第三个子图:散点图
self.axes[1, 0].scatter([1, 2, 3], [4, 5, 6])
self.axes[1, 0].set_title('散点图')
# 绘制第四个子图:饼图
sizes = [15, 30, 45, 10]
labels = ['A', 'B', 'C', 'D']
self.axes[1, 1].pie(sizes, labels=labels, autopct='%1.1f%%')
self.axes[1, 1].set_title('饼图')
# 绘制图形
self.figure.tight_layout()
self.canvas.draw()
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
# 设置窗口标题和大小
self.setWindowTitle('Matplotlib in PyQt5')
self.setGeometry(100, 100, 800, 600)
# 创建 MatplotlibWidget 实例
self.matplotlib_widget = MatplotlibWidget(self)
# 设置中心部件和布局
self.setCentralWidget(self.matplotlib_widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
运行效果: