Python 为什么子地块没有占用嵌入Tkinter的Matplotlib中figure允许的所有空间?

Python 为什么子地块没有占用嵌入Tkinter的Matplotlib中figure允许的所有空间?,python,user-interface,matplotlib,tkinter,subplot,Python,User Interface,Matplotlib,Tkinter,Subplot,我想在Tkinter窗口中显示许多子绘图,并能够向下滚动以查看所有大小良好的绘图。然而,它是所有包装和似乎子地块不采取所有的空间允许在我的数字,只限于窗口的空间。我怎样才能使它的间隔更大,子地块更大 我用tight_layout()选项尝试了不同的填充,更改了图形大小和Tkinter的其他参数,如我的小部件中的fill或expand 将tkinter作为tk导入 从tkinter导入滚动条 从matplotlib.backends.backend_tkagg导入图CAVASTKAGG 将matp

我想在Tkinter窗口中显示许多子绘图,并能够向下滚动以查看所有大小良好的绘图。然而,它是所有包装和似乎子地块不采取所有的空间允许在我的数字,只限于窗口的空间。我怎样才能使它的间隔更大,子地块更大

我用
tight_layout()
选项尝试了不同的填充,更改了图形大小和Tkinter的其他参数,如我的小部件中的
fill
expand

将tkinter作为tk导入
从tkinter导入滚动条
从matplotlib.backends.backend_tkagg导入图CAVASTKAGG
将matplotlib.pyplot作为plt导入
类可滚动窗口:
定义初始化(自、主、图、**选项):
主几何体(“%dx%d+0+0”%(800500))
主焦点集()
fig_wrapper=tk.Frame(主控,宽度=800,高度=fig.get_figheight())
fig_wrapper.pack(fill=tk.BOTH,expand=True)
fig_canvas=FigureCanvasTkAgg(fig,master=fig_包装器)
scrollbar=scrollbar(fig\u包装,orient=tk.VERTICAL,command=fig\u canvas.get\u tk\u widget().yview)
滚动条.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(“全部”),宽度=800,高度=1000)
n列,n行=3,11
图,轴=plt.子批次(图大小=(n列,n行*2),ncols=n列,nrows=n行)
对于范围内的i(轴形状[0]):
对于范围内的j(轴形状[1]):
轴[i,j]。集xlabel(“xlabel”)
轴[i,j]。设置_ylabel(“ylabel”)
图1紧_布局图()
showStatsWindow=tk.tk()
showStatsWindow=可滚动窗口(showStatsWindow,图)
showStatsWindow.mainloop()
下面是一个例子,其中有一个空图,显示了它的外观。我想每行有3或4个子批次,但都挤在一起了。正如您所看到的,我的窗口中有更多的空间,它随着figsize参数的变化而变化,但它都是空白的


首先让我从显示matplotlib图的
tkinter窗口的大小开始,例如
子图
。实际上,它是一个固定的窗口大小
master.geometry(“%dx%d+0+0”%(800500))
,这让你很困扰

当您只需使用tkinter窗口时,它将自动调整自身大小,使其符合图形大小。反过来,如果调整大小,图形也会调整大小。对于上述问题,有一个简单的解决方法

  • 替换以下行:

    master.geometry("%dx%d+0+0" % (800, 500))
    
  • 与:

    master.resizable(width=False, height=False)
    
防止调整tkinter窗口的大小。 现在,要使子批的大小变大或变小,可以通过相应地更改
figsize=()
参数来更改它

fig, axes = plt.subplots(ncols=n_col, nrows=n_row, figsize=(7.5, 25))
我必须建议您使用
PyQT5
,这在您给定的场景中更可行。下面给出了一个工作的示例,其中不调用
tkinter
自定义操作,例如
pack()
config()

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

访问参考:

以下是使用
PyQT5
得到的结果:


问题在于,如果您想了解如何正确设置滚动条,则滚动条的设置方式不正确。请退出此项并

您绘制图形的框架没有展开

