matplotlib chart shrinks tkinter window

Solution 1:

This one has been a thorn in my side for a while. I was getting the exact same behavior that you described until I included "ctypes.windll.shcore.SetProcessDpiAwareness(1)". It's a DPI issue, though there was no way within tkinter that I could find to fix it.

Per the Microsoft documentation for SetProcessDpiAwareness(value):

value: The DPI awareness value to set. Possible values are from the PROCESS_DPI_AWARENESS enumeration.

A "value" of 1 (as above) points to:

PROCESS_SYSTEM_DPI_AWARE: System DPI aware. This app does not scale for DPI changes. It will query for the DPI once and use that value for the lifetime of the app. If the DPI changes, the app will not adjust to the new DPI value. It will be automatically scaled up or down by the system when the DPI changes from the system value.

The example code below is based on a simplified version of what you provided and appears to fix the issue:

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()