You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
artist.axes and .figure should never be reassignable #6793
#3835 ensured that the .axes attribute of an artist cannot be assigned to a new Axes when it is already set to an earlier Axes. However, it does not prevent one from doing so by going via None. Also, nothing is done regarding reassignment of .figure.
In practice there's plenty of code that assumes these invariants (see #6785 for how I ended up here), so I'd suggest tightening the restrictions to
.axes can only ever be set to a non-None value once. Upon removal of the artist from an axes, the private attribute ._discarded is set to prevent further reuse. (If there is truly need for it, we could add a .copy() method that would return, well, a copy of the artist, but with ._discarded unset, so that it can be reassigned to a new Axes.)
.figure follows the same rules, and is additionally automatically set/unset whenever .axes is set/unset.
I have a vague memory of there being a good reason to allow this behavior (it may have been scaffolding for allowing (careful) moving of aritsts between axes in the future).
There is some controls on figure via set_figure.
Artists can be created without being assigned to an axes or figure (and axes can exist without a figure) so those attributes being valid objects is not a strict invariant.
Just removing the clearing of axes/figure in the default remove should be enough? I do not fully follow the use case for _discarded.
I guess you could get away with not clearing .axes/.figure and not using ._discarded in remove() but then you'd need a separate way to check whether an artist is actually part of an axes/figure or not. Something like replacing all calls to artist.axes is not None to artist in artist.axes.<the proper container> (cf. #3944 too). (So in practice I think having an extra bit of state would just avoid a bunch of subtle errors.)
I know that artists can be created without being linked to an axes or figure; I simply suggest that once they are attached to one, they cannot be reassigned to another (you suggest that there may be a use case for such a reassignment?). WRT axes existing independently of figure, this could probably be solved with some pattern like (untested)
@property
def axes(self):
return self._axes
@axes.setter
def axes(self, value):
if self._axes is None:
if value is None: # no change
pass
elif self._discarded: # cannot reuse
raise ValueError
else: # initializing
self._axes = value
else: # has already been set
if value is None: # discarding
self._discarded = True
self._value = None
elif value is self._axes: # resetting to same value
pass
else: # resetting to other value
raise ValueError
@property
def figure(self):
if self._figure is not None:
return self._figure
elif self._axes is not None:
return self._axes.figure
else:
return None
# figure.setter similar to axes.setter, but also checks whether self.axes has been set
I am nominally 👍 on this, but doesn't that implementation still have the problem that the axes/figure can still become None at some point in the lifecycle?
Indeed, the setters for figure and axes should also set the "other" attribute to None when discarding the artist, and that should be enough, right? Or am I missing something?
Since this Problem is still not closed for me in anaconda2 / python 2.7 / matplotlib 2.2.3
I tried another workaround:
My Problem: I'm creating a lot of plots in a loop. In every element of this loop I call a self defined
function SavePlot which gets handed over the name of the png to be produced, a handle of the figure element. By using matplotlib.use('agg') and matplotlib.pyplot as plt I do use multiprocessing.Pool.map to call the handler.savefig function which gets the filename as argument of the p.map routine.
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!
Activity
jenshnielsen commentedon Jul 18, 2016
It sounds sensible to me but I might me missing some subtle issues
tacaswell commentedon Jul 20, 2016
I have a vague memory of there being a good reason to allow this behavior (it may have been scaffolding for allowing (careful) moving of aritsts between axes in the future).
There is some controls on
figureviaset_figure.Artists can be created without being assigned to an axes or figure (and axes can exist without a figure) so those attributes being valid objects is not a strict invariant.
Just removing the clearing of axes/figure in the default
removeshould be enough? I do not fully follow the use case for_discarded.anntzer commentedon Jul 20, 2016
I guess you could get away with not clearing
.axes/.figureand not using._discardedinremove()but then you'd need a separate way to check whether an artist is actually part of an axes/figure or not. Something like replacing all calls toartist.axes is not Nonetoartist in artist.axes.<the proper container>(cf. #3944 too). (So in practice I think having an extra bit of state would just avoid a bunch of subtle errors.)I know that artists can be created without being linked to an axes or figure; I simply suggest that once they are attached to one, they cannot be reassigned to another (you suggest that there may be a use case for such a reassignment?). WRT axes existing independently of figure, this could probably be solved with some pattern like (untested)
tacaswell commentedon Jul 20, 2016
I am nominally 👍 on this, but doesn't that implementation still have the problem that the axes/figure can still become
Noneat some point in the lifecycle?anntzer commentedon Jul 20, 2016
Indeed, the setters for figure and axes should also set the "other" attribute to None when discarding the artist, and that should be enough, right? Or am I missing something?
sparky-corona commentedon Feb 28, 2019
Since this Problem is still not closed for me in anaconda2 / python 2.7 / matplotlib 2.2.3
I tried another workaround:
My Problem: I'm creating a lot of plots in a loop. In every element of this loop I call a self defined
function SavePlot which gets handed over the name of the png to be produced, a handle of the figure element. By using
matplotlib.use('agg')andmatplotlib.pyplot as pltI do usemultiprocessing.Pool.mapto call thehandler.savefigfunction which gets thefilenameas argument of thep.maproutine.There nearly NO memory leak anymore since the
savefigìs now handed over to a PID which is closed byp.close()andp.join().Any ideas why there are problems with this
savefig?greets
[ @tacaswell edited to fix markup ]
MNT: Track if we ever set the Axes or Figure when cleared
MNT: Track if we ever set the Axes or Figure when cleared
MNT: Track if we ever set the Axes or Figure when cleared
github-actions commentedon Jan 29, 2024
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!
anntzer commentedon Jan 30, 2024
Let's not bother for now and assume that if someone "goes through None" to reassign axes/figure, they know what they're doing.
MNT: Track if we ever set the Axes or Figure when cleared
MNT: Track if we ever set the Axes or Figure when cleared