[Matplotlib-devel] New Axes.lines interface

vincent.adrien at gmail.com vincent.adrien at gmail.com
Wed Feb 23 08:23:37 EST 2022


Hi Gregor,

Unfortunately I do not know how future-proof is the use of `ax.lines.clear()`. Maybe one of the active core dev may be able to provide insight on that matter.

In case you only have one line plot on your plot (or you always want to replace only the most recent one), another workaround may simply be to update that line instance rather that clearing (all) the existing lines and creating a brand new line instance every time. Following my previous example, it could be something along the lines:

```python
import matplotlib.pyplot as plt

def replace_line(ax, xs, ys, **kwargs):
     
     if ax.lines:  # there was already a line drawn
         _line = ax.lines[-1]
         _line.set_data(xs, ys)
         _line.update(kwargs)
         # Update the autoscale after setting the new data
         ax.relim()
         ax.autoscale_view(tight=None, scalex=True, scaley=True)
     else:
         ax.plot(xs, ys, **kwargs)
     
     return ax
     
if __name__ == "__main__":
     plt.ion()
     
     fig, ax = plt.subplots(num="test2", clear=True, layout="constrained")
     
     # Initial line
     xs0 = [0, 1]
     ys0 = [0, 1]
     ax.plot(xs0, ys0, color="tab:red")

     # New line that should replace the (last) previous one
     xs1 = [1, 0]
     ys1 = [-1, 2]
     replace_line(ax, xs1, ys1, color="tab:gray")
```

One advantage of the update-the-last-line-instance approach is that it should not matter wether `ax.lines` is made a tuple in the future, thus discarding the worry of `ax.lines.clear()` being deprecated. But of course it requires that updating only the most recently instantiated line is OK with your use case.

Best,
Adrien

Le 23/02/2022 à 12:08, Gregor Mönke a écrit :
> Hello Adrien,
> 
> yes of course it's the obvious thing! I should have inspected the ArtistList object further, thanks a lot for the quick response.
> 
> The interface still looks a lot like that of a <list> type of object, the doc says "these artist lists will likely be replaced by tuples".  Do you know if that .clear() method will be available for the foreseeable future?!
> 
> Cheers,
> Gregor
> 
> On Wed, Feb 23, 2022 at 11:05 AM vincent.adrien at gmail.com <mailto:vincent.adrien at gmail.com> <vincent.adrien at gmail.com <mailto:vincent.adrien at gmail.com>> wrote:
> 
>     Hello Gregor,
> 
>     I am not that much familiar with the very last updates of Matplotlib but it looks like the `ax.lines.clear()` method might be worth a try. The following snippet of code might achieve the kind of behavior that you are looking for (if I understood your needs correctly):
> 
>     ```python
>     import matplotlib.pyplot as plt
> 
>     def replace_line(ax, xs, ys, **kwargs):
>           # Former method:
>           # there was already a line drawn
>           #if ax.lines:
>           #    ax.lines = []
>           # New method:
>           ax.lines.clear()
>           # (re-)draw
>           ax.plot(xs, ys, **kwargs)
> 
>           return ax
> 
>     if __name__ == "__main__":
>           plt.ion()
> 
>           fig, ax = plt.subplots(num="test", clear=True, layout="constrained")
> 
>           # Initial line
>           xs0 = [0, 1]
>           ys0 = [0, 1]
>           ax.plot(xs0, ys0, color="tab:red")
> 
>           # New line that should replace the previous one(s)
>           xs1 = [1, 0]
>           ys1 = [-1, 2]
>           replace_line(ax, xs1, ys1, color="tab:gray")
>     ```
> 
>     Regards,
>     Adrien
> 
>     Le 23/02/2022 à 10:29, Gregor Mönke a écrit :
>      > Hello,
>      >
>      > I am using interactive matplotlib figures inside a PyQT application (https://github.com/tensionhead/pyboat <https://github.com/tensionhead/pyboat> <https://github.com/tensionhead/pyboat <https://github.com/tensionhead/pyboat>>), and often I want to re-draw lines upon new user input onto an Axis which also has other elements (generated by imshow() in my case). For the last years that basically worked like this:
>      >
>      > def draw():
>      >      # there was already a line drawn
>      >      if ax.lines:
>      >          ax.lines = []
>      >      # (re-)draw
>      >      ax.plot(...)
>      >
>      > Now (matplotlib 3.5.1) this does not seem to work anymore, as I get an Attribute error:
>      > AttributeError: can't set attribute 'lines'
>      >
>      > When I inspect the ax.lines I formerly got a list holding `matplotlib.lines.lines2D` objects, now I have a <Axes.ArtistList of 1 lines>. I looked into the API (https://matplotlib.org/devdocs/api/axes_api.html#other <https://matplotlib.org/devdocs/api/axes_api.html#other> <https://matplotlib.org/devdocs/api/axes_api.html#other <https://matplotlib.org/devdocs/api/axes_api.html#other>>), and what I got from there is that this is a transitional class and I should use this 'as it was a tuple already`. I am stuck here now, I tried to `del` the whole ax.lines attribute or setting it to an empty tuple but nothing worked.
>      >
>      > How can I remove a line from an axis without clearing it? Thanks for your help!
>      >
>      > Best,
>      > Gregor
>      >
>      > _______________________________________________
>      > Matplotlib-devel mailing list
>      > Matplotlib-devel at python.org <mailto:Matplotlib-devel at python.org>
>      > https://mail.python.org/mailman/listinfo/matplotlib-devel <https://mail.python.org/mailman/listinfo/matplotlib-devel>
> 



More information about the Matplotlib-devel mailing list