Jér*_*uet 5 python user-interface tkinter matplotlib subplot
我想在 Tkinter 窗口中显示很多子图,并且能够向下滚动以查看所有大小合适的图。但是,它全部打包,并且子图似乎并没有占用我图中允许的所有空间,而仅限制在窗口的空间内。我怎样才能让它更间隔开并使子图更大?
我已经尝试使用该tight_layout()
选项进行不同的填充,更改了 Tkinter 的图形大小和其他参数,例如我的小部件中的fill
或expand
。
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 参数而变化,但都是空白的。
首先让我从显示 matplotlib 图形的大小开始,例如。实际上,固定的窗口大小困扰着您。 tkinter-Window
subplots
master.geometry("%dx%d+0+0" % (800, 500))
当您简单地使用 tkinter 窗口时,它会automatically
根据图形大小调整自身大小。相反,如果调整大小,图形也会调整大小。对于上述问题有一个简单的解决方法。
替换以下行:
Run Code Online (Sandbox Code Playgroud)master.geometry("%dx%d+0+0" % (800, 500))
和:
Run Code Online (Sandbox Code Playgroud)master.resizable(width=False, height=False)
防止 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
: