Repository: matplotlib/matplotlib

Issue:
[Bug]: .remove() on ErrorbarContainer object does not remove the corresponding item from the legend
### Bug summary

When I do `.remove()` on `ErrorbarContainer` objects returned from `Axes.errorbar()`, the objects are removed from the plot but the legend items are not removed. 

### Code for reproduction

```python
# coding="utf-8"

from matplotlib import pyplot

if __name__ == "__main__":
    
    ax = pyplot.gca()

    obj1 = ax.errorbar([1], [1], [1], marker="o", label="foo")

    pyplot.legend()
    pyplot.savefig("test_errorbar_1.pdf") # it has "foo" in the legend as expected

    obj1.remove() # this should remove obj1 from the axes

    ax.errorbar([1.1], [1.1], [1], marker="o", label="bar")

    pyplot.legend()
    pyplot.savefig("test_errorbar_2.pdf") # it has both "foo" and "bar" in the legend
```


### Actual outcome

[test_errorbar_1.pdf](https://github.com/matplotlib/matplotlib/files/10792418/test_errorbar_1.pdf)
[test_errorbar_2.pdf](https://github.com/matplotlib/matplotlib/files/10792419/test_errorbar_2.pdf)


### Expected outcome

The legend in `test_errorbar_2.pdf` contains only one entry corresponding to the second call to `ax.errorbar()`, i.e., the label `"bar"`. 

### Additional information

I am not sure if this is the right way to remove the errorbar objects from the axes after their creation. Please correct me if I am doing it wrong or there is a better way. 

As a side note, when I remove Line2D objects returned from `Axes.plot()`, the corresponding legend items also disappear, as one might expect. Maybe there is a problem specific to errorbar plots?

### Operating system

macOS Ventura 13.0

### Matplotlib Version

3.6.2

### Matplotlib Backend

MacOSX

### Python version

3.10.9

### Jupyter version

_No response_

### Installation

conda


Discussion:
Hey, I am new to open-source projects, but I was wondering where I would go about creating a patch for this issue.
If this helps at all, it looks like when you ask for .get_legend() both entries still show up in the file.
I would like to do this as my first issue, but do you know what .py file I should look into to make the patch? I am still getting used to this structure. Thank you!
Ok, I just added a patch for this bug.
So I was not able to figure it out, but it looks like the crux of the problem appears to be that the self.remove_method is never correctly called on ErrorBar Container. This is perplexing, as for barh(BarContainer), the remove method successfully works.

It also looks like BarContainer is only one Artist object, but ErrorBar Container is three. This is because ErrorBarContainer has children of Line2D and LineCollections(not sure why it is three), both of which are successfully called, hence why the line is not there, but it is still present on the legend. This line might still exist as well(I am not entirely sure),. After a call, it is also strange cause the ErrorBar object still contains three Artists, including Line2D and LineCollections.


Once the ErrorBar container is successfully removed from self.containers, which is around line ~1300 on _base.py, the problem will be solved. Although, ErrorBar still needs to remove ITSELF from self.containers, in order to stay in line with semantics.

It is also supposed to note that this is not a rendering or updating issue, as the container's object still contains ErrorBarContainer. 

What likely happens is that both ErrorBar Container and BarContainer both inherit the same remove method, but likely due to their specific implementation, you cannot remove ErrorBar Container from containers from a self-reference point of view, at least the way this is currently written. These are probably the main files you should look into for fixing this bug:

https://github.com/matplotlib/matplotlib/blob/main/lib/matplotlib/container.py 
https://github.com/matplotlib/matplotlib/blob/main/lib/matplotlib/artist.py
https://github.com/matplotlib/matplotlib/blob/main/lib/matplotlib/axes/_base.py

Hopefully you all figure this out !!
@Higgs32584 Thanks for the detailed look, and leaving some notes for others to follow...  
Hey man, I do not know if you can figure this out, but I could not. I left some notes for you to follow if necessary @rohitchouhan35
@Higgs32584 Thanks man, I'll look into it



Patch:
diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py
index 768e39e9126e..f1f550ed5416 100644
--- a/lib/matplotlib/axes/_axes.py
+++ b/lib/matplotlib/axes/_axes.py
@@ -3853,7 +3853,7 @@ def apply_mask(arrays, mask):
             (data_line, tuple(caplines), tuple(barcols)),
             has_xerr=(xerr is not None), has_yerr=(yerr is not None),
             label=label)
-        self.containers.append(errorbar_container)
+        self.add_container(errorbar_container)
 
         return errorbar_container  # (l0, caplines, barcols)
 


Test patch:
diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py
index cb0646820dab..beac9850539e 100644
--- a/lib/matplotlib/tests/test_axes.py
+++ b/lib/matplotlib/tests/test_axes.py
@@ -4274,6 +4274,24 @@ def test_errorbar_nonefmt():
         assert np.all(errbar.get_color() == mcolors.to_rgba('C0'))
 
 
+def test_errorbar_remove():
+    x = np.arange(5)
+    y = np.arange(5)
+
+    fig, ax = plt.subplots()
+    ec = ax.errorbar(x, y, xerr=1, yerr=1)
+
+    assert len(ax.containers) == 1
+    assert len(ax.lines) == 5
+    assert len(ax.collections) == 2
+
+    ec.remove()
+
+    assert not ax.containers
+    assert not ax.lines
+    assert not ax.collections
+
+
 def test_errorbar_line_specific_kwargs():
     # Check that passing line-specific keyword arguments will not result in
     # errors.