clophfit.prenspire.spectral =========================== .. py:module:: clophfit.prenspire.spectral .. autoapi-nested-parse:: Whole-spectrum global K for EnSpire titrations (see :mod:`clophfit.fitting.spectral`). The wells get the same corrections as the band readouts of :mod:`clophfit.prenspire.bands` - blank plate rows removed, the buffer spectrum of the same plate column subtracted - so that the two methods differ only in the readout: named windows sharing K there, every wavelength of the chosen scans here. Scored with arslanbaeva's ``scripts/score_readout_arms.py`` metrics on the 25 pH plates it ranks (same exclusions; arslanbaeva's ``scripts/score_spectral_arms.py``): the whole excitation scan with a per-well amplitude has the smallest between-session spread of every readout (median 0.10 pH, worst 0.16, against 0.14 and 0.22 for the default band pair) at the same replicate-row spread (0.23). Adding the 420 nm emission scan whole does not help (0.14, worst 0.37), and without the well amplitude it is worse (0.21, worst 0.80). Only five constructs are repeated across sessions, so the ranking of the excitation scan against the band pair is suggestive, not settled. The tryptophan band (330-342 nm of the 278 nm-excited scan) does not depend on pH (Spearman rho 0.02 and -0.06 on G10) and neither causes nor removes the acid-side amplitude drop; it scatters by 15-30 % between wells, more than the fitted amplitudes do (about 5 %), and on these plates it is dominated by the medium's scatter and Raman background - a buffer well keeps ~85 % of it. Dividing wells by it therefore only adds noise without changing K (7.972 against 7.970 unnormalised on G10), so it has been retired: there is no normalisation step in this path. Functions --------- .. autoapisummary:: clophfit.prenspire.spectral.scan_name clophfit.prenspire.spectral.sample_spectra clophfit.prenspire.spectral.fit_titrations_spectral Module Contents --------------- .. py:function:: scan_name(ef, label) Name a scan by the measurement it makes, not by its plate label. The plate's labels are row names: the excitation scan is "C" at 20 C and "E" at 37 C, so the label cannot say which measurement a spectrum is, and the two temperatures of one sample would look like different scans. The monochromator and the wavelength it holds fixed do say: an excitation scan and a 420 nm-excited emission scan are different observables and must not be drawn on one wavelength axis. The name is unique within a temperature: a plate may hold two scans of the same kind (an excitation scan with the filter in the top position and another with it in the bottom one), and those are different measurements. When a name would repeat at the same temperature, the plate label is appended to tell them apart. :param ef: The parsed EnSpire export. :type ef: EnspireFile :param label: The plate label of the scan. :type label: str :returns: The scan's name, e.g. ``"excitation"`` or ``"emission 420"``. :rtype: str .. py:function:: sample_spectra(ef, wells, x, temp, *, is_ph, buffer_wells, bands = EXCITATION_SCAN) Corrected whole spectra of one sample, one entry per scan. :param ef: The parsed EnSpire export. :type ef: EnspireFile :param wells: Wells of this sample. :type wells: list[str] :param x: Titrant value per well. :type x: ArrayF :param temp: Temperature selecting the labels. :type temp: str | float :param is_ph: pH titration (else chloride). :type is_ph: bool :param buffer_wells: Buffer wells declared by the note; blank rows serve when there are none. :type buffer_wells: Sequence[str] :param bands: Band names (as in :func:`~clophfit.prenspire.bands.classify`) whose scans are used whole; the default takes the excitation scan only. :type bands: Sequence[str] :returns: Scan name to (wavelengths, Y[n_lambda, n_wells]), the wells used and their x values. The key is the scan's name (see :func:`scan_name`), not its plate label, so the same measurement keeps one name at every temperature. :rtype: tuple[dict[str, tuple[ArrayF, ArrayF]], list[str], ArrayF] .. py:function:: fit_titrations_spectral(ef, note, *, buffer = True, well_scale = True, fit_hill = False, bands = EXCITATION_SCAN) Fit every sample of a note with the whole-spectrum global model. :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 well_scale: Fit a per-well amplitude as well (see :func:`fit_spectra_global`). :type well_scale: bool :param fit_hill: Also fit the Hill slope. :type fit_hill: bool :param bands: Band names whose scans are used whole (default: the excitation scan only). :type bands: Sequence[str] :returns: One row per (sample, temperature, subset) - ``all`` then each replicate row - and, per ``" "``, the fit on all wells with its species spectra. :rtype: tuple[pd.DataFrame, dict[str, SpectralFit]]