yuzie007 / mpltern

Ternary plots as projections of Matplotlib
https://yuzie007.github.io/mpltern
MIT License
39 stars 2 forks source link

Issue related to Ternary Axes in Figure Export #10

Closed morganjwilliams closed 1 year ago

morganjwilliams commented 1 year ago

With the most recent version of mpltern and matplotlib, there looks to be an issue related to axes handling, and specifically the mpltern._axes.TernaryAxesBase.get_children() method - mostly occurring when saving figures.

Minimal Example

Using mpltern v0.3.5 and matplotlib v3.6.2, an error is raised when the children are accessed when determining e.g. 'tight' bbox limits on export (this is something which is used by default in the pyrolite helper function pyrolite.util.plot.export.save_figure):

import mpltern
import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, subplot_kw=dict(projection="ternary"))
fig.savefig("example.png", bbox_inches="tight")

In this case, xaxis and yaxis are not included in the children attribute (they're explicitly removed), giving an error:

ValueError: list.remove(x): x not in list
*Some filesystem detail removed for brevity:* ```python Traceback (most recent call last): File "", line 1, in File "\site-packages\matplotlib\figure.py", line 3274, in savefig self.canvas.print_figure(fname, **kwargs) File "\site-packages\matplotlib\backends\backend_qtagg.py", line 81, in print_figure super().print_figure(*args, **kwargs) File "\site-packages\matplotlib\backend_bases.py", line 2318, in print_figure bbox_inches = self.figure.get_tightbbox( File "\site-packages\matplotlib\figure.py", line 1729, in get_tightbbox artists = self.get_default_bbox_extra_artists() File "\site-packages\matplotlib\figure.py", line 1694, in get_default_bbox_extra_artists bbox_artists.extend(ax.get_default_bbox_extra_artists()) File "\site-packages\matplotlib\axes\_base.py", line 4354, in get_default_bbox_extra_artists artists.remove(axis) ValueError: list.remove(x): x not in list ```

I'm not sure if it's backend specific, but I've seen it on Windows and Ubuntu.

Possible Patch

In cases where I've been using more recent matplotlib versions, I've used the following patch which negated the issue (the visibility could be toggled elsewhere, but you might have an idea for a more holistic fix?):

"""
A patch for a bug which can pop up under mpltern v0.3.5 and matplotlib > v3.6
"""
import matplotlib.axes 
import mpltern.ternary

def get_children(self):
    children = super(matplotlib.axes._axes.Axes, self).get_children()
    self.xaxis.set_visible(False)
    self.yaxis.set_visible(False)
    return children

mpltern.ternary._axes.TernaryAxesBase.get_children = get_children

Other References

This is also mentioned in a pyrolite issue at https://github.com/morganjwilliams/pyrolite/issues/78

Happy to help out on this one if it is indeed a bug, otherwise I can add some handling around figure export within pyrolite to avoid the scenario if needed.

yuzie007 commented 1 year ago

Thank you very much @morganjwilliams for reporting the issue in very detail! That helped me quite a lot. Indeed the problem was that, since in the original implementation the original xaxis and yaxis were removed, they cannot be removed again in other places. The solution was indeed what you suggested; instead of removing them, simply to make them invisible somewhere:)

This actually even enables us to use tight_layout and constrained_layout together with mpltern. I have now updated mpltern to 0.4.0 (now available in PyPI and within a few days also in conda-forge). Hopefully this works together with pyrolite. Please kindly let me know if there are still some issues.

morganjwilliams commented 1 year ago

Hey @yuzie007! Great, I'll check it out and let you know if I spot any lingering issues. Thanks for checking this out quickly, you'll have certainly kept a few pyrolite users happy/less confused.

morganjwilliams commented 1 year ago

At least the minimal example above runs as expected now, so I'd suggest this one is OK to be closed.