seaborn icon indicating copy to clipboard operation
seaborn copied to clipboard

sns.catplot raises AttributeError: 'NoneType' object has no attribute 'get_legend_handles_labels'

Open eroell opened this issue 1 year ago • 7 comments

Hey, thanks for creating and maintaining this awesome package!

We have came across a feature which seems to not work in 0.13.0 anymore, but did so in 0.12.2 - maybe a bug, maybe me not having immediately grasped a changed usage.

Reproducible Example

import seaborn as sns
import matplotlib.pyplot as plt

df = sns.load_dataset("iris")

x = 'species'
keys = ['setosa', 'versicolor']
y = 'sepal_length'

scale = 'width'

g = sns.catplot(
    y=y,
    data=df,
    kind="violin",
    col=x,
    col_order=keys,
    order=keys,
    cut=0,
    inner=None,
)

plt.show()

Output

Traceback (most recent call last):
  File "/Users/<username>/Documents/seaborn/try_violin.py", line 34, in <module>
    g = sns.catplot(
        ^^^^^^^^^^^^
  File "/Users/<username>Documents/seaborn/seaborn_venv/lib/python3.11/site-packages/seaborn/categorical.py", line 2932, in catplot
    p.plot_violins(
  File "/Users/<username>/Documents/seaborn/seaborn_venv/lib/python3.11/site-packages/seaborn/categorical.py", line 1153, in plot_violins
    self._configure_legend(ax, legend_artist, common_kws)
  File "/Users/<username>/Documents/seaborn/seaborn_venv/lib/python3.11/site-packages/seaborn/categorical.py", line 420, in _configure_legend
    handles, _ = ax.get_legend_handles_labels()
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get_legend_handles_labels'

What I think is wrong This code snipped produces the hoped-for nice violin plot with seaborn=0.12.2, but raises the above error with seaborn=0.13.0. If it helps, I think not setting the order argument helps in getting the plot - without order selection, though.

The specific versions of seaborn and matplotlib

Name: seaborn
Version: 0.13.0

Name: matplotlib
Version: 3.8.0

eroell avatar Oct 16 '23 12:10 eroell

I can confirm that this is a regression in the sense that there is no error on v0.12, but on v0.12 it appears that the order parameter is simply ignored when only one of x or y is defined.

I am not sure what you are expecting order to do here, since a single violin will essentially be plotted at a "null" category position. If anything, the behavior on v0.13 is arguably more correct (but only half right) in that order actually sets the x ticks to the provided categories. Then it runs into an edge case relating to nothing being on the plot when trying to draw the legend. If you set legend=False, you would see a plot that I would consider to be "correct" given what you asked for, but I gather it is not what you expect:

image

In any case, seems like you can just omit order=keys to keep getting the same plot you would have otherwise?

Then I guess there's a question about whether to maintain the "backwards compatibility" of simply ignoring order with only one coordinate variable defined or fixing the legend edge case. Note that somewhat different edge cases are encountered with different categorical plots:

for kind in ["strip", "swarm", "box", "boxen", "violin", "bar", "point"]:
    try:
        g = sns.catplot(df, x="petal_length", order=["a", "b"], kind=kind)
    except Exception as e:
        print(f"{kind}: {e.__class__.__name__}")
    else:
        print(f"{kind}: Success")
    finally:
        plt.close("all")
strip: Success
swarm: Success
box: ValueError
boxen: AttributeError
violin: AttributeError
bar: Success
point: ValueError

mwaskom avatar Oct 16 '23 18:10 mwaskom

Hey! I also had this problem.

I tried investigating a bit, looks like the problem is inside plot_violins function.

The line "handles, _ = ax.get_legend_handles_labels()" comes from "_configure_legend" function that is being called by some functions at categorical.py.

In my case, the problem is specifically on the line 917 at categorical.py, inside "plot_violins" (it calls _configure_legend) there is a "ax = self.ax", but self.ax is not being defined anywhere. Thats why ax is a None value.

victorlga avatar Oct 25 '23 00:10 victorlga

Thanks for getting back to this so quickly! Checked a bit more into this, bottom line is probably that order is not required in our case/the example above. Us calling it anyways was fine until 0.12.2, and now raises an Error in 0.13.0, whose meaning was not immediately clear to me - now it is. We'll adjust our use of seaborn to this update.

Thanks - I will close the issue, am all set.

eroell avatar Nov 02 '23 19:11 eroell

Same bug reported in version 0.13.1🥹

simon7073 avatar Jan 16 '24 04:01 simon7073

This was closed by OP, not fixed. But the arguments above (that it's completely avoidable) still apply...

mwaskom avatar Jan 16 '24 11:01 mwaskom

Not sure what could be fixed here, since this

In any case, seems like you can just omit order=keys to keep getting the same plot you would have otherwise?

is true in my case, dont know about @nsleep though. From my side using order when there was no reason to do so caused this error.

Maybe raising a more meaningful message could be done?

eroell avatar Jan 16 '24 12:01 eroell

I have solved this problem by downgrading the seaborn to 0.11,

RongchuanBjmu avatar May 17 '24 13:05 RongchuanBjmu