Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a8709b5

Browse filesBrowse files
authored
Merge pull request #18375 from meeseeksmachine/auto-backport-of-pr-18293-on-v3.3.x
Backport PR #18293 on branch v3.3.x (Fix scatter3d color/linewidth re-projection)
2 parents 63e7554 + 80fbbb1 commit a8709b5
Copy full SHA for a8709b5

File tree

Expand file treeCollapse file tree

2 files changed

+57
-33
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+57
-33
lines changed

‎lib/mpl_toolkits/mplot3d/art3d.py

Copy file name to clipboardExpand all lines: lib/mpl_toolkits/mplot3d/art3d.py
+7-5Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ def set_3d_properties(self, zs, zdir):
482482
self._facecolor3d = self.get_facecolor()
483483
self._edgecolor3d = self.get_edgecolor()
484484
self._sizes3d = self.get_sizes()
485+
self._linewidth3d = self.get_linewidth()
485486
self.stale = True
486487

487488
def do_3d_projection(self, renderer):
@@ -490,13 +491,10 @@ def do_3d_projection(self, renderer):
490491

491492
fcs = (_zalpha(self._facecolor3d, vzs) if self._depthshade else
492493
self._facecolor3d)
493-
fcs = mcolors.to_rgba_array(fcs, self._alpha)
494-
self.set_facecolors(fcs)
495-
496494
ecs = (_zalpha(self._edgecolor3d, vzs) if self._depthshade else
497495
self._edgecolor3d)
498-
499496
sizes = self._sizes3d
497+
lws = self._linewidth3d
500498

501499
# Sort the points based on z coordinates
502500
# Performance optimization: Create a sorted index array and reorder
@@ -507,11 +505,14 @@ def do_3d_projection(self, renderer):
507505
vzs = vzs[z_markers_idx]
508506
vxs = vxs[z_markers_idx]
509507
vys = vys[z_markers_idx]
510-
if self._depthshade:
508+
if len(fcs) > 1:
511509
fcs = fcs[z_markers_idx]
510+
if len(ecs) > 1:
512511
ecs = ecs[z_markers_idx]
513512
if len(sizes) > 1:
514513
sizes = sizes[z_markers_idx]
514+
if len(lws) > 1:
515+
lws = lws[z_markers_idx]
515516
vps = np.column_stack((vxs, vys))
516517

517518
fcs = mcolors.to_rgba_array(fcs, self._alpha)
@@ -520,6 +521,7 @@ def do_3d_projection(self, renderer):
520521
self.set_edgecolors(ecs)
521522
self.set_facecolors(fcs)
522523
self.set_sizes(sizes)
524+
self.set_linewidth(lws)
523525

524526
PathCollection.set_offsets(self, vps)
525527

‎lib/mpl_toolkits/tests/test_mplot3d.py

Copy file name to clipboardExpand all lines: lib/mpl_toolkits/tests/test_mplot3d.py
+50-28Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.