-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Bug Fix for Legend Label Removal Issue in ErrorbarContainer Object #25396
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@rcomer I believe you have already investigated this issue, so I here is the final result, with test cases!! |
@Higgs32584 Would you consider amending the title to something descriptive, and the PR description to discuss the changes made here? |
alright added some descriptions @jklymak |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @Higgs32584, I just have a minor comment on the test. See also the flake8
checker, which requires an extra line before the test.
|
||
ax.errorbar([1.1], [1.1], [1], marker="o", label="bar") | ||
|
||
plt.legend() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is not needed I think.
Also, stylistically it would be good to remove some of the blank lines here. Try to use blank lines to separate things into related blocks of code. So maybe the lines above this (setting up) could be one block, and the lines below (the actual checks) could be another.
Functionally, this test seems good to me 👍
@rcomer alright I fixed it up. Thank you again! |
What is the status of this? Thank you! |
@Higgs32584 I think now we're just waiting for more reviews/feedback. Feel free to ping again if there's no movement in, say, a week 🙂 |
@melissawm Ok, thanks! I'm looking forward to saying that I completed an OS contribution :) |
@@ -26,6 +26,7 @@ def remove(self): | |||
self, scalarp=lambda x: isinstance(x, Artist)): | |||
if c is not None: | |||
c.remove() | |||
self.set_label("") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is OK - it's a bit strange that legend is treating a Container as an Artist, but "remove" doesn't remove the Artist from consideration by legend. Setting the label to be empty accomplishes legend ignoring the Container, but at this point the Container should not be showing up in the list of Artists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, you would think, right? But I guess for some reason, it still shows up in the legend unless you specifically set the label to empty. Weird, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes - but I think this would be better if it chased down why that doesn't happen. Just blanking the label papers over the problem, but isn't a very robust fix. For instance you could imagine at some point we decide to include legend entries for artists with empty label strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jklymak, the bug has nothing to do with auto-updating; as the test cases show, the auto-updating likely has to do with the flattening of containers.
It likely has something to do with flattening the nested containers, which would probably be of greater risk for something else happening since "cbook.flatten" is referenced so much. I looked into other ways of removing it from the legend, but it seems there are stringent Object-Oriented protocols that I did not want to violate in my pull request. This seemed most in line with the current syntax of the rest of the function. If you query how many labels are in the value, the label is also absent, and the length is one, so there is not just a blank over.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point is that the container is apparently being left in the list of artists on the axis, and it should not be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I understand. Where would you recommend looking?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd look at how we get the list of handles in _get_legend_handles
and decide why the the Collection has not been removed from ax._children
. Note I'm not suggesting changing anything in legend, probably just in Collection.remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at it more, I'd just put a bunch of print statements in container.remvoe
and try and figure out why self._remove_method(self)
is either not being called or not working
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this, however, I think this is a bandaid on the real problem, which is that the Container is not being removed from the list of Artists on the Axes. If the Artist is properly removed, it will never be querried for the legend.
Containers are not properly "in the tree", but are stored independently (for reasons and fixing that is a big project), however the correct fix here is for the container to remove itself from matplotlib/lib/matplotlib/axes/_base.py Line 1307 in 9700f74
Not sure if the best way is to just reach up to the parent Axes and remove itself or if we should do the same remove method injection we do with artists. |
Ok, thank you! Where is the we should do the same remove method injection we do with artists? Also, I realized this code also this correctly changes the legend:
|
Where is the remove method injection we do with artists? |
Can someone help me out with this? I am having a lot of trouble trying to figure it out |
The legend consults a list of artists on the axes and the error bars are still in that list though all their children have been removed. Error bars remove method should remove itself from that list. |
Unfortunately I cannot figure it out. I spent a lot of time trying to decipher everything, but now I am procrastinating on other things. I will get my first commit eventually! |
Following up (too late) for anyone who finds this later, the remove method is injected into the matplotlib/lib/matplotlib/axes/_base.py Lines 2201 to 2220 in 6767738
|
Thanks @Higgs32584 - for quick questions and specific guidance, feel free to join our gitter room. We also have an incubator room specific to new contributors, and folks will be happy to engage. It can be harder to get quick feedback on GitHub because of the (very) high number of notifications we all get daily. We also host new contributor meetings that you are welcome to join - the next one is set to Tuesday, April 4. Cheers! |
PR Summary
Patch for this error:
#25274 [Bug]: .remove() on ErrorbarContainer object does not remove the corresponding item from the legend
Continuation on failed #25386, I had some issues with github and codespaces :(, still getting used to using such a large repo. Turns out that creating a codespace not directly through the branch of the thing you are trying to commit is blocked, so I was running around trying to figure out what was wrong with the push permissions.
Pretty much just removes the label when removed is called on an object, you can read more about the bug under the issue #25274 , I also added a test case modeled after the bug.
what is changed in this patch.
#container.py
set the label to blank when removed called, which removes item from the legend
#container_test.py
test case for container.py, test
The test case is checking that when an object is removed from a legend using the "remove()" method, it is no longer present in the legend. The test case creates an errorbar plot with a marker "foo", removes "foo", adds another errorbar plot with a marker "bar", and then checks that "foo" is not present in the legend and that there is only one handle in the legend.
PR Checklist##
Documentation and Tests