0

I am writing some mass spec data reduction software in Python v3.7.9, and using matplotlib v3.5.3 to display the data.

I recently discovered that I have been using the wrong module, matplotlib.pyplot, which isn't compatible with tkinter. I am now trying to switch to using matplotlib.figure, which is compatible (reference).

This has caused a couple of problems:

  • The layout is now far tighter, causing near overlapping axes and a ton of whitespace around the plots.
  • I cannot add a suptitle (AttributeError: module 'matplotlib.figure' has no attribute 'suptitle'), even though the attribute is clearly defined in the matplotlib docs.

Here are some before and after screenshots: the first is using matplotlib.pyplot with a tight layout, and the second is using matplotlib.figure with the default layout option.

matplotlib.pyplot matplotlib.figure

Manually setting the layout as either 'tight' or 'constrained' doesn't seem to have much effect at all, nor does leaving the layout style undefined.

Is there a way to restore the previous "expanded" layout style without manually defining a ton of parameters?

Here is an example script to work with:

import customtkinter as ctk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

import matplotlib.figure as Figure

# create the window using CTK
window = ctk.CTk()

# create the plot of random data
figure = Figure.Figure(figsize=(15,9))
Figure.layout = 'tight'

# create the subplots
ax1 = figure.add_subplot(2, 3, 1)
ax2 = figure.add_subplot(2, 3, 2)
ax3 = figure.add_subplot(2, 3, 3)
ax4 = figure.add_subplot(2, 3, 4)
ax5 = figure.add_subplot(2, 3, 5)
ax6 = figure.add_subplot(2, 3, 6)

# plot data in each subplot
data = [1, 2, 3, 4, 5]
ax1.plot(data)
ax2.plot(data)
ax3.plot(data)
ax4.plot(data)
ax5.plot(data)
ax6.plot(data)

# add titles to each subplot
ax1.set_title('Subplot 1')
ax2.set_title('Subplot 2')
ax3.set_title('Subplot 3')
ax4.set_title('Subplot 4')
ax5.set_title('Subplot 5')
ax6.set_title('Subplot 6')

# Add the plot to the window
canvas = FigureCanvasTkAgg(figure, master=window)
canvas.draw()
canvas.get_tk_widget().pack(side='top', fill='both', expand=True)

exit_button = ctk.CTkButton(window, text='Exit', command=window.destroy)
exit_button.pack(side='bottom')  # add the exit button to the window

window.mainloop()

Lastly, as I mentioned above, the matplotlib docs clearly show a .suptitle() attribute, however, adding Figure.suptitle('Data') results in AttributeError: module 'matplotlib.figure' has no attribute 'suptitle'. What am I doing wrong?

Thank you in advance!

1
  • As for the suptitle, I was being an idiot and trying to call it on Figure, the module, and not figure, the object, so that is solved. The layout is still too tight regardless of what I'm setting for the layout options, however. Commented May 29, 2024 at 18:23

1 Answer 1

3

Everything might be less confusing if you use more standard naming conventions.

  1. In python, classes are usually capitalised so instead of renaming the module with a capital letter, I suggest importing the class from the module
from matplotlib.figure import Figure
  1. In Matplotlib, a specific instance of the Figure class is often named fig.

You can set the layout when you instantiate your figure

fig = Figure(figsize=(15,9), layout='tight')

suptitle is a method on the figure instance

fig.suptitle('My Title')

Putting this together:

import customtkinter as ctk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

from matplotlib.figure import Figure

# create the window using CTK
window = ctk.CTk()

# create the plot of random data
fig = Figure(figsize=(15,9), layout='tight')
fig.suptitle('My Title')

# create the subplots
ax1 = fig.add_subplot(2, 3, 1)
ax2 = fig.add_subplot(2, 3, 2)
ax3 = fig.add_subplot(2, 3, 3)
ax4 = fig.add_subplot(2, 3, 4)
ax5 = fig.add_subplot(2, 3, 5)
ax6 = fig.add_subplot(2, 3, 6)

# plot data in each subplot
data = [1, 2, 3, 4, 5]
ax1.plot(data)
ax2.plot(data)
ax3.plot(data)
ax4.plot(data)
ax5.plot(data)
ax6.plot(data)

# add titles to each subplot
ax1.set_title('Subplot 1')
ax2.set_title('Subplot 2')
ax3.set_title('Subplot 3')
ax4.set_title('Subplot 4')
ax5.set_title('Subplot 5')
ax6.set_title('Subplot 6')

# Add the plot to the window
canvas = FigureCanvasTkAgg(fig, master=window)
canvas.draw()
canvas.get_tk_widget().pack(side='top', fill='both', expand=True)

exit_button = ctk.CTkButton(window, text='Exit', command=window.destroy)
exit_button.pack(side='bottom')  # add the exit button to the window

window.mainloop()

I get this: enter image description here

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the clarification. This solves the suptitle problem, however, I cannot figure out how to get the layout to expand. Setting tight, constrained, or leaving it as the default yields the same result: figures that are far too closely packed. I don't see any other layout styles in the matplotlib docs.
I have added a screenshot of what I get. Can you clarify if that is not what you are seeing or not what you want?
I see the difference. You are using fig = Figure(figsize=(15,9), layout='tight') whereas I was using fig = Figure(figsize=(15,9)) and fig.layout = 'tight'. For whatever reason, your method works but mine doesn't. But yes, that does give me the layout I am looking for, thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.