def signal_to_noise(fname, col=1, method='var', fname_cov=''): """Return signal to noise ratio for WL measurements in file fname. Parameters ---------- fname: string Input file name col: integer Column number for signal, default=1 method: string Noise method, 'var' (default), 'cov' fname_cov: string Covariance file, optional Returns ------- SNR: float signa to noise ratio """ if method == 'var': dat = ascii.read(fname) y = dat[dat.keys()[col]] # gt or DeltaSigma dy = dat['sqrt_Dcor'] snr = athena.signal_to_noise_w2_var(y, dy) else: mkstuff.error('Method \'{}\' not (yet) implemented'.format(method)) return snr
def plot_histograms(dir, X, hist_type='logM', out_dir='plots', out_name_ext='', verbose=False): """Plot cluster mass and redshift histograms""" if max(X) < 0: # X is array of [-1] if no corresponding column in cluster data found (see get_cluster_data) if verbose is True: print('Columns for hist_type \'{}\' not valid/not found, skipping plot_histogram'.format(hist_type)) return if hist_type == 'logM': # Mass x = np.log10(X) Mman, Mexp = mkstuff.frexp10(X.mean()) text = 'mean $M = {} \\times 10^{{{}}}$'.format('%.1f' % Mman, Mexp) xlabel = '$\\log M$' create_histogram(dir, out_dir, x, xlabel, text, hist_type, name_ext=out_name_ext) elif hist_type == 'z': # Redshift x = X text = 'mean $z$ = {}'.format('%.2f' % X.mean()) xlabel = '$z$' create_histogram(dir, out_dir, x, xlabel, text, hist_type, name_ext=out_name_ext) elif hist_type == 'SNR': # Signal-to-noise x = X text = 'mean SNR = {}'.format('%.2f' % X.mean()) xlabel = 'SNR{}'.format(out_name_ext) create_histogram(dir, out_dir, x, xlabel, text, hist_type, name_ext=out_name_ext) else: mkstuff.error('Wrong hist_type \'{}\''.format(hist_type))
def stack(stack, n_cl=-1, fname='wgl_1.txt', subtype='wgl', verbose=False): """Stack shear profiles of clusters. Call 'mean_allcolumns.pl'. (Formerly in wl_cluster.py.) Parameters ---------- stack : string Stack type: 'physical', 'angular' n_cl : integer Number of clusters for checking, default=-1. If < 0 no check is performed. fname : string File name of wgl output file to be stacked subtype : string 'wgl' (default), 'wgl_res', 'DeltaSigma' verbose : bool Verbose output Returns ------- None """ if stack is None: if verbose is True: print('No stacking') return # TODO: Only use clusters with non-zero profile, modify -t option. in_name = fname if n_cl < 0: t_flag = '' else: t_flag = '-t {}'.format(n_cl) if subtype == 'wgl' or subtype == 'DeltaSigma': w_flags = '-w 3' # Weight column (w) elif subtype == 'wgl_res': w_flags = '-w 2 -f 1/x^2' # rms column, use as w=1/rms^2 else: mkstuff.error('Unknown subtype \'{}\''.format(subtype)) cmd = 'mean_allcolumns.pl -k {} {} -r {}'.format(t_flag, w_flags, in_name) n, out_mgs, err_msg = mkstuff.run_cmd(cmd, verbose=verbose) if n == 0: mkstuff.error('No file \'{}\' found for stacking, exiting populationWL.stack with error'.format(in_name)) mkstuff.mkdir_p('stack') os.rename('{}.mean'.format(in_name), 'stack/{}.mean'.format(in_name)) os.rename('{}.rms'.format(in_name), 'stack/{}.rms'.format(in_name)) os.rename('{}.meanrms'.format(in_name), 'stack/{}.meanrms'.format(in_name)) return n
def __init__(self, name, ra, dec, z, M, unit, scale=1): self.n = len(name) if self.n != len(ra) or self.n != len(dec) or self.n != len(z): mkstuff.error('Unequal lengths for cluster input data') self.name = [str(n) for n in name] self.ra = athena.unit_to_rad(ra, unit) self.dec = athena.unit_to_rad(dec, unit) self.z = z self.M = M self.unit = unit self.scale = scale
def get_bg_cat_zmin(dir, lensing_cat_base, lensing_ext, z): """Return background (lensing) catalogue with zmin > z. Parameters ---------- dir: string Directory of catalogues lensing_cat_base: string Catalogue base name lensing_ext: string Catalogue extension z: float Minimum redshift Returns ------- cat_lens: string Catalogue name. '' if no match found. """ # Find all lensing catalogues base = '{}/{}_zmin_'.format(dir, lensing_cat_base) pattern = '{}*.{}'.format(base, lensing_ext) files = glob.glob(pattern) if len(files) == 0: pattern = '{}.{}'.format(dir, lensing_cat_base, lensing_ext) print(pattern) if os.path.isfile(pattern): return pattern else: mkstuff.error('No matching lensing catalogue slices \'{}\' found'.format(pattern)) # Extract zmin from file name min_zmin = 99 cat_lens = '' for f in files: m = re.findall('{}(.*).{}'.format(base, lensing_ext), f) if len(m) == 0: continue this_zmin = float(m[0]) if this_zmin >= z: if min_zmin > this_zmin: min_zmin = this_zmin cat_lens = f return cat_lens
def run_athena_list(config_names, suffixes=None, n_cpu=1, version='C', verbose=False, run=True): """Run athena. Parameters ---------- config_names: list of strings list of config names suffixes: list of strings list of suffix names, default empty, uses config_names instead n_cpu: integer number of CPUs, default=1 version: string One of ['C' (default)] verbose: boolean verbose output, default False run: boolean if False, do not run athena. Default = True Returns ------- None """ athena_path = get_athena_path(version=version) if verbose: q_ath = '' else: q_ath = ' -q' cmds = [] for i, cn in enumerate(config_names): if os.path.isfile(cn): if suffixes is None or len(suffixes) == 0: suff = cn else: suff = suffixes[i] cmds.append('{}/athena -c {} --out_suf {}{}'.format(athena_path, cn, suff, q_ath)) if verbose is True: print('Running {} athena jobs on {} CPUs'.format(len(cmds), n_cpu)) res = mkstuff.run_cmd_list(cmds, ncpu=n_cpu, verbose=verbose, run=run) if res != 0: mkstuff.error('At least one athena run returned error code {}'.format(res))
def get_unit(field, verbose=False, exit=False): """Returns unit for angular scales, from header line with format e.g. 'theta[UNIT]'. If exit=True, exists with error. If exit=False, returns unit_default. """ for u in units.keys(): if u in field: if verbose == True: print('Unit of input angular scales = {0}'.format(u)) return u if exit == True: mkstuff.error('No unit found, exiting') if verbose == True: warnings.warn('No unit for angular scales found, assuming \'{0}\''.format(unit_default)) return unit_default
def get_athena_path(version='C'): """Return path to athena. Parameters ---------- version: string One of ['C' (default)] Returns ------- path: string /path/to/athena """ if version == 'C': return '{0}/athena_git_Euclid/bin'.format(os.environ['HOME']) else: mkstuff.error('Wrong athena verions {}'.format(version))
def get_col_label(subtype, unit=''): """Return column names and plot labels. Parameters ---------- subtype: string 'wgl', 'wgl_res', 'DeltaSigma' unit: string '', 'M_sun/pc2' Returns ------- None col: array of strings column names label: array of strings labels ylabel: string y-axis label """ if unit == '' and subtype == 'DeltaSigma': unit = 'M_sun/pc2' if unit != '': unit_str = '[{}]'.format(unit) unit_label = '[{}]'.format(u.Unit(unit).to_string('latex_inline')) if subtype == 'wgl': col = ['g_t', 'g_x', 'sqrt_Dcor', 'sqrt_Dcor'] label = ['$\\gamma_{\\rm t}$', '$\\gamma_\\times$'] ylabel = 'Tangential and cross-shear' elif subtype == 'wgl_res': col = ['g_t_resample', 'g_t_rms_resample'] label = ['$\\gamma_{\\rm t}$'] ylabel = 'Tangential shear' elif subtype == 'DeltaSigma': col = ['Delta_Sigma_t{}'.format(unit_str), 'Delta_Sigma_x{}'.format(unit_str), 'sqrt_Dcor', 'sqrt_Dcor'] label = ['$\\Delta \\Sigma_{{\\rm t}}$ {}'.format(unit_label), '$\\Delta \\Sigma_\\times$ {}'.format(unit_label)] ylabel = 'Projected overdensity' else: mkstuff.error('Unknown subtype \'{}\''.format(subtype)) return col, label, ylabel
def dtheta_theta(self, i): """Returns dtheta_i * theta_i """ if self.binning == 'lin': # dtheta * theta d = self.delta * self.theta[i] elif self.binning == 'log': # d log theta * theta^2 = d theta / theta * theta^2 = dtheta * theta d = self.delta * self.theta[i] * self.theta[i] elif self.binning == 'ireg': if i != self.length-1: d = (self.theta[i+1] - self.theta[i]) * self.theta[i] else: d = (self.theta[i] - self.theta[i-1]) * self.theta[i] else: mkstuff.error('Invalid binning type \'{}\''.format(self.binning)) return d
def read_xi(fname, file_format, force_reg, verbose=False): """Reads a shear-shear correlation function file (ascii or fits). """ my_file_format = get_file_format(file_format, fname) if verbose: print("File format is {0}".format(my_file_format)) if my_file_format == 'fits': theta, xip, xim, xix = read_xi_fits(fname, force_reg, verbose) elif my_file_format == 'ascii': theta, xip, xim, xix = read_xi_ascii(fname, force_reg, verbose) else: mkstuff.error('read_xi: Wrong file format \'{0}\', has to be \'ascii\' or \'fits\' (option \'-f\')'.format(my_file_format)) xi = xi_data(theta, xip, xim, xix, my_file_format, force_reg=force_reg, verbose=verbose) return xi
def get_theta_xlabel(scale_mode, wgl, unit_force=None): """Return angular scale column and xlabel string, from file wgl Parameters ---------- scale_mode: string 'physical' or 'angular' wgl: Class table wgl file content, e.g. obtained from ascii.read unit_force: string, default=None If not None, use unit_force for label Returns ------- theta: array of double content of scale column xlabel: string x-axis label """ if scale_mode == "angular": x = ['theta'] for key in units: x.append('theta[{}]'.format(key)) elif scale_mode == "physical": x = ['R[Mpc]', 'R'] theta = None for myx in x: if myx in wgl.keys(): theta = wgl[myx] xlabel = myx break if unit_force is not None: pattern = re.compile('\[.*\]') xlabel = pattern.sub('[{}]'.format(unit_force), xlabel) if theta is None: mkstuff.error('Column for angular scale not found') return theta, xlabel
def get_unit_fits(header, verbose=False, exit=False): if 'UNITS' in header.keys(): unit = header['UNITS'] else: if exit == True: mkstuff.error('No unit found, exiting') if verbose == True: mkstuff.warning('No \'UNITS\' keyword in fits header found, assuming default unit for angular scales \'{0}\''.format(unit_default)) return unit_default # Go through valid units and compare to assigned one (from header) for u in units.keys(): if u == unit: if verbose == True: print('Unit of input angular scales = {0}'.format(u)) return u if verbose == True: mkstuff.warning('Unit from fits header (\'UNITS\' = \'{0}\') not a valid unit, reverting to default unit \'{1}\''.format(unit, unit_default)) return unit_default
def check_fields(header, strings, indices, exit, verbose=False): """Prints error (warning) message if header (array of strings) does not contain necessary (optional) strings. """ if header is None: if verbose is True: mkstuff.warning('No header found, using default columns') if exit is True: return False for i in range(len(strings)): if len(header) <= indices[i] or not strings[i] in header[indices[i]]: msg = 'Field \'{0}\' not found in header (expected in field #{1})'.format(strings[i], indices[i]) if exit is True: mkstuff.error(msg) else: if verbose is True: mkstuff.warning('{}, continuing'.format(msg)) return False return True
def read_xi_ascii(fname, force_reg, verbose=False): """Read a shear-shear correlation function ascii file. """ if verbose is True: print('Reading input xi file \'{0}\''.format(fname)) xi, ncomment, header = mkstuff.read_table(fname, True) if xi.shape[1] <= 2: mkstuff.error('Input file \'{0}\' has only {1} columns. Minimum columns are (theta, xi+, xi-)'.format(fname, xi.shape[1])) if ncomment > 0: fields = header[0].replace('#', '').split() else: fields = None # Required fields check_fields(fields, in_cols.xi_names, in_cols.xi_indices, True, verbose) theta = xi[:, in_cols.scale.num] xip = xi[:, in_cols.signal1['xi'].num] xim = xi[:, in_cols.signal2['xi'].num] # Optional fields has_xix = check_fields(fields, in_cols.xi_names_opt, in_cols.xi_indices_opt, False, verbose) if has_xix == True: xix = xi[:, in_cols.parity['xi'].num] else: xix = None # Units of angular scales if fields is not None: unit = get_unit(fields[in_cols.scale.num], verbose) else: unit = unit_default theta = unit_to_rad(theta, unit) return theta, xip, xim, xix
def __init__(self, fname=None, zdata=None, zbin=None, err_if_empty=False): if fname is None or fname == '': if zdata is None and zbin is None: if err_if_empty == True: mkstuff.error('No redshift info given, not creating empty nofz') # No nofz input given, create empty nofz self.z = None self.n = None self.nz = None self.type = 'none' elif zdata is None or zbin is None: mkstuff.error('Only one of zbin and zdata defined') else: # Input histogram self.n, self.z = np.histogram(zdata, zbin) # Right-most input bin nofz.z[-1] is correctly interpreted as last bin edge. # Returned n has one entry less than z. self.n = np.append(self.n, [0]) self.nz = self.z.shape[0] - 1 self.type = 'hist' else: if zdata is not None or zbin is not None: mkstuff.error('Both n(z) input file name and zdata/zbin defined') else: # Read nofz from file dat, n, head = mkstuff.read_table(fname, count_comment=True) if re.search('hist', head[0]) is not None: self.z = dat[:,0] self.n = dat[:,1] self.nz = dat.shape[0] - 1 self.type = 'hist' else: mkstuff.error('nofz: only \'hist\' type implemented') self.is_valid()
def is_valid(self): """Checks whether nofz has valid format and content. """ if self.n[-1] != 0: mkstuff.error('Wrong histogram format, frequency for rightmost bin corner has ' + 'to be 0, found instead {}'.format(self.n[-1])) if sum(self.n) == 0: mkstuff.error('sum of n(z) is zero') if max(self.z) == 0: mkstuff.error('All redshifts are zero') return True
def read_pkappa_band_fits(fname, verbose=False, stop=False): """Read from file the band-power spectrum P_i. Parameters ---------- fname: string file name verbose: boolean verbose mode if True, default False stop: boolean If True (default), exit with error. If False, return None Returns ------- pb: class pkappa_data data """ try: hdulist = fits.open(fname) except IOError: msg = 'File \'{}\' does not exist'.format(fname) mkstuff.error(msg, stop=stop, verbose=verbose) if stop is False: return None for ihdu, hdu in enumerate(hdulist): header_col_vals = get_header_columns_from_fits_table(hdu) if header_col_vals is not None: check_fields(header_col_vals, in_cols.Pb_names, in_cols.Pb_indices, True, verbose) if verbose is True: print('Table with band-power spectrum data found at hdu #{}'.format(ihdu)) ell = hdu.data[in_cols.scale_F.name] P_E = hdu.data[in_cols.signal1['Pb'].name] P_B = hdu.data[in_cols.signal2['Pb'].name] P_EB = hdu.data[in_cols.parity['Pb'].name] ell_lower = hdu.data[in_cols.scale_lo['Pb'].name] ell_upper = hdu.data[in_cols.scale_hi['Pb'].name] has_errors = check_fields(header_col_vals, in_cols.Pb_names_err, in_cols.Pb_indices_err, False, verbose) if has_errors is True: dP_E = hdu.data[in_cols.error1['Pb'].name] dP_B = hdu.data[in_cols.error2['Pb'].name] dP_EB = hdu.data[in_cols.error_parity['Pb'].name] else: dP_E = None dP_B = None dP_EB = None break hdulist.close() if ell is None: pb = None else: pb = pkappa_data(ell[0], ell[1], band=True, error=True, Nell=len(ell)) pb.ell = ell pb.pE = P_E pb.pB = P_B pb.pEB = P_EB pb.dpE = dP_E pb.dpB = dP_B pb.dpEB = dP_EB return pb
def read_xi_rms_resample_fits(fname, force_reg, verbose=False, stop=True): """Read a shear-shear correlation function resample (containing mean and rms) file in fits format. Parameters ---------- fname: string input file name force_reg: boolean if True, forces regular binning verbose: boolean Verbose output, default=False stop: boolean If True (default), exit with error. If False, return None Returns ------- theta: array of double, length N_theta angular scales xi: array of double, length N_resample x N_theta resampled correlation values resample_type: string resample type, 'bootstrap', 'jackknife' """ hdulist = fits.open(fname) nhdu = len(hdulist) theta = None for hdu in range(nhdu): hdu_type = type(hdulist[hdu]) # TODO: Use get_header_columns_from_fits_table if hdu_type == fits.hdu.table.BinTableHDU or hdu_type == fits.hdu.table.TableHDU: if 'OBJECT' in hdulist[hdu].header and hdulist[hdu].header.get('OBJECT') == 'xi.resample': if verbose == True: print('Table found in fits file {0} (hdu #{1})'.format(input, hdu)) header_all_keys = hdulist[hdu].header.keys() header_col_keys = [s for s in header_all_keys if 'TTYPE' in s] header_col_vals = [hdulist[hdu].header.get(s) for s in header_col_keys] # Required fields check_fields(header_col_vals, in_cols.xi_res_names, in_cols.xi_res_indices, True, verbose) theta = hdulist[hdu].data[in_cols.scale.name] xi_p_res = hdulist[hdu].data[in_cols.signal1['xi_res'].name] xi_m_res = hdulist[hdu].data[in_cols.signal2['xi_res'].name] rms_p_res = hdulist[hdu].data[in_cols.rms1['xi_res'].name] rms_m_res = hdulist[hdu].data[in_cols.rms2['xi_res'].name] # Units of angular scales unit = get_unit_fits(hdulist[hdu].header, verbose) theta = unit_to_rad(theta, unit) break hdulist.close() if theta is None: msg = 'No hdu with resample information (OBJECT \'xi.resample\') found in file {}'.format(fname) if stop is True: mkstuff.error(msg) else: if verbose is True: print('{}, continuing'.format(msg)) return None return theta, xi_p_res, xi_m_res, rms_p_res, rms_m_res
def read_xi_resample_fits(fname, force_reg, check_OBJECT=None, verbose=False): """Read a shear-shear correlation function file with individual resample results, in fits format (xi_p or xi_m). Parameters ---------- fname: string input file name force_reg: boolean if True, forces regular binning check_OBJECT: string If not None, checks whether the given string equals the value of the OBJECT key in fits header, and returns with error if not. Default: None verbose: boolean Verbose output, default=False Returns ------- theta: array of double, length N_theta angular scales xi: array of double, length N_resample x N_theta resampled correlation values resample_type: string resample type, 'bootstrap', 'jackknife' """ hdulist = fits.open(fname) nhdu = len(hdulist) for hdu in range(nhdu): hdu_type = type(hdulist[hdu]) # TODO: Use get_header_columns_from_fits_table if hdu_type == fits.hdu.table.BinTableHDU or hdu_type == fits.hdu.table.TableHDU: if verbose == True: print('Table found in fits file {0} (hdu #{1})'.format(input, hdu)) header_all_keys = hdulist[hdu].header.keys() header_col_keys = [s for s in header_all_keys if 'TTYPE' in s] header_col_vals = [hdulist[hdu].header.get(s) for s in header_col_keys] if check_OBJECT is not None: if 'OBJECT' in hdulist[hdu].header: val = hdulist[hdu].header.get('OBJECT') if val != check_OBJECT: mkstuff.error('Found in fits header \'OBJECT = {}\', not equal to required \'\''.format(val, check_OBJECT)) else: mkstuff.error('Key \'OBJECT\' not found in header') if 'TYPE' in hdulist[hdu].header: resample_type = hdulist[hdu].header.get('TYPE') if resample_type != 'bootstrap' and resample_type != 'jackknife': mkstuff.error('Unknown resample type \'{}\' found in fits file (keyword \'TYPE\')'.format(resample_type)) check_fields(header_col_vals, [in_cols.xi_names[0]], [in_cols.xi_indices[0]], True, verbose) # Angular scales theta = hdulist[hdu].data[in_cols.scale.name] unit = get_unit_fits(hdulist[hdu].header, verbose) theta = unit_to_rad(theta, unit) # Correlation data xi = [] for i in range(1, len(header_col_vals)): key = header_col_vals[i] xi_this_res = hdulist[hdu].data[key] xi.append(xi_this_res) break return theta, xi, resample_type
def plot_corr_w2_col(theta, w2, xlabel, ylabel, label, title='', SNR=False, scales_SNR=None, with0=False, ylog=False): """Plot columns theta versus w2, containing data and error column(s). Called by plot_corr_w2_internal. Parameters ---------- theta: array of length N of float x-axis data w2: array NxNcol of float y-axis data, sets of data and error columns xlabel: string x-axis label ylabel: string y-axis label label: array of length 2 of string labels for the two data sets (w2) title: string title string (default: empty) SNR: boolean If True, calculates and adds as text to plot signa-to-noise ratio. scales_SNR: string, two numbers with separator '_' or ' ' Minimum and maximum scale for SNR calculation. If None (default) use full range. with0: bool If True, adds the y=0 line. Default: False ylog: bool If True, plot log of y-axis, default: False Returns ------- None """ color = ['b', 'g'] msize = [5, 4] sign = [-1, 1] f_err, f_lim, log_x = prepare_plot(theta, title, xlabel, ylabel) if len(w2) == 4: yerr = [w2[2], w2[3]] Ndata = 2 elif len(w2) == 2: yerr = [w2[1]] Ndata = 1 else: mkstuff.error('Wrong number {} of columns in w2'.format(len(w2))) if ylog is True: for i in range(0, Ndata): # dlogy = dy/y yerr[i] = yerr[i] / w2[i] id_pos = np.where(w2[i]>0) id_neg = np.where(w2[i]<=0) y_pos = np.log10(w2[i][id_pos]) y_neg = np.log10(-w2[i][id_neg]) if i == 0: mkplot.make_log_ticks('y', min(y_pos)-2, max(y_pos)+1) plt.plot(log_x[id_pos] + sign[i]*f_err, y_pos, '{}.'.format(color[i]), marker='o', markersize=msize[i], label=label[i]) plt.plot(log_x[id_neg] + sign[i]*f_err, y_neg, '{}o'.format(color[i]), marker='o', mfc='none', markersize=msize[i], label='') plt.errorbar(log_x[id_pos] + sign[i]*f_err, y_pos, yerr=yerr[i][id_pos], fmt='none', ecolor='{}'.format(color[i]), elinewidth=1, label='') plt.errorbar(log_x[id_neg] + sign[i]*f_err, y_neg, yerr=yerr[i][id_neg], fmt='none', ecolor='{}'.format(color[i]), elinewidth=0.5, label='') else: for i in [0, Ndata-1]: plt.plot(log_x + sign[i]*f_err, w2[i], '{}'.format(color[i]), linewidth=1, label=label[i]) plt.errorbar(log_x + sign[i]*f_err, w2[i], yerr=yerr[i], fmt='none', ecolor='{}'.format(color[i]), label='') if with0 is True: plt.plot([min(log_x), max(log_x)], [0, 0], 'k', linewidth=1, label=None) plt.legend(loc='upper right', numpoints=1, frameon=False) if SNR is True: imin, imax = get_index_range(theta, scales_SNR) ax = plt.subplot(1, 1, 1) if len(w2) == 4: snr = signal_to_noise_w2_var(w2[0][imin:imax+1], w2[2][imin:imax+1]) snr_x = signal_to_noise_w2_var(w2[1][imin:imax+1], w2[3][imin:imax+1]) plt.text(0.95, 0.7, 'SNR_x = {}'.format('%.2f' % snr_x), ha='right', transform=ax.transAxes) elif len(w2) == 2: snr = signal_to_noise_w2_var(w2[0][imin:imax+1], w2[1][imin:imax+1]) plt.text(0.95, 0.75, 'SNR_t = {}'.format('%.2f' % snr), ha='right', transform=ax.transAxes) ymin, ymax = plt.ylim() dx2 = (log_x[1] - log_x[0])/2 plt.plot([log_x[imin]-dx2, log_x[imin]-dx2], [ymin, ymax], linestyle='dashed', color='black') plt.plot([log_x[imax]+dx2, log_x[imax]+dx2], [ymin, ymax], linestyle='dashed', color='black') # From plot_wgl.py:plot_stacked_wgl mkplot.update_lim('x', max_new = np.log10(max(theta) * f_lim))