def get_background(self, n_min=<NUM_LIT:10>, n_max=None, focus_stage='<STR_LIT>', bkg_filter=False, f_win=<NUM_LIT:5>, f_n_lim=<NUM_LIT:3>):

allbkgs = {'<STR_LIT>': [],<EOL>'<STR_LIT>': []}<EOL>if focus_stage == '<STR_LIT>':<EOL><INDENT>if '<STR_LIT>' not in self.stages_complete:<EOL><INDENT>focus_stage = '<STR_LIT>'<EOL><DEDENT><DEDENT>for a in self.analytes:<EOL><INDENT>allbkgs[a] = []<EOL><DEDENT>n0 = <NUM_LIT:0><EOL>for s in self.data.values():<EOL><INDENT>if sum(s.bkg) > <NUM_LIT:0>:<EOL><INDENT>allbkgs['<STR_LIT>'].append(s.uTime[s.bkg])<EOL>allbkgs['<STR_LIT>'].append(enumerate_bool(s.bkg, n0)[s.bkg])<EOL>n0 = allbkgs['<STR_LIT>'][-<NUM_LIT:1>][-<NUM_LIT:1>]<EOL>for a in self.analytes:<EOL><INDENT>allbkgs[a].append(s.data[focus_stage][a][s.bkg])<EOL><DEDENT><DEDENT><DEDENT>allbkgs.update((k, np.concatenate(v)) for k, v in allbkgs.items())<EOL>bkgs = pd.DataFrame(allbkgs)  <EOL>self.bkg = Bunch()<EOL>if n_max is None:<EOL><INDENT>self.bkg['<STR_LIT>'] = bkgs.groupby('<STR_LIT>').filter(lambda x: len(x) > n_min)<EOL><DEDENT>else:<EOL><INDENT>self.bkg['<STR_LIT>'] = bkgs.groupby('<STR_LIT>').filter(lambda x: (len(x) > n_min) & (len(x) < n_max))<EOL><DEDENT>self.bkg['<STR_LIT>'] = self.bkg['<STR_LIT>'].groupby('<STR_LIT>').aggregate([np.mean, np.std, stderr])<EOL>self.bkg['<STR_LIT>'].sort_values(('<STR_LIT>', '<STR_LIT>'), inplace=True)<EOL>if bkg_filter:<EOL><INDENT>t = self.bkg['<STR_LIT>'].loc[:, idx[:, '<STR_LIT>']]<EOL>r = t.rolling(f_win).aggregate([np.nanmean, np.nanstd])<EOL>upper = r.loc[:, idx[:, :, '<STR_LIT>']] + f_n_lim * r.loc[:, idx[:, :, '<STR_LIT>']].values<EOL>over = r.loc[:, idx[:, :, '<STR_LIT>']] > np.roll(upper.values, <NUM_LIT:1>, <NUM_LIT:0>)<EOL>ns_drop = over.loc[over.apply(any, <NUM_LIT:1>), :].index.values<EOL>self.bkg['<STR_LIT>'].drop(ns_drop, inplace=True)<EOL>ind = np.ones(self.bkg['<STR_LIT>'].shape[<NUM_LIT:0>], dtype=bool)<EOL>for ns in ns_drop:<EOL><INDENT>ind = ind & (self.bkg['<STR_LIT>'].loc[:, '<STR_LIT>'] != ns)<EOL><DEDENT>self.bkg['<STR_LIT>'] = self.bkg['<STR_LIT>'].loc[ind, :]<EOL><DEDENT>return<EOL>

Extract all background data from all samples on universal time scale.
Used by both 'polynomial' and 'weightedmean' methods.

Parameters
----------
n_min : int
    The minimum number of points a background region must
    have to be included in calculation.
n_max : int
    The maximum number of points a background region must
    have to be included in calculation.
filter : bool
    If true, apply a rolling filter to the isolated background regions
    to exclude regions with anomalously high values. If True, two parameters
    alter the filter's behaviour:
f_win : int
    The size of the rolling window
f_n_lim : float
    The number of standard deviations above the rolling mean
    to set the threshold.
focus_stage : str
    Which stage of analysis to apply processing to.
    Defaults to 'despiked' if present, or 'rawdata' if not.
    Can be one of:
    * 'rawdata': raw data, loaded from csv file.
    * 'despiked': despiked data.
    * 'signal'/'background': isolated signal and background data.
      Created by self.separate, after signal and background
      regions have been identified by self.autorange.
    * 'bkgsub': background subtracted data, created by
      self.bkg_correct
    * 'ratios': element ratio data, created by self.ratio.
    * 'calibrated': ratio data calibrated to standards, created by self.calibrate.

Returns
-------
pandas.DataFrame object containing background data.


@_log<EOL><INDENT>def bkg_calc_weightedmean(self, analytes=None, weight_fwhm=None,<EOL>n_min=<NUM_LIT:20>, n_max=None, cstep=None,<EOL>bkg_filter=False, f_win=<NUM_LIT:7>, f_n_lim=<NUM_LIT:3>, focus_stage='<STR_LIT>'):<DEDENT>

