def fit_odr(data, correlant, odr_function, poly_order, weights): if weights == 'relative': std = 0.1 mydata = _odr.RealData( data, correlant, sx=data * std, sy=correlant * std) # , wd=1. / self.sx ** 2, we=1. / self.sy ** 2) elif weights == 'absolute': sx, sy = (1, 1) mydata = _odr.Data(data, correlant, wd=1. / sx**2, we=1. / sy**2) else: raise ValueError('weights has to be scalar or absolute') if odr_function != 'linear': raise ( 'only "linear" allowed at this point, programming required!' ) model = _odr.polynomial(poly_order) myodr = _odr.ODR(mydata, model) myoutput = myodr.run() odr_res = { 'model': myodr, 'output': myoutput, 'function': _np.polynomial.Polynomial(myoutput.beta) } return odr_res
def test_polynomial_model(self): x = np.linspace(0.0, 5.0) y = 1.0 + 2.0 * x + 3.0 * x**2 + 4.0 * x**3 poly_model = polynomial(3) data = Data(x, y) odr_obj = ODR(data, poly_model) output = odr_obj.run() assert_array_almost_equal(output.beta, [1.0, 2.0, 3.0, 4.0])
def _linear_regression(x: np.array, y: np.array, sx: np.array, sy: np.array): """Optimize and apply a linear regression using masked arrays Generates a linear fit f using orthogonal distance regression and returns the applied model f(x). If y is completely masked, return y and sy. Args: x: The independent variable of the regression y: The dependent variable of the regression sx: Standard deviations of x sy: Standard deviations of y Returns: The applied linear regression on x as a masked array The uncertainty in the applied linear regression as a masked array """ x = np.ma.array(x) # This type cast will propagate into returns y = np.ma.array(y) # It also ensures that x, y have a .mask attribute if y.mask.all(): return y, sy # Fit data with orthogonal distance regression (ODR) indices = ~np.logical_or(x.mask, y.mask) data = RealData(x=x[indices], y=y[indices], sx=sx[indices], sy=sy[indices]) odr = ODR(data, polynomial(1), beta0=[0., 1.]) fit_results = odr.run() fit_fail = 'Numerical error detected' in fit_results.stopreason if fit_fail: raise RuntimeError(fit_results.stopreason) # Apply the linear regression b, m = fit_results.beta applied_fit = m * x + b applied_fit.mask = np.logical_or(x.mask, applied_fit <= 0) std = np.ma.std(y[indices] - m * x[indices] - b) error = np.ma.zeros(applied_fit.shape) + std error.mask = applied_fit.mask return applied_fit, error
print(params) fit_values = fit_func.pdf(edges, *params) max_fit_value_index = np.where(fit_values == np.max(fit_values)) print(max_fit_value_index) plt.figure(figsize=(15, 5)) plt.plot(hist / np.sum(hist)) plt.plot(ma / np.sum(ma)) plt.plot(edges, fit_values) plt.semilogx() # %% x = edges[:-1] y = hist poly_model = odr.polynomial(3) data = odr.Data(x, y) odr_obj = odr.ODR(data, poly_model) output = odr_obj.run() poly = np.poly1d(output.beta[::-1]) poly_y = poly(x) plt.figure(figsize=(15, 5)) plt.plot(x, y) plt.plot(x, poly_y) plt.semilogx() # %% # https://en.wikipedia.org/wiki/Gaussian_filter # use FWHM
def main(): parser = argparse.ArgumentParser() parser.add_argument('-r', '--rthreshold', type=float, default=0.85) parser.add_argument('-rp', '--regression-plot', dest='regression_plot', action='store_true') parser.add_argument('wind_csv', type=Path, default=False) params = parser.parse_args() matplotlib.rcParams.update({'font.size': 8.5}) global_subplots_params = { 'figsize': (4.69, 3.52), 'constrained_layout': True } trials_result = dict() all_points = list() with open(params.wind_csv, 'r', newline='') as wind_csv: wind_reader = csv.reader(wind_csv) # skip the header row next(wind_reader) for trial in wind_reader: if trial[4].startswith('skip'): continue print('processing', trial[0]) ddm_time_fit_file_prefix = Path( trial[1]) / 'auto_correlate_data_lin_diff_diff.npy' params_fit_path = \ ddm_time_fit_file_prefix.with_stem(ddm_time_fit_file_prefix.stem + '.polar.params_fit') median_angle_path = \ ddm_time_fit_file_prefix.with_stem(ddm_time_fit_file_prefix.stem + '.polar.median_angle') median_radius_path = \ ddm_time_fit_file_prefix.with_stem(ddm_time_fit_file_prefix.stem + '.polar.median_radius') params_fit = np.load(params_fit_path) median_angle = np.load(median_angle_path) median_radius = np.load(median_radius_path) with open(trial[3]) as vid_info_file: vid_info = json.load(vid_info_file) with open(trial[2]) as calibration_file: calibration = json.load(calibration_file) frame_interval = vid_info['framerate'][1] / vid_info['framerate'][0] # freq_factor = np.pi / ((max_time_index - 1) * frame_interval) # freq_factor = 1 / frame_interval wavenumber_factor = 2 * np.pi / (vid_info['fft']['size'] * calibration['calibration_factor']) wavenumber_unit = '\\mathrm{{rad}}\\,\\mathrm{{{}}}^{{-1}}'.format( calibration['physical_unit']) # print(f'wavenumber_factor = {wavenumber_factor}') # print(f'frame_interval = {frame_interval} s') params_fit[..., 2] /= frame_interval freq_fit = params_fit[:, 1:, 2] angle_indices = (int(i) for i in trial[4].split()) if trial[4] else range( freq_fit.shape[0]) do_plot = trial[6].lower( )[0] == 't' if trial[6] else params.regression_plot slope_list = list() slopeerr_list = list() wavenumber_space = median_radius[1:] * wavenumber_factor fig_path_prefix = ddm_time_fit_file_prefix.with_suffix('.png') fig_stem_prefix = ddm_time_fit_file_prefix.stem + '.polar.freq_fit' for angle_index in angle_indices: finite_mark = np.isfinite(freq_fit[angle_index]) regress = linregress(wavenumber_space[finite_mark], freq_fit[angle_index, finite_mark]) # print(trial[0], angle_index, regress.slope, regress.intercept, regress.rvalue, regress.stderr) if regress.rvalue >= params.rthreshold: print('using', angle_index) slope_list.append(regress.slope) slopeerr_list.append(regress.stderr) else: print('skipping', angle_index) if do_plot: lin_fit = regress.intercept + wavenumber_space * regress.slope suptitle = 'Radial dependence of $\\Omega$ parameter as fitted along median ' + \ f'$q_\\theta={median_angle[angle_index]}\\degree$\n$R={regress.rvalue}$' # fig, ax = plt.subplots(**global_subplots_params) fig = matplotlib.figure.Figure(**global_subplots_params) ax = fig.add_subplot() ax: matplotlib.axes.Axes ax.plot(wavenumber_space, freq_fit[angle_index]) ax.plot(wavenumber_space, lin_fit) ax.set_xlabel(f'$q_r$ (${wavenumber_unit}$)') ax.set_ylabel('$\\Omega$ (rad/s)') fig.suptitle(suptitle) fig.savefig( fig_path_prefix.with_stem(fig_stem_prefix + str(angle_index).zfill(2)), dpi=300) slopes = np.array(slope_list) slope_av = np.mean(slopes) if len(slope_list) <= 1: slope_std = 0 else: slope_std = np.std(slopes, ddof=1) slopes_err = np.array(slopeerr_list) slopes_err_av = np.mean(slopes_err) print(slope_std, slopes_err_av) slope_err = max(slope_std, slopes_err_av) entry = (float(trial[-2]), float(trial[-1]), slope_av, slope_err) print(trial[-3], *entry) trials_list = trials_result.setdefault(trial[-3], list()) trials_list.append(entry) if not (trial[6] and trial[6].lower()[0] == 't'): all_points.append(entry) all_points = np.array(all_points) odr_data = odr.RealData(all_points[:, 0], all_points[:, -2], all_points[:, 1], all_points[:, -1]) linear_model = odr.polynomial(1) odr_obj = odr.ODR(odr_data, linear_model) odr_output = odr_obj.run() odr_output.pprint() fit_x = np.linspace(0, 3) fit_y = odr_output.beta[0] + odr_output.beta[1] * fit_x # fit_y_min = (odr_output.beta[0] + odr_output.sd_beta[0]) + \ # (odr_output.beta[1] - odr_output.sd_beta[1]) * fit_x # fit_y_max = (odr_output.beta[0] - odr_output.sd_beta[0]) + \ # (odr_output.beta[1] + odr_output.sd_beta[1]) * fit_x # regress_result = linregress(all_points[:, 0], all_points[:, -2]) # fit_x = np.linspace(0, 3) # fit_y = regress_result.intercept + regress_result.slope * fit_x # colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', # '#17becf', '#1a55FF'] colors = ['maroon', 'indianred', 'royalblue'] fig, ax = plt.subplots(**global_subplots_params) fig = plt.Figure(**global_subplots_params) ax = fig.add_subplot() ax: matplotlib.axes.Axes ax.plot(fit_x, fit_y, color='slategrey', linewidth=.7, linestyle='-', label='Linear fit') # ax.plot(fit_x, fit_y_min) # ax.plot(fit_x, fit_y_max) for c, (wind_type, trials_list) in zip(colors, trials_result.items()): trials_array = np.array(trials_list) print(c, wind_type) ax.errorbar(trials_array[:, 0], trials_array[:, -2], trials_array[:, -1], trials_array[:, 1], linestyle='', ecolor=c, capsize=3, capthick=1, label=wind_type) ax.set_xlim(0, 3) ax.set_ylim(0) ax.set_xlabel(r'Wind speed ($\mathrm{m}\,\mathrm{s}^{-1}$)') ax.set_ylabel(r'Wave speed ($\mathrm{m}\,\mathrm{s}^{-1}$)') ax.legend() fig.savefig('fig.svg', dpi=300)