def test_saveload_modelresult_roundtrip(method): """Test for modelresult.loads()/dumps() and repeating that""" def mfunc(x, a, b): return a * (x - b) model = Model(mfunc) params = model.make_params(a=0.1, b=3.0) params['a'].set(min=.01, max=1, brute_step=0.01) params['b'].set(min=.01, max=3.1, brute_step=0.01) np.random.seed(2020) xx = np.linspace(-5, 5, 201) yy = 0.5 * (xx - 0.22) + np.random.normal(scale=0.01, size=len(xx)) result1 = model.fit(yy, params=params, x=xx, method=method) result2 = ModelResult(model, Parameters()) result2.loads(result1.dumps(), funcdefs={'mfunc': mfunc}) result3 = ModelResult(model, Parameters()) result3.loads(result2.dumps(), funcdefs={'mfunc': mfunc}) assert result3 is not None assert_allclose(result2.params['a'], 0.5, rtol=1.0e-2) assert_allclose(result2.params['b'], 0.22, rtol=1.0e-2) assert_allclose(result3.params['a'], 0.50, rtol=1.0e-2) assert_allclose(result3.params['b'], 0.22, rtol=1.0e-2)
def hatchplot_fit(xp: XPS_experiment, region: str, fitRes: ModelResult, lb: str = None, marker='o', ls: str = 'solid', colc: str = None, ax=None, plot_comps: bool = True, flag_fill: bool = False): """"Plot fit result with predefined hatch patterns for each component (up to three components)""" if ax == None: ax = plt.gca() if lb == None: lb = xp.name if colc == None: colc = xp.color p1 = ax.scatter(xp.dfx[region].energy, xp.dfx[region].counts, marker=marker, label=lb, zorder=1) p1.set_color(colc) x = xp.dfx[region].dropna().energy ax.plot(x, fitRes.best_fit, linestyle=ls, color=colc, lw=1.5, label='Fit, $\chi^2_N$ = %i' % fitRes.redchi) hatch = ['//', 'ox', '+'] if plot_comps: comps = fitRes.eval_components(x=x) for i, compo in enumerate(comps): posx = fitRes.best_values[compo + 'center'] ax.text(x=posx, y=comps[compo].max() * 1.02, s='%.1f' % posx, fontsize=12) ax.fill_between(x, y1=0, y2=comps[compo], alpha=1, label='Component @ %.1f eV' % posx, facecolor='w', hatch=hatch[i], edgecolor=colc, zorder=-1) ax.legend(loc='best') #, bbox_to_anchor=(1.12, 0.5), fontsize=16) cosmetics_plot() return ax
def plot_model(axes: Axes, soil, fit_result: ModelResult): # position chi square text text_height = 0.02 x_location = 0.7 y_ORG = 0.7 y_MIN = y_ORG - text_height y_UNC = y_MIN - text_height locations = ((x_location, y_ORG), (x_location, y_MIN), (x_location, y_UNC)) CHI_SQUARE_LOCATION = dict(zip(SOILS, locations)) data_kws = { 'color': COLORS[soil], 'marker': MARKERS[soil], 'markersize': 12, } fit_kws = { 'color': COLORS[soil], 'linewidth': 3, } model = fit_result.model parameters = fit_result.params X = numpy.arange(DAYS_TO_FIT[0], DAYS_TO_FIT[-1], 1 / 24) # 24 time points for each day in time_range y_fit = model.eval(t=X, params=parameters) lines = fit_result.plot_fit(ax=axes, numpoints=480, data_kws=data_kws, fit_kws=fit_kws) dely = fit_result.eval_uncertainty(sigma=1, t=X) axes.fill_between(X, y_fit - dely, y_fit + dely, color="#ABABAB") reduced_chi_square = get_chi_square(fit_result) x = CHI_SQUARE_LOCATION[soil][0] y = CHI_SQUARE_LOCATION[soil][1] axes.text(x, y, str(reduced_chi_square), transform=axes.transAxes)
def plot_fit_result(xp: XPS_experiment, region: str, fitRes: ModelResult, lb: str = None, ax=None, plot_comps: bool = True, flag_fill: bool = False): if ax == None: ax = plt.gca() col = plot_region(xp, region, ax=ax, lb=lb).get_color() x = xp.dfx[region].dropna().energy ax.plot(x, fitRes.best_fit, '--', color=col, lw=1.5, label='best fit, $\chi^2_N$ = %i' % fitRes.redchi) ax.legend() if plot_comps: comps = fitRes.eval_components(x=x) for compo in comps: posx = fitRes.best_values[compo + 'center'] colc = ax.plot(x, comps[compo], ls='dotted', lw=1.5, color=col, label='__nolabel__')[0].get_color() ax.vlines(x=posx, ymin=0, ymax=comps[compo].max(), linestyle='dotted', colors=col) ax.text(x=posx, y=comps[compo].max() * 0.9, s='%.1f' % posx, fontsize=12) if flag_fill: ax.fill_between(x, y1=0, y2=comps[compo], alpha=0.3, color=colc) return ax
def run_preview(data: Table, m_def, pool, state: TaskState): def progress_interrupt(_: float): if state.is_interruption_requested(): raise InterruptException # Protects against running the task in succession many times, as would # happen when adding a preprocessor (there, commit() is called twice). # Wait 100 ms before processing - if a new task is started in meanwhile, # allow that is easily` cancelled. for _ in range(10): time.sleep(0.010) progress_interrupt(0) orig_data = data model, parameters = create_composite_model(m_def) model_result = {} x = getx(data) if data is not None and model is not None: for row in data: progress_interrupt(0) res = pool.schedule(pool_fit2, (row.x, model.dumps(), parameters, x)) while not res.done(): try: progress_interrupt(0) except InterruptException: # CANCEL if multiprocessing.get_start_method( ) != "fork" and res.running(): # If slower start methods are used, give the current computation # some time to exit gracefully; this avoids reloading processes concurrent.futures.wait([res], 1.0) if not res.done(): res.cancel() raise concurrent.futures.wait([res], 0.05) fits = res.result() model_result[row.id] = ModelResult(model, parameters).loads( fits, **LMFIT_LOADS_KWARGS) progress_interrupt(0) return orig_data, data, model_result
def plot_one_week_fit( data, fit_result: ModelResult, figure_number=None, ): # model function model = fit_result.model # time points X = data.index.values # measured y data y = data.values # best fit y data from_zero = [x - X[0] for x in X] X_from_zero = np.linspace(from_zero[0], from_zero[-1], 100) best_fit_params = fit_result.params best_fit_y = model.eval(params=best_fit_params, t=X_from_zero) # pdb.set_trace() # new figure if figure_number: plt.figure(figure_number) # plot measured data plt.plot(X, y, 'bo') # plot best fit curve best_fit_X = np.linspace(X[0], X[-1], 100) plt.plot(best_fit_X, best_fit_y, 'r-', label='best fit') # uncertainty band best_fit = fit_result.best_fit n_sigma = 1 error = fit_result.eval_uncertainty(sigma=n_sigma, t=X_from_zero) plt.fill_between( best_fit_X, best_fit_y - error, best_fit_y + error, color="#ABABAB", label=f'{n_sigma}$\sigma$ uncertainty band', )
def test_saveload_modelresult_roundtrip(): """Test for modelresult.loads()/dumps() and repeating that""" def mfunc(x, a, b): return a * (x - b) model = Model(mfunc) params = model.make_params(a=0.0, b=3.0) xx = np.linspace(-5, 5, 201) yy = 0.5 * (xx - 0.22) + np.random.normal(scale=0.01, size=len(xx)) result1 = model.fit(yy, params, x=xx) result2 = ModelResult(model, Parameters()) result2.loads(result1.dumps(), funcdefs={'mfunc': mfunc}) result3 = ModelResult(model, Parameters()) result3.loads(result2.dumps(), funcdefs={'mfunc': mfunc}) assert result3 is not None assert_param_between(result2.params['a'], 0.48, 0.52) assert_param_between(result2.params['b'], 0.20, 0.25) assert_param_between(result3.params['a'], 0.48, 0.52) assert_param_between(result3.params['b'], 0.20, 0.25)
def test_saveload_modelresult_roundtrip(): """Test for modelresult.loads()/dumps() and repeating that""" def mfunc(x, a, b): return a * (x-b) model = Model(mfunc) params = model.make_params(a=0.0, b=3.0) xx = np.linspace(-5, 5, 201) yy = 0.5 * (xx - 0.22) + np.random.normal(scale=0.01, size=len(xx)) result1 = model.fit(yy, params, x=xx) result2 = ModelResult(model, Parameters()) result2.loads(result1.dumps(), funcdefs={'mfunc': mfunc}) result3 = ModelResult(model, Parameters()) result3.loads(result2.dumps(), funcdefs={'mfunc': mfunc}) assert result3 is not None assert_param_between(result2.params['a'], 0.48, 0.52) assert_param_between(result2.params['b'], 0.20, 0.25) assert_param_between(result3.params['a'], 0.48, 0.52) assert_param_between(result3.params['b'], 0.20, 0.25)
def run_task(data: Table, m_def, state: TaskState): def progress_interrupt(i: float): state.set_progress_value(i) if state.is_interruption_requested(): raise InterruptException # Protects against running the task in succession many times, as would # happen when adding a preprocessor (there, commit() is called twice). # Wait 100 ms before processing - if a new task is started in meanwhile, # allow that is easily` cancelled. for _ in range(10): time.sleep(0.010) progress_interrupt(0) model, parameters = create_composite_model(m_def) data_fits = data_anno = data_resid = None if data is not None and model is not None: orig_data = data output = [] x = getx(data) n = len(data) fits = [] residuals = [] with multiprocessing.Pool(processes=N_PROCESSES, initializer=pool_initializer, initargs=(model.dumps(), parameters, x)) as p: res = p.map_async(pool_fit, data.X, chunksize=1) def done(): try: return n - res._number_left * res._chunksize except AttributeError: return 0 while not res.ready(): progress_interrupt(done() / n * 99) res.wait(0.05) fitsr = res.get() progress_interrupt(99) for fit, bpar, fitted, resid in fitsr: out = ModelResult(model, parameters).loads(fit, **LMFIT_LOADS_KWARGS) output.append(bpar) fits.append(fitted) residuals.append(resid) progress_interrupt(99) data = fit_results_table(np.vstack(output), out, orig_data) data_fits = orig_data.from_table_rows(orig_data, ...) # a shallow copy with data_fits.unlocked_reference(data_fits.X): data_fits.X = np.vstack(fits) data_resid = orig_data.from_table_rows(orig_data, ...) # a shallow copy with data_resid.unlocked_reference(data_resid.X): data_resid.X = np.vstack(residuals) dom_anno = Domain( orig_data.domain.attributes, orig_data.domain.class_vars, orig_data.domain.metas + data.domain.attributes, ) data_anno = orig_data.transform(dom_anno) with data_anno.unlocked(data_anno.metas): data_anno.metas[:, len(orig_data.domain.metas):] = data.X progress_interrupt(100) return data, data_fits, data_resid, data_anno
def plot_figure_for_fit( fit_result: ModelResult, xlabel: str = 'x', ylabel: str = 'y', xscale: float = 1.0, yscale: float = 1.0, title: str = '', figsize=DEFAULT_FIG_SIZE, axis_fontsize: tuple = DEFAULT_AXIS_FONT_SIZE, report_fontsize: float = DEFAULT_REPORT_FONT_SIZE) -> plt.figure: """ Plots fit and residuals from lmfit with residuals *below* fit. Also shows fit result text below. :param fit_result: lmfit fit result object :param xlabel: label for the shared x axis :param ylabel: ylabel for fit plot :param xscale: xaxis will be divided by xscale :param yscale: yaxis will be divided by yscale :param title: title of the plot :param figsize: size of the plot :param axis_fontsize: size of the font :param report_fontsize: size of font for the stats report :return: matplotlib figure """ # layout subplots for fit plot and residuals fig, axs = plt.subplots(nrows=2, ncols=1, sharex=True, gridspec_kw={'height_ratios': (3, 1)}, figsize=figsize) # add space for fit result text at bottom plt.subplots_adjust(hspace=0, top=0.9, bottom=0.3) # plot the fits and residuals fit_result.plot_fit(ax=axs[0], **FIT_PLOT_KWS) fit_result.plot_residuals(ax=axs[1], data_kws=FIT_PLOT_KWS["data_kws"], fit_kws=FIT_PLOT_KWS["fit_kws"]) # title and labels axs[1].set_title('') axs[1].set_ylabel('residuals', fontsize=axis_fontsize) axs[1].set_xlabel(xlabel, fontsize=axis_fontsize) axs[0].set_ylabel(ylabel, fontsize=axis_fontsize) axs[0].set_title(title, fontsize=axis_fontsize) # residuals don't need a legend axs[1].legend().set_visible(False) # adjust tick labels for scales xticks = ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(x / xscale)) axs[1].xaxis.set_major_formatter(xticks) yticks = ticker.FuncFormatter(lambda y, pos: '{0:g}'.format(y / yscale)) for ax in axs: ax.yaxis.set_major_formatter(yticks) # print fit report in space below plot, after dropping first two lines report = fit_result.fit_report(show_correl=False) report = ''.join(report.splitlines(True)[2:]) fig.suptitle(report, fontsize=report_fontsize, family='monospace', horizontalalignment='left', x=0.1, y=0.25) return fig, axs