Matplotlib图表缩小了Tkinter窗口

3
我已将一个matplotlib图表添加到我的tkinter窗口中,但每次我点击“确定”并将其添加到应用程序中时,它会重新调整整个窗口大小,并且还会切断轴刻度。我尝试过调整figsizecanvas,但无法解决这个问题。有人能解释一下这种行为的原因吗?
我简化了代码,使其可以通过单击“确定”来运行。
点击“确定”之前:

Before 点击“确定”之后:

After
from tkinter import *
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

class StockApp(Frame):
    def __init__(self, master):
        super(StockApp, self).__init__(master)
        self.place()
        self.widgets()

    def widgets(self):
        # width * height
        root.geometry('500x400')
        root.configure(bg='#FFFFFF')

        # Header
        header_label = Label(text='Stock Prices', font=(
            'Calibri', 22, 'bold'), bg='#FFFFFF')
        header_label.place(x=30, y=15)

        # Enter your API key
        api_key_label = Label(text='API key', font=(
            'Calibri', 10), bg='#FFFFFF')
        api_key_label.place(x=30, y=65)

        self.api_key_field = Entry(
            width=32, font=('Calibri', 10), bg='#F4F4F4')
        self.api_key_field.config(show="*")
        self.api_key_field.place(x=30, y=90)

        # Enter an index
        index_label = Label(text='Stock index', font=(
            'Calibri', 10), bg='#FFFFFF')
        index_label.place(x=280, y=65)

        self.index_field = Entry(width=15, font=('Calibri', 10), bg='#F4F4F4')
        self.index_field.place(x=280, y=90)

        # OK button
        ok_btn = Button(text='OK', command=self.ok, font=(
            'Calibri', 8), bg='#F4F4F4', width=5)
        ok_btn.place(x=400, y=88)

    def call_api(self):
        pass
       
    def format_df(self):

        self.df = pd.DataFrame({'date': ['2020-11-06', '2020-11-07', '2020-11-08', '2020-11-09'], 'adj_close': [200, 210, 205, 215]})
        self.df['date'] = pd.to_datetime(self.df['date'])
        self.df.set_index('date', inplace = True)

    def draw_chart(self):

        #plot data
        fig, ax = plt.subplots(figsize=(2,1), dpi=50)
        self.df.plot(ax=ax)

        # #set major ticks format
        ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))

        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)

        ax.get_legend().remove()

        canvas = FigureCanvasTkAgg(fig, master=root)
        canvas.draw() # TK-Drawingarea
        # Do I need to place both?
        canvas.get_tk_widget().place(x = 30, y = 150)
        canvas._tkcanvas.place(x = 30, y = 150)

    def ok(self):
        self.call_api()
        self.format_df()
        self.draw_chart()


if __name__ == "__main__":
    root= Tk()
    app= StockApp(root)
    root.title('Stock prices')
    mainloop()

figsize=(2,1) 太小了,请尝试更大的值。并且您使用 place() 来布置小部件,它不会缩小窗口。 - acw1668
如果我将figsize更改为更大的尺寸,例如(10,5),图表甚至无法适应窗口,并且仍然会被调整大小。 - Omega
如图片所示,窗口没有被绘图缩小。 - acw1668
是的,我已经测试了你的代码,无法复现你的问题。 - acw1668
好的,那还行。那么很奇怪,但我可以尝试在另一台机器上运行它。编辑:我刚在Jupyter Notebook中运行了它,它完美地工作了。非常奇怪。 - Omega
2个回答

4

这个问题一直困扰着我。直到我加入了"ctypes.windll.shcore.SetProcessDpiAwareness(1)",才得以解决您描述的完全相同的行为。

这是一个DPI问题,尽管在tkinter中我找不到任何解决方法。

根据Microsoft对SetProcessDpiAwareness(value)文档

value:要设置的DPI感知值。可能值来自PROCESS_DPI_AWARENESS枚举。

“value”为1(如上所示)指向:

PROCESS_SYSTEM_DPI_AWARE:系统DPI感知。此应用程序不会针对DPI更改进行缩放。它将查询DPI一次并在应用程序的生命周期中使用该值。如果DPI更改,则应用程序不会调整为新的DPI值。当DPI从系统值更改时,系统会自动缩放它们。

下面的示例代码基于您提供的简化版本,并似乎解决了此问题:

from tkinter import *
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import ctypes


class StockApp(Frame):
    def __init__(self, master):
        self.master = master
        super(StockApp, self).__init__(master)
        self.place()
        self.widgets()

    def widgets(self):
        # width * height
        root.geometry('500x400')

        # OK button
        ok_btn = Button(text='OK', command=self.ok, bg='#F4F4F4', width=5)
        ok_btn.pack(side=tk.TOP)

    def format_df(self):
        self.df = pd.DataFrame({'date': ['2020-11-06', '2020-11-07', '2020-11-08', '2020-11-09'], 'adj_close': [200, 210, 205, 215]})
        self.df['date'] = pd.to_datetime(self.df['date'])
        self.df.set_index('date', inplace=True)

    def draw_chart(self):
        fig, ax = plt.subplots(figsize=(2, 1), dpi=100)
        self.df.plot(ax=ax)

        canvas = FigureCanvasTkAgg(fig, master=root)
        canvas.draw()
        canvas.get_tk_widget().pack(side=tk.TOP)

    def ok(self):
        self.format_df()
        self.draw_chart()


if __name__ == "__main__":
    ctypes.windll.shcore.SetProcessDpiAwareness(1)
    root= Tk()

    app= StockApp(root)
    root.title('Stock prices')
    mainloop()

0

我曾经遇到过和你一样的问题。 我通过添加以下内容解决了这个问题:

import ctypes
 
ctypes.windll.shcore.SetProcessDpiAwareness(1)

但请记住,这也会影响您的tkinter窗口几何形状。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接