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

Skip to content

Commit 52f7f42

Browse files
authored
Merge pull request #18293 from QuLogic/scatter3d-color
Fix scatter3d color/linewidth re-projection
2 parents 705a140 + 828c60b commit 52f7f42

File tree

2 files changed

+57
-33
lines changed

2 files changed

+57
-33
lines changed

lib/mpl_toolkits/mplot3d/art3d.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ def set_3d_properties(self, zs, zdir):
488488
self._facecolor3d = self.get_facecolor()
489489
self._edgecolor3d = self.get_edgecolor()
490490
self._sizes3d = self.get_sizes()
491+
self._linewidth3d = self.get_linewidth()
491492
self.stale = True
492493

493494
def do_3d_projection(self, renderer):
@@ -496,13 +497,10 @@ def do_3d_projection(self, renderer):
496497

497498
fcs = (_zalpha(self._facecolor3d, vzs) if self._depthshade else
498499
self._facecolor3d)
499-
fcs = mcolors.to_rgba_array(fcs, self._alpha)
500-
self.set_facecolors(fcs)
501-
502500
ecs = (_zalpha(self._edgecolor3d, vzs) if self._depthshade else
503501
self._edgecolor3d)
504-
505502
sizes = self._sizes3d
503+
lws = self._linewidth3d
506504

507505
# Sort the points based on z coordinates
508506
# Performance optimization: Create a sorted index array and reorder
@@ -513,11 +511,14 @@ def do_3d_projection(self, renderer):
513511
vzs = vzs[z_markers_idx]
514512
vxs = vxs[z_markers_idx]
515513
vys = vys[z_markers_idx]
516-
if self._depthshade:
514+
if len(fcs) > 1:
517515
fcs = fcs[z_markers_idx]
516+
if len(ecs) > 1:
518517
ecs = ecs[z_markers_idx]
519518
if len(sizes) > 1:
520519
sizes = sizes[z_markers_idx]
520+
if len(lws) > 1:
521+
lws = lws[z_markers_idx]
521522
vps = np.column_stack((vxs, vys))
522523

523524
fcs = mcolors.to_rgba_array(fcs, self._alpha)
@@ -526,6 +527,7 @@ def do_3d_projection(self, renderer):
526527
self.set_edgecolors(ecs)
527528
self.set_facecolors(fcs)
528529
self.set_sizes(sizes)
530+
self.set_linewidth(lws)
529531

530532
PathCollection.set_offsets(self, vps)
531533

lib/mpl_toolkits/tests/test_mplot3d.py

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import functools
2+
import itertools
23

34
import pytest
45

@@ -242,39 +243,60 @@ def test_scatter3d_color():
242243
color='b', marker='s')
243244

244245

245-
def test_scatter3d_depthshade_false():
246-
"""
247-
Test that 3d scatter plot doesn't throw
248-
IndexError with depthshade=False (issue #18037)
249-
"""
250-
x = y = z = np.arange(16)
251-
fig_test = plt.figure()
252-
ax_test = fig_test.add_subplot(projection='3d')
253-
ax_test.scatter(x, y, z, depthshade=False)
246+
@pytest.mark.parametrize('depthshade', [True, False])
247+
@check_figures_equal(extensions=['png'])
248+
def test_scatter3d_sorting(fig_ref, fig_test, depthshade):
249+
"""Test that marker properties are correctly sorted."""
254250

251+
y, x = np.mgrid[:10, :10]
252+
z = np.arange(x.size).reshape(x.shape)
255253

256-
@check_figures_equal(extensions=['png'])
257-
def test_scatter3d_size(fig_ref, fig_test):
258-
"""Test that large markers in correct position (issue #18135)"""
259-
x = np.arange(10)
260-
x, y = np.meshgrid(x, x)
261-
z = np.arange(100).reshape(10, 10)
262-
263-
s = np.full(z.shape, 5)
264-
s[0, 0] = 100
265-
s[-1, 0] = 100
266-
s[0, -1] = 100
267-
s[-1, -1] = 100
254+
sizes = np.full(z.shape, 25)
255+
sizes[0::2, 0::2] = 100
256+
sizes[1::2, 1::2] = 100
268257

269-
ax_ref = fig_ref.gca(projection='3d')
270-
ax_test = fig_test.gca(projection='3d')
258+
facecolors = np.full(z.shape, 'C0')
259+
facecolors[:5, :5] = 'C1'
260+
facecolors[6:, :4] = 'C2'
261+
facecolors[6:, 6:] = 'C3'
271262

272-
small = np.ma.masked_array(z, s == 100, dtype=float)
273-
large = np.ma.masked_array(z, s != 100, dtype=float)
263+
edgecolors = np.full(z.shape, 'C4')
264+
edgecolors[1:5, 1:5] = 'C5'
265+
edgecolors[5:9, 1:5] = 'C6'
266+
edgecolors[5:9, 5:9] = 'C7'
274267

275-
ax_ref.scatter(x, y, large, s=100, c="C0", alpha=1)
276-
ax_ref.scatter(x, y, small, s=5, c="C0", alpha=1)
277-
ax_test.scatter(x, y, z, s=s, c="C0", alpha=1)
268+
linewidths = np.full(z.shape, 2)
269+
linewidths[0::2, 0::2] = 5
270+
linewidths[1::2, 1::2] = 5
271+
272+
x, y, z, sizes, facecolors, edgecolors, linewidths = [
273+
a.flatten()
274+
for a in [x, y, z, sizes, facecolors, edgecolors, linewidths]
275+
]
276+
277+
ax_ref = fig_ref.gca(projection='3d')
278+
sets = (np.unique(a) for a in [sizes, facecolors, edgecolors, linewidths])
279+
for s, fc, ec, lw in itertools.product(*sets):
280+
subset = (
281+
(sizes != s) |
282+
(facecolors != fc) |
283+
(edgecolors != ec) |
284+
(linewidths != lw)
285+
)
286+
subset = np.ma.masked_array(z, subset, dtype=float)
287+
288+
# When depth shading is disabled, the colors are passed through as
289+
# single-item lists; this triggers single path optimization. The
290+
# following reshaping is a hack to disable that, since the optimization
291+
# would not occur for the full scatter which has multiple colors.
292+
fc = np.repeat(fc, sum(~subset.mask))
293+
294+
ax_ref.scatter(x, y, subset, s=s, fc=fc, ec=ec, lw=lw, alpha=1,
295+
depthshade=depthshade)
296+
297+
ax_test = fig_test.gca(projection='3d')
298+
ax_test.scatter(x, y, z, s=sizes, fc=facecolors, ec=edgecolors,
299+
lw=linewidths, alpha=1, depthshade=depthshade)
278300

279301

280302
@pytest.mark.parametrize('azim', [-50, 130]) # yellow first, blue first

0 commit comments

Comments
 (0)