def get_dH_curve(DEM, dDEM, glacier_mask, bins=None, mode='mean'): valid = np.logical_and(np.isfinite(DEM), np.isfinite(dDEM)) dem_data = DEM[valid] ddem_data = dDEM[valid] if bins is None: bins = get_bins(DEM, glacier_mask) mean_dH, bin_areas = bin_data(bins, ddem_data, dem_data, mode=mode, nbinned=True) return bins, mean_dH, bin_areas
def plot_dh_elevation(dDEM, DEM, glacier_mask=None, binning=None, bin_width=50, polyorder=None): """ :param dDEM: :param DEM: :param glacier_mask: :param binning: :param bin_width: :param polyorder: :return: """ fig = plt.figure() plt.ion() if glacier_mask is not None: ddem_data = dDEM.img[np.logical_and( np.logical_and(np.isfinite(dDEM.img), np.isfinite(DEM.img)), glacier_mask)] dem_data = DEM.img[np.logical_and( np.logical_and(np.isfinite(dDEM.img), np.isfinite(DEM.img)), glacier_mask)] else: ddem_data = dDEM.img[np.logical_and(np.isfinite(dDEM.img), np.isfinite(DEM.img))] dem_data = DEM.img[np.logical_and(np.isfinite(dDEM.img), np.isfinite(DEM.img))] plt.plot(dem_data, ddem_data, '+') if binning is not None: if binning not in ['mean', 'median', 'poly']: raise ValueError('binning must be one of mean, median, polyfit') min_el = np.nanmin(dem_data) - (np.nanmin(dem_data) % bin_width) max_el = np.nanmax(dem_data) - (bin_width - (np.nanmax(dem_data) % bin_width)) bins = np.arange(min_el, max_el, bin_width) if binning in ['mean', 'median']: binned_data = bin_data(bins, ddem_data, dem_data, mode=binning) plt.plot(bins, binned_data, 'r', linewidth=3) else: if polyorder is None: raise ValueError( 'polyorder must be defined to use polynomial fitting.') pfit = polyfit(dem_data, ddem_data, polyorder) interp_points = polyval(bins, pfit) plt.plot(bins, interp_points, 'r', linewidth=3) return fig
def parse_elev_func_args(func_name, dDEM, **kwargs): # first, make sure we use one of the right function names if func_name not in ['mean', 'median', 'poly']: raise ValueError('{} not one of mean, median, poly'.format(func_name)) if 'DEM' not in kwargs: raise ValueError( 'to use {}, you must supply a base DEM'.format(func_name)) else: # if we've been supplied a DEM, we have to check that it's the right size. DEM = kwargs['DEM'] if type(DEM) is not GeoImg: raise TypeError('DEM must be a GeoImg') if DEM.img.shape != dDEM.img.shape: raise ValueError('dDEM and DEM must have the same shape') if 'glacier_mask' in kwargs: ddem_data = dDEM.img[np.logical_and( np.logical_and(np.isfinite(dDEM.img), np.isfinite(DEM.img)), kwargs['glacier_mask'])] dem_data = DEM.img[np.logical_and( np.logical_and(np.isfinite(dDEM.img), np.isfinite(DEM.img)), kwargs['glacier_mask'])] else: ddem_data = dDEM.img[np.logical_and(np.isfinite(dDEM.img), np.isfinite(DEM.img))] dem_data = DEM.img[np.logical_and(np.isfinite(dDEM.img), np.isfinite(DEM.img))] # now, figure out which of mean, median, polyfit we're using, and do it. if func_name == 'poly': if 'poly_order' not in kwargs: raise ValueError( 'poly_order must be defined to use polynomial fitting') # now we fit a polynomial of order poly_order to the data: pfit = polyfit(dem_data, ddem_data, kwargs['poly_order']) # need a way to put hole values in the right place if 'glacier_mask' in kwargs: hole_inds = np.where( np.logical_and( np.logical_and(np.isnan(dDEM.img), np.isfinite(DEM.img)), kwargs['glacier_mask'])) else: hole_inds = np.where( np.logical_and(np.isfinite(dDEM.img), np.isfinite(DEM.img))) hole_elevs = DEM.img[hole_inds] interp_points = polyval(hole_elevs, pfit) dDEM.img[hole_inds] = interp_points if 'valid_area' in kwargs: dDEM.img[np.logical_not(kwargs['valid_area'])] = np.nan return dDEM elif func_name == 'mean' or func_name == 'median': if 'bins' not in kwargs: # if we haven't been handed bins, we have to make our own. if 'bin_width' not in kwargs: bin_width = 50 # if we haven't been told what bin width to use, default to 50. else: bin_width = kwargs['bin_width'] min_el = np.nanmin(dem_data) - (np.nanmin(dem_data) % bin_width) max_el = np.nanmax(dem_data) + (bin_width - (np.nanmax(dem_data) % bin_width)) bins = np.arange(min_el, max_el + 1, bin_width) else: bins = kwargs['bins'] binned_dH = bin_data(bins, ddem_data, dem_data, mode=func_name) # now, we interpolate the missing DH values to the binned values. f_elev = interp1d(bins, binned_dH, fill_value="extrapolate") # pull out missing values from dDEM if 'glacier_mask' in kwargs: hole_inds = np.where( np.logical_and( np.logical_and(np.isnan(dDEM.img), np.isfinite(DEM.img)), kwargs['glacier_mask'])) else: hole_inds = np.where( np.logical_and(np.isfinite(dDEM.img), np.isfinite(DEM.img))) hole_elevs = DEM.img[hole_inds] filled = f_elev(hole_elevs) tmp_dDEM = dDEM.copy() tmp_dDEM.img[hole_inds] = filled if 'valid_area' in kwargs: tmp_dDEM.img[np.logical_not(kwargs['valid_area'])] = np.nan return tmp_dDEM else: raise ValueError( 'Somehow we made it this far without naming a correct fitting function. Oops.' )
def get_elev_curve(DEM, dDEM, glacier_mask=None, bins=None, mode='mean', outlier=False, fill=False, poly_order=3): """ Get a dh(z) curve for a glacier/region of interest, given a DEM and a difference DEM (dDEM). Available modes are 'mean'/'median', calculating the mean(median) of each elevation bin, or poly, fitting a polynomial (default third-order) to the means of each elevation bin. :param DEM: DEM to determine z in dh(z) :param dDEM: difference DEM to determine dh in dh(z) :param glacier_mask: mask representing glacier outline :param bins: values representing the lower edge of elevation bins :param mode: how to determine the dh(z) relationship :param outlier: filter outliers using an iterative 3-sigma filter :param fill: fill missing bins using a polynomial fit (default third order) :param poly_order: order for any polynomial fitting :type DEM: array-like :type dDEM: array-like :type glacier_mask: array-like :type bins: array-like :type mode: str :type outlier: bool :type fill: bool :type poly_order: int :returns bins, curve, bin_areas: elevation bins, dh(z) curve, and number of pixels per elevation bin. """ assert mode in ['mean', 'median', 'poly'], "mode not recognized: {}".format(mode) if glacier_mask is None: valid = np.logical_and(np.isfinite(DEM), np.isfinite(dDEM)) else: valid = np.logical_and( glacier_mask, np.logical_and(np.isfinite(DEM), np.isfinite(dDEM))) dem_data = DEM[valid] ddem_data = dDEM[valid] if bins is None: bins = get_bins(DEM, glacier_mask) if outlier: # ddem_data = outlier_removal(bins, dem_data, ddem_data) ddem_data = nmad_outlier_removal(bins, dem_data, ddem_data) if mode in ['mean', 'median']: curve, bin_areas = bin_data(bins, ddem_data, dem_data, mode=mode, nbinned=True) if fill: _bins = bins[np.isfinite(curve)] _curve = bins[np.isfinite(curve)] p = polyfit(bins, curve, poly_order) fill_ = polyval(bins, p) curve[np.isnan(curve)] = fill_[np.isnan(curve)] else: _mean, bin_areas = bin_data(bins, ddem_data, dem_data, mode='mean', nbinned=True) p = polyfit(bins, _mean, poly_order) curve = polyval(bins, p) return bins, curve, bin_areas