mantispy.tl.dose_direction

Contents

mantispy.tl.dose_direction#

mantispy.tl.dose_direction(adata, compound_key='Metadata_Compound', dose_key='Metadata_Concentration', reference='negcon', split_by='Metadata_Plate', min_doses=4, count_key='Metadata_CellCount', site_key='Metadata_SiteCount', min_viability=0.5, reproducible=0.5, key_added='dose_direction', copy=False)#

Whether a compound’s phenotype only grows with concentration, or turns into a different one.

A dose series is usually summarised by one number per concentration, how far the wells sit from the controls. That number cannot tell a phenotype that is getting louder from a phenotype that is being replaced. This reads the direction as well as the distance: each concentration gets an amplitude, its cosine_to_top against the highest concentration’s profile, and a split_half_cosine that says whether its direction reproduces across replicates at all.

The three read together. A concentration whose split_half_cosine is near zero has no direction to speak of, only noise, however large its amplitude. One that reproduces but sits at a low cosine_to_top is a real phenotype, and a different one from the top concentration’s.

phase turns that reading into a label, so the stretch of the ladder worth analysing can be subset out rather than described. A concentration is silent while nothing reproducible is happening, responding while the profile is still moving from the concentration below it, saturated once it has stopped, and cytotoxic once the cells are gone and the profile is the morphology of dying cells. The label is broadcast to obs, so adata[adata.obs["dose_direction_phase"] == "responding"] is the window, and dose_features(), differential_features() and the rest work on it unchanged.

Parameters:
  • adata (AnnData) – Object carrying a compound and a dose per row, at well resolution.

  • compound_key (str (default: 'Metadata_Compound')) – obs column holding the compound identity.

  • dose_key (str (default: 'Metadata_Concentration')) – obs column holding the concentration. Rows with a zero or missing dose are left out.

  • reference (str | None (default: 'negcon')) – Rows that set each feature’s baseline and spread. "negcon" reads Metadata_Control.

  • split_by (str | None (default: 'Metadata_Plate')) – obs column whose levels split the replicates in two for split_half_cosine, normally the plate. It also lays out the control groups amplitude_null is drawn from. None, or a column with one level, splits the wells by position instead.

  • min_doses (int (default: 4)) – Distinct doses below which a compound is left out of the table. One concentration says nothing about how a response changes with concentration.

  • count_key (str (default: 'Metadata_CellCount')) – obs column holding the cell count, which sets viability. Without it no concentration is marked cytotoxic.

  • site_key (str | None (default: 'Metadata_SiteCount')) – obs column holding the number of fields that count covers, so a well missing a field does not read as cell loss. None compares the counts as they are.

  • min_viability (float (default: 0.5)) – Fraction of its own plate’s control cell count below which a concentration is cytotoxic. The US EPA’s phenotypic pipeline drops a concentration that has lost more than half its cells before fitting anything.

  • reproducible (float | None (default: 0.5)) – split_half_cosine a concentration needs before it can be anything but silent. None drops the requirement, which is what a screen with one well per concentration has to do, at the cost of calling noise a phenotype.

  • key_added (str (default: 'dose_direction')) – Name for the output table.

  • copy (bool (default: False)) – Return a modified copy instead of mutating in place.

Return type:

AnnData | None

Returns:

None, or the modified copy. Writes uns["mantispy"][key_added], one row per compound and concentration, with compound, dose, n_wells, amplitude, amplitude_null, step_amplitude, split_half_cosine, cosine_to_top, viability and phase. The phase is broadcast to obs[key_added + "_phase"] so the window can be subset like any other annotation. amplitude is the root-mean-square response over the features, in MADs of the controls, and amplitude_null is what control wells spread over the same plates in the same numbers reach, so the two are read against each other. step_amplitude is the same measure applied to the change from the concentration below, which is what tells a response that is still moving from one that has arrived. phase is one of DOSE_PHASES.

Raises:
  • KeyErrorobs has no compound_key, no dose_key, or no split_by column.

  • ValueError – Fewer than two reference rows, so there is no scale to read a direction in.

Notes

The cosines are taken over the features scaled by the controls’ spread, so a feature the controls happen to measure loosely does not set the direction on its own. Features whose controls show no spread are left out.

amplitude_null is the median over twenty-five draws, and is NaN when the controls cannot fill the layout, for instance when a plate carries treated wells but no vehicle.

split_half_cosine needs at least two wells at a concentration, and reproduces the plate structure when split_by names it: halving by plate answers whether the direction survives a different plate, which is the harder and more useful question. With one well per concentration it is NaN, and the table then says nothing about whether any single concentration’s direction is real.