|
1 | 1 | import functools
|
| 2 | +import itertools |
2 | 3 |
|
3 | 4 | import pytest
|
4 | 5 |
|
@@ -242,39 +243,60 @@ def test_scatter3d_color():
|
242 | 243 | color='b', marker='s')
|
243 | 244 |
|
244 | 245 |
|
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.""" |
254 | 250 |
|
| 251 | + y, x = np.mgrid[:10, :10] |
| 252 | + z = np.arange(x.size).reshape(x.shape) |
255 | 253 |
|
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 |
268 | 257 |
|
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' |
271 | 262 |
|
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' |
274 | 267 |
|
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) |
278 | 300 |
|
279 | 301 |
|
280 | 302 | @pytest.mark.parametrize('azim', [-50, 130]) # yellow first, blue first
|
|
0 commit comments