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

Skip to content

Commit cc10355

Browse files
authored
Merge pull request #17378 from timhoffm/fix-marker-overlap2
FIX: marker overlap order in 3D scatter
2 parents a6f82b9 + 4428da6 commit cc10355

File tree

2 files changed

+69
-7
lines changed

2 files changed

+69
-7
lines changed

lib/mpl_toolkits/mplot3d/art3d.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -494,9 +494,27 @@ def do_3d_projection(self, renderer):
494494

495495
ecs = (_zalpha(self._edgecolor3d, vzs) if self._depthshade else
496496
self._edgecolor3d)
497+
498+
# Sort the points based on z coordinates
499+
# Performance optimization: Create a sorted index array and reorder
500+
# points and point properties according to the index array
501+
z_markers_idx = np.argsort(vzs)[::-1]
502+
503+
# Re-order items
504+
vzs = vzs[z_markers_idx]
505+
vxs = vxs[z_markers_idx]
506+
vys = vys[z_markers_idx]
507+
fcs = fcs[z_markers_idx]
508+
ecs = ecs[z_markers_idx]
509+
vps = np.column_stack((vxs, vys))
510+
511+
fcs = mcolors.to_rgba_array(fcs, self._alpha)
497512
ecs = mcolors.to_rgba_array(ecs, self._alpha)
513+
498514
self.set_edgecolors(ecs)
499-
PathCollection.set_offsets(self, np.column_stack([vxs, vys]))
515+
self.set_facecolors(fcs)
516+
517+
PathCollection.set_offsets(self, vps)
500518

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

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

666-
segments_2d = [s for z, s, fc, ec, idx in z_segments_2d]
684+
zzs, segments_2d, self._facecolors2d, self._edgecolors2d, idxs = \
685+
zip(*z_segments_2d)
686+
667687
if self._codes3d is not None:
668-
codes = [self._codes3d[idx] for z, s, fc, ec, idx in z_segments_2d]
688+
codes = [self._codes3d[idx] for idx in idxs]
669689
PolyCollection.set_verts_and_codes(self, segments_2d, codes)
670690
else:
671691
PolyCollection.set_verts(self, segments_2d, self._closed)
672692

673-
self._facecolors2d = [fc for z, s, fc, ec, idx in z_segments_2d]
674-
if len(self._edgecolors3d) == len(cface):
675-
self._edgecolors2d = [ec for z, s, fc, ec, idx in z_segments_2d]
676-
else:
693+
if len(self._edgecolors3d) != len(cface):
677694
self._edgecolors2d = self._edgecolors3d
678695

679696
# Return zorder value

lib/mpl_toolkits/tests/test_mplot3d.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,51 @@ def test_scatter3d_color():
230230
color='b', marker='s')
231231

232232

233+
@pytest.mark.parametrize('azim', [-50, 130]) # yellow first, blue first
234+
@check_figures_equal(extensions=['png'])
235+
def test_marker_draw_order_data_reversed(fig_test, fig_ref, azim):
236+
"""
237+
Test that the draw order does not depend on the data point order.
238+
239+
For the given viewing angle at azim=-50, the yellow marker should be in
240+
front. For azim=130, the blue marker should be in front.
241+
"""
242+
x = [-1, 1]
243+
y = [1, -1]
244+
z = [0, 0]
245+
color = ['b', 'y']
246+
ax = fig_test.add_subplot(projection='3d')
247+
ax.scatter(x, y, z, s=3500, c=color)
248+
ax.view_init(elev=0, azim=azim)
249+
ax = fig_ref.add_subplot(projection='3d')
250+
ax.scatter(x[::-1], y[::-1], z[::-1], s=3500, c=color[::-1])
251+
ax.view_init(elev=0, azim=azim)
252+
253+
254+
@check_figures_equal(extensions=['png'])
255+
def test_marker_draw_order_view_rotated(fig_test, fig_ref):
256+
"""
257+
Test that the draw order changes with the direction.
258+
259+
If we rotate *azim* by 180 degrees and exchange the colors, the plot
260+
plot should look the same again.
261+
"""
262+
azim = 130
263+
x = [-1, 1]
264+
y = [1, -1]
265+
z = [0, 0]
266+
color = ['b', 'y']
267+
ax = fig_test.add_subplot(projection='3d')
268+
# axis are not exactly invariant under 180 degree rotation -> deactivate
269+
ax.set_axis_off()
270+
ax.scatter(x, y, z, s=3500, c=color)
271+
ax.view_init(elev=0, azim=azim)
272+
ax = fig_ref.add_subplot(projection='3d')
273+
ax.set_axis_off()
274+
ax.scatter(x, y, z, s=3500, c=color[::-1]) # color reversed
275+
ax.view_init(elev=0, azim=azim - 180) # view rotated by 180 degrees
276+
277+
233278
@mpl3d_image_comparison(['plot_3d_from_2d.png'], tol=0.01)
234279
def test_plot_3d_from_2d():
235280
fig = plt.figure()

0 commit comments

Comments
 (0)