I am writing mass spec data reduction software and am offering the user a button to toggle a subplot between two different data sets.
Before, when I was using matplotlib.pyplot
, I didn’t have any problems, but now using matplotlib.figure
(for compatibility with tkinter), two new problems have cropped up:
UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.
This is directly related to the button, since without it the error goes away.- Rapidly toggling the button, followed by moving the mouse away from the button, then back over the button, causes the program to hang.
Here is a basic example:
import random
import mplcursors
import customtkinter as ctk
from matplotlib.figure import Figure
from matplotlib.widgets import Button
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
# create the window and frames
window = ctk.CTk()
data_frame = ctk.CTkFrame(window)
button_frame = ctk.CTkFrame(window)
data_frame.pack(side=ctk.TOP)
button_frame.pack(side=ctk.BOTTOM)
# lines to plot
lines = {}
# Create the figure and subplots
fig = Figure(figsize=(13, 9), tight_layout=True)
canvas = FigureCanvasTkAgg(fig, master=data_frame)
canvas.draw()
canvas.get_tk_widget().pack(side=ctk.TOP, fill=ctk.BOTH, expand=True)
axes = fig.subplots(2, 2)
# Create some sample data
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y = {}
y_new = {}
for i in range(1, 101):
y[i] = [random.randint(1, 10) for _ in range(len(x))]
y_new[i] = [random.randint(1, 10) for _ in range(len(x))]
# create a boolean var for toggling between y and y_new in 1,1
show_y_new = ctk.BooleanVar(False)
# Plot the normal data on each subplot
for i in range(2):
for j in range(2):
for k in range(1, 101):
line, = axes[i, j].plot(x, y[k], label=f'Line {k}')
lines[line] = line
# Create a cursor for hover indicators
cursor = mplcursors.cursor(lines, hover=True)
cursor.connect("add")
def on_hover(sel):
x, y = sel.target
sel.annotation.set_text(f"({x:.2f}, {y:.2f})")
# create a button to toggle the 1,1 subplot between y and y_new
def on_click(cursor):
show_y_new.set(not show_y_new.get())
if show_y_new.get():
for line in lines:
if line.axes == axes[1, 1]:
line.set_ydata(y_new[int(line.get_label().split(' ')[1])])
else:
for line in lines:
if line.axes == axes[1, 1]:
line.set_ydata(y[int(line.get_label().split(' ')[1])])
valid_lines = [line for line in lines.values() if line.figure is not None]
canvas.draw()
cursor.remove()
cursor = mplcursors.cursor(valid_lines, hover=True)
cursor.connect("add", on_hover)
# Create the toggle button
global button # do not remove-prevents garbage collection
button_axes = fig.add_axes([0.8885, 0.467, 0.1, 0.04])
button = Button(button_axes, label='Toggle 1,1 data')
button.on_clicked(lambda event: on_click(cursor))
# create the exit button
exit_button = ctk.CTkButton(window, text='Exit', command=window.destroy)
exit_button.pack(side='bottom') # add the exit button to the window
# Show the plot
canvas.draw()
window.mainloop()
How can I get rid of, or at least suppress, the warning message? And why does moving the mouse away from, then back over, the button cause the program to become unstable?