@@ -402,43 +402,34 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
402402 # have to resample to the correct number of pixels
403403
404404 # TODO slice input array first
405- inp_dtype = A .dtype
406405 a_min = A .min ()
407406 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.
414408 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.
416410 scaled_dtype = np .dtype (
417411 np .float64 if A .dtype .itemsize > 4 else np .float32 )
418412 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 .
424418 da = a_max .astype (np .float64 ) - a_min .astype (np .float64 )
425- # give more breathing room if a big dynamic range
426419 scaled_dtype = np .float64 if da > 1e8 else np .float32
427420
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+
435427 # Always copy, and don't allow array subtypes.
436428 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.
442433 self .norm .autoscale_None (A )
443434 dv = np .float64 (self .norm .vmax ) - np .float64 (self .norm .vmin )
444435 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,
456447 if newmax is not None or newmin is not None :
457448 np .clip (A_scaled , newmin , newmax , out = A_scaled )
458449
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 fully 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
465455 # quantized) colormapping step).
466456 offset = .1
467457 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.
474461 vmin , vmax = self .norm .vmin , self .norm .vmax
475462 if vmin is np .ma .masked :
476463 vmin , vmax = a_min , a_max
477464 vrange = np .array ([vmin , vmax ], dtype = scaled_dtype )
478465
479466 A_scaled -= a_min
480467 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.
483469 a_min = a_min .astype (scaled_dtype ).item ()
484470 a_max = a_max .astype (scaled_dtype ).item ()
485471
@@ -490,13 +476,11 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
490476 vrange += offset
491477 # resample the input data to the correct resolution and shape
492478 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.
500484 A_resampled -= offset
501485 vrange -= offset
502486 if a_min != a_max :
@@ -514,8 +498,7 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
514498 # we always have to interpolate the mask to account for
515499 # non-affine transformations
516500 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!
519502 # Agg updates out_alpha in place. If the pixel has no image
520503 # data it will not be updated (and still be 0 as we initialized
521504 # 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,
539522 s_vmin = np .finfo (scaled_dtype ).eps
540523 # Block the norm from sending an update signal during the
541524 # 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 )
548528 else :
549529 if A .ndim == 2 : # _interpolation_stage == 'rgba'
550530 self .norm .autoscale_None (A )
@@ -558,8 +538,7 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
558538 self , _rgb_to_rgba (A [..., :3 ]), out_shape , t , alpha = alpha )
559539 output [..., 3 ] = output_alpha # recombine rgb and alpha
560540
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
563542 # or an RGBA array of re-sampled input
564543 output = self .to_rgba (output , bytes = True , norm = False )
565544 # 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,
568547 if A .ndim == 2 :
569548 alpha = self ._get_scalar_alpha ()
570549 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 [:] = ( # Assignment will cast to uint8.
551+ alpha_channel .astype (np .float32 ) * out_alpha * alpha )
574552
575553 else :
576554 if self ._imcache is None :
577555 self ._imcache = self .to_rgba (A , bytes = True , norm = (A .ndim == 2 ))
578556 output = self ._imcache
579557
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.
582559 subset = TransformedBbox (clip_bbox , t0 .inverted ()).frozen ()
583560 output = output [
584561 int (max (subset .ymin , 0 )):
0 commit comments