Open
Description
Bug summary
Plotting data, and then replotting over the same plot and toolbar results in the plot expanding in size, but only if the screen scaling (as set in the Windows display settings) is set to greater than 100%.
Code for reproduction is a MWE based on my actual program structure.
Code for reproduction
import PySimpleGUI as sg
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.pyplot as plt
import matplotlib as mpl
class PlotData:
def __init__(self, m_canvas_x, m_canvas_y):
self.canvas_x = m_canvas_x
self.canvas_y = m_canvas_y
def plot(self, x, y, fig):
dpi = plt.gcf().get_dpi()
print(f"{dpi=}")
if fig:
plt.close(fig)
fig, ax = plt.subplots(1, 1)
fig = plt.gcf()
fig.set_size_inches(self.canvas_x / float(dpi), self.canvas_y / float(dpi))
print(f"{fig.get_size_inches()=}")
fig.set_tight_layout(True)
plt.margins(x=0)
ax.plot(x, y, label="a legend entry")
ax.set_xlabel("X ordinate")
ax.set_ylabel("Y ordinate")
plt.title("Title", loc="left")
return fig
# if this next line is there, and you're using matplotlib 3.5.1,
# the plot grows when you press "plot" multiple times.
# matplotlib v3.4.3 works fine.
# What does this line do? If dpi_awarenes is not None, then the following is activated in PySimpleGUI
# if running_windows():
# if platform.release() == "7":
# ctypes.windll.user32.SetProcessDPIAware()
# elif platform.release() == "8" or platform.release() == "10":
# ctypes.windll.shcore.SetProcessDpiAwareness(1)
sg.set_options(dpi_awareness=True)
canvas_x = 600
canvas_y = 300
plot = PlotData(canvas_x, canvas_y)
figure = None
figure_agg = None
x_data = [1, 2, 3, 4, 5]
y_data = [[2, 6, 4, 7, 9], [7, 3, 7, 3, 5]]
# https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Matplotlib_Embedded_Toolbar.py
# https://github.com/PySimpleGUI/PySimpleGUI/issues/3989#issuecomment-794005240
def draw_figure_w_toolbar(canvas, figure, canvas_toolbar):
print(f"{canvas.winfo_width()=}, {canvas.winfo_height()=}")
if canvas.children:
for child in canvas.winfo_children():
child.destroy()
if canvas_toolbar.children:
for child in canvas_toolbar.winfo_children():
child.destroy()
figure_canvas_agg = FigureCanvasTkAgg(figure, master=canvas)
figure_canvas_agg.draw()
toolbar = Toolbar(figure_canvas_agg, canvas_toolbar)
toolbar.update()
figure_canvas_agg.get_tk_widget().pack(side='right', fill='both', expand=1)
return figure_canvas_agg
# https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Matplotlib_Embedded_Toolbar.py
class Toolbar(NavigationToolbar2Tk):
def __init__(self, *args, **kwargs):
super(Toolbar, self).__init__(*args, **kwargs)
layout = \
[
[sg.Button("Plot", key="plot_data"), sg.Button("Exit", key="exit")],
[sg.Column(layout=[[sg.Canvas(size=(canvas_x, canvas_y), key="single_plot", expand_x=True, expand_y=True)]], pad=(0, 0), expand_x=True, expand_y=True)],
[sg.Sizer(v_pixels=60), sg.Canvas(key="single_matplotlib_controls")]
]
def gui() -> None:
global figure, figure_agg
window = sg.Window("Data plotter", layout, finalize=True, resizable=True)
print(f"{mpl.__version__=}")
i = 0
while True:
event, values = window.read()
i += 1
print(f"{i=}")
if event in (None, "exit"):
break
elif event == "plot_data":
figure = plot.plot(x_data, y_data[i % 2], figure)
figure_agg = draw_figure_w_toolbar(window["single_plot"].TKCanvas, figure,
window["single_matplotlib_controls"].TKCanvas)
if __name__ == "__main__":
gui()
Actual outcome
Actual and expected outcomes are both shown here:
Expected outcome
Actual and expected outcomes are both shown here:
Additional information
If the program is made DPI aware (ctypes.windll.shcore.SetProcessDpiAwareness(1)
, done by sg.set_options(dpi_awareness=True)
) then the bad behaviour occurs.
If not, then the behaviour is not seen.
There is no issue seen at all if using 3.4.3
Operating system
Windows 10
Matplotlib Version
3.5.1
Matplotlib Backend
TKAgg
Python version
3.9.4
Jupyter version
No response
Installation
pip