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
I understand that 3d plotting is as yet a bit hacky, but from what little I understand of the code for Path3DCollection (or is it Patch3DCollection as the docstring for scatter says?), it feels like this should be fixable (patches aren't intersecting each other here).
I'm using Matplotlib v1.5.0. The zorder of markers plotted by 3d scatter goes wrong in certain views.
Here's a minimal example:
importnumpyasnpimportmatplotlib.pyplotaspltfrommpl_toolkits.mplot3dimportAxes3Dx=np.array([-1, 0, 1])
y=np.array([0, 0, 0])
fig=plt.figure()
ax=fig.add_subplot(111, projection='3d')
patches=ax.scatter(x, y, y, s=2500, c=x)
plt.show()
I've made the marker sizes really huge to illustrate the point clearly - in the initial view, the overlap is correct (in this example), but on rotation, it goes wrong:
It's not fully clear because of the depthshading, but red is on top of green, which is on top of blue.
It definitely looks like some zorder information is present - depthshade is using it correctly - but it's not being used to update the drawing order correctly.
This problem gets severely exacerbated as the number of scatter points increases. To demonstrate, execution of this gist produces the following ugly result:
The sphere ought to be mostly red (it's the top view of a spherical grid with color=z-coordinate), instead it's mostly blue because of poor ordering. Rotating it will make it seem like there are holes in the sphere at different places because of incorrect overlap in some strange patterns.
Reacted by Obusmydealz, Arkady Zgonnikov and Alexander Barth
Indeed. I think this has been noticed before in the theoretical sense, but
no one until now has provided an actual example of it performing really
badly. IIRC, this was one of my motivations for #4090, which would have
brought proper z-order handling across all collections, and potentially
allow for intra-collection ordering as well. I never had the time to really
pursue it, though.
Just a minor addition. I've run into what I assume is the same bug. But I tracked down the particular elevation at which the problem occurs for me: 48.02450 degrees. Maybe this is just down to the peculiar particulars of precisely my problem, but maybe you could find it an interesting test or helpful in some other way. I've gisted the example here.
The problem here is that the drawing order of the patches needs to change when the camera view changes so that the patches that are behind others wrt the line of sight get drawn first. The order of the patches is decided upon initializing the PathCollection, but in this case, where all the patches are the same, we can reorder them at draw time by the distance from the camera position like this (with inspiration from my SO answer to a similar related problem):
importnumpyasnpimportmatplotlib.pyplotaspltfrommpl_toolkits.mplot3dimportAxes3Ddefget_camera_position(ax):
"""returns the camera position for 3D axes in cartesian coordinates"""r=np.square(ax.xy_viewLim.max).sum()
theta, phi=np.radians((90-ax.elev, ax.azim))
returnnp.array(sph2cart(r, theta, phi), ndmin=2).Tdefsph2cart(r, theta, phi):
"""spherical to cartesian transformation."""x=r*np.sin(theta) *np.cos(phi)
y=r*np.sin(theta) *np.sin(phi)
z=r*np.cos(theta)
returnx, y, zdefreorder_camera_distance():
""" Sort the patches (via their offsets) by decreasing distance from camera position so that the furthest gets drawn first. """# camera position in xyzcamera=get_camera_position(ax)
# distance of patches from camerad=np.square(np.subtract(camera, patches._offsets3d)).sum(0)
o=d.argsort()[::-1]
patches._offsets3d=tuple(np.array(patches._offsets3d)[:, o])
patches._facecolor3d=patches._facecolor3d[o]
patches._edgecolor3d=patches._edgecolor3d[o]
# todo: similar for linestyles, linewidths, etc.... defon_draw(event):
reorder_camera_distance()
# MWEx=np.array([-1, 0, 1])
y=np.array([0, 0, 0])
z=yfig, ax=plt.subplots(subplot_kw=dict(projection='3d'))
patches=ax.scatter(x, y, z, s=2500, c=x)
# connect to draw event (re-orders patches each time the canvas draws)fig.canvas.mpl_connect('draw_event', on_draw)
Things should now be drawn in the correct order irrespective of the viewing angle.
Using the data from your gist:
Reacted by Praveen Venkatesh, austinlostinboston, kiril-chilingarashvili, Max and Xingguang (Kevin) Yan
Really? To me it looks like #15594 just sorts along z and does not take the distance to the "camera" into account? Edit: seems I misinterpreted some of the variable names. Ignore this.
@ImportanceOfBeingErnest Yes, I personally find this section of code quite opaque, partly due to the choice of variable names, sparse comments and lack of docstrings...
Activity
tacaswell commentedon Jan 11, 2016
attn @WeatherGod
It looks like the zsort logic from
Poly3DCollectionneeds to be ported toPath3DCollectionas well.WeatherGod commentedon Jan 11, 2016
Indeed. I think this has been noticed before in the theoretical sense, but
no one until now has provided an actual example of it performing really
badly. IIRC, this was one of my motivations for #4090, which would have
brought proper z-order handling across all collections, and potentially
allow for intra-collection ordering as well. I never had the time to really
pursue it, though.
On Mon, Jan 11, 2016 at 7:54 AM, Thomas A Caswell notifications@github.com
wrote:
moble commentedon Feb 25, 2016
Just a minor addition. I've run into what I assume is the same bug. But I tracked down the particular elevation at which the problem occurs for me: 48.02450 degrees. Maybe this is just down to the peculiar particulars of precisely my problem, but maybe you could find it an interesting test or helpful in some other way. I've gisted the example here.
techdragon commentedon Jul 23, 2019
I've run into this with the z-order of markers not applying on top of a surface plot. It's the same as in @moble 's gist.
astromancer commentedon Mar 4, 2020
The problem here is that the drawing order of the patches needs to change when the camera view changes so that the patches that are behind others wrt the line of sight get drawn first. The order of the patches is decided upon initializing the
PathCollection, but in this case, where all the patches are the same, we can reorder them at draw time by the distance from the camera position like this (with inspiration from my SO answer to a similar related problem):Things should now be drawn in the correct order irrespective of the viewing angle.
Using the data from your gist:

timhoffm commentedon Mar 4, 2020
Might be addressed by #15594.
astromancer commentedon Mar 4, 2020
Indeed, I wasn't aware of that PR since it wasn't linked here, but from what I can tell it should fix this issue.
ImportanceOfBeingErnest commentedon Mar 4, 2020
Really? To me it looks like #15594 just sorts along z and does not take the distance to the "camera" into account?Edit: seems I misinterpreted some of the variable names. Ignore this.astromancer commentedon Mar 4, 2020
@ImportanceOfBeingErnest Yes, I personally find this section of code quite opaque, partly due to the choice of variable names, sparse comments and lack of docstrings...
QuLogic commentedon May 13, 2020
Should be fixed by #17378.