Skip to content

[Bug]: fig.savefig throws error after radiobutton axes is removed #30325

@rolfverberg

Description

@rolfverberg

Bug summary

If I create a figure with a radiobutton widget and then remove the radio widget axes in order to save the figure without the radiobutton box shown it throws an error in fig.savefig

Code for reproduction

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import RadioButtons

# data creation
x = np.arange(0.0, 3.0, 0.01)
y = np.sin(2*np.pi*x)

# plotting data
fig, ax = plt.subplots()
l, = ax.plot(x, y)
plt.subplots_adjust(left = 0.3)

# creating radio buttons
rax = plt.axes([0.05, 0.5, 0.15, 0.30])
radio = RadioButtons(
    rax, labels = ['red', 'blue', 'green'], active=2, activecolor='black')
l.set_color(radio.value_selected)

def color(label):
    l.set_color(label)
    fig.canvas.draw()

radio.on_clicked(color)

plt.show()

# remove radio buttons axes
radio.ax.remove()

fig.tight_layout()
fig.savefig('figure.png')

Actual outcome

Traceback (most recent call last):
File "/nfs/chess/user/rv43/miniforge3/envs/CHAP_tomo/lib/python3.10/site-packages/matplotlib/cbook.py", line 298, in process
func(*args, **kwargs)
File "/nfs/chess/user/rv43/miniforge3/envs/CHAP_tomo/lib/python3.10/site-packages/matplotlib/widgets.py", line 1665, in _clear
if self.ignore(event) or self.canvas.is_saving():
File "/nfs/chess/user/rv43/miniforge3/envs/CHAP_tomo/lib/python3.10/site-packages/matplotlib/widgets.py", line 120, in
canvas = property(lambda self: self.ax.figure.canvas)
AttributeError: 'NoneType' object has no attribute 'canvas'
Traceback (most recent call last):
File "/nfs/chess/user/rv43/miniforge3/envs/CHAP_tomo/lib/python3.10/site-packages/matplotlib/cbook.py", line 298, in process
func(*args, **kwargs)
File "/nfs/chess/user/rv43/miniforge3/envs/CHAP_tomo/lib/python3.10/site-packages/matplotlib/widgets.py", line 1665, in _clear
if self.ignore(event) or self.canvas.is_saving():
File "/nfs/chess/user/rv43/miniforge3/envs/CHAP_tomo/lib/python3.10/site-packages/matplotlib/widgets.py", line 120, in
canvas = property(lambda self: self.ax.figure.canvas)
AttributeError: 'NoneType' object has no attribute 'canvas'

Expected outcome

This example does produce the correct figure (one with a tight layout and no radiobuttons box), since the error that is thrown is caught by matplotlib and only printed as a warning.

Additional information

In matplotlib/widgets.py:
Replacing:
def _clear(self, event):
"""Internal event handler to clear the buttons."""
if self.ignore(event) or self.canvas.is_saving():
return
self._background = self.canvas.copy_from_bbox(self.ax.bbox)
self.ax.draw_artist(self._buttons)
With:
def _clear(self, event):
"""Internal event handler to clear the buttons."""
if self.ax._stale or self.ignore(event) or self.canvas.is_saving():
return
self._background = self.canvas.copy_from_bbox(self.ax.bbox)
self.ax.draw_artist(self._buttons)
Suppresses the issue, but I'm not sure if that is the desired fix or if self.ax._stale has another purpose. I have not tested CheckButtons widgets, but I'm wondering if the same happens there.

It may be wrapped up in self.ignore(event) by setting self.active = False when the radiobuttons get removed, but I don't know if that has other side effects.

Operating system

Scientific Linux 7, AlmaLinux-9

Matplotlib Version

3.9.2, 3.10.3

Matplotlib Backend

qtagg

Python version

3.10.18

Jupyter version

N/A

Installation

conda

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions