clophfit.prenspire.bands ======================== .. py:module:: clophfit.prenspire.bands .. autoapi-nested-parse:: Band readouts of EnSpire spectra, and the K fitted from them. A spectral titration can be reduced to one number per well in two ways. The SVD path (:func:`clophfit.fitting.core.analyze_spectra`) projects each spectrum onto its first principal component; this module instead averages the intensity over a named window - the anionic and neutral excitation bands, the emission band - and lets several such bands share one K while keeping their own plateaus. Neither readout is uniformly more precise: on replicate rows of the same plate they trade places. The band path is here for what it makes visible. Its plateaus are in the measured units, so ``S1/S0 = 0.01`` reads as "the bound state is dark"; several bands give a consistency check that a single component cannot; and a band that has stopped reporting the transition (a flat neutral band, a readout that reverses sign between runs) is named and dropped rather than folded into a component that still returns a number. Two corrections belong to the well, not to the readout, and are applied first: the buffer well of the same plate column is subtracted, and blank plate rows are removed by level. There is deliberately no tryptophan normalisation: on these plates that band is dominated by the medium's scatter and Raman background (a buffer well keeps ~85 % of it), so dividing by it only adds well-to-well noise while shifting K by a third of a standard error. Classes ------- .. autoapisummary:: clophfit.prenspire.bands.Readout clophfit.prenspire.bands.BandFit Functions --------- .. autoapisummary:: clophfit.prenspire.bands.classify clophfit.prenspire.bands.band_values clophfit.prenspire.bands.subtract_buffer clophfit.prenspire.bands.blank_rows clophfit.prenspire.bands.band_rho clophfit.prenspire.bands.screen_bands clophfit.prenspire.bands.fit_bands clophfit.prenspire.bands.fit_titrations clophfit.prenspire.bands.plot_sample Module Contents --------------- .. py:class:: Readout Bases: :py:obj:`NamedTuple` One band of one label. .. py:class:: BandFit Bases: :py:obj:`NamedTuple` K with the interval and the residual scale it came with. .. py:attribute:: masks :type: dict[str, numpy.ndarray] Per band, which points the screen kept. .. py:function:: classify(ef, temp = None, *, is_ph = True) Split a temperature's labels into the titrating bands their scans offer. Each label declares its monochromator and the wavelength it holds fixed, so which windows it can offer is read from the file rather than configured: an excitation scan carries the anionic and neutral bands, an emission scan excited below 350 nm carries the emission band as seen from that excitation (``em_exc278``), and any other emission scan carries the emission band alone (``em_exc420``). :param ef: The parsed EnSpire export. :type ef: EnspireFile :param temp: Keep only labels measured at this temperature; None keeps every label. :type temp: str | float | None :param is_ph: Which anionic-band window to use: ``ANIONIC`` (480-495 nm, where a pH titration's own reproducibility is best) for a pH titration, or ``ANIONIC_CL`` (395-495 nm) for a chloride one - the two titrations respond over different parts of the excitation scan and one window does not serve both; see ``ANIONIC_CL``'s definition for the numbers. :type is_ph: bool :returns: The titrating bands the labels of this temperature offer, in scan order. :rtype: list[Readout] .. py:function:: band_values(ef, readout, wells) Mean intensity of one label over one window, per well. :param ef: The parsed EnSpire export. :type ef: EnspireFile :param readout: Label and window to average. :type readout: Readout :param wells: Wells to read, in order. :type wells: Sequence[str] :returns: One value per well, indexed by well. :rtype: pd.Series .. py:function:: subtract_buffer(values, buffer) Subtract the buffer well of the same plate column from each sample well. :param values: Sample values indexed by well. :type values: pd.Series :param buffer: Buffer values indexed by well; the plate column is what pairs them, because a column is one titration step. :type buffer: pd.Series :returns: *values* with the matching buffer removed. :rtype: pd.Series .. py:function:: blank_rows(values, *, frac = _BLANK_FRACTION) Plate rows holding no protein, whatever the note calls them. Some notes name every well after the mutant while one row of the plate is buffer. Such a row sits at the instrument's floor, so it is found by level: a row whose median is below *frac* of the brightest row's median is blank. :param values: Raw band intensity per well, indexed by well. :type values: pd.Series :param frac: Fraction of the brightest row's median below which a row is blank. :type frac: float :returns: The blank plate rows, as single letters. :rtype: list[str] .. py:function:: band_rho(x, y, wells) Rank correlation of a band with the titrant, taken within replicate rows. Replicate rows sit at slightly different levels, so ranking the pooled points can hide a perfectly monotone titration. Each row is ranked alone and the rows are pooled by median. :param x: Titrant value per point. :type x: np.ndarray :param y: Band value per point. :type y: np.ndarray :param wells: Well of each point; its plate row groups the replicates. :type wells: Sequence[str] :returns: Median within-row Spearman rho, or the pooled one if no row qualifies. :rtype: float .. py:function:: screen_bands(data, wells, *, wanted = DIRECT_BANDS, min_rho = 0.8) Keep the requested bands that titrate monotonically with the titrant. :param data: Band name to its (x, y). :type data: dict[str, tuple[np.ndarray, np.ndarray]] :param wells: Well of each point, in the same order. :type wells: Sequence[str] :param wanted: Bands allowed into the shared fit; the rest are reported only. :type wanted: Sequence[str] :param min_rho: Smallest acceptable |rho| between a band and the titrant. :type min_rho: float :returns: The bands to fit, and why each of the others is out. :rtype: tuple[list[str], dict[str, str]] .. py:function:: fit_bands(data, *, is_ph, screen = DEFAULT_SCREEN) Fit the given bands with one shared K and a plateau pair each. :param data: Band name to its (x, y). :type data: dict[str, tuple[np.ndarray, np.ndarray]] :param is_ph: pH titration (else ligand concentration). :type is_ph: bool :param screen: Outlier specification handed to :func:`fit_binding_glob`, or None. :type screen: str | None :returns: The fit, or None when it does not converge or has too few points to fit. :rtype: BandFit | None .. py:function:: fit_titrations(ef, note, *, buffer = True, wanted = DIRECT_BANDS, min_rho = 0.8, screen = DEFAULT_SCREEN) Fit every sample of a note from its bands. :param ef: The parsed EnSpire export. :type ef: EnspireFile :param note: Normalised note, with ``Well``, ``pH``, ``Cl``, ``Name`` and ``Temp``. :type note: pd.DataFrame :param buffer: Subtract the buffer well of the same plate column. :type buffer: bool :param wanted: Bands allowed into the shared K; the others are reported only. :type wanted: Sequence[str] :param min_rho: Monotonicity gate for a band. :type min_rho: float :param screen: Point screen handed to :func:`fit_binding_glob`. :type screen: str | None :returns: The table of fits, the points the screen removed, and per sample the band data with its shared fit, for plotting. :rtype: TitrationFits .. py:function:: plot_sample(ax, sample, title) Draw one sample's bands, their shared curve, and the screened points. :param ax: Where to draw. :type ax: Axes :param sample: Band data with the fit that shares K across them. :type sample: Sample :param title: Panel title; K and its interval are appended. :type title: str