From 97a00bcfc2f3fa3d7cc0152c1e147d2df49ceb4c Mon Sep 17 00:00:00 2001 From: NJMarchese Date: Tue, 1 Jul 2025 10:41:57 -0700 Subject: [PATCH 1/3] Added ability to do segmented peak detection on polar transform of DP --- py4DSTEM/process/diffraction/flowlines.py | 6 +- py4DSTEM/process/polar/polar_datacube.py | 3 + py4DSTEM/process/polar/polar_peaks.py | 442 +++++++++++++++++++++- py4DSTEM/visualize/vis_special.py | 4 + 4 files changed, 449 insertions(+), 6 deletions(-) diff --git a/py4DSTEM/process/diffraction/flowlines.py b/py4DSTEM/process/diffraction/flowlines.py index 5af64f73e..25167f671 100644 --- a/py4DSTEM/process/diffraction/flowlines.py +++ b/py4DSTEM/process/diffraction/flowlines.py @@ -1297,7 +1297,11 @@ def fit_dist(x, *coefs): z = np.maximum(z, 1.0) coefs = [np.max(z), np.min(z), x[-1] * 0.25, 2] bounds = ((1e-3, 0, 1e-3, 1.0), (np.inf, np.inf, np.inf, np.inf)) - coefs = curve_fit(fit_dist, x, z, p0=coefs, bounds=bounds)[0] + try: + coefs = curve_fit(fit_dist, x, z, p0=coefs, bounds=bounds)[0] + except RuntimeError as e: + print(f"A runtime error has occured: {e}") + continue coef_annular = coefs[2] * (np.log(1 / fraction_coefs) ** (1 / coefs[3])) if orient_corr[ind, 0, 0] <= orient_corr[ind, -1, 0]: coef_annular = orient_corr.shape[1] - 1 - coef_annular diff --git a/py4DSTEM/process/polar/polar_datacube.py b/py4DSTEM/process/polar/polar_datacube.py index de3c463b8..3d3ea33c4 100644 --- a/py4DSTEM/process/polar/polar_datacube.py +++ b/py4DSTEM/process/polar/polar_datacube.py @@ -115,6 +115,9 @@ def __init__( plot_radial_background, model_radial_background, make_orientation_histogram, + # Added + find_peaks_single_pattern_segmented, + find_peaks_segmented, ) # sampling methods + properties diff --git a/py4DSTEM/process/polar/polar_peaks.py b/py4DSTEM/process/polar/polar_peaks.py index 16d0531db..4eecf030e 100644 --- a/py4DSTEM/process/polar/polar_peaks.py +++ b/py4DSTEM/process/polar/polar_peaks.py @@ -160,6 +160,8 @@ def find_peaks_single_pattern( sub = im_mask > 0.001 * np.max(im_mask) im_polar_sm[sub] /= im_mask[sub] + # return im_polar_sm + # Find local maxima peaks = peak_local_max( im_polar_sm, @@ -309,8 +311,10 @@ def find_peaks_single_pattern( t = np.linspace(0, 2 * np.pi, 180 + 1) ct = np.cos(t) st = np.sin(t) - - fig, ax = plt.subplots(figsize=figsize) + if kwargs.get('figax'): + fig, ax = kwargs.pop('figax') + else: + fig, ax = plt.subplots(figsize=figsize) cmap = kwargs.pop("cmap", "gray") vmax = kwargs.pop("vmax", 1) @@ -321,7 +325,8 @@ def find_peaks_single_pattern( ax.scatter( peaks_polar["qr"], peaks_polar["qt"], - s=peaks_polar["intensity"] * plot_scale_size, + # s=peaks_polar["intensity"] * plot_scale_size, + s=10, marker="o", color=(1, 0, 0), ) @@ -370,9 +375,285 @@ def find_peaks_single_pattern( return peaks_polar +def find_peaks_single_pattern_segmented( + self, + x, + y, + mask=None, + bragg_peaks=None, + bragg_mask_radius=None, + sigma_annular_deg=10.0, + sigma_radial_px=3.0, + sigma_annular_deg_max=None, + radial_background_subtract=True, + radial_background_thresh=0.25, + num_peaks_max=100, + threshold_abs=1.0, + threshold_prom_annular=None, + threshold_prom_radial=None, + remove_masked_peaks=False, + scale_sigma_annular=0.5, + scale_sigma_radial=0.25, + return_background=False, + plot_result=True, + plot_power_scale=1.0, + plot_scale_size=10.0, + figsize=(12, 6), + returnfig=False, + **kwargs +): + """ + Peak detection function for polar transformations. + + Parameters + -------- + x: int + x index of diffraction pattern + y: int + y index of diffraction pattern + mask: np.array + Boolean mask in Cartesian space, to filter detected peaks. + bragg_peaks: py4DSTEM.BraggVectors + Set of Bragg peaks used to generated a mask in Cartesian space, to filter detected peaks + sigma_annular_deg: float + smoothing along the annular direction in degrees, periodic + sigma_radial_px: float + smoothing along the radial direction in pixels, not periodic + sigma_annular_deg_max: float + Specify this value for the max annular sigma. Peaks larger than this will be split + into multiple peaks, depending on the ratio. + radial_background_subtract: bool + If true, subtract radial background estimate + radial_background_thresh: float + Relative order of sorted values to use as background estimate. + Setting to 0.5 is equivalent to median, 0.0 is min value. + num_peaks_max = 100 + Max number of peaks to return. + threshold_abs: float + Absolute image intensity threshold for peaks. + threshold_prom_annular: float + Threshold for prominance, along annular direction. + threshold_prom_radial: float + Threshold for prominance, along radial direction. + remove_masked_peaks: bool + Delete peaks that are in the region masked by "mask" + scale_sigma_annular: float + Scaling of the estimated annular standard deviation. + scale_sigma_radial: float + Scaling of the estimated radial standard deviation. + return_background: bool + Return the background signal. + plot_result: + Plot the detector peaks + plot_power_scale: float + Image intensity power law scaling. + plot_scale_size: float + Marker scaling in the plot. + figsize: 2-tuple + Size of the result plotting figure. + returnfig: bool + Return the figure and axes handles. + + Returns + -------- + + peaks_polar : pointlist + The detected peaks + fig, ax : (optional) + Figure and axes handles + + """ + + from skimage.feature import peak_local_max + + # if needed, generate mask from Bragg peaks + if bragg_peaks is not None: + mask_bragg = self._datacube.get_braggmask( + bragg_peaks, + x, + y, + radius=bragg_mask_radius, + ) + if mask is None: + mask = mask_bragg + else: + mask = np.logical_or(mask, mask_bragg) + + # Convert sigma values into units of bins + sigma_annular = np.deg2rad(sigma_annular_deg) / self.annular_step + sigma_radial = sigma_radial_px / self.qstep + + # Get transformed image and normalization array + im_polar, im_polar_norm, norm_array, mask_bool = self.transform( + self._datacube.data[x, y], + mask=mask, + returnval="all_zeros", + origin=(self.calibration.qx0[x, y], self.calibration.qy0[x, y]), + ) + # Change sign convention of mask + mask_bool = np.logical_not(mask_bool) + + # Background subtraction + if radial_background_subtract: + sig_bg = np.zeros(im_polar.shape[1]) + for a0 in range(im_polar.shape[1]): + if np.any(mask_bool[:, a0]): + vals = np.sort(im_polar[mask_bool[:, a0], a0]) + ind = np.round(radial_background_thresh * (vals.shape[0] - 1)).astype( + "int" + ) + sig_bg[a0] = vals[ind] + sig_bg_mask = np.sum(mask_bool, axis=0) >= (im_polar.shape[0] // 2) + im_polar = np.maximum(im_polar - sig_bg[None, :], 0) + + # apply smoothing and normalization + im_polar_sm = gaussian_filter( + im_polar * norm_array, + sigma=(sigma_annular, sigma_radial), + mode=("wrap", "nearest"), + ) + im_mask = gaussian_filter( + norm_array, + sigma=(sigma_annular, sigma_radial), + mode=("wrap", "nearest"), + ) + sub = im_mask > 0.001 * np.max(im_mask) + im_polar_sm[sub] /= im_mask[sub] + + # return im_polar_sm + + # Find local maxima + peaks = peak_local_max( + im_polar_sm, + num_peaks=num_peaks_max, + threshold_abs=threshold_abs, + exclude_border=False, + ) + + # check if peaks should be removed from the polar transformation mask + if remove_masked_peaks: + peaks = np.delete( + peaks, + mask_bool[peaks[:, 0], peaks[:, 1]] == False, # noqa: E712 + axis=0, + ) + + # peak intensity + peaks_int = im_polar_sm[peaks[:, 0], peaks[:, 1]] + + # Estimate prominance of peaks, and their size in units of pixels + peaks_prom = np.zeros((peaks.shape[0], 4)) + annular_ind_center = np.atleast_1d( + np.array(im_polar_sm.shape[0] // 2).astype("int") + ) + for a0 in range(peaks.shape[0]): + # annular + trace_annular = np.roll( + np.squeeze(im_polar_sm[:, peaks[a0, 1]]), annular_ind_center - peaks[a0, 0] + ) + p_annular = peak_prominences( + trace_annular, + annular_ind_center, + ) + sigma_annular = scale_sigma_annular * np.minimum( + annular_ind_center - p_annular[1], p_annular[2] - annular_ind_center + ) + + # radial + trace_radial = im_polar_sm[peaks[a0, 0], :] + p_radial = peak_prominences( + trace_radial, + np.atleast_1d(peaks[a0, 1]), + ) + sigma_radial = scale_sigma_radial * np.minimum( + peaks[a0, 1] - p_radial[1], p_radial[2] - peaks[a0, 1] + ) + + # output + peaks_prom[a0, 0] = p_annular[0] + peaks_prom[a0, 1] = sigma_annular[0] + peaks_prom[a0, 2] = p_radial[0] + peaks_prom[a0, 3] = sigma_radial[0] + + # if needed, remove peaks using prominance criteria + if threshold_prom_annular is not None: + remove = peaks_prom[:, 0] < threshold_prom_annular + peaks = np.delete( + peaks, + remove, + axis=0, + ) + peaks_int = np.delete( + peaks_int, + remove, + ) + peaks_prom = np.delete( + peaks_prom, + remove, + axis=0, + ) + if threshold_prom_radial is not None: + remove = peaks_prom[:, 2] < threshold_prom_radial + peaks = np.delete( + peaks, + remove, + axis=0, + ) + peaks_int = np.delete( + peaks_int, + remove, + ) + peaks_prom = np.delete( + peaks_prom, + remove, + axis=0, + ) + + # combine peaks into one array + peaks_all = np.column_stack((peaks, peaks_int, peaks_prom)) + + # Split peaks into multiple peaks if they have sigma values larger than user-specified threshold + if sigma_annular_deg_max is not None: + peaks_new = np.zeros((0, peaks_all.shape[1])) + for a0 in range(peaks_all.shape[0]): + if peaks_all[a0, 4] >= (1.5 * sigma_annular_deg_max): + num = np.round(peaks_all[a0, 4] / sigma_annular_deg_max) + sigma_annular_new = peaks_all[a0, 4] / num + + v = np.arange(num) + v -= np.mean(v) + t_new = np.mod( + peaks_all[a0, 0] + 2 * v * sigma_annular_new, self._n_annular + ) + + for a1 in range(num.astype("int")): + peaks_new = np.vstack( + ( + peaks_new, + np.array( + ( + t_new[a1], + peaks_all[a0, 1], + peaks_all[a0, 2], + peaks_all[a0, 3], + sigma_annular_new, + peaks_all[a0, 5], + peaks_all[a0, 6], + ) + ), + ) + ) + else: + peaks_new = np.vstack((peaks_new, peaks_all[a0, :])) + peaks_all = peaks_new + + return peaks_all, sig_bg, sig_bg_mask + + def find_peaks( self, mask=None, + mask_real=None, bragg_peaks=None, bragg_mask_radius=None, sigma_annular_deg=10.0, @@ -436,6 +717,8 @@ def find_peaks( ), dtype="bool", ) + if mask_real is None: + mask_real = np.ones((self._datacube.Rshape[0], self._datacube.Rshape[1])).astype(bool) # Loop over probe positions for rx, ry in tqdmnd( @@ -445,6 +728,9 @@ def find_peaks( unit=" images", disable=not progress_bar, ): + # Skip values if masked + if mask_real[rx, ry] == False: + continue polar_peaks, sig_bg, sig_bg_mask = self.find_peaks_single_pattern( rx, ry, @@ -472,6 +758,148 @@ def find_peaks( self.background_radial_mask[rx, ry] = sig_bg_mask +def find_peaks_segmented( + self, + mask=None, + mask_real=None, + bragg_peaks=None, + bragg_mask_radius=None, + sigma_annular_deg=10.0, + sigma_radial_px=3.0, + sigma_annular_deg_max=None, + radial_background_subtract=True, + radial_background_thresh=0.25, + num_peaks_max=100, + threshold_abs=1.0, + threshold_prom_annular=None, + threshold_prom_radial=None, + remove_masked_peaks=False, + scale_sigma_annular=0.5, + scale_sigma_radial=0.25, + progress_bar=True, + kwargs_pass=None, +): + """ + Peak detection function for polar transformations. Loop through all probe positions, + find peaks. Store the peak positions and background signals. + + Parameters + -------- + sigma_annular_deg: float + smoothing along the annular direction in degrees, periodic + sigma_radial_px: float + smoothing along the radial direction in pixels, not periodic + + Returns + -------- + + """ + + # init + self.bragg_peaks = bragg_peaks + self.bragg_mask_radius = bragg_mask_radius + self.peaks = PointListArray( + dtype=[ + ("qt", " Date: Mon, 14 Jul 2025 13:40:00 -0700 Subject: [PATCH 2/3] Re-formatted previous commit's files with black linter --- py4DSTEM/process/polar/polar_peaks.py | 91 ++++++++++++++------------- py4DSTEM/visualize/vis_special.py | 8 +-- 2 files changed, 53 insertions(+), 46 deletions(-) diff --git a/py4DSTEM/process/polar/polar_peaks.py b/py4DSTEM/process/polar/polar_peaks.py index 4eecf030e..9d4f3a795 100644 --- a/py4DSTEM/process/polar/polar_peaks.py +++ b/py4DSTEM/process/polar/polar_peaks.py @@ -311,8 +311,8 @@ def find_peaks_single_pattern( t = np.linspace(0, 2 * np.pi, 180 + 1) ct = np.cos(t) st = np.sin(t) - if kwargs.get('figax'): - fig, ax = kwargs.pop('figax') + if kwargs.get("figax"): + fig, ax = kwargs.pop("figax") else: fig, ax = plt.subplots(figsize=figsize) @@ -376,31 +376,31 @@ def find_peaks_single_pattern( def find_peaks_single_pattern_segmented( - self, - x, - y, - mask=None, - bragg_peaks=None, - bragg_mask_radius=None, - sigma_annular_deg=10.0, - sigma_radial_px=3.0, - sigma_annular_deg_max=None, - radial_background_subtract=True, - radial_background_thresh=0.25, - num_peaks_max=100, - threshold_abs=1.0, - threshold_prom_annular=None, - threshold_prom_radial=None, - remove_masked_peaks=False, - scale_sigma_annular=0.5, - scale_sigma_radial=0.25, - return_background=False, - plot_result=True, - plot_power_scale=1.0, - plot_scale_size=10.0, - figsize=(12, 6), - returnfig=False, - **kwargs + self, + x, + y, + mask=None, + bragg_peaks=None, + bragg_mask_radius=None, + sigma_annular_deg=10.0, + sigma_radial_px=3.0, + sigma_annular_deg_max=None, + radial_background_subtract=True, + radial_background_thresh=0.25, + num_peaks_max=100, + threshold_abs=1.0, + threshold_prom_annular=None, + threshold_prom_radial=None, + remove_masked_peaks=False, + scale_sigma_annular=0.5, + scale_sigma_radial=0.25, + return_background=False, + plot_result=True, + plot_power_scale=1.0, + plot_scale_size=10.0, + figsize=(12, 6), + returnfig=False, + **kwargs ): """ Peak detection function for polar transformations. @@ -646,7 +646,7 @@ def find_peaks_single_pattern_segmented( else: peaks_new = np.vstack((peaks_new, peaks_all[a0, :])) peaks_all = peaks_new - + return peaks_all, sig_bg, sig_bg_mask @@ -718,7 +718,9 @@ def find_peaks( dtype="bool", ) if mask_real is None: - mask_real = np.ones((self._datacube.Rshape[0], self._datacube.Rshape[1])).astype(bool) + mask_real = np.ones( + (self._datacube.Rshape[0], self._datacube.Rshape[1]) + ).astype(bool) # Loop over probe positions for rx, ry in tqdmnd( @@ -827,7 +829,9 @@ def find_peaks_segmented( dtype="bool", ) if mask_real is None: - mask_real = np.ones((self._datacube.Rshape[0], self._datacube.Rshape[1])).astype(bool) + mask_real = np.ones( + (self._datacube.Rshape[0], self._datacube.Rshape[1]) + ).astype(bool) # Loop over probe positions for rx, ry in tqdmnd( @@ -841,16 +845,16 @@ def find_peaks_segmented( if mask_real[rx, ry] == False: continue for k0 in range(len(kwargs_pass)): - if 'sigma_annular_deg' in kwargs_pass[k0]: - sigma_annular_deg = kwargs_pass[k0]['sigma_annular_deg'] - if 'sigma_radial_px' in kwargs_pass[k0]: - sigma_radial_px = kwargs_pass[k0]['sigma_radial_px'] - if 'threshold_abs' in kwargs_pass[k0]: - threshold_abs = kwargs_pass[k0]['threshold_abs'] - if 'threshold_prom_radial' in kwargs_pass[k0]: - threshold_prom_radial = kwargs_pass[k0]['threshold_prom_radial'] - if 'threshold_prom_annular' in kwargs_pass[k0]: - threshold_prom_annular = kwargs_pass[k0]['threshold_prom_annular'] + if "sigma_annular_deg" in kwargs_pass[k0]: + sigma_annular_deg = kwargs_pass[k0]["sigma_annular_deg"] + if "sigma_radial_px" in kwargs_pass[k0]: + sigma_radial_px = kwargs_pass[k0]["sigma_radial_px"] + if "threshold_abs" in kwargs_pass[k0]: + threshold_abs = kwargs_pass[k0]["threshold_abs"] + if "threshold_prom_radial" in kwargs_pass[k0]: + threshold_prom_radial = kwargs_pass[k0]["threshold_prom_radial"] + if "threshold_prom_annular" in kwargs_pass[k0]: + threshold_prom_annular = kwargs_pass[k0]["threshold_prom_annular"] peaks, sig_bg, sig_bg_mask = self.find_peaks_single_pattern_segmented( rx, @@ -874,7 +878,10 @@ def find_peaks_segmented( plot_result=False, ) # print((kwargs_pass[k0]['radial_lower_bound'] <= peaks[:, 1]) & (peaks[:, 1] < kwargs_pass[k0]['radial_upper_bound'])) - peaks = peaks[(kwargs_pass[k0]['radial_lower_bound'] <= peaks[:, 1]) & (peaks[:, 1] < kwargs_pass[k0]['radial_upper_bound'])] + peaks = peaks[ + (kwargs_pass[k0]["radial_lower_bound"] <= peaks[:, 1]) + & (peaks[:, 1] < kwargs_pass[k0]["radial_upper_bound"]) + ] if k0 == 0: peaks_all = peaks else: @@ -1200,7 +1207,7 @@ def plot_radial_peaks( if returnfig: return fig, ax - + if return_plot_data: return q_bins, int_peaks diff --git a/py4DSTEM/visualize/vis_special.py b/py4DSTEM/visualize/vis_special.py index 38295c239..d41bf2dcb 100644 --- a/py4DSTEM/visualize/vis_special.py +++ b/py4DSTEM/visualize/vis_special.py @@ -159,10 +159,10 @@ def show_amorphous_ring_fit( return_intensity_range=True, **kwargs, ) - if kwargs.get('vmax') is not None: - vmax = kwargs.pop('vmax') - if kwargs.get('vmin') is not None: - vmin = kwargs.pop('vmin') + if kwargs.get("vmax") is not None: + vmax = kwargs.pop("vmax") + if kwargs.get("vmin") is not None: + vmin = kwargs.pop("vmin") show( fit, scaling=scaling, From 0fe7e8aa9c9e05be993e2017f23143b7c5503936 Mon Sep 17 00:00:00 2001 From: NJMarchese Date: Thu, 9 Oct 2025 11:40:52 -0700 Subject: [PATCH 3/3] Refactor peak plotting and add mask parameters for peak detection - Updated `find_peaks_single_pattern` to restore intensity scaling for scatter plot. - Enhanced `find_peaks_segmented` with new mask parameters for improved peak detection. - Modified `plot_radial_peaks` to allow customizable vertical lines. - Adjusted orientation histogram calculation to ensure angle conversion is in radians. - Added vmin and vmax parameters to `show_amorphous_ring_fit` for better visualization control. --- py4DSTEM/process/polar/polar_datacube.py | 1 - py4DSTEM/process/polar/polar_peaks.py | 26 +++++++++++++++++++----- py4DSTEM/visualize/vis_special.py | 12 ++++++----- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/py4DSTEM/process/polar/polar_datacube.py b/py4DSTEM/process/polar/polar_datacube.py index 3d3ea33c4..25aad46c7 100644 --- a/py4DSTEM/process/polar/polar_datacube.py +++ b/py4DSTEM/process/polar/polar_datacube.py @@ -115,7 +115,6 @@ def __init__( plot_radial_background, model_radial_background, make_orientation_histogram, - # Added find_peaks_single_pattern_segmented, find_peaks_segmented, ) diff --git a/py4DSTEM/process/polar/polar_peaks.py b/py4DSTEM/process/polar/polar_peaks.py index 9d4f3a795..7c4b3bf14 100644 --- a/py4DSTEM/process/polar/polar_peaks.py +++ b/py4DSTEM/process/polar/polar_peaks.py @@ -325,8 +325,7 @@ def find_peaks_single_pattern( ax.scatter( peaks_polar["qr"], peaks_polar["qt"], - # s=peaks_polar["intensity"] * plot_scale_size, - s=10, + s=peaks_polar["intensity"] * plot_scale_size, marker="o", color=(1, 0, 0), ) @@ -787,10 +786,17 @@ def find_peaks_segmented( Parameters -------- + mask: + mask for diffraction image pixels + mask_real: + mask for which real space probe positions to do peak detection on sigma_annular_deg: float smoothing along the annular direction in degrees, periodic sigma_radial_px: float smoothing along the radial direction in pixels, not periodic + kwargs_pass: + a list of dictionaries, with each dictionary containing the parameters for + peak finding for a given q-range Returns -------- @@ -1097,6 +1103,7 @@ def plot_radial_peaks( label_y_axis=False, figsize=(8, 4), v_lines=None, + v_lines_colors=None, returnfig=False, return_plot_data=False, ): @@ -1200,10 +1207,18 @@ def plot_radial_peaks( y_min, y_max = ax.get_ylim() if np.isscalar(v_lines): - ax.vlines(v_lines, y_min, y_max, color="g") + if v_lines_colors is None: + color = "g" + else: + color = v_lines_colors + ax.vlines(v_lines, y_min, y_max, color=color) else: for a0 in range(len(v_lines)): - ax.vlines(v_lines[a0], y_min, y_max, color="g") + if v_lines_colors is None: + color = "g" + else: + color = v_lines_colors[a0] + ax.vlines(v_lines[a0], y_min, y_max, color=color) if returnfig: return fig, ax @@ -1766,7 +1781,8 @@ def make_orientation_histogram( theta = self.peaks[rx, ry]["qt"][sub] * self._annular_step if orientation_flip_sign: theta *= -1 - theta += orientation_offset_degrees + # theta += orientation_offset_degrees + theta += orientation_offset_degrees * np.pi / 180 # theta is in radians so need to convert t = theta / dtheta diff --git a/py4DSTEM/visualize/vis_special.py b/py4DSTEM/visualize/vis_special.py index d41bf2dcb..d2f79c0db 100644 --- a/py4DSTEM/visualize/vis_special.py +++ b/py4DSTEM/visualize/vis_special.py @@ -97,6 +97,8 @@ def show_amorphous_ring_fit( ellipse_alpha=0.7, ellipse_lw=2, returnfig=False, + vmin=None, + vmax=None, **kwargs, ): """ @@ -149,7 +151,7 @@ def show_amorphous_ring_fit( fit = double_sided_gaussian(p_dsg, qxx, qyy) # Show - (fig, ax), (vmin, vmax) = show( + (fig, ax), (_vmin, _vmax) = show( dp, scaling=scaling, cmap=cmap_data, @@ -159,10 +161,10 @@ def show_amorphous_ring_fit( return_intensity_range=True, **kwargs, ) - if kwargs.get("vmax") is not None: - vmax = kwargs.pop("vmax") - if kwargs.get("vmin") is not None: - vmin = kwargs.pop("vmin") + if vmin is None: + vmin = _vmin + if vmax is None: + vmax = _vmax show( fit, scaling=scaling,