Collections attribute deprecation in version > 3.8

Hi everyone,

I have been using matplotlib for a few years now, and I am really happy with it, therefore I’d first like to thank everyone contributing to the module and to this forum.

I have a little question about the versions > 3.8. I am using the matplotlib.pyplot.contour and contourf functions, and I’d like to access each path individually, even if they are at the same level. To do so, I used to use the collections attribute and everything worked, but now there is this little message that worries me:

“MatplotlibDeprecationWarning: The collections attribute was deprecated in Matplotlib 3.8 and will be removed two minor releases later.”

Does anyone know what I could use instead ? I mean, my program is working atm, but I’d like it to work in a few months as well - and it definitely won’t if the collection attribute is removed and if I have no subtitute.

I have checked the documentation, but found nothing about a substitution. I may have missed it tho.

Thanks for reading that far,


Since the ContourSet now inherits directly from Collection, you can use the get_paths method. E.g.

cs = plt.contour(...)
paths = cs.get_paths()

I agree that this is not as obvious as it could be from the documentation.

1 Like

Hi rcomer,

Thank you very much for your immediate answer.
This works perfectly.



1 Like


Hello! I am having a similar problem here, but in my case, in the past I was doing:
for i, (level, path_collection) in enumerate(zip(ax.levels, ax.collections)):
Which allowed me to separate each path per level. It seems like ax.get_paths() will put them all together.
The second issue I am having is that in the past, I would get in return open paths, but now it seems I am getting closed paths. Is there any way I can get both open paths again and separation by levels?
Thanks very much for your help!

@jreniel there is now one path per level so you can do

cs = plt.contour([[0, 1], [1, 2]])
for level, path in zip(cs.levels, cs.get_paths()):

Within each path, individual contour lines are separated by the MOVETO code. I’m afraid I don’t understand your question about open vs closed paths: the actual contour lines are the same and it is only the way they are organised that has changed.

Hi @rcomer, thank you for the clarification, that makes sense.
In the past, all the countours were completely “independent” from each other. In this new version, when one finishes it connects to the next, and I believe this has to do with the MOVETO (maybe). In the current version, it seems I have to explicitly divide them, whereas in the previous version they were already divided.
In any case, I found another thread where you posted the solution: use contourpy directly.
Thanks a lot for your help!

1 Like

Hi, @rcomer.

Could you please clarify, what is the proper way to change the following code (which was removing contours from plot):

            if isinstance(contour, ContourSet):
                for lineset in contour.collections:

The problem for me is that if I try to replace collection with get_paths, then remove method does not work on path.
If I try removing path via del (for example, as follows):

            for k, path in enumerate(contour.get_paths()):
                 del contour.get_paths()[k]

then the contour to be removed remains in the image.

Many thanks in advance

@hedgehog if you want to remove all the contours you can go ahead and use the remove method on the ContourSet itself


@rcomer Thank you very much

1 Like