if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL>self.bkg = Bunch()<EOL><DEDENT>elif isinstance(analytes, str):<EOL><INDENT>analytes = [analytes]<EOL><DEDENT>if weight_fwhm is None:<EOL><INDENT>weight_fwhm = <NUM_LIT>  <EOL><DEDENT>self.get_background(n_min=n_min, n_max=n_max,<EOL>bkg_filter=bkg_filter,<EOL>f_win=f_win, f_n_lim=f_n_lim, focus_stage=focus_stage)<EOL>if '<STR_LIT>' not in self.bkg.keys():<EOL><INDENT>if cstep is None:<EOL><INDENT>cstep = weight_fwhm / <NUM_LIT:20><EOL><DEDENT>elif cstep > weight_fwhm:<EOL><INDENT>warnings.warn("<STR_LIT>" +<EOL>"<STR_LIT>")<EOL><DEDENT>bkg_t = np.linspace(<NUM_LIT:0>,<EOL>self.max_time,<EOL>self.max_time // cstep)<EOL>self.bkg['<STR_LIT>'] = Bunch()<EOL>self.bkg['<STR_LIT>']['<STR_LIT>'] = bkg_t<EOL><DEDENT>mean, std, stderr = gauss_weighted_stats(self.bkg['<STR_LIT>'].uTime,<EOL>self.bkg['<STR_LIT>'].loc[:, analytes].values,<EOL>self.bkg['<STR_LIT>']['<STR_LIT>'],<EOL>fwhm=weight_fwhm)<EOL>for i, a in enumerate(analytes):<EOL><INDENT>self.bkg['<STR_LIT>'][a] = {'<STR_LIT>': mean[i],<EOL>'<STR_LIT>': std[i],<EOL>'<STR_LIT>': stderr[i]}<EOL><DEDENT>

Background calculation using a gaussian weighted mean.

Parameters
----------
analytes : str or iterable
    Which analyte or analytes to calculate.
weight_fwhm : float
    The full-width-at-half-maximum of the gaussian used
    to calculate the weighted average.
n_min : int
    Background regions with fewer than n_min points
    will not be included in the fit.
cstep : float or None
    The interval between calculated background points.
filter : bool
    If true, apply a rolling filter to the isolated background regions
    to exclude regions with anomalously high values. If True, two parameters
    alter the filter's behaviour:
f_win : int
    The size of the rolling window
f_n_lim : float
    The number of standard deviations above the rolling mean
    to set the threshold.
focus_stage : str
    Which stage of analysis to apply processing to.
    Defaults to 'despiked' if present, or 'rawdata' if not.
    Can be one of:
    * 'rawdata': raw data, loaded from csv file.
    * 'despiked': despiked data.
    * 'signal'/'background': isolated signal and background data.
      Created by self.separate, after signal and background
      regions have been identified by self.autorange.
    * 'bkgsub': background subtracted data, created by
      self.bkg_correct
    * 'ratios': element ratio data, created by self.ratio.
    * 'calibrated': ratio data calibrated to standards, created by self.calibrate.


@_log<EOL><INDENT>def bkg_calc_interp1d(self, analytes=None, kind=<NUM_LIT:1>, n_min=<NUM_LIT:10>, n_max=None, cstep=None,<EOL>bkg_filter=False, f_win=<NUM_LIT:7>, f_n_lim=<NUM_LIT:3>, focus_stage='<STR_LIT>'):<DEDENT>

if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL>self.bkg = Bunch()<EOL><DEDENT>elif isinstance(analytes, str):<EOL><INDENT>analytes = [analytes]<EOL><DEDENT>self.get_background(n_min=n_min, n_max=n_max,<EOL>bkg_filter=bkg_filter,<EOL>f_win=f_win, f_n_lim=f_n_lim, focus_stage=focus_stage)<EOL>def pad(a, lo=None, hi=None):<EOL><INDENT>if lo is None:<EOL><INDENT>lo = [a[<NUM_LIT:0>]]<EOL><DEDENT>if hi is None:<EOL><INDENT>hi = [a[-<NUM_LIT:1>]]<EOL><DEDENT>return np.concatenate((lo, a, hi))<EOL><DEDENT>if '<STR_LIT>' not in self.bkg.keys():<EOL><INDENT>bkg_t = pad(self.bkg['<STR_LIT>'].loc[:, ('<STR_LIT>', '<STR_LIT>')], [<NUM_LIT:0>], [self.max_time])<EOL>self.bkg['<STR_LIT>'] = Bunch()<EOL>self.bkg['<STR_LIT>']['<STR_LIT>'] = bkg_t<EOL><DEDENT>d = self.bkg['<STR_LIT>']<EOL>with self.pbar.set(total=len(analytes), desc='<STR_LIT>') as prog:<EOL><INDENT>for a in analytes:<EOL><INDENT>self.bkg['<STR_LIT>'][a] = {'<STR_LIT>': pad(d.loc[:, (a, '<STR_LIT>')].values),<EOL>'<STR_LIT>': pad(d.loc[:, (a, '<STR_LIT>')].values),<EOL>'<STR_LIT>': pad(d.loc[:, (a, '<STR_LIT>')].values)}<EOL>prog.update()<EOL><DEDENT><DEDENT>self.bkg['<STR_LIT>']<EOL>return<EOL>

Background calculation using a 1D interpolation.

scipy.interpolate.interp1D is used for interpolation.

Parameters
----------
analytes : str or iterable
    Which analyte or analytes to calculate.
kind : str or int
    Integer specifying the order of the spline interpolation
    used, or string specifying a type of interpolation.
    Passed to `scipy.interpolate.interp1D`
n_min : int
    Background regions with fewer than n_min points
    will not be included in the fit.
cstep : float or None
    The interval between calculated background points.
filter : bool
    If true, apply a rolling filter to the isolated background regions
    to exclude regions with anomalously high values. If True, two parameters
    alter the filter's behaviour:
f_win : int
    The size of the rolling window
f_n_lim : float
    The number of standard deviations above the rolling mean
    to set the threshold.
focus_stage : str
    Which stage of analysis to apply processing to.
    Defaults to 'despiked' if present, or 'rawdata' if not.
    Can be one of:
    * 'rawdata': raw data, loaded from csv file.
    * 'despiked': despiked data.
    * 'signal'/'background': isolated signal and background data.
      Created by self.separate, after signal and background
      regions have been identified by self.autorange.
    * 'bkgsub': background subtracted data, created by
      self.bkg_correct
    * 'ratios': element ratio data, created by self.ratio.
    * 'calibrated': ratio data calibrated to standards, created by self.calibrate.


@_log<EOL><INDENT>def bkg_subtract(self, analytes=None, errtype='<STR_LIT>', focus_stage='<STR_LIT>'):<DEDENT>

if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL><DEDENT>elif isinstance(analytes, str):<EOL><INDENT>analytes = [analytes]<EOL><DEDENT>if focus_stage == '<STR_LIT>':<EOL><INDENT>if '<STR_LIT>' not in self.stages_complete:<EOL><INDENT>focus_stage = '<STR_LIT>'<EOL><DEDENT><DEDENT>bkg_interps = {}<EOL>for a in analytes:<EOL><INDENT>bkg_interps[a] = un_interp1d(x=self.bkg['<STR_LIT>']['<STR_LIT>'],<EOL>y=un.uarray(self.bkg['<STR_LIT>'][a]['<STR_LIT>'],<EOL>self.bkg['<STR_LIT>'][a][errtype]))<EOL><DEDENT>self.bkg_interps = bkg_interps<EOL>with self.pbar.set(total=len(self.data), desc='<STR_LIT>') as prog:<EOL><INDENT>for d in self.data.values():<EOL><INDENT>[d.bkg_subtract(a, bkg_interps[a].new(d.uTime), ~d.sig, focus_stage=focus_stage) for a in analytes]<EOL>d.setfocus('<STR_LIT>')<EOL>prog.update()<EOL><DEDENT><DEDENT>self.stages_complete.update(['<STR_LIT>'])<EOL>self.focus_stage = '<STR_LIT>'<EOL>return<EOL>

Subtract calculated background from data.

Must run bkg_calc first!

Parameters
----------
analytes : str or iterable
    Which analyte(s) to subtract.
errtype : str
    Which type of error to propagate. default is 'stderr'.
focus_stage : str
    Which stage of analysis to apply processing to.
    Defaults to 'despiked' if present, or 'rawdata' if not.
    Can be one of:
    * 'rawdata': raw data, loaded from csv file.
    * 'despiked': despiked data.
    * 'signal'/'background': isolated signal and background data.
      Created by self.separate, after signal and background
      regions have been identified by self.autorange.
    * 'bkgsub': background subtracted data, created by
      self.bkg_correct
    * 'ratios': element ratio data, created by self.ratio.
    * 'calibrated': ratio data calibrated to standards, created by self.calibrate.


@_log<EOL><INDENT>def correct_spectral_interference(self, target_analyte, source_analyte, f):<DEDENT>

if target_analyte not in self.analytes:<EOL><INDENT>raise ValueError('<STR_LIT>'.format(target_analyte, '<STR_LIT:U+002CU+0020>'.join(self.analytes)))<EOL><DEDENT>if source_analyte not in self.analytes:<EOL><INDENT>raise ValueError('<STR_LIT>'.format(source_analyte, '<STR_LIT:U+002CU+0020>'.join(self.analytes)))<EOL><DEDENT>with self.pbar.set(total=len(self.data), desc='<STR_LIT>') as prog:<EOL><INDENT>for d in self.data.values():<EOL><INDENT>d.correct_spectral_interference(target_analyte, source_analyte, f)<EOL>prog.update()<EOL><DEDENT><DEDENT>

Correct spectral interference.

Subtract interference counts from target_analyte, based on the
intensity of a source_analayte and a known fractional contribution (f).

Correction takes the form:
target_analyte -= source_analyte * f

Only operates on background-corrected data ('bkgsub'). To undo a correction,
rerun `self.bkg_subtract()`.

Example
-------
To correct 44Ca+ for an 88Sr++ interference, where both 43.5 and 44 Da
peaks are known:
f = abundance(88Sr) / (abundance(87Sr)

counts(44Ca) = counts(44 Da) - counts(43.5 Da) * f

Parameters
----------
target_analyte : str
    The name of the analyte to modify.
source_analyte : str
    The name of the analyte to base the correction on.
f : float
    The fraction of the intensity of the source_analyte to
    subtract from the target_analyte. Correction is:
    target_analyte - source_analyte * f

Returns
-------
None


@_log<EOL><INDENT>def bkg_plot(self, analytes=None, figsize=None, yscale='<STR_LIT>',<EOL>ylim=None, err='<STR_LIT>', save=True):<DEDENT>

if not hasattr(self, '<STR_LIT>'):<EOL><INDENT>raise ValueError("<STR_LIT>" +<EOL>"<STR_LIT>" +<EOL>"<STR_LIT>" +<EOL>"<STR_LIT>")<EOL><DEDENT>if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL><DEDENT>elif isinstance(analytes, str):<EOL><INDENT>analytes = [analytes]<EOL><DEDENT>if figsize is None:<EOL><INDENT>if len(self.samples) > <NUM_LIT:50>:<EOL><INDENT>figsize = (len(self.samples) * <NUM_LIT>, <NUM_LIT:5>)<EOL><DEDENT>else:<EOL><INDENT>figsize = (<NUM_LIT>, <NUM_LIT:5>)<EOL><DEDENT><DEDENT>fig = plt.figure(figsize=figsize)<EOL>ax = fig.add_axes([<NUM_LIT>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>])<EOL>with self.pbar.set(total=len(analytes), desc='<STR_LIT>') as prog:<EOL><INDENT>for a in analytes:<EOL><INDENT>ax.scatter(self.bkg['<STR_LIT>'].uTime, self.bkg['<STR_LIT>'].loc[:, a],<EOL>alpha=<NUM_LIT:0.5>, s=<NUM_LIT:3>, c=self.cmaps[a],<EOL>lw=<NUM_LIT:0.5>)<EOL>for i, r in self.bkg['<STR_LIT>'].iterrows():<EOL><INDENT>x = (r.loc['<STR_LIT>', '<STR_LIT>'] - r.loc['<STR_LIT>', '<STR_LIT>'] * <NUM_LIT:2>,<EOL>r.loc['<STR_LIT>', '<STR_LIT>'] + r.loc['<STR_LIT>', '<STR_LIT>'] * <NUM_LIT:2>)<EOL>yl = [r.loc[a, '<STR_LIT>'] - r.loc[a, err]] * <NUM_LIT:2><EOL>yu = [r.loc[a, '<STR_LIT>'] + r.loc[a, err]] * <NUM_LIT:2><EOL>ax.fill_between(x, yl, yu, alpha=<NUM_LIT>, lw=<NUM_LIT:0.5>, color=self.cmaps[a], zorder=<NUM_LIT:1>)<EOL><DEDENT>prog.update()<EOL><DEDENT><DEDENT>if yscale == '<STR_LIT>':<EOL><INDENT>ax.set_yscale('<STR_LIT>')<EOL><DEDENT>if ylim is not None:<EOL><INDENT>ax.set_ylim(ylim)<EOL><DEDENT>else:<EOL><INDENT>ax.set_ylim(ax.get_ylim() * np.array([<NUM_LIT:1>, <NUM_LIT:10>]))  <EOL><DEDENT>for a in analytes:<EOL><INDENT>x = self.bkg['<STR_LIT>']['<STR_LIT>']<EOL>y = self.bkg['<STR_LIT>'][a]['<STR_LIT>']<EOL>yl = self.bkg['<STR_LIT>'][a]['<STR_LIT>'] - self.bkg['<STR_LIT>'][a][err]<EOL>yu = self.bkg['<STR_LIT>'][a]['<STR_LIT>'] + self.bkg['<STR_LIT>'][a][err]<EOL>if yscale == '<STR_LIT>':<EOL><INDENT>yl[yl < ax.get_ylim()[<NUM_LIT:0>]] = ax.get_ylim()[<NUM_LIT:0>]<EOL><DEDENT>ax.plot(x, y,<EOL>c=self.cmaps[a], zorder=<NUM_LIT:2>, label=a)<EOL>ax.fill_between(x, yl, yu,<EOL>color=self.cmaps[a], alpha=<NUM_LIT>, zorder=-<NUM_LIT:1>)<EOL><DEDENT>ax.set_xlabel('<STR_LIT>')<EOL>ax.set_ylabel('<STR_LIT>')<EOL>ax.set_title('<STR_LIT>'.format(err, err),<EOL>fontsize=<NUM_LIT:10>)<EOL>ha, la = ax.get_legend_handles_labels()<EOL>ax.legend(labels=la[:len(analytes)], handles=ha[:len(analytes)], bbox_to_anchor=(<NUM_LIT:1>, <NUM_LIT:1>))<EOL>xlim = rangecalc(self.bkg['<STR_LIT>']['<STR_LIT>'], <NUM_LIT>)<EOL>ax.set_xlim(xlim)<EOL>for s, d in self.data.items():<EOL><INDENT>ax.axvline(d.uTime[<NUM_LIT:0>], alpha=<NUM_LIT>, color='<STR_LIT:k>', zorder=-<NUM_LIT:1>)<EOL>ax.text(d.uTime[<NUM_LIT:0>], ax.get_ylim()[<NUM_LIT:1>], s, rotation=<NUM_LIT>,<EOL>va='<STR_LIT>', ha='<STR_LIT:left>', zorder=-<NUM_LIT:1>, fontsize=<NUM_LIT:7>)<EOL><DEDENT>if save:<EOL><INDENT>fig.savefig(self.report_dir + '<STR_LIT>', dpi=<NUM_LIT:200>)<EOL><DEDENT>return fig, ax<EOL>

Plot the calculated background.

Parameters
----------
analytes : str or iterable
    Which analyte(s) to plot.
figsize : tuple
    The (width, height) of the figure, in inches.
    If None, calculated based on number of samples.
yscale : str
    'log' (default) or 'linear'.
ylim : tuple
    Manually specify the y scale.
err : str
    What type of error to plot. Default is stderr.
save : bool
    If True, figure is saved.

Returns
-------
fig, ax : matplotlib.figure, matplotlib.axes


if '<STR_LIT>' not in self.stages_complete:<EOL><INDENT>raise RuntimeError('<STR_LIT>')<EOL><DEDENT>if internal_standard is not None:<EOL><INDENT>self.internal_standard = internal_standard<EOL>self.minimal_analytes.update([internal_standard])<EOL><DEDENT>with self.pbar.set(total=len(self.data), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in self.data.values():<EOL><INDENT>s.ratio(internal_standard=self.internal_standard)<EOL>prog.update()<EOL><DEDENT><DEDENT>self.stages_complete.update(['<STR_LIT>'])<EOL>self.focus_stage = '<STR_LIT>'<EOL>return<EOL>

Calculates the ratio of all analytes to a single analyte.

Parameters
----------
internal_standard : str
    The name of the analyte to divide all other analytes
    by.

Returns
-------
None


def srm_id_auto(self, srms_used=['<STR_LIT>', '<STR_LIT>', '<STR_LIT>'], n_min=<NUM_LIT:10>, reload_srm_database=False):

if isinstance(srms_used, str):<EOL><INDENT>srms_used = [srms_used]<EOL><DEDENT>self.srm_compile_measured(n_min)<EOL>stdtab = self.stdtab.copy()<EOL>self.srm_load_database(srms_used, reload_srm_database)<EOL>srm_tab = self.srmdat.loc[:, ['<STR_LIT>', '<STR_LIT>']].reset_index().pivot(index='<STR_LIT>', columns='<STR_LIT>', values='<STR_LIT>')<EOL>meas_tab = stdtab.loc[:, (slice(None), '<STR_LIT>')]  <EOL>meas_tab.columns = meas_tab.columns.droplevel(<NUM_LIT:1>)  <EOL>meas_tab.columns = [re.findall('<STR_LIT>', a)[<NUM_LIT:0>] for a in meas_tab.columns]  <EOL>meas_tab = meas_tab.T.groupby(level=<NUM_LIT:0>).first().T  <EOL>ranges = nominal_values(meas_tab.apply(lambda a: np.ptp(a) / np.nanmean(a), <NUM_LIT:0>))  <EOL>def normalise(a):<EOL><INDENT>a = nominal_values(a)<EOL>if np.nanmin(a) < np.nanmax(a):<EOL><INDENT>return (a - np.nanmin(a)) / np.nanmax(a - np.nanmin(a))<EOL><DEDENT>else:<EOL><INDENT>return np.ones(a.shape)<EOL><DEDENT><DEDENT>nmeas = meas_tab.apply(normalise, <NUM_LIT:0>)<EOL>nmeas.dropna(<NUM_LIT:1>, inplace=True)  <EOL>nsrm_tab = srm_tab.apply(normalise, <NUM_LIT:0>)<EOL>nsrm_tab.dropna(<NUM_LIT:1>, inplace=True)<EOL>for uT, r in nmeas.iterrows():  <EOL><INDENT>idx = np.nansum(((nsrm_tab - r) * ranges)**<NUM_LIT:2>, <NUM_LIT:1>)<EOL>idx = abs((nsrm_tab - r) * ranges).sum(<NUM_LIT:1>)<EOL>stdtab.loc[uT, '<STR_LIT>'] = srm_tab.index[idx == min(idx)].values[<NUM_LIT:0>]<EOL><DEDENT>stdtab.reset_index(inplace=True)<EOL>stdtab.sort_index(<NUM_LIT:1>, inplace=True)<EOL>uT = stdtab.loc[:, ['<STR_LIT>', '<STR_LIT>']].set_index('<STR_LIT>')<EOL>uT.sort_index(inplace=True)<EOL>uTm = uT.groupby(level=<NUM_LIT:0>).mean()  <EOL>stdtab.set_index(['<STR_LIT>'], inplace=True)<EOL>stdtab.loc[:, '<STR_LIT>'] = uTm<EOL>stdtab.reset_index(inplace=True)<EOL>stdtab.set_index(['<STR_LIT>', '<STR_LIT>', '<STR_LIT>'], inplace=True)<EOL>srmtabs = Bunch()<EOL>for a in self.analytes:<EOL><INDENT>el = re.findall('<STR_LIT>', a)[<NUM_LIT:0>]<EOL>sub = stdtab.loc[:, a]<EOL>srmsub = self.srmdat.loc[self.srmdat.element == el, ['<STR_LIT>', '<STR_LIT>']]<EOL>srmtab = sub.join(srmsub)<EOL>srmtab.columns = ['<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>']<EOL>srmtabs[a] = srmtab<EOL><DEDENT>self.srmtabs = pd.concat(srmtabs).apply(nominal_values).sort_index()<EOL>self.srmtabs.dropna(subset=['<STR_LIT>'], inplace=True)<EOL>self.srmtabs.loc[:, ['<STR_LIT>', '<STR_LIT>']] = self.srmtabs.loc[:, ['<STR_LIT>', '<STR_LIT>']].replace(np.nan, <NUM_LIT:0>)<EOL>self.srmtabs.drop(self.internal_standard, inplace=True)<EOL>self.srms_ided = True<EOL>return<EOL>

Function for automarically identifying SRMs

Parameters
----------
srms_used : iterable
    Which SRMs have been used. Must match SRM names
    in SRM database *exactly* (case sensitive!).
n_min : int
    The minimum number of data points a SRM measurement
    must contain to be included.


@_log<EOL><INDENT>def calibrate(self, analytes=None, drift_correct=True,<EOL>srms_used=['<STR_LIT>', '<STR_LIT>', '<STR_LIT>'],<EOL>zero_intercept=True, n_min=<NUM_LIT:10>, reload_srm_database=False):<DEDENT>

if analytes is None:<EOL><INDENT>analytes = self.analytes[self.analytes != self.internal_standard]<EOL><DEDENT>elif isinstance(analytes, str):<EOL><INDENT>analytes = [analytes]<EOL><DEDENT>if not hasattr(self, '<STR_LIT>'):<EOL><INDENT>self.srm_id_auto(srms_used=srms_used, n_min=n_min, reload_srm_database=reload_srm_database)<EOL><DEDENT>if not hasattr(self, '<STR_LIT>'):<EOL><INDENT>gTime = self.stdtab.gTime.unique()<EOL>self.calib_params = pd.DataFrame(columns=pd.MultiIndex.from_product([analytes, ['<STR_LIT:m>']]),<EOL>index=gTime)<EOL><DEDENT>calib_analytes = self.srmtabs.index.get_level_values(<NUM_LIT:0>).unique()<EOL>if zero_intercept:<EOL><INDENT>fn  = lambda x, m: x * m<EOL><DEDENT>else:<EOL><INDENT>fn = lambda x, m, c: x * m + c<EOL><DEDENT>for a in calib_analytes:<EOL><INDENT>if zero_intercept:<EOL><INDENT>if (a, '<STR_LIT:c>') in self.calib_params:<EOL><INDENT>self.calib_params.drop((a, '<STR_LIT:c>'), <NUM_LIT:1>, inplace=True)<EOL><DEDENT><DEDENT>if drift_correct:<EOL><INDENT>for g in self.stdtab.gTime.unique():<EOL><INDENT>ind = idx[a, :, :, g]<EOL>if self.srmtabs.loc[ind].size == <NUM_LIT:0>:<EOL><INDENT>continue<EOL><DEDENT>meas = self.srmtabs.loc[ind, '<STR_LIT>']<EOL>srm = self.srmtabs.loc[ind, '<STR_LIT>']<EOL>merr = self.srmtabs.loc[ind, '<STR_LIT>']<EOL>serr = self.srmtabs.loc[ind, '<STR_LIT>']<EOL>sigma = np.sqrt(merr**<NUM_LIT:2> + serr**<NUM_LIT:2>)<EOL>if len(meas) > <NUM_LIT:1>:<EOL><INDENT>p, cov = curve_fit(fn, meas, srm, sigma=sigma)<EOL>pe = unc.correlated_values(p, cov)                <EOL>self.calib_params.loc[g, (a, '<STR_LIT:m>')] = pe[<NUM_LIT:0>]<EOL>if not zero_intercept:<EOL><INDENT>self.calib_params.loc[g, (a, '<STR_LIT:c>')] = pe[<NUM_LIT:1>]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>self.calib_params.loc[g, (a, '<STR_LIT:m>')] = (un.uarray(srm, serr) / <EOL>un.uarray(meas, merr))[<NUM_LIT:0>]<EOL>if not zero_intercept:<EOL><INDENT>self.calib_params.loc[g, (a, '<STR_LIT:c>')] = <NUM_LIT:0><EOL><DEDENT><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>ind = idx[a, :, :, :]<EOL>meas = self.srmtabs.loc[ind, '<STR_LIT>']<EOL>srm = self.srmtabs.loc[ind, '<STR_LIT>']<EOL>merr = self.srmtabs.loc[ind, '<STR_LIT>']<EOL>serr = self.srmtabs.loc[ind, '<STR_LIT>']<EOL>sigma = np.sqrt(merr**<NUM_LIT:2> + serr**<NUM_LIT:2>)<EOL>if len(meas) > <NUM_LIT:1>:<EOL><INDENT>p, cov = curve_fit(fn, meas, srm, sigma=sigma)<EOL>pe = unc.correlated_values(p, cov)                <EOL>self.calib_params.loc[:, (a, '<STR_LIT:m>')] = pe[<NUM_LIT:0>]<EOL>if not zero_intercept:<EOL><INDENT>self.calib_params.loc[:, (a, '<STR_LIT:c>')] = pe[<NUM_LIT:1>]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>self.calib_params.loc[:, (a, '<STR_LIT:m>')] = (un.uarray(srm, serr) / <EOL>un.uarray(meas, merr))[<NUM_LIT:0>]<EOL>if not zero_intercept:<EOL><INDENT>self.calib_params.loc[:, (a, '<STR_LIT:c>')] = <NUM_LIT:0><EOL><DEDENT><DEDENT><DEDENT><DEDENT>if self.calib_params.index.min() == <NUM_LIT:0>:<EOL><INDENT>self.calib_params.drop(<NUM_LIT:0>, inplace=True)<EOL>self.calib_params.drop(self.calib_params.index.max(), inplace=True)<EOL><DEDENT>self.calib_params.loc[<NUM_LIT:0>, :] = self.calib_params.loc[self.calib_params.index.min(), :]<EOL>maxuT = np.max([d.uTime.max() for d in self.data.values()])  <EOL>self.calib_params.loc[maxuT, :] = self.calib_params.loc[self.calib_params.index.max(), :]<EOL>self.calib_params.sort_index(<NUM_LIT:1>, inplace=True)<EOL>self.calib_params.sort_index(<NUM_LIT:0>, inplace=True)<EOL>self.calib_ps = Bunch()<EOL>for a in analytes:<EOL><INDENT>self.calib_ps[a] = {'<STR_LIT:m>': un_interp1d(self.calib_params.index.values,<EOL>self.calib_params.loc[:, (a, '<STR_LIT:m>')].values)}<EOL>if not zero_intercept:<EOL><INDENT>self.calib_ps[a]['<STR_LIT:c>'] = un_interp1d(self.calib_params.index.values,<EOL>self.calib_params.loc[:, (a, '<STR_LIT:c>')].values)<EOL><DEDENT><DEDENT>with self.pbar.set(total=len(self.data), desc='<STR_LIT>') as prog:<EOL><INDENT>for d in self.data.values():<EOL><INDENT>d.calibrate(self.calib_ps, analytes)<EOL>prog.update()<EOL><DEDENT><DEDENT>markers = '<STR_LIT>'  <EOL>if not hasattr(self, '<STR_LIT>'):<EOL><INDENT>self.srms_used = set(srms_used)<EOL><DEDENT>else:<EOL><INDENT>self.srms_used.update(srms_used)<EOL><DEDENT>self.srm_mdict = {k: markers[i] for i, k in enumerate(self.srms_used)}<EOL>self.stages_complete.update(['<STR_LIT>'])<EOL>self.focus_stage = '<STR_LIT>'<EOL>return<EOL>

Calibrates the data to measured SRM values.

Assumes that y intercept is zero.

Parameters
----------
analytes : str or iterable
    Which analytes you'd like to calibrate. Defaults to all.
drift_correct : bool
    Whether to pool all SRM measurements into a single calibration,
    or vary the calibration through the run, interpolating
    coefficients between measured SRMs.
srms_used : str or iterable
    Which SRMs have been measured. Must match names given in
    SRM data file *exactly*.
n_min : int
    The minimum number of data points an SRM measurement
    must have to be included.

Returns
-------
None


@_log<EOL><INDENT>def make_subset(self, samples=None, name=None):<DEDENT>

<EOL>for k, v in self.subsets.items():<EOL><INDENT>if set(v) == set(samples) and k != '<STR_LIT>':<EOL><INDENT>return k<EOL><DEDENT><DEDENT>if isinstance(samples, str):<EOL><INDENT>samples = [samples]<EOL><DEDENT>not_exists = [s for s in samples if s not in self.subsets['<STR_LIT>']]<EOL>if len(not_exists) > <NUM_LIT:0>:<EOL><INDENT>raise ValueError('<STR_LIT:U+002CU+0020>'.join(not_exists) + '<STR_LIT>')<EOL><DEDENT>if name is None:<EOL><INDENT>name = max([-<NUM_LIT:1>] + [x for x in self.subsets.keys() if isinstance(x, int)]) + <NUM_LIT:1><EOL><DEDENT>self._subset_names.append(name)<EOL>if samples is not None:<EOL><INDENT>self.subsets[name] = samples<EOL>for s in samples:<EOL><INDENT>try:<EOL><INDENT>self.subsets['<STR_LIT>'].remove(s)<EOL><DEDENT>except ValueError:<EOL><INDENT>pass<EOL><DEDENT><DEDENT><DEDENT>self._has_subsets = True<EOL>return name<EOL>

Creates a subset of samples, which can be treated independently.

Parameters
----------
samples : str or array - like
    Name of sample, or list of sample names.
name : (optional) str or number
    The name of the sample group. Defaults to n + 1, where n is
    the highest existing group number


if focus_stage is None:<EOL><INDENT>focus_stage = self.focus_stage<EOL><DEDENT>for s in self.data.values():<EOL><INDENT>ind = np.ones(len(s.Time), dtype=bool)<EOL>for v in s.data[focus_stage].values():<EOL><INDENT>ind = ind & (nominal_values(v) > <NUM_LIT:0>)<EOL><DEDENT>for k in s.data[focus_stage].keys():<EOL><INDENT>s.data[focus_stage][k][~ind] = unc.ufloat(np.nan, np.nan)<EOL><DEDENT><DEDENT>self.set_focus(focus_stage)<EOL>return<EOL>

Remove all points containing data below zero (which are impossible!)


@_log<EOL><INDENT>def filter_threshold(self, analyte, threshold,<EOL>samples=None, subset=None):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>self.minimal_analytes.update([analyte])<EOL>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>self.data[s].filter_threshold(analyte, threshold)<EOL>prog.update()<EOL><DEDENT><DEDENT>

Applies a threshold filter to the data.

Generates two filters above and below the threshold value for a
given analyte.

Parameters
----------
analyte : str
    The analyte that the filter applies to.
threshold : float
    The threshold value.
filt : bool
    Whether or not to apply existing filters to the data before
    calculating this filter.
samples : array_like or None
    Which samples to apply this filter to. If None, applies to all
    samples.
subset : str or number
    The subset of samples (defined by make_subset) you want to apply
    the filter to.

Returns
-------
None


@_log<EOL><INDENT>def filter_threshold_percentile(self, analyte, percentiles, level='<STR_LIT>', filt=False,<EOL>samples=None, subset=None):<DEDENT>

params = locals()<EOL>del(params['<STR_LIT>'])<EOL>if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>self.minimal_analytes.update([analyte])<EOL>if isinstance(percentiles, (int, float)):<EOL><INDENT>percentiles = [percentiles]<EOL><DEDENT>if level == '<STR_LIT>':<EOL><INDENT>self.get_focus(filt=filt, subset=subset, nominal=True)<EOL>dat = self.focus[analyte][~np.isnan(self.focus[analyte])]<EOL>lims = np.percentile(dat, percentiles)<EOL><DEDENT>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>d = self.data[s]<EOL>setn = d.filt.maxset + <NUM_LIT:1><EOL>g = d.focus[analyte]<EOL>if level == '<STR_LIT>':<EOL><INDENT>gt = nominal_values(g)<EOL>lims = np.percentile(gt[~np.isnan(gt)], percentiles)<EOL><DEDENT>if len(lims) == <NUM_LIT:1>:<EOL><INDENT>above = g >= lims[<NUM_LIT:0>]<EOL>below = g < lims[<NUM_LIT:0>]<EOL>d.filt.add(analyte + '<STR_LIT>'.format(percentiles[<NUM_LIT:0>]),<EOL>below,<EOL>'<STR_LIT>'.format(percentiles[<NUM_LIT:0>], analyte, lims[<NUM_LIT:0>]),<EOL>params, setn=setn)<EOL>d.filt.add(analyte + '<STR_LIT>'.format(percentiles[<NUM_LIT:0>]),<EOL>above,<EOL>'<STR_LIT>'.format(percentiles[<NUM_LIT:0>], analyte, lims[<NUM_LIT:0>]),<EOL>params, setn=setn)<EOL><DEDENT>elif len(lims) == <NUM_LIT:2>:<EOL><INDENT>inside = (g >= min(lims)) & (g <= max(lims))<EOL>outside = (g < min(lims)) | (g > max(lims))<EOL>lpc = '<STR_LIT:->'.join(['<STR_LIT>'.format(p) for p in percentiles])<EOL>d.filt.add(analyte + '<STR_LIT:_>' + lpc + '<STR_LIT>',<EOL>inside,<EOL>'<STR_LIT>' + lpc + '<STR_LIT:U+0020>' + analyte + '<STR_LIT>',<EOL>params, setn=setn)<EOL>d.filt.add(analyte + '<STR_LIT:_>' + lpc + '<STR_LIT>',<EOL>outside,<EOL>'<STR_LIT>' + lpc + '<STR_LIT:U+0020>' + analyte + '<STR_LIT>',<EOL>params, setn=setn)<EOL><DEDENT>prog.update()<EOL><DEDENT><DEDENT>return<EOL>

Applies a threshold filter to the data.

Generates two filters above and below the threshold value for a
given analyte.

Parameters
----------
analyte : str
    The analyte that the filter applies to.
percentiles : float or iterable of len=2
    The percentile values.
level : str
    Whether to calculate percentiles from the entire dataset
    ('population') or for each individual sample ('individual')
filt : bool
    Whether or not to apply existing filters to the data before
    calculating this filter.
samples : array_like or None
    Which samples to apply this filter to. If None, applies to all
    samples.
subset : str or number
    The subset of samples (defined by make_subset) you want to apply
    the filter to.

Returns
-------
None


@_log<EOL><INDENT>def filter_gradient_threshold(self, analyte, threshold, win=<NUM_LIT:15>,<EOL>samples=None, subset=None):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>self.minimal_analytes.update([analyte])<EOL>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>self.data[s].filter_gradient_threshold(analyte, win, threshold)<EOL>prog.update()<EOL><DEDENT><DEDENT>

Calculate a gradient threshold filter to the data.

Generates two filters above and below the threshold value for a
given analyte.

Parameters
----------
analyte : str
    The analyte that the filter applies to.
win : int
    The window over which to calculate the moving gradient
threshold : float
    The threshold value.
filt : bool
    Whether or not to apply existing filters to the data before
    calculating this filter.
samples : array_like or None
    Which samples to apply this filter to. If None, applies to all
    samples.
subset : str or number
    The subset of samples (defined by make_subset) you want to apply
    the filter to.

Returns
-------
None


@_log<EOL><INDENT>def filter_gradient_threshold_percentile(self, analyte, percentiles, level='<STR_LIT>', win=<NUM_LIT:15>, filt=False,<EOL>samples=None, subset=None):<DEDENT>

params = locals()<EOL>del(params['<STR_LIT>'])<EOL>if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>self.minimal_analytes.update([analyte])<EOL>self.get_gradients(analytes=[analyte], win=win, filt=filt, subset=subset)<EOL>grad = self.gradients[analyte][~np.isnan(self.gradients[analyte])]<EOL>if isinstance(percentiles, (int, float)):<EOL><INDENT>percentiles = [percentiles]<EOL><DEDENT>if level == '<STR_LIT>':<EOL><INDENT>lims = np.percentile(grad, percentiles)<EOL><DEDENT>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>d = self.data[s]<EOL>setn = d.filt.maxset + <NUM_LIT:1><EOL>g = calc_grads(d.Time, d.focus, [analyte], win)[analyte]<EOL>if level == '<STR_LIT>':<EOL><INDENT>gt = nominal_values(g)<EOL>lims = np.percentile(gt[~np.isnan(gt)], percentiles)<EOL><DEDENT>if len(lims) == <NUM_LIT:1>:<EOL><INDENT>above = g >= lims[<NUM_LIT:0>]<EOL>below = g < lims[<NUM_LIT:0>]<EOL>d.filt.add(analyte + '<STR_LIT>'.format(percentiles[<NUM_LIT:0>]),<EOL>below,<EOL>'<STR_LIT>'.format(percentiles[<NUM_LIT:0>], analyte, lims[<NUM_LIT:0>]),<EOL>params, setn=setn)<EOL>d.filt.add(analyte + '<STR_LIT>'.format(percentiles[<NUM_LIT:0>]),<EOL>above,<EOL>'<STR_LIT>'.format(percentiles[<NUM_LIT:0>], analyte, lims[<NUM_LIT:0>]),<EOL>params, setn=setn)<EOL><DEDENT>elif len(lims) == <NUM_LIT:2>:<EOL><INDENT>inside = (g >= min(lims)) & (g <= max(lims))<EOL>outside = (g < min(lims)) | (g > max(lims))<EOL>lpc = '<STR_LIT:->'.join(['<STR_LIT>'.format(p) for p in percentiles])<EOL>d.filt.add(analyte + '<STR_LIT:_>' + lpc + '<STR_LIT>',<EOL>inside,<EOL>'<STR_LIT>' + lpc + '<STR_LIT:U+0020>' + analyte + '<STR_LIT>',<EOL>params, setn=setn)<EOL>d.filt.add(analyte + '<STR_LIT:_>' + lpc + '<STR_LIT>',<EOL>outside,<EOL>'<STR_LIT>' + lpc + '<STR_LIT:U+0020>' + analyte + '<STR_LIT>',<EOL>params, setn=setn)<EOL><DEDENT>prog.update()<EOL><DEDENT><DEDENT>return<EOL>

Calculate a gradient threshold filter to the data.

Generates two filters above and below the threshold value for a
given analyte.

Parameters
----------
analyte : str
    The analyte that the filter applies to.
win : int
    The window over which to calculate the moving gradient
percentiles : float or iterable of len=2
    The percentile values.
filt : bool
    Whether or not to apply existing filters to the data before
    calculating this filter.
samples : array_like or None
    Which samples to apply this filter to. If None, applies to all
    samples.
subset : str or number
    The subset of samples (defined by make_subset) you want to apply
    the filter to.

Returns
-------
None


@_log<EOL><INDENT>def filter_clustering(self, analytes, filt=False, normalise=True,<EOL>method='<STR_LIT>', include_time=False, samples=None,<EOL>sort=True, subset=None, level='<STR_LIT>', min_data=<NUM_LIT:10>, **kwargs):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>if isinstance(analytes, str):<EOL><INDENT>analytes = [analytes]<EOL><DEDENT>self.minimal_analytes.update(analytes)<EOL>if level == '<STR_LIT>':<EOL><INDENT>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>self.data[s].filter_clustering(analytes=analytes, filt=filt,<EOL>normalise=normalise,<EOL>method=method,<EOL>include_time=include_time,<EOL>min_data=min_data,<EOL>sort=sort,<EOL>**kwargs)<EOL>prog.update()<EOL><DEDENT><DEDENT><DEDENT>if level == '<STR_LIT>':<EOL><INDENT>if isinstance(sort, bool):<EOL><INDENT>sort_by = <NUM_LIT:0><EOL><DEDENT>else:<EOL><INDENT>sort_by = sort<EOL><DEDENT>name = '<STR_LIT:_>'.join(analytes) + '<STR_LIT>'.format(method)<EOL>self.fit_classifier(name=name, analytes=analytes, method=method,<EOL>subset=subset, filt=filt, sort_by=sort_by, **kwargs)<EOL>self.apply_classifier(name=name, subset=subset)<EOL><DEDENT>

Applies an n - dimensional clustering filter to the data.

Parameters
----------
analytes : str
    The analyte(s) that the filter applies to.
filt : bool
    Whether or not to apply existing filters to the data before
    calculating this filter.
normalise : bool
    Whether or not to normalise the data to zero mean and unit
    variance. Reccomended if clustering based on more than 1 analyte.
    Uses `sklearn.preprocessing.scale`.
method : str
    Which clustering algorithm to use:

    * 'meanshift': The `sklearn.cluster.MeanShift` algorithm.
      Automatically determines number of clusters
      in data based on the `bandwidth` of expected
      variation.
    * 'kmeans': The `sklearn.cluster.KMeans` algorithm. Determines
      the characteristics of a known number of clusters
      within the data. Must provide `n_clusters` to specify
      the expected number of clusters.
level : str
    Whether to conduct the clustering analysis at the 'sample' or
    'population' level.
include_time : bool
    Whether or not to include the Time variable in the clustering
    analysis. Useful if you're looking for spatially continuous
    clusters in your data, i.e. this will identify each spot in your
    analysis as an individual cluster.
samples : optional, array_like or None
    Which samples to apply this filter to. If None, applies to all
    samples.
sort : bool
    Whether or not you want the cluster labels to
    be sorted by the mean magnitude of the signals
    they are based on (0 = lowest)
min_data : int
    The minimum number of data points that should be considered by
    the filter. Default = 10.
**kwargs
    Parameters passed to the clustering algorithm specified by
    `method`.
Meanshift Parameters
    bandwidth : str or float
        The bandwith (float) or bandwidth method ('scott' or 'silverman')
        used to estimate the data bandwidth.
    bin_seeding : bool
        Modifies the behaviour of the meanshift algorithm. Refer to
        sklearn.cluster.meanshift documentation.
K-Means Parameters
    n_clusters : int
        The number of clusters expected in the data.

Returns
-------
None


@_log<EOL><INDENT>def fit_classifier(self, name, analytes, method, samples=None,<EOL>subset=None, filt=True, sort_by=<NUM_LIT:0>, **kwargs):<DEDENT>

<EOL>if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>self.get_focus(subset=subset, filt=filt)<EOL>c = classifier(analytes,<EOL>sort_by)<EOL>c.fit(data=self.focus,<EOL>method=method,<EOL>**kwargs)<EOL>self.classifiers[name] = c<EOL>return name<EOL>

Create a clustering classifier based on all samples, or a subset.

Parameters
----------
name : str
    The name of the classifier.
analytes : str or iterable
    Which analytes the clustering algorithm should consider.
method : str
    Which clustering algorithm to use. Can be:

    'meanshift'
        The `sklearn.cluster.MeanShift` algorithm.
        Automatically determines number of clusters
        in data based on the `bandwidth` of expected
        variation.
    'kmeans'
        The `sklearn.cluster.KMeans` algorithm. Determines
        the characteristics of a known number of clusters
        within the data. Must provide `n_clusters` to specify
        the expected number of clusters.
samples : iterable
    list of samples to consider. Overrides 'subset'.
subset : str
    The subset of samples used to fit the classifier. Ignored if
    'samples' is specified.
sort_by : int
    Which analyte the resulting clusters should be sorted
    by - defaults to 0, which is the first analyte.
**kwargs :
    method-specific keyword parameters - see below.
Meanshift Parameters
    bandwidth : str or float
        The bandwith (float) or bandwidth method ('scott' or 'silverman')
        used to estimate the data bandwidth.
    bin_seeding : bool
        Modifies the behaviour of the meanshift algorithm. Refer to
        sklearn.cluster.meanshift documentation.
K - Means Parameters
    n_clusters : int
        The number of clusters expected in the data.

Returns
-------
name : str


@_log<EOL><INDENT>def apply_classifier(self, name, samples=None, subset=None):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>c = self.classifiers[name]<EOL>labs = c.classifier.ulabels_<EOL>with self.pbar.set(total=len(samples), desc='<STR_LIT>' + name + '<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>d = self.data[s]<EOL>try:<EOL><INDENT>f = c.predict(d.focus)<EOL><DEDENT>except ValueError:<EOL><INDENT>f = np.array([-<NUM_LIT:2>] * len(d.Time))<EOL><DEDENT>for l in labs:<EOL><INDENT>ind = f == l<EOL>d.filt.add(name=name + '<STR_LIT>'.format(l),<EOL>filt=ind,<EOL>info=name + '<STR_LIT:U+0020>' + c.method + '<STR_LIT>',<EOL>params=(c.analytes, c.method))<EOL><DEDENT>prog.update()<EOL><DEDENT><DEDENT>return name<EOL>

Apply a clustering classifier based on all samples, or a subset.

Parameters
----------
name : str
    The name of the classifier to apply.
subset : str
    The subset of samples to apply the classifier to.
Returns
-------
name : str


@_log<EOL><INDENT>def filter_correlation(self, x_analyte, y_analyte, window=None,<EOL>r_threshold=<NUM_LIT>, p_threshold=<NUM_LIT>, filt=True,<EOL>samples=None, subset=None):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>self.minimal_analytes.update([x_analyte, y_analyte])<EOL>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>self.data[s].filter_correlation(x_analyte, y_analyte,<EOL>window=window,<EOL>r_threshold=r_threshold,<EOL>p_threshold=p_threshold,<EOL>filt=filt)<EOL>prog.update()<EOL><DEDENT><DEDENT>

Applies a correlation filter to the data.

Calculates a rolling correlation between every `window` points of
two analytes, and excludes data where their Pearson's R value is
above `r_threshold` and statistically significant.

Data will be excluded where their absolute R value is greater than
`r_threshold` AND the p - value associated with the correlation is
less than `p_threshold`. i.e. only correlations that are statistically
significant are considered.

Parameters
----------
x_analyte, y_analyte : str
    The names of the x and y analytes to correlate.
window : int, None
    The rolling window used when calculating the correlation.
r_threshold : float
    The correlation index above which to exclude data.
    Note: the absolute pearson R value is considered, so
    negative correlations below -`r_threshold` will also
    be excluded.
p_threshold : float
    The significant level below which data are excluded.
filt : bool
    Whether or not to apply existing filters to the data before
    calculating this filter.

Returns
-------
None


@_log<EOL><INDENT>def correlation_plots(self, x_analyte, y_analyte, window=<NUM_LIT:15>, filt=True, recalc=False, samples=None, subset=None, outdir=None):<DEDENT>

if outdir is None:<EOL><INDENT>outdir = self.report_dir + '<STR_LIT>'<EOL><DEDENT>if not os.path.isdir(outdir):<EOL><INDENT>os.mkdir(outdir)<EOL><DEDENT>if subset is not None:<EOL><INDENT>samples = self._get_samples(subset)<EOL><DEDENT>elif samples is None:<EOL><INDENT>samples = self.subsets['<STR_LIT>']<EOL><DEDENT>elif isinstance(samples, str):<EOL><INDENT>samples = [samples]<EOL><DEDENT>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>f, a = self.data[s].correlation_plot(x_analyte=x_analyte, y_analyte=y_analyte,<EOL>window=window, filt=filt, recalc=recalc)<EOL>f.savefig('<STR_LIT>'.format(outdir, s, x_analyte, y_analyte))<EOL>plt.close(f)<EOL>prog.update()<EOL><DEDENT><DEDENT>return<EOL>

Plot the local correlation between two analytes.

Parameters
----------
x_analyte, y_analyte : str
    The names of the x and y analytes to correlate.
window : int, None
    The rolling window used when calculating the correlation.
filt : bool
    Whether or not to apply existing filters to the data before
    calculating this filter.
recalc : bool
    If True, the correlation is re-calculated, even if it is already present.

Returns
-------
None


@_log<EOL><INDENT>def filter_on(self, filt=None, analyte=None, samples=None, subset=None, show_status=False):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>for s in samples:<EOL><INDENT>try:<EOL><INDENT>self.data[s].filt.on(analyte, filt)<EOL><DEDENT>except:<EOL><INDENT>warnings.warn("<STR_LIT>" + s)<EOL><DEDENT><DEDENT>if show_status:<EOL><INDENT>self.filter_status(subset=subset)<EOL><DEDENT>return<EOL>

Turns data filters on for particular analytes and samples.

Parameters
----------
filt : optional, str or array_like
    Name, partial name or list of names of filters. Supports
    partial matching. i.e. if 'cluster' is specified, all
    filters with 'cluster' in the name are activated.
    Defaults to all filters.
analyte : optional, str or array_like
    Name or list of names of analytes. Defaults to all analytes.
samples : optional, array_like or None
    Which samples to apply this filter to. If None, applies to all
    samples.

Returns
-------
None


@_log<EOL><INDENT>def filter_off(self, filt=None, analyte=None, samples=None, subset=None, show_status=False):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>for s in samples:<EOL><INDENT>try:<EOL><INDENT>self.data[s].filt.off(analyte, filt)<EOL><DEDENT>except:<EOL><INDENT>warnings.warn("<STR_LIT>" + s)<EOL><DEDENT><DEDENT>if show_status:<EOL><INDENT>self.filter_status(subset=subset)<EOL><DEDENT>return<EOL>

Turns data filters off for particular analytes and samples.

Parameters
----------
filt : optional, str or array_like
    Name, partial name or list of names of filters. Supports
    partial matching. i.e. if 'cluster' is specified, all
    filters with 'cluster' in the name are activated.
    Defaults to all filters.
analyte : optional, str or array_like
    Name or list of names of analytes. Defaults to all analytes.
samples : optional, array_like or None
    Which samples to apply this filter to. If None, applies to all
    samples.

Returns
-------
None


def filter_status(self, sample=None, subset=None, stds=False):

s = '<STR_LIT>'<EOL>if sample is None and subset is None:<EOL><INDENT>if not self._has_subsets:<EOL><INDENT>s += '<STR_LIT>'<EOL>s += self.data[self.subsets['<STR_LIT>'][<NUM_LIT:0>]].filt.__repr__()<EOL><DEDENT>else:<EOL><INDENT>for n in sorted(str(sn) for sn in self._subset_names):<EOL><INDENT>if n in self.subsets:<EOL><INDENT>pass<EOL><DEDENT>elif int(n) in self.subsets:<EOL><INDENT>n = int(n)<EOL>pass<EOL><DEDENT>s += '<STR_LIT>' + str(n) + '<STR_LIT:\n>'<EOL>s += '<STR_LIT>' + '<STR_LIT:U+002CU+0020>'.join(self.subsets[n]) + '<STR_LIT>'<EOL>s += self.data[self.subsets[n][<NUM_LIT:0>]].filt.__repr__()<EOL><DEDENT>if len(self.subsets['<STR_LIT>']) > <NUM_LIT:0>:<EOL><INDENT>s += '<STR_LIT>'<EOL>s += '<STR_LIT>' + '<STR_LIT:U+002CU+0020>'.join(self.subsets['<STR_LIT>']) + '<STR_LIT>'<EOL>s += self.data[self.subsets['<STR_LIT>'][<NUM_LIT:0>]].filt.__repr__()<EOL><DEDENT><DEDENT>print(s)<EOL>return<EOL><DEDENT>elif sample is not None:<EOL><INDENT>s += '<STR_LIT>' + sample + '<STR_LIT:\n>'<EOL>s += self.data[sample].filt.__repr__()<EOL>print(s)<EOL>return<EOL><DEDENT>elif subset is not None:<EOL><INDENT>if isinstance(subset, (str, int, float)):<EOL><INDENT>subset = [subset]<EOL><DEDENT>for n in subset:<EOL><INDENT>s += '<STR_LIT>' + str(n) + '<STR_LIT:\n>'<EOL>s += '<STR_LIT>' + '<STR_LIT:U+002CU+0020>'.join(self.subsets[n]) + '<STR_LIT>'<EOL>s += self.data[self.subsets[n][<NUM_LIT:0>]].filt.__repr__()<EOL><DEDENT>print(s)<EOL>return<EOL><DEDENT>

Prints the current status of filters for specified samples.

Parameters
----------
sample : str
    Which sample to print.
subset : str
    Specify a subset
stds : bool
    Whether or not to include standards.


@_log<EOL><INDENT>def filter_clear(self, samples=None, subset=None):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>for s in samples:<EOL><INDENT>self.data[s].filt.clear()<EOL><DEDENT>


@_log<EOL><INDENT>def filter_defragment(self, threshold, mode='<STR_LIT>', filt=True, samples=None, subset=None):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>for s in samples:<EOL><INDENT>f = self.data[s].filt.grab_filt(filt)<EOL>self.data[s].filt.add(name='<STR_LIT>'.format(mode, threshold),<EOL>filt=filters.defrag(f, threshold, mode),<EOL>info='<STR_LIT>'.format(mode, threshold),<EOL>params=(threshold, mode, filt, samples, subset))<EOL><DEDENT>

Remove 'fragments' from the calculated filter

Parameters
----------
threshold : int
    Contiguous data regions that contain this number
    or fewer points are considered 'fragments'
mode : str
    Specifies wither to 'include' or 'exclude' the identified
    fragments.
filt : bool or filt string
    Which filter to apply the defragmenter to. Defaults to True
samples : array_like or None
    Which samples to apply this filter to. If None, applies to all
    samples.
subset : str or number
    The subset of samples (defined by make_subset) you want to apply
    the filter to.

Returns
-------
None


@_log<EOL><INDENT>def filter_exclude_downhole(self, threshold, filt=True, samples=None, subset=None):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>for s in samples:<EOL><INDENT>self.data[s].filter_exclude_downhole(threshold, filt)<EOL><DEDENT>

Exclude all points down-hole (after) the first excluded data.

Parameters
----------
threhold : int
    The minimum number of contiguous excluded data points
    that must exist before downhole exclusion occurs.
file : valid filter string or bool
    Which filter to consider. If True, applies to currently active
    filters.


@_log<EOL><INDENT>def filter_trim(self, start=<NUM_LIT:1>, end=<NUM_LIT:1>, filt=True, samples=None, subset=None):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>for s in samples:<EOL><INDENT>self.data[s].filter_trim(start, end, filt)<EOL><DEDENT>

Remove points from the start and end of filter regions.

Parameters
----------
start, end : int
    The number of points to remove from the start and end of
    the specified filter.
filt : valid filter string or bool
    Which filter to trim. If True, applies to currently active
    filters.


def filter_nremoved(self, filt=True, quiet=False):

rminfo = {}<EOL>for n in self.subsets['<STR_LIT>']:<EOL><INDENT>s = self.data[n]<EOL>rminfo[n] = s.filt_nremoved(filt)<EOL><DEDENT>if not quiet:<EOL><INDENT>maxL = max([len(s) for s in rminfo.keys()])<EOL>print('<STR_LIT>'.format(string='<STR_LIT>', number=maxL + <NUM_LIT:3>) +<EOL>'<STR_LIT>'.format(total='<STR_LIT>') +<EOL>'<STR_LIT>'.format(removed='<STR_LIT>') +<EOL>'<STR_LIT>'.format(percent='<STR_LIT>'))<EOL>for k, (ntot, nfilt, pcrm) in rminfo.items():<EOL><INDENT>print('<STR_LIT>'.format(string=k, number=maxL + <NUM_LIT:3>) +<EOL>'<STR_LIT>'.format(total=ntot) +<EOL>'<STR_LIT>'.format(removed=nfilt) +<EOL>'<STR_LIT>'.format(percent=pcrm))<EOL><DEDENT><DEDENT>return rminfo<EOL>

Report how many data are removed by the active filters.


@_log<EOL><INDENT>def optimise_signal(self, analytes, min_points=<NUM_LIT:5>,<EOL>threshold_mode='<STR_LIT>', <EOL>threshold_mult=<NUM_LIT:1.>, x_bias=<NUM_LIT:0>, filt=True,<EOL>weights=None, mode='<STR_LIT>',<EOL>samples=None, subset=None):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>if isinstance(analytes, str):<EOL><INDENT>analytes = [analytes]<EOL><DEDENT>self.minimal_analytes.update(analytes)<EOL>errs = []<EOL>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>e = self.data[s].signal_optimiser(analytes=analytes, min_points=min_points,<EOL>threshold_mode=threshold_mode, threshold_mult=threshold_mult,<EOL>x_bias=x_bias, weights=weights, filt=filt, mode=mode)<EOL>if e != '<STR_LIT>':<EOL><INDENT>errs.append(e)<EOL><DEDENT>prog.update()<EOL><DEDENT><DEDENT>if len(errs) > <NUM_LIT:0>:<EOL><INDENT>print('<STR_LIT>' + '<STR_LIT:\n>'.join(errs) + '<STR_LIT>')<EOL><DEDENT>

Optimise data selection based on specified analytes.

Identifies the longest possible contiguous data region in
the signal where the relative standard deviation (std) and
concentration of all analytes is minimised.

Optimisation is performed via a grid search of all possible
contiguous data regions. For each region, the mean std and
mean scaled analyte concentration ('amplitude') are calculated.

The size and position of the optimal data region are identified
using threshold std and amplitude values. Thresholds are derived
from all calculated stds and amplitudes using the method specified
by `threshold_mode`. For example, using the 'kde_max' method, a
probability density function (PDF) is calculated for std and
amplitude values, and the threshold is set as the maximum of the
PDF. These thresholds are then used to identify the size and position
of the longest contiguous region where the std is below the threshold,
and the amplitude is either below the threshold.

All possible regions of the data that have at least
`min_points` are considered.

For a graphical demonstration of the action of signal_optimiser,
use `optimisation_plot`.

Parameters
----------
d : latools.D object
    An latools data object.
analytes : str or array-like
    Which analytes to consider.
min_points : int
    The minimum number of contiguous points to
    consider.
threshold_mode : str
    The method used to calculate the optimisation
    thresholds. Can be 'mean', 'median', 'kde_max'
    or 'bayes_mvs', or a custom function. If a
    function, must take a 1D array, and return a
    single, real number.
weights : array-like of length len(analytes)
    An array of numbers specifying the importance of
    each analyte considered. Larger number makes the
    analyte have a greater effect on the optimisation.
    Default is None.


@_log<EOL><INDENT>def optimisation_plots(self, overlay_alpha=<NUM_LIT:0.5>, samples=None, subset=None, **kwargs):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>outdir=self.report_dir + '<STR_LIT>'<EOL>if not os.path.isdir(outdir):<EOL><INDENT>os.mkdir(outdir)<EOL><DEDENT>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>figs = self.data[s].optimisation_plot(overlay_alpha, **kwargs)<EOL>n = <NUM_LIT:1><EOL>for f, _ in figs:<EOL><INDENT>if f is not None:<EOL><INDENT>f.savefig(outdir + '<STR_LIT:/>' + s + '<STR_LIT>'.format(n))<EOL>plt.close(f)<EOL><DEDENT>n += <NUM_LIT:1><EOL><DEDENT>prog.update()<EOL><DEDENT><DEDENT>return<EOL>

Plot the result of signal_optimise.

`signal_optimiser` must be run first, and the output
stored in the `opt` attribute of the latools.D object.

Parameters
----------
d : latools.D object
    A latools data object.
overlay_alpha : float
    The opacity of the threshold overlays. Between 0 and 1.
**kwargs
    Passed to `tplot`


@_log<EOL><INDENT>def set_focus(self, focus_stage=None, samples=None, subset=None):<DEDENT>

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>if subset is None:<EOL><INDENT>subset = '<STR_LIT>'<EOL><DEDENT>samples = self._get_samples(subset)<EOL>if focus_stage is None:<EOL><INDENT>focus_stage = self.focus_stage<EOL><DEDENT>else:<EOL><INDENT>self.focus_stage = focus_stage<EOL><DEDENT>for s in samples:<EOL><INDENT>self.data[s].setfocus(focus_stage)<EOL><DEDENT>

Set the 'focus' attribute of the data file.

The 'focus' attribute of the object points towards data from a
particular stage of analysis. It is used to identify the 'working
stage' of the data. Processing functions operate on the 'focus'
stage, so if steps are done out of sequence, things will break.

Names of analysis stages:

* 'rawdata': raw data, loaded from csv file when object
  is initialised.
* 'despiked': despiked data.
* 'signal'/'background': isolated signal and background data,
  padded with np.nan. Created by self.separate, after
  signal and background regions have been identified by
  self.autorange.
* 'bkgsub': background subtracted data, created by
  self.bkg_correct
* 'ratios': element ratio data, created by self.ratio.
* 'calibrated': ratio data calibrated to standards, created by
  self.calibrate.

Parameters
----------
focus : str
    The name of the analysis stage desired.

Returns
-------
None


def get_focus(self, filt=False, samples=None, subset=None, nominal=False):

if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>focus = {'<STR_LIT>': []}<EOL>focus.update({a: [] for a in self.analytes})<EOL>for sa in samples:<EOL><INDENT>s = self.data[sa]<EOL>focus['<STR_LIT>'].append(s.uTime)<EOL>ind = s.filt.grab_filt(filt)<EOL>for a in self.analytes:<EOL><INDENT>tmp = s.focus[a].copy()<EOL>tmp[~ind] = np.nan<EOL>focus[a].append(tmp)<EOL><DEDENT><DEDENT>if nominal:<EOL><INDENT>self.focus.update({k: nominal_values(np.concatenate(v)) for k, v, in focus.items()})<EOL><DEDENT>else:<EOL><INDENT>self.focus.update({k: np.concatenate(v) for k, v, in focus.items()})<EOL><DEDENT>return<EOL>

Collect all data from all samples into a single array.
Data from standards is not collected.

Parameters
----------
filt : str, dict or bool
    Either logical filter expression contained in a str,
    a dict of expressions specifying the filter string to
    use for each analyte or a boolean. Passed to `grab_filt`.
samples : str or list
    which samples to get
subset : str or int
    which subset to get

Returns
-------
None


def get_gradients(self, analytes=None, win=<NUM_LIT:15>, filt=False, samples=None, subset=None, recalc=True):

if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL><DEDENT>if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>if all([self.data[s].grads_calced for s in samples]) and hasattr(self, '<STR_LIT>'):<EOL><INDENT>if not recalc:<EOL><INDENT>print("<STR_LIT>")<EOL>return<EOL><DEDENT><DEDENT>if not hasattr(self, '<STR_LIT>'):<EOL><INDENT>self.gradients = Bunch()<EOL><DEDENT>focus = {'<STR_LIT>': []}<EOL>focus.update({a: [] for a in analytes})<EOL>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for sa in samples:<EOL><INDENT>s = self.data[sa]<EOL>focus['<STR_LIT>'].append(s.uTime)<EOL>ind = s.filt.grab_filt(filt)<EOL>grads = calc_grads(s.uTime, s.focus, keys=analytes, win=win)<EOL>for a in analytes:<EOL><INDENT>tmp = grads[a]<EOL>tmp[~ind] = np.nan<EOL>focus[a].append(tmp)<EOL>s.grads = tmp<EOL><DEDENT>s.grads_calced = True<EOL>prog.update()<EOL><DEDENT><DEDENT>self.gradients.update({k: np.concatenate(v) for k, v, in focus.items()})<EOL>return<EOL>


def gradient_histogram(self, analytes=None, win=<NUM_LIT:15>, filt=False, bins=None, samples=None, subset=None, recalc=True, ncol=<NUM_LIT:4>):

if analytes is None:<EOL><INDENT>analytes = [a for a in self.analytes if self.internal_standard not in a]<EOL><DEDENT>if not hasattr(self, '<STR_LIT>'):<EOL><INDENT>self.gradients = Bunch()<EOL><DEDENT>ncol = int(ncol)<EOL>n = len(analytes)<EOL>nrow = plot.calc_nrow(n, ncol)<EOL>if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>self.get_gradients(analytes=analytes, win=win, filt=filt, subset=subset, recalc=recalc)<EOL>fig, axs = plt.subplots(nrow, ncol, figsize=[<NUM_LIT> * ncol, <NUM_LIT> * nrow])<EOL>if not isinstance(axs, np.ndarray):<EOL><INDENT>axs = [axs]<EOL><DEDENT>i = <NUM_LIT:0><EOL>for a, ax in zip(analytes, axs.flatten()):<EOL><INDENT>d = nominal_values(self.gradients[a])<EOL>d = d[~np.isnan(d)]<EOL>m, u = unitpicker(d, focus_stage=self.focus_stage, denominator=self.internal_standard)<EOL>if bins is None:<EOL><INDENT>ibins = np.linspace(*np.percentile(d * m, [<NUM_LIT:1>, <NUM_LIT>]), <NUM_LIT:50>)<EOL><DEDENT>else:<EOL><INDENT>ibins = bins<EOL><DEDENT>ax.hist(d * m, bins=ibins, color=self.cmaps[a])<EOL>ax.axvline(<NUM_LIT:0>, ls='<STR_LIT>', lw=<NUM_LIT:1>, c=(<NUM_LIT:0>,<NUM_LIT:0>,<NUM_LIT:0>,<NUM_LIT>))<EOL>ax.set_title(a, loc='<STR_LIT:left>')<EOL>if ax.is_first_col():<EOL><INDENT>ax.set_ylabel('<STR_LIT:N>')<EOL><DEDENT>ax.set_xlabel(u + '<STR_LIT>')<EOL>i += <NUM_LIT:1><EOL><DEDENT>if i < ncol * nrow:<EOL><INDENT>for ax in axs.flatten()[i:]:<EOL><INDENT>ax.set_visible(False)<EOL><DEDENT><DEDENT>fig.tight_layout()<EOL>return fig, axs<EOL>

Plot a histogram of the gradients in all samples.

Parameters
----------
filt : str, dict or bool
    Either logical filter expression contained in a str,
    a dict of expressions specifying the filter string to
    use for each analyte or a boolean. Passed to `grab_filt`.
bins : None or array-like
    The bins to use in the histogram
samples : str or list
    which samples to get
subset : str or int
    which subset to get
recalc : bool
    Whether to re-calculate the gradients, or use existing gradients.

Returns
-------
fig, ax


@_log<EOL><INDENT>def crossplot(self, analytes=None, lognorm=True,<EOL>bins=<NUM_LIT>, filt=False, samples=None,<EOL>subset=None, figsize=(<NUM_LIT:12>, <NUM_LIT:12>), save=False,<EOL>colourful=True, mode='<STR_LIT>', **kwargs):<DEDENT>

if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL><DEDENT>if self.focus_stage in ['<STR_LIT>', '<STR_LIT>']:<EOL><INDENT>analytes = [a for a in analytes if self.internal_standard not in a]<EOL><DEDENT>try:<EOL><INDENT>analytes = sorted(analytes, key=lambda x: float(re.findall('<STR_LIT>', x)[<NUM_LIT:0>]))<EOL><DEDENT>except IndexError:<EOL><INDENT>analytes = sorted(analytes)<EOL><DEDENT>self.get_focus(filt=filt, samples=samples, subset=subset)<EOL>fig, axes = plot.crossplot(dat=self.focus, keys=analytes, lognorm=lognorm,<EOL>bins=bins, figsize=figsize, colourful=colourful,<EOL>focus_stage=self.focus_stage, cmap=self.cmaps,<EOL>denominator=self.internal_standard, mode=mode)<EOL>if save or isinstance(save, str):<EOL><INDENT>if isinstance(save, str):<EOL><INDENT>fig.savefig(self.report_dir + '<STR_LIT:/>' + save, dpi=<NUM_LIT:200>)            <EOL><DEDENT>else:<EOL><INDENT>fig.savefig(self.report_dir + '<STR_LIT>', dpi=<NUM_LIT:200>)<EOL><DEDENT><DEDENT>return fig, axes<EOL>

Plot analytes against each other.

Parameters
----------
analytes : optional, array_like or str
    The analyte(s) to plot. Defaults to all analytes.
lognorm : bool
    Whether or not to log normalise the colour scale
    of the 2D histogram.
bins : int
    The number of bins in the 2D histogram.
filt : str, dict or bool
    Either logical filter expression contained in a str,
    a dict of expressions specifying the filter string to
    use for each analyte or a boolean. Passed to `grab_filt`.
figsize : tuple
    Figure size (width, height) in inches.
save : bool or str
    If True, plot is saves as 'crossplot.png', if str plot is
    saves as str.
colourful : bool
    Whether or not the plot should be colourful :).
mode : str
    'hist2d' (default) or 'scatter'

Returns
-------
(fig, axes)


@_log<EOL><INDENT>def gradient_crossplot(self, analytes=None, win=<NUM_LIT:15>, lognorm=True,<EOL>bins=<NUM_LIT>, filt=False, samples=None,<EOL>subset=None, figsize=(<NUM_LIT:12>, <NUM_LIT:12>), save=False,<EOL>colourful=True, mode='<STR_LIT>', recalc=True, **kwargs):<DEDENT>

if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL><DEDENT>if self.focus_stage in ['<STR_LIT>', '<STR_LIT>']:<EOL><INDENT>analytes = [a for a in analytes if self.internal_standard not in a]<EOL><DEDENT>try:<EOL><INDENT>analytes = sorted(analytes, key=lambda x: float(re.findall('<STR_LIT>', x)[<NUM_LIT:0>]))<EOL><DEDENT>except IndexError:<EOL><INDENT>analytes = sorted(analytes)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>self.get_gradients(analytes=analytes, win=win, filt=filt, subset=subset, recalc=recalc)<EOL>fig, axes = plot.crossplot(dat=self.gradients, keys=analytes, lognorm=lognorm,<EOL>bins=bins, figsize=figsize, colourful=colourful,<EOL>focus_stage=self.focus_stage, cmap=self.cmaps,<EOL>denominator=self.internal_standard, mode=mode)<EOL>if save:<EOL><INDENT>fig.savefig(self.report_dir + '<STR_LIT>', dpi=<NUM_LIT:200>)<EOL><DEDENT>return fig, axes<EOL>

Plot analyte gradients against each other.

Parameters
----------
analytes : optional, array_like or str
    The analyte(s) to plot. Defaults to all analytes.
lognorm : bool
    Whether or not to log normalise the colour scale
    of the 2D histogram.
bins : int
    The number of bins in the 2D histogram.
filt : str, dict or bool
    Either logical filter expression contained in a str,
    a dict of expressions specifying the filter string to
    use for each analyte or a boolean. Passed to `grab_filt`.
figsize : tuple
    Figure size (width, height) in inches.
save : bool or str
    If True, plot is saves as 'crossplot.png', if str plot is
    saves as str.
colourful : bool
    Whether or not the plot should be colourful :).
mode : str
    'hist2d' (default) or 'scatter'
recalc : bool
    Whether to re-calculate the gradients, or use existing gradients.

Returns
-------
(fig, axes)


def histograms(self, analytes=None, bins=<NUM_LIT>, logy=False,<EOL>filt=False, colourful=True):

if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL><DEDENT>if self.focus_stage in ['<STR_LIT>', '<STR_LIT>']:<EOL><INDENT>analytes = [a for a in analytes if self.internal_standard not in a]<EOL><DEDENT>if colourful:<EOL><INDENT>cmap = self.cmaps<EOL><DEDENT>else:<EOL><INDENT>cmap = None<EOL><DEDENT>self.get_focus(filt=filt)<EOL>fig, axes = plot.histograms(self.focus, keys=analytes,<EOL>bins=bins, logy=logy, cmap=cmap)<EOL>return fig, axes<EOL>

Plot histograms of analytes.

Parameters
----------
analytes : optional, array_like or str
    The analyte(s) to plot. Defaults to all analytes.
bins : int
    The number of bins in each histogram (default = 25)
logy : bool
    If true, y axis is a log scale.
filt : str, dict or bool
    Either logical filter expression contained in a str,
    a dict of expressions specifying the filter string to
    use for each analyte or a boolean. Passed to `grab_filt`.
colourful : bool
    If True, histograms are colourful :)

Returns
-------
(fig, axes)


def filter_effect(self, analytes=None, stats=['<STR_LIT>', '<STR_LIT>'], filt=True):

if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL><DEDENT>if isinstance(analytes, str):<EOL><INDENT>analytes = [analytes]<EOL><DEDENT>self.sample_stats(['<STR_LIT>', '<STR_LIT>'], stats=stats, filt=False)<EOL>suf = self.stats.copy()<EOL>self.sample_stats(['<STR_LIT>', '<STR_LIT>'], stats=stats, filt=filt)<EOL>sf = self.stats.copy()<EOL>cols = []<EOL>for s in self.stats_calced:<EOL><INDENT>cols += ['<STR_LIT>'.format(s), '<STR_LIT>'.format(s)] <EOL><DEDENT>comp = pd.DataFrame(index=self.samples,<EOL>columns=pd.MultiIndex.from_arrays([cols, [None] * len(cols)]))<EOL>for k, v in suf.items():<EOL><INDENT>vf = sf[k]<EOL>for i, a in enumerate(v['<STR_LIT>']):<EOL><INDENT>for s in self.stats_calced:<EOL><INDENT>comp.loc[k, ('<STR_LIT>'.format(s), a)] = v[s][i,<NUM_LIT:0>]<EOL>comp.loc[k, ('<STR_LIT>'.format(s), a)] = vf[s][i,<NUM_LIT:0>]<EOL><DEDENT><DEDENT><DEDENT>comp.dropna(<NUM_LIT:0>, '<STR_LIT:all>', inplace=True)<EOL>comp.dropna(<NUM_LIT:1>, '<STR_LIT:all>', inplace=True)<EOL>comp.sort_index(<NUM_LIT:1>, inplace=True)<EOL>rats = []<EOL>for s in self.stats_calced:<EOL><INDENT>rat = comp.loc[:, '<STR_LIT>'.format(s)] / comp.loc[:, '<STR_LIT>'.format(s)]<EOL>rat.columns = pd.MultiIndex.from_product([['<STR_LIT>'.format(s)], rat.columns])<EOL>rats.append(rat)<EOL><DEDENT>comp = comp.join(pd.concat(rats, <NUM_LIT:1>))<EOL>comp.sort_index(<NUM_LIT:1>, inplace=True)<EOL>return comp.loc[:, (pd.IndexSlice[:], pd.IndexSlice[analytes])]<EOL>

Quantify the effects of the active filters.

Parameters
----------
analytes : str or list
    Which analytes to consider.
stats : list
    Which statistics to calculate.
file : valid filter string or bool
    Which filter to consider. If True, applies all
    active filters.

Returns
-------
pandas.DataFrame
    Contains statistics calculated for filtered and
    unfiltered data, and the filtered/unfiltered ratio.


def crossplot_filters(self, filter_string, analytes=None,<EOL>samples=None, subset=None, filt=None):

if analytes is None:<EOL><INDENT>analytes = [a for a in self.analytes if self.internal_standard not in a]<EOL><DEDENT>if samples is None:<EOL><INDENT>samples = self._get_samples(subset)<EOL><DEDENT>filts = self.data[samples[<NUM_LIT:0>]].filt.components.keys()<EOL>cfilts = [f for f in filts if filter_string in f]<EOL>flab = re.compile('<STR_LIT>')  <EOL>self.get_focus(subset=subset, filt=filt)<EOL>numvars = len(analytes)<EOL>fig, axes = plt.subplots(nrows=numvars, ncols=numvars,<EOL>figsize=(<NUM_LIT:12>, <NUM_LIT:12>))<EOL>fig.subplots_adjust(hspace=<NUM_LIT>, wspace=<NUM_LIT>)<EOL>for ax in axes.flat:<EOL><INDENT>ax.xaxis.set_visible(False)<EOL>ax.yaxis.set_visible(False)<EOL>if ax.is_first_col():<EOL><INDENT>ax.yaxis.set_ticks_position('<STR_LIT:left>')<EOL><DEDENT>if ax.is_last_col():<EOL><INDENT>ax.yaxis.set_ticks_position('<STR_LIT:right>')<EOL><DEDENT>if ax.is_first_row():<EOL><INDENT>ax.xaxis.set_ticks_position('<STR_LIT>')<EOL><DEDENT>if ax.is_last_row():<EOL><INDENT>ax.xaxis.set_ticks_position('<STR_LIT>')<EOL><DEDENT><DEDENT>cmlist = ['<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>']<EOL>focus = {k: nominal_values(v) for k, v in self.focus.items()}<EOL>udict = {a: unitpicker(np.nanmean(focus[a]),<EOL>focus_stage=self.focus_stage,<EOL>denominator=self.internal_standard) for a in analytes}<EOL>rdict = {a: (np.nanmin(focus[a] * udict[a][<NUM_LIT:0>]),<EOL>np.nanmax(focus[a] * udict[a][<NUM_LIT:0>])) for a in analytes}<EOL>for f in cfilts:<EOL><INDENT>self.get_focus(f, subset=subset)<EOL>focus = {k: nominal_values(v) for k, v in self.focus.items()}<EOL>lab = flab.match(f).groups()[<NUM_LIT:0>]<EOL>axes[<NUM_LIT:0>, <NUM_LIT:0>].scatter([], [], s=<NUM_LIT:10>, label=lab)<EOL>for i, j in zip(*np.triu_indices_from(axes, k=<NUM_LIT:1>)):<EOL><INDENT>ai = analytes[i]<EOL>aj = analytes[j]<EOL>pi = focus[ai][~np.isnan(focus[ai])] * udict[ai][<NUM_LIT:0>]<EOL>pj = focus[aj][~np.isnan(focus[aj])] * udict[aj][<NUM_LIT:0>]<EOL>axes[i, j].scatter(pj, pi, alpha=<NUM_LIT>, s=<NUM_LIT:10>, lw=<NUM_LIT:0.5>, edgecolor='<STR_LIT:k>')<EOL>axes[j, i].scatter(pi, pj, alpha=<NUM_LIT>, s=<NUM_LIT:10>, lw=<NUM_LIT:0.5>, edgecolor='<STR_LIT:k>')<EOL>axes[i, j].set_ylim(*rdict[ai])<EOL>axes[i, j].set_xlim(*rdict[aj])<EOL>axes[j, i].set_ylim(*rdict[aj])<EOL>axes[j, i].set_xlim(*rdict[ai])<EOL><DEDENT><DEDENT>for a, n in zip(analytes, np.arange(len(analytes))):<EOL><INDENT>axes[n, n].annotate(a + '<STR_LIT:\n>' + udict[a][<NUM_LIT:1>], (<NUM_LIT:0.5>, <NUM_LIT:0.5>),<EOL>xycoords='<STR_LIT>',<EOL>ha='<STR_LIT>', va='<STR_LIT>')<EOL>axes[n, n].set_xlim(*rdict[a])<EOL>axes[n, n].set_ylim(*rdict[a])<EOL><DEDENT>axes[<NUM_LIT:0>, <NUM_LIT:0>].legend(loc='<STR_LIT>', title=filter_string)<EOL>for i, j in zip(range(numvars), itertools.cycle((-<NUM_LIT:1>, <NUM_LIT:0>))):<EOL><INDENT>axes[j, i].xaxis.set_visible(True)<EOL>for label in axes[j, i].get_xticklabels():<EOL><INDENT>label.set_rotation(<NUM_LIT>)<EOL><DEDENT>axes[i, j].yaxis.set_visible(True)<EOL><DEDENT>return fig, axes<EOL>

Plot the results of a group of filters in a crossplot.

Parameters
----------
filter_string : str
    A string that identifies a group of filters.
    e.g. 'test' would plot all filters with 'test' in the
    name.
analytes : optional, array_like or str
    The analyte(s) to plot. Defaults to all analytes.

Returns
-------
fig, axes objects


@_log<EOL><INDENT>def trace_plots(self, analytes=None, samples=None, ranges=False,<EOL>focus=None, outdir=None, filt=None, scale='<STR_LIT>',<EOL>figsize=[<NUM_LIT:10>, <NUM_LIT:4>], stats=False, stat='<STR_LIT>',<EOL>err='<STR_LIT>', subset='<STR_LIT>'):<DEDENT>

if focus is None:<EOL><INDENT>focus = self.focus_stage<EOL><DEDENT>if outdir is None:<EOL><INDENT>outdir = self.report_dir + '<STR_LIT:/>' + focus<EOL><DEDENT>if not os.path.isdir(outdir):<EOL><INDENT>os.mkdir(outdir)<EOL><DEDENT>if subset is not None:<EOL><INDENT>samples = self._get_samples(subset)<EOL><DEDENT>elif samples is None:<EOL><INDENT>samples = self.subsets['<STR_LIT>']<EOL><DEDENT>elif isinstance(samples, str):<EOL><INDENT>samples = [samples]<EOL><DEDENT>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>f, a = self.data[s].tplot(analytes=analytes, figsize=figsize,<EOL>scale=scale, filt=filt,<EOL>ranges=ranges, stats=stats,<EOL>stat=stat, err=err, focus_stage=focus)<EOL>f.savefig(outdir + '<STR_LIT:/>' + s + '<STR_LIT>')<EOL>plt.close(f)<EOL>prog.update()<EOL><DEDENT><DEDENT>return<EOL>

Plot analytes as a function of time.

Parameters
----------
analytes : optional, array_like or str
    The analyte(s) to plot. Defaults to all analytes.
samples: optional, array_like or str
    The sample(s) to plot. Defaults to all samples.
ranges : bool
    Whether or not to show the signal/backgroudn regions
    identified by 'autorange'.
focus : str
    The focus 'stage' of the analysis to plot. Can be
    'rawdata', 'despiked':, 'signal', 'background',
    'bkgsub', 'ratios' or 'calibrated'.
outdir : str
    Path to a directory where you'd like the plots to be
    saved. Defaults to 'reports/[focus]' in your data directory.
filt : str, dict or bool
    Either logical filter expression contained in a str,
    a dict of expressions specifying the filter string to
    use for each analyte or a boolean. Passed to `grab_filt`.
scale : str
    If 'log', plots the data on a log scale.
figsize : array_like
    Array of length 2 specifying figure [width, height] in
    inches.
stats : bool
    Whether or not to overlay the mean and standard deviations
    for each trace.
stat, err: str
    The names of the statistic and error components to plot.
    Deafaults to 'nanmean' and 'nanstd'.

Returns
-------
None


@_log<EOL><INDENT>def gradient_plots(self, analytes=None, win=<NUM_LIT:15>, samples=None, ranges=False,<EOL>focus=None, outdir=None,<EOL>figsize=[<NUM_LIT:10>, <NUM_LIT:4>], subset='<STR_LIT>'):<DEDENT>

if focus is None:<EOL><INDENT>focus = self.focus_stage<EOL><DEDENT>if outdir is None:<EOL><INDENT>outdir = self.report_dir + '<STR_LIT:/>' + focus + '<STR_LIT>'<EOL><DEDENT>if not os.path.isdir(outdir):<EOL><INDENT>os.mkdir(outdir)<EOL><DEDENT>if subset is not None:<EOL><INDENT>samples = self._get_samples(subset)<EOL><DEDENT>elif samples is None:<EOL><INDENT>samples = self.subsets['<STR_LIT>']<EOL><DEDENT>elif isinstance(samples, str):<EOL><INDENT>samples = [samples]<EOL><DEDENT>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>f, a = self.data[s].gplot(analytes=analytes, win=win, figsize=figsize,<EOL>ranges=ranges, focus_stage=focus)<EOL>f.savefig(outdir + '<STR_LIT:/>' + s + '<STR_LIT>')<EOL>plt.close(f)<EOL>prog.update()<EOL><DEDENT><DEDENT>return<EOL>

Plot analyte gradients as a function of time.

Parameters
----------
analytes : optional, array_like or str
    The analyte(s) to plot. Defaults to all analytes.
samples: optional, array_like or str
    The sample(s) to plot. Defaults to all samples.
ranges : bool
    Whether or not to show the signal/backgroudn regions
    identified by 'autorange'.
focus : str
    The focus 'stage' of the analysis to plot. Can be
    'rawdata', 'despiked':, 'signal', 'background',
    'bkgsub', 'ratios' or 'calibrated'.
outdir : str
    Path to a directory where you'd like the plots to be
    saved. Defaults to 'reports/[focus]' in your data directory.
filt : str, dict or bool
    Either logical filter expression contained in a str,
    a dict of expressions specifying the filter string to
    use for each analyte or a boolean. Passed to `grab_filt`.
scale : str
    If 'log', plots the data on a log scale.
figsize : array_like
    Array of length 2 specifying figure [width, height] in
    inches.
stats : bool
    Whether or not to overlay the mean and standard deviations
    for each trace.
stat, err: str
    The names of the statistic and error components to plot.
    Deafaults to 'nanmean' and 'nanstd'.

Returns
-------
None


@_log<EOL><INDENT>def filter_reports(self, analytes, filt_str='<STR_LIT:all>', nbin=<NUM_LIT:5>, samples=None,<EOL>outdir=None, subset='<STR_LIT>'):<DEDENT>

if outdir is None:<EOL><INDENT>outdir = self.report_dir + '<STR_LIT>' + filt_str<EOL>if not os.path.isdir(self.report_dir + '<STR_LIT>'):<EOL><INDENT>os.mkdir(self.report_dir + '<STR_LIT>')<EOL><DEDENT><DEDENT>if not os.path.isdir(outdir):<EOL><INDENT>os.mkdir(outdir)<EOL><DEDENT>if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>with self.pbar.set(total=len(samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in samples:<EOL><INDENT>_ = self.data[s].filter_report(filt=filt_str,<EOL>analytes=analytes,<EOL>savedir=outdir,<EOL>nbin=nbin)<EOL>prog.update()<EOL><DEDENT><DEDENT>return<EOL>

Plot filter reports for all filters that contain ``filt_str``
in the name.


@_log<EOL><INDENT>def sample_stats(self, analytes=None, filt=True,<EOL>stats=['<STR_LIT>', '<STR_LIT>'],<EOL>eachtrace=True, csf_dict={}):<DEDENT>

if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL><DEDENT>elif isinstance(analytes, str):<EOL><INDENT>analytes = [analytes]<EOL><DEDENT>self.stats = Bunch()<EOL>self.stats_calced = []<EOL>stat_fns = Bunch()<EOL>stat_dict = {'<STR_LIT>': np.nanmean,<EOL>'<STR_LIT>': np.nanstd,<EOL>'<STR_LIT>': np.nanmean,<EOL>'<STR_LIT>': np.nanstd,<EOL>'<STR_LIT>': stderr,<EOL>'<STR_LIT>': H15_mean,<EOL>'<STR_LIT>': H15_std,<EOL>'<STR_LIT>': H15_se}<EOL>for s in stats:<EOL><INDENT>if isinstance(s, str):<EOL><INDENT>if s in stat_dict.keys():<EOL><INDENT>self.stats_calced.append(s)<EOL>stat_fns[s] = stat_dict[s]<EOL><DEDENT>if s in csf_dict.keys():<EOL><INDENT>self.stats_calced.append(s)<EOL>exec(csf_dict[s])<EOL>stat_fns[s] = eval(s)<EOL><DEDENT><DEDENT>elif callable(s):<EOL><INDENT>self.stats_calced.append(s.__name__)<EOL>stat_fns[s.__name__] = s<EOL>if not hasattr(self, '<STR_LIT>'):<EOL><INDENT>self.custom_stat_functions = '<STR_LIT>'<EOL><DEDENT>self.custom_stat_functions += inspect.getsource(s) + '<STR_LIT>'<EOL><DEDENT><DEDENT>with self.pbar.set(total=len(self.samples), desc='<STR_LIT>') as prog:<EOL><INDENT>for s in self.samples:<EOL><INDENT>if self.srm_identifier not in s:<EOL><INDENT>self.data[s].sample_stats(analytes, filt=filt,<EOL>stat_fns=stat_fns,<EOL>eachtrace=eachtrace)<EOL>self.stats[s] = self.data[s].stats<EOL><DEDENT>prog.update()<EOL><DEDENT><DEDENT>

Calculate sample statistics.

Returns samples, analytes, and arrays of statistics
of shape (samples, analytes). Statistics are calculated
from the 'focus' data variable, so output depends on how
the data have been processed.

Included stat functions:

* :func:`~latools.stat_fns.mean`: arithmetic mean
* :func:`~latools.stat_fns.std`: arithmetic standard deviation
* :func:`~latools.stat_fns.se`: arithmetic standard error
* :func:`~latools.stat_fns.H15_mean`: Huber mean (outlier removal)
* :func:`~latools.stat_fns.H15_std`: Huber standard deviation (outlier removal)
* :func:`~latools.stat_fns.H15_se`: Huber standard error (outlier removal)

Parameters
----------
analytes : optional, array_like or str
    The analyte(s) to calculate statistics for. Defaults to
    all analytes.
filt : str, dict or bool
    Either logical filter expression contained in a str,
    a dict of expressions specifying the filter string to
    use for each analyte or a boolean. Passed to `grab_filt`.
stats : array_like
    take a single array_like input, and return a single statistic.
    list of functions or names (see above) or functions that
    Function should be able to cope with NaN values.
eachtrace : bool
    Whether to calculate the statistics for each analysis
    spot individually, or to produce per - sample means.
    Default is True.

Returns
-------
None
    Adds dict to analyse object containing samples, analytes and
    functions and data.


@_log<EOL><INDENT>def statplot(self, analytes=None, samples=None, figsize=None,<EOL>stat='<STR_LIT>', err='<STR_LIT>', subset=None):<DEDENT>

if not hasattr(self, '<STR_LIT>'):<EOL><INDENT>self.sample_stats()<EOL><DEDENT>if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL><DEDENT>elif isinstance(analytes, str):<EOL><INDENT>analytes = [analytes]<EOL><DEDENT>if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>analytes = [a for a in analytes if a !=<EOL>self.internal_standard]<EOL>if figsize is None:<EOL><INDENT>figsize = (<NUM_LIT> * len(self.stats), <NUM_LIT:3> * len(analytes))<EOL><DEDENT>fig, axs = plt.subplots(len(analytes), <NUM_LIT:1>, figsize=figsize)<EOL>for ax, an in zip(axs, analytes):<EOL><INDENT>i = <NUM_LIT:0><EOL>stab = self.getstats()<EOL>m, u = unitpicker(np.percentile(stab.loc[:, an].dropna(), <NUM_LIT>), <NUM_LIT:0.1>,<EOL>focus_stage='<STR_LIT>',<EOL>denominator=self.internal_standard)<EOL>for s in samples:<EOL><INDENT>if self.srm_identifier not in s:<EOL><INDENT>d = self.stats[s]<EOL>if d[stat].ndim == <NUM_LIT:2>:<EOL><INDENT>n = d[stat].shape[-<NUM_LIT:1>]<EOL>x = np.linspace(i - <NUM_LIT> * n / <NUM_LIT:2>, i + <NUM_LIT> * n / <NUM_LIT:2>, n)<EOL><DEDENT>else:<EOL><INDENT>x = [i]<EOL><DEDENT>a_ind = d['<STR_LIT>'] == an<EOL>ax.errorbar(x, d[stat][a_ind][<NUM_LIT:0>] * m,<EOL>yerr=d[err][a_ind][<NUM_LIT:0>] * m,<EOL>marker='<STR_LIT:o>', color=self.cmaps[an],<EOL>lw=<NUM_LIT:0>, elinewidth=<NUM_LIT:1>)<EOL>ax.set_ylabel('<STR_LIT>' % (pretty_element(an),<EOL>pretty_element(self.internal_standard),<EOL>u))<EOL>if len(x) > <NUM_LIT:1>:<EOL><INDENT>mean = np.nanmean(d[stat][a_ind][<NUM_LIT:0>] * m)<EOL>std = np.nanstd(d[stat][a_ind][<NUM_LIT:0>] * m)<EOL>ax.plot(x, [mean] * len(x), c=self.cmaps[an], lw=<NUM_LIT:2>)<EOL>ax.fill_between(x, [mean + std] * len(x),<EOL>[mean - std] * len(x),<EOL>lw=<NUM_LIT:0>, alpha=<NUM_LIT>, color=self.cmaps[an])<EOL><DEDENT>if i % <NUM_LIT:2> == <NUM_LIT:1>:<EOL><INDENT>ax.axvspan(i - <NUM_LIT>, i + <NUM_LIT>, color=(<NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT>), lw=<NUM_LIT:0>)<EOL><DEDENT>i += <NUM_LIT:1><EOL><DEDENT><DEDENT>ax.set_xticks(np.arange(<NUM_LIT:0>, len(self.stats)))<EOL>ax.set_xlim(-<NUM_LIT:0.5>, len(self.stats) - <NUM_LIT>)<EOL>ax.set_xticklabels(samples)<EOL><DEDENT>return fig, ax<EOL>

Function for visualising per-ablation and per-sample means.

Parameters
----------
analytes : str or iterable
    Which analyte(s) to plot
samples : str or iterable
    Which sample(s) to plot
figsize : tuple
    Figure (width, height) in inches
stat : str
    Which statistic to plot. Must match
    the name of the functions used in
    'sample_stats'.
err : str
    Which uncertainty to plot.
subset : str
    Which subset of samples to plot.


@_log<EOL><INDENT>def getstats(self, save=True, filename=None, samples=None, subset=None, ablation_time=False):<DEDENT>

slst = []<EOL>if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>for s in self.stats_calced:<EOL><INDENT>for nm in [n for n in samples if self.srm_identifier<EOL>not in n]:<EOL><INDENT>if self.stats[nm][s].ndim == <NUM_LIT:2>:<EOL><INDENT>reps = np.arange(self.stats[nm][s].shape[-<NUM_LIT:1>])<EOL>ss = np.array([s] * reps.size)<EOL>nms = np.array([nm] * reps.size)<EOL>stdf = pd.DataFrame(self.stats[nm][s].T,<EOL>columns=self.stats[nm]['<STR_LIT>'],<EOL>index=[ss, nms, reps])<EOL>stdf.index.set_names(['<STR_LIT>', '<STR_LIT>', '<STR_LIT>'],<EOL>inplace=True)<EOL><DEDENT>else:<EOL><INDENT>stdf = pd.DataFrame(self.stats[nm][s],<EOL>index=self.stats[nm]['<STR_LIT>'],<EOL>columns=[[s], [nm]]).T<EOL>stdf.index.set_names(['<STR_LIT>', '<STR_LIT>'],<EOL>inplace=True)<EOL><DEDENT>slst.append(stdf)<EOL><DEDENT><DEDENT>out = pd.concat(slst)<EOL>if ablation_time:<EOL><INDENT>ats = self.ablation_times(samples=samples, subset=subset)<EOL>ats['<STR_LIT>'] = '<STR_LIT>'<EOL>ats.set_index('<STR_LIT>', append=True, inplace=True)<EOL>ats = ats.reorder_levels(['<STR_LIT>', '<STR_LIT>', '<STR_LIT>'])<EOL>out = out.join(ats)<EOL><DEDENT>out.drop(self.internal_standard, <NUM_LIT:1>, inplace=True)<EOL>if save:<EOL><INDENT>if filename is None:<EOL><INDENT>filename = '<STR_LIT>'<EOL><DEDENT>out.to_csv(self.export_dir + '<STR_LIT:/>' + filename)<EOL><DEDENT>self.stats_df = out<EOL>return out<EOL>

Return pandas dataframe of all sample statistics.


def _minimal_export_traces(self, outdir=None, analytes=None,<EOL>samples=None, subset='<STR_LIT>'):

if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL><DEDENT>elif isinstance(analytes, str):<EOL><INDENT>analytes = [analytes]<EOL><DEDENT>if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>focus_stage = '<STR_LIT>'<EOL>if not os.path.isdir(outdir):<EOL><INDENT>os.mkdir(outdir)<EOL><DEDENT>for s in samples:<EOL><INDENT>d = self.data[s].data[focus_stage]<EOL>out = Bunch()<EOL>for a in analytes:<EOL><INDENT>out[a] = d[a]<EOL><DEDENT>out = pd.DataFrame(out, index=self.data[s].Time)<EOL>out.index.name = '<STR_LIT>'<EOL>d = dateutil.parser.parse(self.data[s].meta['<STR_LIT:date>'])<EOL>header = ['<STR_LIT>' %<EOL>(time.strftime('<STR_LIT>')),<EOL>"<STR_LIT>",<EOL>'<STR_LIT>',<EOL>'<STR_LIT:#>',<EOL>'<STR_LIT>' % (s),<EOL>'<STR_LIT>' + d.strftime('<STR_LIT>')]<EOL>header = '<STR_LIT:\n>'.join(header) + '<STR_LIT:\n>'<EOL>csv = out.to_csv()<EOL>with open('<STR_LIT>' % (outdir, s), '<STR_LIT:w>') as f:<EOL><INDENT>f.write(header)<EOL>f.write(csv)<EOL><DEDENT><DEDENT>return<EOL>

Used for exporting minimal dataset. DON'T USE.


@_log<EOL><INDENT>def export_traces(self, outdir=None, focus_stage=None, analytes=None,<EOL>samples=None, subset='<STR_LIT>', filt=False, zip_archive=False):<DEDENT>

if analytes is None:<EOL><INDENT>analytes = self.analytes<EOL><DEDENT>elif isinstance(analytes, str):<EOL><INDENT>analytes = [analytes]<EOL><DEDENT>if samples is not None:<EOL><INDENT>subset = self.make_subset(samples)<EOL><DEDENT>samples = self._get_samples(subset)<EOL>if focus_stage is None:<EOL><INDENT>focus_stage = self.focus_stage<EOL><DEDENT>if focus_stage in ['<STR_LIT>', '<STR_LIT>']:<EOL><INDENT>analytes = [a for a in analytes if a != self.internal_standard]<EOL><DEDENT>if outdir is None:<EOL><INDENT>outdir = os.path.join(self.export_dir, '<STR_LIT>')<EOL><DEDENT>ud = {'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': '<STR_LIT>'}<EOL>if focus_stage in ['<STR_LIT>', '<STR_LIT>']:<EOL><INDENT>ud[focus_stage] = ud[focus_stage].format(self.internal_standard)<EOL><DEDENT>if not os.path.isdir(outdir):<EOL><INDENT>os.mkdir(outdir)<EOL><DEDENT>for s in samples:<EOL><INDENT>d = self.data[s].data[focus_stage]<EOL>ind = self.data[s].filt.grab_filt(filt)<EOL>out = Bunch()<EOL>for a in analytes:<EOL><INDENT>out[a] = nominal_values(d[a][ind])<EOL>if focus_stage not in ['<STR_LIT>', '<STR_LIT>']:<EOL><INDENT>out[a + '<STR_LIT>'] = std_devs(d[a][ind])<EOL>out[a + '<STR_LIT>'][out[a + '<STR_LIT>'] == <NUM_LIT:0>] = np.nan<EOL><DEDENT><DEDENT>out = pd.DataFrame(out, index=self.data[s].Time[ind])<EOL>out.index.name = '<STR_LIT>'<EOL>header = ['<STR_LIT>' % (s),<EOL>'<STR_LIT>' %<EOL>(time.strftime('<STR_LIT>')),<EOL>'<STR_LIT>' % (self.config['<STR_LIT>']),<EOL>'<STR_LIT>' % (focus_stage),<EOL>'<STR_LIT>' % ud[focus_stage]]<EOL>header = '<STR_LIT:\n>'.join(header) + '<STR_LIT:\n>'<EOL>csv = out.to_csv()<EOL>with open('<STR_LIT>' % (outdir, s, focus_stage), '<STR_LIT:w>') as f:<EOL><INDENT>f.write(header)<EOL>f.write(csv)<EOL><DEDENT><DEDENT>if zip_archive:<EOL><INDENT>utils.zipdir(outdir, delete=True)<EOL><DEDENT>return<EOL>

Function to export raw data.

Parameters
----------
outdir : str
    directory to save toe traces. Defaults to 'main-dir-name_export'.
focus_stage : str
    The name of the analysis stage to export.

    * 'rawdata': raw data, loaded from csv file.
    * 'despiked': despiked data.
    * 'signal'/'background': isolated signal and background data.
      Created by self.separate, after signal and background
      regions have been identified by self.autorange.
    * 'bkgsub': background subtracted data, created by
      self.bkg_correct
    * 'ratios': element ratio data, created by self.ratio.
    * 'calibrated': ratio data calibrated to standards, created by self.calibrate.

    Defaults to the most recent stage of analysis.
analytes : str or array - like
    Either a single analyte, or list of analytes to export.
    Defaults to all analytes.
samples : str or array - like
    Either a single sample name, or list of samples to export.
    Defaults to all samples.
filt : str, dict or bool
    Either logical filter expression contained in a str,
    a dict of expressions specifying the filter string to
    use for each analyte or a boolean. Passed to `grab_filt`.


def save_log(self, directory=None, logname=None, header=None):

if directory is None:<EOL><INDENT>directory = self.export_dir<EOL><DEDENT>if not os.path.isdir(directory):<EOL><INDENT>directory = os.path.dirname(directory)<EOL><DEDENT>if logname is None:<EOL><INDENT>logname = '<STR_LIT>'<EOL><DEDENT>if header is None:<EOL><INDENT>header = self._log_header()<EOL><DEDENT>loc = logging.write_logfile(self.log, header, <EOL>os.path.join(directory, logname))<EOL>return loc<EOL>

Save analysis.lalog in specified location


def minimal_export(self, target_analytes=None, path=None):

if target_analytes is None:<EOL><INDENT>target_analytes = self.analytes<EOL><DEDENT>if isinstance(target_analytes, str):<EOL><INDENT>target_analytes = [target_analytes]<EOL><DEDENT>self.minimal_analytes.update(target_analytes)<EOL>zip_archive = False<EOL>if path is None:<EOL><INDENT>path = self.export_dir + '<STR_LIT>'<EOL><DEDENT>if path.endswith('<STR_LIT>'):<EOL><INDENT>path = path.replace('<STR_LIT>', '<STR_LIT>')<EOL>zip_archive = True<EOL><DEDENT>if not os.path.isdir(path):<EOL><INDENT>os.mkdir(path)<EOL><DEDENT>self._minimal_export_traces(path + '<STR_LIT>', analytes=self.minimal_analytes)<EOL>log_header = ['<STR_LIT>' %<EOL>(time.strftime('<STR_LIT>')),<EOL>'<STR_LIT>']<EOL>if hasattr(self, '<STR_LIT>'):<EOL><INDENT>log_header.append('<STR_LIT>')<EOL>els = np.unique([re.sub('<STR_LIT>', '<STR_LIT>', a) for a in self.minimal_analytes])<EOL>srmdat = []<EOL>for e in els:<EOL><INDENT>srmdat.append(self.srmdat.loc[self.srmdat.element == e, :])<EOL><DEDENT>srmdat = pd.concat(srmdat)<EOL>with open(path + '<STR_LIT>', '<STR_LIT:w>') as f:<EOL><INDENT>f.write(srmdat.to_csv())<EOL><DEDENT><DEDENT>if hasattr(self, '<STR_LIT>'):<EOL><INDENT>with open(path + '<STR_LIT>', '<STR_LIT:w>') as f:<EOL><INDENT>f.write(self.custom_stat_functions)<EOL><DEDENT>log_header.append('<STR_LIT>')<EOL><DEDENT>log_header.append('<STR_LIT>')<EOL>lss = [(i, l) for i, l in enumerate(self.log) if '<STR_LIT>' in l]<EOL>rep = re.compile("<STR_LIT>")<EOL>for i, l in lss:<EOL><INDENT>self.log[i] = rep.sub(r'<STR_LIT>' + str(self.stats_calced) + r'<STR_LIT>', l)<EOL><DEDENT>self.save_log(path, '<STR_LIT>', header=log_header)<EOL>if zip_archive:<EOL><INDENT>utils.zipdir(directory=path, delete=True)<EOL><DEDENT>return<EOL>

Exports a analysis parameters, standard info and a minimal dataset,
which can be imported by another user.

Parameters
----------
target_analytes : str or iterable
    Which analytes to include in the export. If specified, the export
    will contain these analytes, and all other analytes used during
    data processing (e.g. during filtering). If not specified,
    all analytes are exported.
path : str
    Where to save the minimal export.
    If it ends with .zip, a zip file is created.
    If it's a folder, all data are exported to a folder.


def by_regex(file, outdir=None, split_pattern=None, global_header_rows=<NUM_LIT:0>, fname_pattern=None, trim_tail_lines=<NUM_LIT:0>, trim_head_lines=<NUM_LIT:0>):

<EOL>if outdir is None:<EOL><INDENT>outdir = os.path.join(os.path.dirname(file), '<STR_LIT>')<EOL><DEDENT>if not os.path.exists(outdir):<EOL><INDENT>os.mkdir(outdir)<EOL><DEDENT>with open(file, '<STR_LIT:r>') as f:<EOL><INDENT>lines = f.readlines()<EOL><DEDENT>extension = os.path.splitext(file)[-<NUM_LIT:1>]<EOL>global_header = lines[:global_header_rows]<EOL>starts = []<EOL>for i, line in enumerate(lines):<EOL><INDENT>if re.search(split_pattern, line):<EOL><INDENT>starts.append(i)    <EOL><DEDENT><DEDENT>starts.append(len(lines))  <EOL>splits = {}<EOL>for i in range(len(starts) - <NUM_LIT:1>):<EOL><INDENT>m = re.search(fname_pattern, lines[starts[i]])<EOL>if m:<EOL><INDENT>fname = m.groups()[<NUM_LIT:0>].strip()<EOL><DEDENT>else:<EOL><INDENT>fname = '<STR_LIT>'.format(i)<EOL><DEDENT>splits[fname] = global_header + lines[starts[i]:starts[i+<NUM_LIT:1>]][trim_head_lines:trim_tail_lines]<EOL><DEDENT>print('<STR_LIT>'.format(outdir))<EOL>for k, v in splits.items():<EOL><INDENT>fname = (k + extension).replace('<STR_LIT:U+0020>', '<STR_LIT:_>')<EOL>with open(os.path.join(outdir, fname), '<STR_LIT:w>') as f:<EOL><INDENT>f.writelines(v)<EOL><DEDENT>print('<STR_LIT>'.format(fname))<EOL><DEDENT>print('<STR_LIT>')<EOL>return outdir<EOL>

Split one long analysis file into multiple smaller ones.

Parameters
----------
file : str
    The path to the file you want to split.
outdir : str
    The directory to save the split files to.
    If None, files are saved to a new directory
    called 'split', which is created inside the
    data directory.
split_pattern : regex string
    A regular expression that will match lines in the
    file that mark the start of a new section. Does
    not have to match the whole line, but must provide
    a positive match to the lines containing the pattern.
global_header_rows : int
    How many rows at the start of the file to include
    in each new sub-file.
fname_pattern : regex string
    A regular expression that identifies a new file name
    in the lines identified by split_pattern. If none,
    files will be called 'noname_N'. The extension of the
    main file will be used for all sub-files.
trim_head_lines : int
    If greater than zero, this many lines are removed from the start of each segment
trim_tail_lines : int
    If greater than zero, this many lines are removed from the end of each segment

Returns
-------
Path to new directory : str


def long_file(data_file, dataformat, sample_list, savedir=None, srm_id=None, **autorange_args):

if isinstance(sample_list, str):<EOL><INDENT>if os.path.exists(sample_list):<EOL><INDENT>sample_list = np.genfromtxt(sample_list, dtype=str)<EOL><DEDENT>else:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT><DEDENT>elif not isinstance(sample_list, (list, np.ndarray)):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>if srm_id is not None:<EOL><INDENT>srm_replace = []<EOL>for s in sample_list:<EOL><INDENT>if srm_id in s:<EOL><INDENT>s = srm_id<EOL><DEDENT>srm_replace.append(s)<EOL><DEDENT>sample_list = srm_replace<EOL><DEDENT>_, _, dat, meta = read_data(data_file, dataformat=dataformat, name_mode='<STR_LIT:file>')<EOL>if '<STR_LIT:date>' in meta:<EOL><INDENT>d = dateutil.parser.parse(meta['<STR_LIT:date>'])<EOL><DEDENT>else:<EOL><INDENT>d = datetime.datetime.now()<EOL><DEDENT>bkg, sig, trn, _ = autorange(dat['<STR_LIT>'], dat['<STR_LIT>'], **autorange_args)<EOL>ns = np.zeros(sig.size)<EOL>ns[sig] = np.cumsum((sig ^ np.roll(sig, <NUM_LIT:1>)) & sig)[sig]<EOL>n = int(max(ns))<EOL>if len(sample_list) != n:<EOL><INDENT>warn('<STR_LIT>' + <EOL>'<STR_LIT>')<EOL><DEDENT>bounds = []<EOL>lower = <NUM_LIT:0><EOL>sn = <NUM_LIT:0><EOL>next_sample = '<STR_LIT>'<EOL>for ni in range(n-<NUM_LIT:1>):<EOL><INDENT>sample = sample_list[sn]<EOL>next_sample = sample_list[sn + <NUM_LIT:1>]<EOL>if sample != next_sample:<EOL><INDENT>current_end = np.argwhere(dat['<STR_LIT>'] == dat['<STR_LIT>'][ns == ni + <NUM_LIT:1>].max())[<NUM_LIT:0>]<EOL>next_start = np.argwhere(dat['<STR_LIT>'] == dat['<STR_LIT>'][ns == ni + <NUM_LIT:2>].min())[<NUM_LIT:0>]<EOL>upper = (current_end + next_start) // <NUM_LIT:2><EOL>bounds.append((sample, (int(lower), int(upper))))<EOL>lower = upper + <NUM_LIT:1><EOL><DEDENT>sn += <NUM_LIT:1><EOL><DEDENT>bounds.append((sample_list[-<NUM_LIT:1>], (int(upper) + <NUM_LIT:1>, len(ns))))<EOL>sections = {}<EOL>seen = {}<EOL>for s, (lo, hi) in bounds:<EOL><INDENT>if s not in seen:<EOL><INDENT>seen[s] = <NUM_LIT:0><EOL><DEDENT>else:<EOL><INDENT>seen[s] += <NUM_LIT:1><EOL>s += '<STR_LIT>'.format(seen[s])<EOL><DEDENT>sections[s] = {'<STR_LIT>': dat['<STR_LIT>'][lo:hi]}<EOL>sections[s]['<STR_LIT>'] = sections[s]['<STR_LIT>'] - np.nanmin(sections[s]['<STR_LIT>'])<EOL>sections[s]['<STR_LIT>'] = {}<EOL>for k, v in dat['<STR_LIT>'].items():<EOL><INDENT>sections[s]['<STR_LIT>'][k] = v[lo:hi]<EOL><DEDENT>sections[s]['<STR_LIT>'] = d + datetime.timedelta(seconds=np.nanmin(sections[s]['<STR_LIT>']))<EOL><DEDENT>if savedir is None:<EOL><INDENT>savedir = os.path.join(os.path.dirname(os.path.abspath(data_file)), os.path.splitext(os.path.basename(data_file))[<NUM_LIT:0>] + '<STR_LIT>')<EOL><DEDENT>if not os.path.isdir(savedir):<EOL><INDENT>os.makedirs(savedir)<EOL><DEDENT>header = ['<STR_LIT>'.format(datetime.datetime.now().strftime('<STR_LIT>'))]<EOL>if '<STR_LIT:date>' not in meta:<EOL><INDENT>header.append('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>header.append('<STR_LIT>')<EOL>header.append('<STR_LIT>')<EOL>header.append('<STR_LIT>')<EOL><DEDENT>flist = [savedir]<EOL>for s, dat in sections.items():<EOL><INDENT>iheader = header.copy()<EOL>iheader.append('<STR_LIT>'.format(s))<EOL>iheader.append('<STR_LIT>'.format(dat['<STR_LIT>'].strftime('<STR_LIT>')))<EOL>iheader = '<STR_LIT:\n>'.join(iheader) + '<STR_LIT:\n>'<EOL>out = pd.DataFrame({analyte_2_namemass(k): v for k, v in dat['<STR_LIT>'].items()}, index=dat['<STR_LIT>'])<EOL>out.index.name = '<STR_LIT>'<EOL>csv = out.to_csv()<EOL>with open('<STR_LIT>'.format(savedir, s), '<STR_LIT:w>') as f:<EOL><INDENT>f.write(iheader)<EOL>f.write(csv)<EOL><DEDENT>flist.append('<STR_LIT>'.format(s))<EOL><DEDENT>print("<STR_LIT>".format(n, '<STR_LIT:\n>'.join(flist)))<EOL>return None<EOL>

TODO: Check for existing files in savedir, don't overwrite?