From tensionheadx at gmail.com Wed Feb 23 04:29:39 2022 From: tensionheadx at gmail.com (=?UTF-8?Q?Gregor_M=C3=B6nke?=) Date: Wed, 23 Feb 2022 10:29:39 +0100 Subject: [Matplotlib-devel] New Axes.lines interface Message-ID: Hello, I am using interactive matplotlib figures inside a PyQT application ( 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 . I looked into the API ( 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 -------------- next part -------------- An HTML attachment was scrubbed... URL: From vincent.adrien at gmail.com Wed Feb 23 05:06:11 2022 From: vincent.adrien at gmail.com (vincent.adrien at gmail.com) Date: Wed, 23 Feb 2022 11:06:11 +0100 Subject: [Matplotlib-devel] New Axes.lines interface In-Reply-To: References: Message-ID: <7184957e-e401-9933-fe05-b1069d4b6ca0@gmail.com> 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 ), 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 . I looked into the API (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 > https://mail.python.org/mailman/listinfo/matplotlib-devel From tensionheadx at gmail.com Wed Feb 23 06:08:35 2022 From: tensionheadx at gmail.com (=?UTF-8?Q?Gregor_M=C3=B6nke?=) Date: Wed, 23 Feb 2022 12:08:35 +0100 Subject: [Matplotlib-devel] New Axes.lines interface In-Reply-To: <7184957e-e401-9933-fe05-b1069d4b6ca0@gmail.com> References: <7184957e-e401-9933-fe05-b1069d4b6ca0@gmail.com> Message-ID: 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 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 < 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>), 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 lines>. I looked into the API ( > 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 > > https://mail.python.org/mailman/listinfo/matplotlib-devel > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From vincent.adrien at gmail.com Wed Feb 23 08:23:37 2022 From: vincent.adrien at gmail.com (vincent.adrien at gmail.com) Date: Wed, 23 Feb 2022 14:23:37 +0100 Subject: [Matplotlib-devel] New Axes.lines interface In-Reply-To: References: <7184957e-e401-9933-fe05-b1069d4b6ca0@gmail.com> Message-ID: 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 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 > 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 >), 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 . I looked into the API (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 > > https://mail.python.org/mailman/listinfo/matplotlib-devel >