【问题标题】:matplotlib chart shrinks tkinter windowmatplotlib 图表缩小 tkinter 窗口
【发布时间】:2021-02-22 21:47:23
【问题描述】:

我已经在我的 tkinter 窗口中实现了一个 matplotlib 图表,但是每次我点击“确定”并将其添加到应用程序时,它都会调整整个窗口的大小并切断轴刻度。我玩过figsizecanvas,但没能解决。有人对此行为有解释吗?

我已简化代码,以便通过单击“确定”运行。

点击确定前:

点击确定后:


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() 来布置小部件,它不会缩小窗口。
  • 如果我将 figsize 更改为更大的值,例如 (10, 5),图表甚至不再适合窗口,它仍然会调整大小。
  • 如图所示,窗口没有被剧情缩小。
  • 是的,我已经测试了您的代码,但无法重现您的问题。
  • 还不错。那很奇怪,但我可能会尝试在另一台机器上运行它。编辑:我只是在 Jupyter Notebook 中运行它,它工作得很好。很奇怪。

标签: python matplotlib tkinter


【解决方案1】:

这个问题一直是我的眼中钉。在我包含“ctypes.windll.shcore.SetProcessDpiAwareness(1)”之前,我得到的行为与您描述的完全相同。 这是一个 DPI 问题,尽管我无法在 tkinter 中找到修复它的方法。

根据 Microsoft documentation 的 SetProcessDpiAwareness(value):

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

“值”为 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()

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2014-09-26
      • 1970-01-01
      • 2019-07-28
      • 2012-07-01
      • 2017-10-17
      • 1970-01-01
      • 2016-11-27
      • 2018-02-03
      • 2023-03-06
      相关资源
      最近更新 更多