Skip to content

[Bug] Error: 'PathCollection' object has no attribute 'do_3d_projection' when doing contourf in 3d with extend = 'both' #21016

Closed
@heavysink

Description

@heavysink

Bug summary

When doing contourf in 3D with given levels and extend = 'both', matplotlib will raise error 'PathCollection' object has no attribute 'do_3d_projection'.

Code for reproduction

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np

ax = plt.figure().add_subplot(projection='3d')
X, Y, Z = axes3d.get_test_data(0.1)
levels = np.arange(-70.0,70.0,1.0)

# Plot projections of the contours for each dimension.  By choosing offsets
# that match the appropriate axes limits, the projected contours will sit on
# the 'walls' of the graph
cset = ax.contourf(X, Y, Z, zdir='z', offset=-100, levels = levels, extend='both', cmap=cm.coolwarm)

ax.set_xlim(-40, 40)
ax.set_ylim(-40, 40)
ax.set_zlim(-100, 100)

ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')

plt.show()

Actual outcome

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/usr/lib/python3.9/site-packages/IPython/core/formatters.py in __call__(self, obj)
    339                 pass
    340             else:
--> 341                 return printer(obj)
    342             # Finally look for special method names
    343             method = get_real_method(obj, self.print_method)

/usr/lib/python3.9/site-packages/IPython/core/pylabtools.py in <lambda>(fig)
    248 
    249     if 'png' in formats:
--> 250         png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
    251     if 'retina' in formats or 'png2x' in formats:
    252         png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))

/usr/lib/python3.9/site-packages/IPython/core/pylabtools.py in print_figure(fig, fmt, bbox_inches, **kwargs)
    132         FigureCanvasBase(fig)
    133 
--> 134     fig.canvas.print_figure(bytes_io, **kw)
    135     data = bytes_io.getvalue()
    136     if fmt == 'svg':

/usr/lib/python3.9/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2228                        else suppress())
   2229                 with ctx:
-> 2230                     self.figure.draw(renderer)
   2231 
   2232             if bbox_inches:

/usr/lib/python3.9/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     72     @wraps(draw)
     73     def draw_wrapper(artist, renderer, *args, **kwargs):
---> 74         result = draw(artist, renderer, *args, **kwargs)
     75         if renderer._rasterizing:
     76             renderer.stop_rasterizing()

/usr/lib/python3.9/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     49                 renderer.start_filter()
     50 
---> 51             return draw(artist, renderer, *args, **kwargs)
     52         finally:
     53             if artist.get_agg_filter() is not None:

/usr/lib/python3.9/site-packages/matplotlib/figure.py in draw(self, renderer)
   2778 
   2779             self.patch.draw(renderer)
-> 2780             mimage._draw_list_compositing_images(
   2781                 renderer, self, artists, self.suppressComposite)
   2782 

/usr/lib/python3.9/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    130     if not_composite or not has_images:
    131         for a in artists:
--> 132             a.draw(renderer)
    133     else:
    134         # Composite any adjacent images together

/usr/lib/python3.9/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     49                 renderer.start_filter()
     50 
---> 51             return draw(artist, renderer, *args, **kwargs)
     52         finally:
     53             if artist.get_agg_filter() is not None:

/usr/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axes3d.py in draw(self, renderer)
    483                                 for axis in self._get_axis_list()) + 1
    484             for i, col in enumerate(
--> 485                     sorted(self.collections,
    486                            key=do_3d_projection,
    487                            reverse=True)):

/usr/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axes3d.py in do_3d_projection(artist)
    476                     "do_3d_projection() was deprecated in Matplotlib "
    477                     "%(since)s and will be removed %(removal)s.")
--> 478                 return artist.do_3d_projection(renderer)
    479 
    480             # Calculate projection of collections and patches and zorder them.

AttributeError: 'PathCollection' object has no attribute 'do_3d_projection'

Expected outcome

Removing extend='both' the code works fine

2021-09-08_01-58

Operating system

Arch

Matplotlib Version

3.4.2

Matplotlib Backend

module://matplotlib_inline.backend_inline

Python version

python 3.9.6

Jupyter version

3.1.6

Other libraries

No response

Installation

Linux package manager (Debian/Fedora/etc.)

Conda channel

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions