Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix marker overlap #15594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions lib/mpl_toolkits/mplot3d/art3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,27 @@ def do_3d_projection(self, renderer):

ecs = (_zalpha(self._edgecolor3d, vzs) if self._depthshade else
self._edgecolor3d)

# Sort the points based on z coordinates
# Performance optimization: Create a sorted index array and reorder
# points and point properties according to the index array
z_markers_idx = np.argsort(vzs)[::-1]

# Re-order items
vzs = vzs[z_markers_idx]
vxs = vxs[z_markers_idx]
vys = vys[z_markers_idx]
fcs = fcs[z_markers_idx]
ecs = ecs[z_markers_idx]
vps = np.vstack((vxs, vys)).T
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change to vstack.T instead of column_stack?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both are fine. I've changed to column_stack, which seems a bit clearer.

Interestingly, vstack.T is marginally faster for > 10k elements:
grafik
But 10ms difference is not the end of the world also for 1e6 elements. Probably all the surrounding code is much slower anyway.


fcs = mcolors.to_rgba_array(fcs, self._alpha)
ecs = mcolors.to_rgba_array(ecs, self._alpha)

self.set_edgecolors(ecs)
PathCollection.set_offsets(self, np.column_stack([vxs, vys]))
self.set_facecolors(fcs)

PathCollection.set_offsets(self, vps)

return np.min(vzs) if vzs.size else np.nan

Expand Down Expand Up @@ -663,17 +681,16 @@ def do_3d_projection(self, renderer):
in enumerate(zip(xyzlist, cface, cedge))),
key=lambda x: x[0], reverse=True)

segments_2d = [s for z, s, fc, ec, idx in z_segments_2d]
zzs, segments_2d, self._facecolors2d, self._edgecolors2d, idxs = \
zip(*z_segments_2d)

if self._codes3d is not None:
codes = [self._codes3d[idx] for z, s, fc, ec, idx in z_segments_2d]
codes = [self._codes3d[idx] for idx in idxs]
PolyCollection.set_verts_and_codes(self, segments_2d, codes)
else:
PolyCollection.set_verts(self, segments_2d, self._closed)

self._facecolors2d = [fc for z, s, fc, ec, idx in z_segments_2d]
if len(self._edgecolors3d) == len(cface):
self._edgecolors2d = [ec for z, s, fc, ec, idx in z_segments_2d]
else:
if len(self._edgecolors3d) != len(cface):
self._edgecolors2d = self._edgecolors3d

# Return zorder value
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions lib/mpl_toolkits/tests/test_mplot3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,51 @@ def test_scatter3d_color():
color='b', marker='s')


@pytest.mark.parametrize('azim', [-50, 130]) # yellow first, blue first
@check_figures_equal(extensions=['png'])
def test_marker_draw_order_data_reversed(fig_test, fig_ref, azim):
"""
Test that the draw order does not depend on the data point order.

For the given viewing angle at azim=-50, the yellow marker should be in
front. For azim=130, the blue marker should be in front.
"""
x = [-1, 1]
y = [1, -1]
z = [0, 0]
color = ['b', 'y']
ax = fig_test.add_subplot(projection='3d')
ax.scatter(x, y, z, s=3500, c=color)
ax.view_init(elev=0, azim=azim)
ax = fig_ref.add_subplot(projection='3d')
ax.scatter(x[::-1], y[::-1], z[::-1], s=3500, c=color[::-1])
ax.view_init(elev=0, azim=azim)


@check_figures_equal(extensions=['png'])
def test_marker_draw_order_view_rotated(fig_test, fig_ref):
"""
Test that the draw order changes with the direction.

If we rotate *azim* by 180 degrees and exchange the colors, the plot
plot should look the same again.
"""
azim = 130
x = [-1, 1]
y = [1, -1]
z = [0, 0]
color = ['b', 'y']
ax = fig_test.add_subplot(projection='3d')
# axis are not exactly invariant under 180 degree rotation -> deactivate
ax.set_axis_off()
ax.scatter(x, y, z, s=3500, c=color)
ax.view_init(elev=0, azim=azim)
ax = fig_ref.add_subplot(projection='3d')
ax.set_axis_off()
ax.scatter(x, y, z, s=3500, c=color[::-1]) # color reversed
ax.view_init(elev=0, azim=azim - 180) # view rotated by 180 degrees


@mpl3d_image_comparison(['plot_3d_from_2d.png'], tol=0.01)
def test_plot_3d_from_2d():
fig = plt.figure()
Expand Down