Description
Bug summary
When plotting a surface and scatter points with Axes3D
, either none of the scatter points are occluded by the surface or all of them are occluded. Whether or not they are occluded appears to depend upon a numerical threshold. (Speculation: perhaps the occlusion of a single point?)
Code for reproduction
# On two separate plots, plot a surface and five lines via scatter3D.
# The five lines are vertically offset by a constant.
# The two separate plots differ by an imperceptible difference in offset.
# - The rendered difference is significant.
# - Neither is correct.
import numpy as np
import matplotlib.pyplot as plt
def surface(x, y):
return np.sin(x) + 0.5 * y * np.cos(x)
def plot_surface_and_lines(vertical_line_offset):
x, y = np.meshgrid(
np.linspace(-5, 5, 100),
np.linspace(-5, 5, 100),
)
fig = plt.figure(dpi=150)
ax = fig.add_subplot(projection='3d')
ax.set(
xlabel='x',
ylabel='y',
zlim=(-3, 3),
title=f'z offset = {vertical_line_offset}',
)
ax.plot_surface(x, y, surface(x, y))
a, b = np.meshgrid(np.linspace(-5, 5, 5), np.linspace(-5, 5, 100))
ax.scatter3D(a, b, surface(a, b) + vertical_line_offset, color='red')
plt.show()
plot_surface_and_lines(0.253)
plot_surface_and_lines(0.254)
Actual outcome


Expected outcome
Both plots should look like this, with occlusion determined point-by-point.
(This was manually composited with an image editing tool, AFAICT this cannot be generated by matplotlib until the bug is fixed.)
Additional information
This global occlusion occurs with many combinations of plots, not exclusively .plot_surface
and .scatter3D
. The occluder or the occluded can be generated by any of
.plot_trisurf
.plot_surface
.scatter3D
.plot_wireframe
and possibly others. I did not test to find the numerical edge of occlusion/non-occlusion with the other combinations.
Perhaps this is related to other github issues related to depth testing or the underlying z-buffer.
Operating system
Ubuntu 18.04.5 LTS, kernel 5.4.188+
Matplotlib Version
3.2.2
Matplotlib Backend
module://ipykernel.pylab.backend_inline
Python version
3.7.13
Jupyter version
5.3.1 (via google colab release 2022/6/10)
Installation
No response
Activity
oscargus commentedon Jul 6, 2022
FYI, in the current main branch they both look as the 0.253 case, so something has happened although it is still not as expected.
jklymak commentedon Jul 6, 2022
This is a duplicate of #12260 unfortunately Matplotlib cannot do proper 3D rendering.
kdbanman commentedon Jul 6, 2022
@jklymak #12260 appears to be about some quite unrelated example code. Can you explain the relationship to this issue?
tacaswell commentedon Jul 6, 2022
This is a known issue, I suspect a typo the cross referencing. I'm not sure what issue Jody was aiming for though.
kdbanman commentedon Jul 6, 2022
Thanks for the clarification @tacaswell! Upon further research, I see that the z-order of 3D objects with nontrivial occlusions is indeed a common issue.
Is it possible for me to contribute here? I have some experience with OpenGL. I notice this part of the current docs
and this part as well
jklymak commentedon Jul 6, 2022
Sorry #12620!
It would be great to have proper rendering but that is a big project!
dopplershift commentedon Jul 6, 2022
@kdbanman The problem is that Matplotlib doesn't really have a 3D-capable renderer/rasterizer. To do this properly you'd need to do one of:
kdbanman commentedon Jul 6, 2022
@dopplershift thanks for the context. mplot3d's capabilities are impressive, considering it's not already wrapped OpenGL. I had assumed there was a wrapper in place which might just need patching.
Is there an existing example of wrapped renderer in matplotlib I could refer to?
I'm curious to see a rough example of architecture. Obviously OpenGL is a bit of a different animal - I'm guessing platform and backend portability would be big challenges.
WeatherGod commentedon Jul 7, 2022