mantispy.tl.map#

mantispy.tl.map(adata, pos_sameby=None, pos_diffby=(), neg_sameby=(), neg_diffby=(), mode=None, label=None, batch='Metadata_Plate', annotation_key=None, label_sep=None, reference='negcon', use_rep=None, null_size=10000, threshold=0.05, seed=0, distance='cosine', null='copied', null_sampler='exact', key_added='map', copy=False)[source]#

Mean average precision per group, with a null to test it against.

Parameters:
adata AnnData

Profiles to score, normally well-level.

pos_sameby Sequence[str] | None (default: None)

obs columns a positive pair must share, in copairs’ terms. Pass the four pair arguments or mode, not both.

pos_diffby Sequence[str] (default: ())

obs columns in which a positive pair must differ.

neg_sameby Sequence[str] (default: ())

obs columns a negative pair must share.

neg_diffby Sequence[str] (default: ())

obs columns in which a negative pair must differ.

mode str | None (default: None)

A preset for the pair definitions, one of the following.

"activity"

Is this perturbation distinguishable from the negative controls it was plated with? Its replicates are retrieved against the control profiles on the query’s own plate only. This is the phenotypic activity of Kalinin et al. [2025]. Needs reference and the batch column; queries on a plate without controls are left out, with a warning. In a CRISPR screen, non-targeting controls do not cut DNA, so nearly every knockout can come out active from the cutting response alone; guides against genes the cell line does not express (unexpressed_genes()) are a cutting control to retrieve against instead, and empirical_fdr() calibrates the calls.

"consistency"

Do perturbations sharing an annotation look more alike than those that do not? This is the phenotypic consistency of Kalinin et al. [2025]. Needs annotation_key (a mechanism, target or gene column) and is meant for consensus profiles of perturbations already known to be active. When annotation_key holds a list of labels per row, a pair is positive if the two lists share any label, and a perturbation with several labels is scored toward each of its classes. This multilabel scoring is supported through mode="consistency".

"replicability"

Do a perturbation’s replicates retrieve each other against the other perturbations on the query’s plate? This is the mAP-nonrep of Arevalo et al. [2024], which leaves the controls out; reference=None keeps them in.

"cross_plate"

Do a perturbation’s replicates on other plates retrieve each other against all other profiles? A replicate counts only if it is on a different plate, which separates reproducible biology from plate effects.

label str | None (default: None)

The obs column naming the perturbation, which the presets group replicates by. Defaults to the perturbation column the object records, else Metadata_Perturbation.

batch str (default: 'Metadata_Plate')

The obs column naming the plate or batch, which the presets draw negatives from.

annotation_key str | None (default: None)

The obs column mode="consistency" groups by. A column holding a list of labels per row is scored as multilabel (see the mode description); a scalar column is a single label. A list-valued obs column does not survive write_h5ad, so store the labels as a delimited string, which does survive, and split it with label_sep.

label_sep str | None (default: None)

Split a string annotation_key on this separator into a list of labels per row, so a stored "MEK|ERK" is scored as multilabel. None leaves the column as it is. An entry that is already a list, or is missing, is left untouched.

reference str | None (default: 'negcon')

Which rows are the negative controls, which mode="activity" retrieves against and mode="replicability" leaves out: "negcon", the name of a boolean obs column, or None for none.

use_rep str | None (default: None)

Score obsm[use_rep] instead of X.

null_size int (default: 10000)

Number of draws of the null. No p-value falls below 1 / (null_size + 1), so the correction over many groups needs a large one, and a warning says when it is too small to call a group on its own.

threshold float (default: 0.05)

Significance threshold of the p- and q-values.

seed int (default: 0)

Seed of the null.

distance str (default: 'cosine')

Distance to rank by: "cosine" (the default), "abs_cosine", "correlation", "euclidean", "manhattan", "chebyshev", or a scipy.spatial.distance.cdist() metric name, each turned into a similarity as copairs does.

null Literal['copied', 'permutation', 'joint'] (default: 'copied')

The null model the group mAP is tested against, one of the three copairs defines. The default is "copied", the model of Kalinin et al. [2025] and of copairs before 0.6, which copairs 0.6 replaced with "permutation" as its default. mantispy keeps "copied" because its p-values are conservative for groups with several replicates, while "joint" can give p-values that are too small for groups with many replicates, which copairs warns about too.

"copied"

Compares each member’s average precision with random rankings that have the member’s numbers of positives and pairs, and averages over the members. Members with the same numbers share one random draw, which widens the null, so the test is conservative for groups with several replicates.

"joint"

Draws the members’ average precisions together, so a positive pair between two members is one random rank in both of their lists.

"permutation"

Moves the group’s label at random among the profiles its members are ranked with, and recomputes the mAP from the observed similarities. It is the slowest of the three. It needs every profile holding a label in the scored table, so it fails on a multilabel annotation where a profile has no negative pair, and it ranks by the six named distances, not by a scipy metric. It holds at most mantispy.settings.map_table_bytes of sorted similarities, half of the machine’s memory by default, and refuses a screen that would need more.

null_sampler Literal['exact', 'floyd'] (default: 'exact')

How the "copied" null is drawn. "exact" gives the same p-values as copairs for the same seed, so published copairs numbers reproduce. "floyd" is faster on large screens and draws from the same null distribution, but its p-values differ from copairs’ by the random error of the draws. Keep "exact" for numbers you report.

key_added str (default: 'map')

Where to store results.

copy bool (default: False)

Return a modified copy instead of mutating in place.

Return type:

AnnData | None

Returns:

None, or the modified copy. Writes the per-group table to uns["mantispy"][key_added] and joins obs[key_added] and obs[key_added + "_qvalue"] back onto the rows. The call’s parameters, the null and seed among them, go to uns["mantispy"]["params"]["map:" + key_added]. A group with one member has no within-group pair to score, so it is absent from the table. A multilabel annotation has no single score per row, so it writes the per-class table to uns only and clears obs[key_added] and obs[key_added + "_qvalue"].

Raises:
  • ValueError – mode was passed together with explicit pair arguments or neither was passed, mode is not one of MODES, mode="consistency" came without annotation_key, mode="activity" found no controls, no profile has a positive pair or a negative pair to be ranked against, the profiles hold missing or infinite values or a cosine norm of zero or overflow, which cannot be ranked, a label column mixes list-valued and scalar entries, more than one positive-pair column is list-valued, or the null, sampler or distance is not supported.

  • KeyError – obs is missing a column the pair definitions or reference name.

Notes

The pairs are never stored: a query’s positives and negatives follow from the group codes of the pair columns, so memory does not grow with the number of pairs, while time does. An explicit pair query that pairs across a high-cardinality column (every compound against every other) is best run on consensus profiles (consensus()), and a warning says when a query ranks so many pairs that it would run for a long time.

The scoring runs on numba’s threads, one per core by default. Cap them with numba.set_num_threads.

tl.map and copairs lists how the arguments and nulls of copairs map onto this function.