为什么子图没有占用嵌入 Tkinter 的 Matplotlib 中图形允许的所有空间?

Jér*_*uet 5 python user-interface tkinter matplotlib subplot

我想在 Tkinter 窗口中显示很多子图,并且能够向下滚动以查看所有大小合适的图。但是,它全部打包,并且子图似乎并没有占用我图中允许的所有空间,而仅限制在窗口的空间内。我怎样才能让它更间隔开并使子图更大?

我已经尝试使用该tight_layout()选项进行不同的填充,更改了 Tkinter 的图形大小和其他参数,例如我的小部件中的fillexpand

import tkinter as tk
from tkinter import Scrollbar
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

import matplotlib.pyplot as plt

class ScrollableWindow:

    def __init__(self, master, fig, **options):

        master.geometry("%dx%d+0+0" % (800, 500))
        master.focus_set()

        fig_wrapper = tk.Frame(master, width=800, height=fig.get_figheight())
        fig_wrapper.pack(fill=tk.BOTH, expand=True)

        fig_canvas = FigureCanvasTkAgg(fig, master=fig_wrapper)

        scrollbar = Scrollbar(fig_wrapper, orient=tk.VERTICAL, command=fig_canvas.get_tk_widget().yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        fig_canvas.get_tk_widget().pack(fill=tk.BOTH, side=tk.LEFT, expand=True)
        fig_canvas.get_tk_widget().config(yscrollcommand = scrollbar.set, scrollregion=fig_canvas.get_tk_widget().bbox("all"), width=800, height=1000)



n_col, n_row = 3, 11

fig, axes = plt.subplots(figsize=(n_col,n_row*2), ncols=n_col, nrows=n_row)
for i in range(axes.shape[0]):
    for j in range(axes.shape[1]):
        axes[i,j].set_xlabel("xlabel")
        axes[i,j].set_ylabel("ylabel")
fig.tight_layout()
showStatsWindow = tk.Tk()
showStatsWindow_ = ScrollableWindow(showStatsWindow, fig)
showStatsWindow.mainloop()
Run Code Online (Sandbox Code Playgroud)

这是一个带有空图的示例。我想每行有 3 或 4 个子图,但它们都挤在一起。如您所见,我的窗口下方有更多空间,它随 figsize 参数而变化,但都是空白的。

Muh*_*man 3

首先让我从显示 matplotlib 图形的大小开始,例如。实际上,固定的窗口大小困扰着您。 tkinter-Windowsubplotsmaster.geometry("%dx%d+0+0" % (800, 500))

当您简单地使用 tkinter 窗口时,它会automatically根据图形大小调整自身大小。相反,如果调整大小,图形也会调整大小。对于上述问题有一个简单的解决方法。

防止 tkinter 窗口被调整大小。现在,要使子图的大小更大或更小,您可以通过figsize=()相应地更改参数来更改它。

fig, axes = plt.subplots(ncols=n_col, nrows=n_row, figsize=(7.5, 25))
Run Code Online (Sandbox Code Playgroud)

我必须推荐您使用 use PyQT5,这在您给定的场景中更可行。下面给出了一个工作示例,其中不调用tkinter诸如pack()等自定义操作config()

Qt5将图形放入带有滚动条的画布中,以便图形保留其原始大小并可以在 Qt 窗口中滚动。您不必处理类内部的详细信息,而只需处理脚本末尾的调用。

访问参考:用 Python 开发 GUI:Tkinter 与 PyQt

import matplotlib
from PyQt5 import QtWidgets
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar

matplotlib.use('Qt5Agg')
matplotlib.use('TkAgg')


class ScrollableWindow(QtWidgets.QMainWindow):
    def __init__(self, fig):

        self.q_app = QtWidgets.QApplication([])

        QtWidgets.QMainWindow.__init__(self)

        #  To set this size of the Display Window
        self.setFixedSize(800, 500)

        self.widget = QtWidgets.QWidget()
        self.setCentralWidget(self.widget)
        self.widget.setLayout(QtWidgets.QVBoxLayout())
        self.widget.layout().setContentsMargins(0, 0, 0, 0)
        self.widget.layout().setSpacing(10)

        self.fig = fig
        self.canvas = FigureCanvas(self.fig)
        self.canvas.draw()
        self.scroll = QtWidgets.QScrollArea(self.widget)
        self.scroll.setWidget(self.canvas)

        self.nav = NavigationToolbar(self.canvas, self.widget)
        self.widget.layout().addWidget(self.nav)
        self.widget.layout().addWidget(self.scroll)

        self.show()
        exit(self.q_app.exec_())


fig, axes = plt.subplots(ncols=3, nrows=11, figsize=(7.5, 25))

for i in range(axes.shape[0]):
    for j in range(axes.shape[1]):
        axes[i, j].set_xlabel("x-label")
        axes[i, j].set_ylabel("y-label")


fig.tight_layout()
ScrollableWindow(fig)
Run Code Online (Sandbox Code Playgroud)

这是使用的结果PyQT5

PyQT5 的简单结果