You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
'Poly3DCollection' object has no attribute '_facecolors2d' #4067
The following minimal example demonstrates the issue:
import numpy as np
import matplotlib.tri as mtri
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
y,x = np.ogrid[1:10:100j, 1:10:100j]
z2 = np.cos(x)**3 - np.sin(y)**2
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
r = ax.plot_surface(x,y,z2, cmap='hot')
r.get_facecolors()
It fails on the last line with the following traceback:
AttributeError Traceback (most recent call last)
<ipython-input-13-de0f41d662cd> in <module>()
----> 1 r.get_facecolors()
/home/oliver/.virtualenvs/mpl/local/lib/python2.7/site-packages/mpl_toolkits/mplot3d/art3d.pyc in get_facecolors(self)
634
635 def get_facecolors(self):
--> 636 return self._facecolors2d
637 get_facecolor = get_facecolors
638
AttributeError: 'Poly3DCollection' object has no attribute '_facecolors2d'
Tested with mpl versions 1.3.1 and 1.4.2.
Sent here by Benjamin, from the mpl users mailing list (mail with the same title). Sorry for dumping this without more assistance, I'm not yet at a python level where I can help in debugging, I think (well, it seems daunting).
Ok, I have a "fix", in the sense that that attribute will be defined upon initialization. However, for your example, the facecolors returned is completely useless ([[0, 0, 1, 1]] -- all blue, which is default). I suspect that there is a deeper problem with ScalarMappables in general in that they don't set their facecolors until draw time?
I believe I'm still running into this issue today. Below is the error message I receive when attempting to convert hb_made (a hexbin PolyCollection) into a Poly3DCollection. Are there any other ways to convert 2D PolyCollections into 3D PolyCollections?
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mpl_toolkits/mplot3d/axes3d.py", line 2201, in add_collection3d
art3d.poly_collection_2d_to_3d(col, zs=zs, zdir=zdir)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mpl_toolkits/mplot3d/art3d.py", line 716, in poly_collection_2d_to_3d
col.set_3d_properties()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mpl_toolkits/mplot3d/art3d.py", line 595, in set_3d_properties
self._edgecolors3d = PolyCollection.get_edgecolors(self)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/collections.py", line 626, in get_edgecolor
return self.get_facecolors()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mpl_toolkits/mplot3d/art3d.py", line 699, in get_facecolors
return self._facecolors2d
AttributeError: 'Poly3DCollection' object has no attribute '_facecolors2d'
While a permanent fix is find, I found that a simple temporary fix is to explicitly set the _facecolors2d and _edgecolors2d parameters after creating the surface plot.
Reacted by Andrii Iakovliev, Roman Yurchak, Manjot Virdee, Jianshen Liu, Edouard Berthe, Kprzeorski, Felipe Gutierrez-Barragan, Laurent Vermue, gnikit, David Ollodart and 7 more
I also could not get the legend to show in my 3d plot of planes with the error:"AttributeError: 'Poly3DCollection' object has no attribute '_edgecolors2d'".
Although the fix from @felipegb94 worked:
surf._facecolors2d=surf._facecolors3d
surf._edgecolors2d=surf._edgecolors3d
None of the workarounds work in matplotlib 3.5.1
It works after modifying for the available attributes _facecolors and _edgecolors: surf._facecolors2d = surf._facecolors surf._edgecolors2d = surf._edgecolors
Hint: if there are multiple surfaces on the same axes, the workaround must be applied to each surface individually.
@nina-wwc I just checked the minimal working example in this thread using matplotlib-3.5.1 and 3.5.2 (latest) and my workaround works as it did before, as does yours. Could you test the example code in a virtual environment perhaps, if you haven't already done so?
The problem still is that we update some state during the draw process. Internally we do the updating and the access in just the right order so that in most cases we do not notice that we also add the attributes on the fly.
The best workaround for the current case (assuming 3.5):
importnumpyasnpimportmatplotlib.triasmtriimportmatplotlib.pyplotaspltfrommpl_toolkits.mplot3dimportAxes3Dy,x=np.ogrid[1:10:100j, 1:10:100j]
z2=np.cos(x)**3-np.sin(y)**2fig=plt.figure()
ax=fig.add_subplot(111, projection='3d')
r=ax.plot_surface(x,y,z2, cmap='hot')
fig.draw_without_rendering() # <--- This is the key liner.get_facecolors()
However, I still think the best solution is #4067 (comment) which will require looking in get_facecolors to detect when these attributes are missing (and if stale?) and then force what ever needs to be done to update them.
Labeling this as a good first issue because it clearly has affected a lot of people for a long time, there is a very clear reproduction example (that will make a perfect test), and there are no API design choices to be made, but medium difficulty because it will require understanding some slightly tricking inheritance and how our 3D artists draw them selves.
Activity
WeatherGod commentedon Feb 7, 2015
Ok, I have a "fix", in the sense that that attribute will be defined upon initialization. However, for your example, the facecolors returned is completely useless ([[0, 0, 1, 1]] -- all blue, which is default). I suspect that there is a deeper problem with ScalarMappables in general in that they don't set their facecolors until draw time?
tacaswell commentedon Feb 7, 2015
The solution is to probably force the evaluation of the norm + cmap in
get_facecolors.WeatherGod commentedon Feb 8, 2015
The bigger question I have is if regular PolyCollections that are
ScalarMappables suffer from the same problem?
On Sat, Feb 7, 2015 at 6:42 PM, Thomas A Caswell [email protected]
wrote:
WeatherGod commentedon Feb 9, 2015
PR #4090 addresses this. Although, it still doesn't return any useful
value... it just does the same thing that regular PolyCollections do.
On Mon, Feb 9, 2015 at 3:47 PM, Thomas A Caswell [email protected]
wrote:
syee commentedon Apr 10, 2016
I believe I'm still running into this issue today. Below is the error message I receive when attempting to convert hb_made (a hexbin PolyCollection) into a Poly3DCollection. Are there any other ways to convert 2D PolyCollections into 3D PolyCollections?
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mpl_toolkits/mplot3d/axes3d.py", line 2201, in add_collection3d
art3d.poly_collection_2d_to_3d(col, zs=zs, zdir=zdir)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mpl_toolkits/mplot3d/art3d.py", line 716, in poly_collection_2d_to_3d
col.set_3d_properties()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mpl_toolkits/mplot3d/art3d.py", line 595, in set_3d_properties
self._edgecolors3d = PolyCollection.get_edgecolors(self)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/collections.py", line 626, in get_edgecolor
return self.get_facecolors()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mpl_toolkits/mplot3d/art3d.py", line 699, in get_facecolors
return self._facecolors2d
AttributeError: 'Poly3DCollection' object has no attribute '_facecolors2d'
felipegb94 commentedon Jan 15, 2018
I don't know if this is the appropriate place to post this, but here is a temporary fix for anyone who is waiting on the permanent fix.
I encounter this same error when trying to add a legend to my 3D surface plot.
While a permanent fix is find, I found that a simple temporary fix is to explicitly set the
_facecolors2dand_edgecolors2dparameters after creating the surface plot.Kprzeorski commentedon Oct 14, 2018
I also could not get the legend to show in my 3d plot of planes with the error:"AttributeError: 'Poly3DCollection' object has no attribute '_edgecolors2d'".
Although the fix from @felipegb94 worked:
surf._facecolors2d=surf._facecolors3d
surf._edgecolors2d=surf._edgecolors3d
5 remaining items
ulijh commentedon Sep 16, 2020
I ran into this today, with version 3.3.1.post1012+g5584ba764, the workaround did the trick.
maximedelboo commentedon Nov 23, 2020
I ran in to this as well, and the fix works in version 3.3.1 but not in 3.3.3
JeS24 commentedon Jan 3, 2021
@Bootje2000 Apparently some attributes have been renamed or moved around (prima facie). Try this slight modification to @felipegb94's workaround:
Note the lack of "s" on the RHS.
_facecolors3dand_edgecolors3ddo not seem to exist anymore.This works in
matplotlib 3.3.3as of January 04, 2021.fix bug in 3d plot
fix bug
nina-wwc commentedon Jul 2, 2022
None of the workarounds work in matplotlib 3.5.1
It works after modifying for the available attributes
_facecolorsand_edgecolors:surf._facecolors2d = surf._facecolorssurf._edgecolors2d = surf._edgecolorsHint: if there are multiple surfaces on the same axes, the workaround must be applied to each surface individually.
JeS24 commentedon Jul 2, 2022
@nina-wwc I just checked the minimal working example in this thread using
matplotlib-3.5.1and3.5.2(latest) and my workaround works as it did before, as does yours. Could you test the example code in a virtual environment perhaps, if you haven't already done so?tacaswell commentedon Jul 3, 2022
The problem still is that we update some state during the draw process. Internally we do the updating and the access in just the right order so that in most cases we do not notice that we also add the attributes on the fly.
The best workaround for the current case (assuming 3.5):
However, I still think the best solution is #4067 (comment) which will require looking in
get_facecolorsto detect when these attributes are missing (and if stale?) and then force what ever needs to be done to update them.Labeling this as a good first issue because it clearly has affected a lot of people for a long time, there is a very clear reproduction example (that will make a perfect test), and there are no API design choices to be made, but medium difficulty because it will require understanding some slightly tricking inheritance and how our 3D artists draw them selves.