下面是我如何修复它的

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):
        def on_configure(event):
            # update scrollregion after starting 'mainloop'
            # when all widgets are in canvas
            canvas.configure(scrollregion=canvas.bbox('all'))

            # expand canvas_frame when canvas changes its size
            canvas_width = event.width
            canvas.itemconfig(canvas_frame, width=canvas_width)


        # --- create canvas with scrollbar ---
        canvas = tk.Canvas(master, )
        canvas.pack(side=tk.LEFT, fill='both', expand=True)

        scrollbar = tk.Scrollbar(master, command=canvas.yview)
        scrollbar.pack(side=tk.RIGHT, fill='both')

        canvas.configure(yscrollcommand=scrollbar.set)

        # update scrollregion after starting 'mainloop'
        # when all widgets are in canvas
        canvas.bind('<Configure>', on_configure)

        # --- put frame in canvas ---

        fig_wrapper = tk.Frame(canvas)

        canvas_frame= canvas.create_window((0, 0), window=fig_wrapper,)

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

        fig_canvas = FigureCanvasTkAgg(fig, master=fig_wrapper)
        fig_canvas.get_tk_widget().pack(fill=tk.BOTH, side=tk.LEFT, expand=True)


n_col, n_row = 3, 11

fig, axes = plt.subplots(figsize=(n_col*2,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()
将tkinter作为tk导入
从tkinter导入滚动条
从matplotlib.backends.backend_tkagg导入图CAVASTKAGG
将matplotlib.pyplot作为plt导入
类可滚动窗口:
定义初始化(自、主、图、**选项):
def on_配置(事件):
#启动“mainloop”后更新scrollregion
#当所有小部件都在画布中时
configure(scrollregion=canvas.bbox('all'))
#当画布更改其大小时展开画布框架
画布宽度=event.width
itemconfig(canvas\u frame,width=canvas\u width)
#---使用滚动条创建画布---
canvas=tk.canvas(master,)
canvas.pack(side=tk.LEFT,fill='both',expand=True)
scrollbar=tk.scrollbar(主控,命令=canvas.yview)
scrollbar.pack(side=tk.RIGHT,fill='both')
configure(yscrollcommand=scrollbar.set)
#启动“mainloop”后更新scrollregion
#当所有小部件都在画布中时
canvas.bind(“”,在配置上)
#---把框架放在画布上---
fig_wrapper=tk.框架(画布)
canvas\u frame=canvas.create\u window((0,0),window=fig\u wrapper,)
主几何体(“%dx%d+0+0”%(800500))
主焦点集()
fig_canvas=FigureCanvasTkAgg(fig,master=fig_包装器)
fig_canvas.get_tk_widget().pack(fill=tk.BOTH,side=tk.LEFT,expand=True)
n列,n行=3,11
图,轴=plt.子批次(图大小=(n列*2,n行*2),ncols=n列,nrows=n行,)
对于范围内的i(轴形状[0]):
对于范围内的j(轴形状[1]):
轴[i,j]。集xlabel(“xlabel”)
轴[i,j]。设置_ylabel(“ylabel”)
图1紧_布局图()
showStatsWindow=tk.tk()
showStatsWindow=可滚动窗口(showStatsWindow,图)
showStatsWindow.mainloop()
这是我得到的结果


如果需要通过tkinter grid调用此函数,可以进行更多可选自定义

import tkinter as tk
from tkinter import *
from tkinter import Scrollbar
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


class ScrollableTkAggY(FigureCanvasTkAgg):
    def __init__(self, figure, master, *args, **kwargs):
        # --- create canvas with scrollbar ---
        self.canvas = tk.Canvas(master)
        self.canvas.grid(row=0, column=0, sticky=tk.NSEW)
        self.canvas.rowconfigure(0, weight=1)
        self.canvas.columnconfigure(0, weight=1)

        self.fig_wrapper = tk.Frame(self.canvas)
        self.fig_wrapper.grid(row=0, column=0, sticky=tk.NSEW)
        self.fig_wrapper.rowconfigure(0, weight=1)
        self.fig_wrapper.columnconfigure(0, weight=1)

        super(ScrollableTkAggY, self).__init__(figure, master=self.fig_wrapper, *args, **kwargs)
        self.tkagg = self.get_tk_widget()
        self.tkagg.grid(row=0, column=0, sticky=tk.NSEW)

        self.vbar = Scrollbar(self.canvas, orient=tk.VERTICAL, command=self.canvas.yview)
        self.vbar.grid(row=0, column=1, sticky=tk.NS)

        self.canvas.configure(yscrollcommand=self.vbar.set, scrollregion=self.canvas.bbox(tk.ALL))

        # when all widgets are in canvas
        self.canvas.bind('<Configure>', self.on_configure)
        # --- put frame in canvas ---
        self.canvas_frame = self.canvas.create_window((0, 0), window=self.fig_wrapper, anchor=tk.NW)

        ScrollableTkAggY_meths = vars(ScrollableTkAggY).keys()
        methods = vars(Pack).keys() | vars(Grid).keys() | vars(Place).keys()
        methods = methods.difference(ScrollableTkAggY_meths)

        for m in methods:
            if m[0] != '_' and m != 'config' and m != 'configure':
                setattr(self, m, getattr(self.canvas, m))

    def __str__(self):
        return str(self.canvas)

    # expand canvas_frame when canvas changes its size
    def on_configure(self, event):
        # update scrollregion after starting 'mainloop'

        self.canvas.configure(scrollregion=self.canvas.bbox(tk.ALL))
        # when all widgets are in canvas
        canvas_width = event.width
        self.canvas.itemconfig(self.canvas_frame, width=canvas_width - 20)


class ScrollableTkAggX(FigureCanvasTkAgg):
    def __init__(self, figure, master, *args, **kwargs):
        # --- create canvas with scrollbar ---
        self.canvas = tk.Canvas(master)
        self.canvas.grid(row=0, column=0, sticky=tk.NSEW)
        self.canvas.rowconfigure(0, weight=1)
        self.canvas.columnconfigure(0, weight=1)

        self.fig_wrapper = tk.Frame(self.canvas)
        self.fig_wrapper.grid(row=0, column=0, sticky=tk.NSEW)
        self.fig_wrapper.rowconfigure(0, weight=1)
        self.fig_wrapper.columnconfigure(0, weight=1)

        super(ScrollableTkAggX, self).__init__(figure, master=self.fig_wrapper, *args, **kwargs)
        self.tkagg = self.get_tk_widget()
        self.tkagg.grid(row=0, column=0, sticky=tk.NSEW)

        self.hbar = Scrollbar(self.canvas, orient=tk.HORIZONTAL, command=self.canvas.xview)
        self.hbar.grid(row=1, column=0, sticky=tk.EW)

        self.canvas.configure(xscrollcommand=self.hbar.set, scrollregion=self.canvas.bbox(tk.ALL))

        # when all widgets are in canvas
        self.canvas.bind('<Configure>', self.on_configure)
        # --- put frame in canvas ---
        self.canvas_frame = self.canvas.create_window((0, 0), window=self.fig_wrapper, anchor=tk.NW)

        ScrollableTkAggX_meths = vars(ScrollableTkAggX).keys()
        methods = vars(Pack).keys() | vars(Grid).keys() | vars(Place).keys()
        methods = methods.difference(ScrollableTkAggX_meths)

        for m in methods:
            if m[0] != '_' and m != 'config' and m != 'configure':
                setattr(self, m, getattr(self.canvas, m))

    def __str__(self):
        return str(self.canvas)

        # expand canvas_frame when canvas changes its size

    def on_configure(self, event):
        # update scrollregion after starting 'mainloop'

        self.canvas.configure(scrollregion=self.canvas.bbox(tk.ALL))
        # when all widgets are in canvas
        canvas_height = event.height
        self.canvas.itemconfig(self.canvas_frame, height=canvas_height - 20)


class mclass:
    def __init__(self, window):
        self.figY = Figure(figsize=(10, 30))
        self.axesY = self.figY.subplots(ncols=3, nrows=10)

        self.figX = Figure(figsize=(30, 10))
        self.axesX = self.figX.subplots(ncols=10, nrows=3)

        self.canvasY = ScrollableTkAggY(figure=self.figY, master=window)
        self.canvasY.grid(row=0, column=0, sticky='nsew')
        self.canvasY.rowconfigure(0, weight=1)
        self.canvasY.columnconfigure(0, weight=1)

        self.canvasX = ScrollableTkAggX(figure=self.figX, master=window)
        self.canvasX.grid(row=1, column=0, sticky='nsew')
        self.canvasX.rowconfigure(0, weight=1)
        self.canvasX.columnconfigure(0, weight=1)

        window.geometry("%dx%d+0+0" % (800, 600))
        window.focus_set()

        self.do_plot()

    def do_plot(self):
        # Color used in mpl online documentation.
        mpl_grey_rvb = (51. / 255., 51. / 255., 51. / 255.)
        self.figY.suptitle("Matplotlib's math rendering engine ScrollableTkAggY",
                           color=mpl_grey_rvb, fontsize=14, weight='bold')

        self.figX.suptitle("Matplotlib's math rendering engine ScrollableTkAggX",
                           color=mpl_grey_rvb, fontsize=14, weight='bold')

        # Plotting features demonstration formulae

        for i in range(self.axesY.shape[0]):
            for j in range(self.axesY.shape[1]):
                self.axesY[i, j].set_xlabel("xlabel")
                self.axesY[i, j].set_ylabel("ylabel")
        self.figY.tight_layout()
        self.canvasY.draw()

        for i in range(self.axesX.shape[0]):
            for j in range(self.axesX.shape[1]):
                self.axesX[i, j].set_xlabel("xlabel")
                self.axesX[i, j].set_ylabel("ylabel")
        self.figX.tight_layout()
        self.canvasX.draw()


if __name__ == '__main__':
    window = Tk()
    start = mclass(window)
    window.rowconfigure(0, weight=1)
    window.rowconfigure(1, weight=1)
    window.columnconfigure(0, weight=1)
    # window.columnconfigure(1, weight=1)
    window.mainloop()
将tkinter作为tk导入
从tkinter进口*
从tkinter导入滚动条
从matplotlib.figure导入图形
从matplotlib.backends.backend_tkagg导入图CAVASTKAGG
类ScrollableTkAggY(图CAVASTKAGG):
定义初始值(自身、图形、主参数、*args、**kwargs):
import tkinter as tk
from tkinter import *
from tkinter import Scrollbar
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


class ScrollableTkAggY(FigureCanvasTkAgg):
    def __init__(self, figure, master, *args, **kwargs):
        # --- create canvas with scrollbar ---
        self.canvas = tk.Canvas(master)
        self.canvas.grid(row=0, column=0, sticky=tk.NSEW)
        self.canvas.rowconfigure(0, weight=1)
        self.canvas.columnconfigure(0, weight=1)

        self.fig_wrapper = tk.Frame(self.canvas)
        self.fig_wrapper.grid(row=0, column=0, sticky=tk.NSEW)
        self.fig_wrapper.rowconfigure(0, weight=1)
        self.fig_wrapper.columnconfigure(0, weight=1)

        super(ScrollableTkAggY, self).__init__(figure, master=self.fig_wrapper, *args, **kwargs)
        self.tkagg = self.get_tk_widget()
        self.tkagg.grid(row=0, column=0, sticky=tk.NSEW)

        self.vbar = Scrollbar(self.canvas, orient=tk.VERTICAL, command=self.canvas.yview)
        self.vbar.grid(row=0, column=1, sticky=tk.NS)

        self.canvas.configure(yscrollcommand=self.vbar.set, scrollregion=self.canvas.bbox(tk.ALL))

        # when all widgets are in canvas
        self.canvas.bind('<Configure>', self.on_configure)
        # --- put frame in canvas ---
        self.canvas_frame = self.canvas.create_window((0, 0), window=self.fig_wrapper, anchor=tk.NW)

        ScrollableTkAggY_meths = vars(ScrollableTkAggY).keys()
        methods = vars(Pack).keys() | vars(Grid).keys() | vars(Place).keys()
        methods = methods.difference(ScrollableTkAggY_meths)

        for m in methods:
            if m[0] != '_' and m != 'config' and m != 'configure':
                setattr(self, m, getattr(self.canvas, m))

    def __str__(self):
        return str(self.canvas)

    # expand canvas_frame when canvas changes its size
    def on_configure(self, event):
        # update scrollregion after starting 'mainloop'

        self.canvas.configure(scrollregion=self.canvas.bbox(tk.ALL))
        # when all widgets are in canvas
        canvas_width = event.width
        self.canvas.itemconfig(self.canvas_frame, width=canvas_width - 20)


class ScrollableTkAggX(FigureCanvasTkAgg):
    def __init__(self, figure, master, *args, **kwargs):
        # --- create canvas with scrollbar ---
        self.canvas = tk.Canvas(master)
        self.canvas.grid(row=0, column=0, sticky=tk.NSEW)
        self.canvas.rowconfigure(0, weight=1)
        self.canvas.columnconfigure(0, weight=1)

        self.fig_wrapper = tk.Frame(self.canvas)
        self.fig_wrapper.grid(row=0, column=0, sticky=tk.NSEW)
        self.fig_wrapper.rowconfigure(0, weight=1)
        self.fig_wrapper.columnconfigure(0, weight=1)

        super(ScrollableTkAggX, self).__init__(figure, master=self.fig_wrapper, *args, **kwargs)
        self.tkagg = self.get_tk_widget()
        self.tkagg.grid(row=0, column=0, sticky=tk.NSEW)

        self.hbar = Scrollbar(self.canvas, orient=tk.HORIZONTAL, command=self.canvas.xview)
        self.hbar.grid(row=1, column=0, sticky=tk.EW)

        self.canvas.configure(xscrollcommand=self.hbar.set, scrollregion=self.canvas.bbox(tk.ALL))

        # when all widgets are in canvas
        self.canvas.bind('<Configure>', self.on_configure)
        # --- put frame in canvas ---
        self.canvas_frame = self.canvas.create_window((0, 0), window=self.fig_wrapper, anchor=tk.NW)

        ScrollableTkAggX_meths = vars(ScrollableTkAggX).keys()
        methods = vars(Pack).keys() | vars(Grid).keys() | vars(Place).keys()
        methods = methods.difference(ScrollableTkAggX_meths)

        for m in methods:
            if m[0] != '_' and m != 'config' and m != 'configure':
                setattr(self, m, getattr(self.canvas, m))

    def __str__(self):
        return str(self.canvas)

        # expand canvas_frame when canvas changes its size

    def on_configure(self, event):
        # update scrollregion after starting 'mainloop'

        self.canvas.configure(scrollregion=self.canvas.bbox(tk.ALL))
        # when all widgets are in canvas
        canvas_height = event.height
        self.canvas.itemconfig(self.canvas_frame, height=canvas_height - 20)


class mclass:
    def __init__(self, window):
        self.figY = Figure(figsize=(10, 30))
        self.axesY = self.figY.subplots(ncols=3, nrows=10)

        self.figX = Figure(figsize=(30, 10))
        self.axesX = self.figX.subplots(ncols=10, nrows=3)

        self.canvasY = ScrollableTkAggY(figure=self.figY, master=window)
        self.canvasY.grid(row=0, column=0, sticky='nsew')
        self.canvasY.rowconfigure(0, weight=1)
        self.canvasY.columnconfigure(0, weight=1)

        self.canvasX = ScrollableTkAggX(figure=self.figX, master=window)
        self.canvasX.grid(row=1, column=0, sticky='nsew')
        self.canvasX.rowconfigure(0, weight=1)
        self.canvasX.columnconfigure(0, weight=1)

        window.geometry("%dx%d+0+0" % (800, 600))
        window.focus_set()

        self.do_plot()

    def do_plot(self):
        # Color used in mpl online documentation.
        mpl_grey_rvb = (51. / 255., 51. / 255., 51. / 255.)
        self.figY.suptitle("Matplotlib's math rendering engine ScrollableTkAggY",
                           color=mpl_grey_rvb, fontsize=14, weight='bold')

        self.figX.suptitle("Matplotlib's math rendering engine ScrollableTkAggX",
                           color=mpl_grey_rvb, fontsize=14, weight='bold')

        # Plotting features demonstration formulae

        for i in range(self.axesY.shape[0]):
            for j in range(self.axesY.shape[1]):
                self.axesY[i, j].set_xlabel("xlabel")
                self.axesY[i, j].set_ylabel("ylabel")
        self.figY.tight_layout()
        self.canvasY.draw()

        for i in range(self.axesX.shape[0]):
            for j in range(self.axesX.shape[1]):
                self.axesX[i, j].set_xlabel("xlabel")
                self.axesX[i, j].set_ylabel("ylabel")
        self.figX.tight_layout()
        self.canvasX.draw()


if __name__ == '__main__':
    window = Tk()
    start = mclass(window)
    window.rowconfigure(0, weight=1)
    window.rowconfigure(1, weight=1)
    window.columnconfigure(0, weight=1)
    # window.columnconfigure(1, weight=1)
    window.mainloop()