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

Skip to content

Commit c3b37ca

Browse files
authored
Merge pull request #17636 from tacaswell/fix_image_vlim_clipping_again
Fix image vlim clipping again
2 parents efda565 + ca53448 commit c3b37ca

File tree

5 files changed

+134
-60
lines changed

5 files changed

+134
-60
lines changed

lib/matplotlib/image.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -460,15 +460,36 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
460460
if newmax is not None or newmin is not None:
461461
np.clip(A_scaled, newmin, newmax, out=A_scaled)
462462

463+
# used to rescale the raw data to [offset, 1-offset]
464+
# so that the resampling code will run cleanly. Using
465+
# dyadic numbers here could reduce the error, but
466+
# would not full eliminate it and breaks a number of
467+
# tests (due to the slightly different error bouncing
468+
# some pixels across a boundary in the (very
469+
# quantized) color mapping step).
470+
offset = .1
471+
frac = .8
472+
# we need to run the vmin/vmax through the same rescaling
473+
# that we run the raw data through because there are small
474+
# errors in the round-trip due to float precision. If we
475+
# do not run the vmin/vmax through the same pipeline we can
476+
# have values close or equal to the boundaries end up on the
477+
# wrong side.
478+
vrange = np.array([self.norm.vmin, self.norm.vmax],
479+
dtype=scaled_dtype)
480+
463481
A_scaled -= a_min
482+
vrange -= a_min
464483
# a_min and a_max might be ndarray subclasses so use
465484
# item to avoid errors
466485
a_min = a_min.astype(scaled_dtype).item()
467486
a_max = a_max.astype(scaled_dtype).item()
468487

469488
if a_min != a_max:
470-
A_scaled /= ((a_max - a_min) / 0.8)
471-
A_scaled += 0.1
489+
A_scaled /= ((a_max - a_min) / frac)
490+
vrange /= ((a_max - a_min) / frac)
491+
A_scaled += offset
492+
vrange += offset
472493
# resample the input data to the correct resolution and shape
473494
A_resampled = _resample(self, A_scaled, out_shape, t)
474495
# done with A_scaled now, remove from namespace to be sure!
@@ -478,10 +499,13 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
478499
# below the original min/max will still be above /
479500
# below, but possibly clipped in the case of higher order
480501
# interpolation + drastically changing data.
481-
A_resampled -= 0.1
502+
A_resampled -= offset
503+
vrange -= offset
482504
if a_min != a_max:
483-
A_resampled *= ((a_max - a_min) / 0.8)
505+
A_resampled *= ((a_max - a_min) / frac)
506+
vrange *= ((a_max - a_min) / frac)
484507
A_resampled += a_min
508+
vrange += a_min
485509
# if using NoNorm, cast back to the original datatype
486510
if isinstance(self.norm, mcolors.NoNorm):
487511
A_resampled = A_resampled.astype(A.dtype)
@@ -508,7 +532,14 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
508532
out_alpha *= _resample(self, alpha, out_shape,
509533
t, resample=True)
510534
# mask and run through the norm
511-
output = self.norm(np.ma.masked_array(A_resampled, out_mask))
535+
resampled_masked = np.ma.masked_array(A_resampled, out_mask)
536+
# we have re-set the vmin/vmax to account for small errors
537+
# that may have moved input values in/out of range
538+
with cbook._setattr_cm(self.norm,
539+
vmin=vrange[0],
540+
vmax=vrange[1],
541+
):
542+
output = self.norm(resampled_masked)
512543
else:
513544
if A.shape[2] == 3:
514545
A = _rgb_to_rgba(A)
Binary file not shown.

0 commit comments

Comments
 (0)