@@ -402,43 +402,34 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
402
402
# have to resample to the correct number of pixels
403
403
404
404
# TODO slice input array first
405
- inp_dtype = A .dtype
406
405
a_min = A .min ()
407
406
a_max = A .max ()
408
- # figure out the type we should scale to. For floats,
409
- # leave as is. For integers cast to an appropriate-sized
410
- # float. Small integers get smaller floats in an attempt
411
- # to keep the memory footprint reasonable.
412
- if a_min is np .ma .masked :
413
- # all masked, so values don't matter
407
+ if a_min is np .ma .masked : # All masked; values don't matter.
414
408
a_min , a_max = np .int32 (0 ), np .int32 (1 )
415
- if inp_dtype . kind == 'f' :
409
+ if A . dtype . kind == 'f' : # Float dtype: scale to same dtype.
416
410
scaled_dtype = np .dtype (
417
411
np .float64 if A .dtype .itemsize > 4 else np .float32 )
418
412
if scaled_dtype .itemsize < A .dtype .itemsize :
419
- _api .warn_external (
420
- f"Casting input data from { A . dtype } to "
421
- f" { scaled_dtype } for imshow" )
422
- else :
423
- # probably an integer of some type .
413
+ _api .warn_external (f"Casting input data from { A . dtype } "
414
+ f" to { scaled_dtype } for imshow." )
415
+ else : # Int dtype, likely.
416
+ # Scale to appropriately sized float: use float32 if the
417
+ # dynamic range is small, to limit the memory footprint .
424
418
da = a_max .astype (np .float64 ) - a_min .astype (np .float64 )
425
- # give more breathing room if a big dynamic range
426
419
scaled_dtype = np .float64 if da > 1e8 else np .float32
427
420
428
- # scale the input data to [.1, .9]. The Agg
429
- # interpolators clip to [0, 1] internally, use a
430
- # smaller input scale to identify which of the
431
- # interpolated points need to be should be flagged as
432
- # over / under.
433
- # This may introduce numeric instabilities in very broadly
434
- # scaled data
421
+ # Scale the input data to [.1, .9]. The Agg interpolators clip
422
+ # to [0, 1] internally, and we use a smaller input scale to
423
+ # identify the interpolated points that need to be flagged as
424
+ # over/under. This may introduce numeric instabilities in very
425
+ # broadly scaled data.
426
+
435
427
# Always copy, and don't allow array subtypes.
436
428
A_scaled = np .array (A , dtype = scaled_dtype )
437
- # clip scaled data around norm if necessary.
438
- # This is necessary for big numbers at the edge of
439
- # float64's ability to represent changes. Applying
440
- # a norm first would be good, but ruins the interpolation
441
- # of over numbers.
429
+ # Clip scaled data around norm if necessary. This is necessary
430
+ # for big numbers at the edge of float64's ability to represent
431
+ # changes. Applying a norm first would be good, but ruins the
432
+ # interpolation of over numbers.
442
433
self .norm .autoscale_None (A )
443
434
dv = np .float64 (self .norm .vmax ) - np .float64 (self .norm .vmin )
444
435
vmid = np .float64 (self .norm .vmin ) + dv / 2
@@ -456,30 +447,25 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
456
447
if newmax is not None or newmin is not None :
457
448
np .clip (A_scaled , newmin , newmax , out = A_scaled )
458
449
459
- # used to rescale the raw data to [offset, 1-offset]
460
- # so that the resampling code will run cleanly. Using
461
- # dyadic numbers here could reduce the error, but
462
- # would not full eliminate it and breaks a number of
463
- # tests (due to the slightly different error bouncing
464
- # some pixels across a boundary in the (very
450
+ # Rescale the raw data to [offset, 1-offset] so that the
451
+ # resampling code will run cleanly. Using dyadic numbers here
452
+ # could reduce the error, but would not full eliminate it and
453
+ # breaks a number of tests (due to the slightly different
454
+ # error bouncing some pixels across a boundary in the (very
465
455
# quantized) colormapping step).
466
456
offset = .1
467
457
frac = .8
468
- # we need to run the vmin/vmax through the same rescaling
469
- # that we run the raw data through because there are small
470
- # errors in the round-trip due to float precision. If we
471
- # do not run the vmin/vmax through the same pipeline we can
472
- # have values close or equal to the boundaries end up on the
473
- # wrong side.
458
+ # Run vmin/vmax through the same rescaling as the raw data;
459
+ # otherwise, data values close or equal to the boundaries can
460
+ # end up on the wrong side due to floating point error.
474
461
vmin , vmax = self .norm .vmin , self .norm .vmax
475
462
if vmin is np .ma .masked :
476
463
vmin , vmax = a_min , a_max
477
464
vrange = np .array ([vmin , vmax ], dtype = scaled_dtype )
478
465
479
466
A_scaled -= a_min
480
467
vrange -= a_min
481
- # a_min and a_max might be ndarray subclasses so use
482
- # item to avoid errors
468
+ # .item() handles a_min/a_max being ndarray subclasses.
483
469
a_min = a_min .astype (scaled_dtype ).item ()
484
470
a_max = a_max .astype (scaled_dtype ).item ()
485
471
@@ -490,13 +476,11 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
490
476
vrange += offset
491
477
# resample the input data to the correct resolution and shape
492
478
A_resampled = _resample (self , A_scaled , out_shape , t )
493
- # done with A_scaled now, remove from namespace to be sure!
494
- del A_scaled
495
- # un-scale the resampled data to approximately the
496
- # original range things that interpolated to above /
497
- # below the original min/max will still be above /
498
- # below, but possibly clipped in the case of higher order
499
- # interpolation + drastically changing data.
479
+ del A_scaled # Make sure we don't use A_scaled anymore!
480
+ # Un-scale the resampled data to approximately the original
481
+ # range. Things that interpolated to outside the original range
482
+ # will still be outside, but possibly clipped in the case of
483
+ # higher order interpolation + drastically changing data.
500
484
A_resampled -= offset
501
485
vrange -= offset
502
486
if a_min != a_max :
@@ -514,8 +498,7 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
514
498
# we always have to interpolate the mask to account for
515
499
# non-affine transformations
516
500
out_alpha = _resample (self , mask , out_shape , t , resample = True )
517
- # done with the mask now, delete from namespace to be sure!
518
- del mask
501
+ del mask # Make sure we don't use mask anymore!
519
502
# Agg updates out_alpha in place. If the pixel has no image
520
503
# data it will not be updated (and still be 0 as we initialized
521
504
# it), if input data that would go into that output pixel than
@@ -539,12 +522,9 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
539
522
s_vmin = np .finfo (scaled_dtype ).eps
540
523
# Block the norm from sending an update signal during the
541
524
# temporary vmin/vmax change
542
- with self .norm .callbacks .blocked ():
543
- with cbook ._setattr_cm (self .norm ,
544
- vmin = s_vmin ,
545
- vmax = s_vmax ,
546
- ):
547
- output = self .norm (resampled_masked )
525
+ with self .norm .callbacks .blocked (), \
526
+ cbook ._setattr_cm (self .norm , vmin = s_vmin , vmax = s_vmax ):
527
+ output = self .norm (resampled_masked )
548
528
else :
549
529
if A .ndim == 2 : # _interpolation_stage == 'rgba'
550
530
self .norm .autoscale_None (A )
@@ -558,8 +538,7 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
558
538
self , _rgb_to_rgba (A [..., :3 ]), out_shape , t , alpha = alpha )
559
539
output [..., 3 ] = output_alpha # recombine rgb and alpha
560
540
561
- # at this point output is either a 2D array of normed data
562
- # (of int or float)
541
+ # output is now either a 2D array of normed (int or float) data
563
542
# or an RGBA array of re-sampled input
564
543
output = self .to_rgba (output , bytes = True , norm = False )
565
544
# output is now a correctly sized RGBA array of uint8
@@ -568,17 +547,15 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
568
547
if A .ndim == 2 :
569
548
alpha = self ._get_scalar_alpha ()
570
549
alpha_channel = output [:, :, 3 ]
571
- alpha_channel [:] = np .asarray (
572
- np .asarray (alpha_channel , np .float32 ) * out_alpha * alpha ,
573
- np .uint8 )
550
+ alpha_channel [:] = (
551
+ alpha_channel .astype (np .float32 ) * out_alpha * alpha )
574
552
575
553
else :
576
554
if self ._imcache is None :
577
555
self ._imcache = self .to_rgba (A , bytes = True , norm = (A .ndim == 2 ))
578
556
output = self ._imcache
579
557
580
- # Subset the input image to only the part that will be
581
- # displayed
558
+ # Subset the input image to only the part that will be displayed.
582
559
subset = TransformedBbox (clip_bbox , t0 .inverted ()).frozen ()
583
560
output = output [
584
561
int (max (subset .ymin , 0 )):
0 commit comments