Bring your own data#
This page takes a pycytominer or CellProfiler table to a stamped mantispy object.
Everything downstream reads the stamp, so an object that carries it works with every mt.pp, mt.tl and mt.pl function.
What a row is#
Pick the resolution that matches the table, then make sure obs carries the identifier columns it requires.
|
One row is |
Required |
|
|---|---|---|---|
|
one segmented cell or other object |
|
defaults |
|
one well |
|
defaults to plate and well |
|
one consensus profile, such as a gene or a compound |
none |
you give it, for example |
There is no guide level. Rows are objects, wells or aggregates, and guides are values in a column.
Metadata_Well is a zero-padded well name such as A03, not A3.
mt.io.read_profiles normalizes the spelling when it reads a table or a platemap.
An object assembled by hand has to use it already.
Metadata_Perturbation is the canonical perturbation column.
Compound names, gene symbols and ORF identifiers all go there, and the tools that need to know what was done to a row read it first.
Keep a more specific column such as Metadata_Compound or Metadata_Gene beside it if you want one.
Read a table#
import mantispy as mt
adata = mt.io.read_profiles("profiles.parquet", platemap="platemap.csv")
read_profiles splits the measurements from the metadata and records resolution="well" for files.
platemap is a table, or a path to one, with a Metadata_Well column and optionally Metadata_Plate.
It is left-joined onto obs, which is how the perturbation reaches each well.
Pass resolution="aggregate" with grouped_by for a table that holds one row per gene.
Mark the controls#
mt.pp.annotate_controls(adata, negcon=["DMSO"])
annotate_controls marks the negative controls, and optionally the positive ones, from the perturbation column.
Readouts such as mt.tl.map and mt.tl.hit_calling compare against these rows.
Stamp an object that came from elsewhere#
A published h5ad, another pipeline’s output or a matrix of embeddings has no stamp yet.
mt.io.stamp records the resolution and the kind of feature, and rejects the object if obs lacks a required column.
# one row per well, CellProfiler measurements
mt.io.stamp(adata, resolution="well", feature_kind="measurement")
# one row per gene
mt.io.stamp(adata, resolution="aggregate", grouped_by=["Metadata_Perturbation"], feature_kind="measurement")
# learned embeddings
mt.io.stamp(adata, resolution="well", feature_kind="embedding")
X is stored in the dtype you give it, float32, float64 or an integer type, and mantispy’s tools write their results in that dtype too.
float32 takes half the memory of float64, so convert with adata.X = adata.X.astype("float32") if a large matrix does not fit.
Build one from a DataFrame#
from_dataframe() turns a table that is already in memory into a stamped object.
It splits Metadata_* columns from features and parses CellProfiler feature names.
A slide or any other table without plates and wells needs no Metadata_Plate or Metadata_Well at object resolution.
The field of view comes from Metadata_Site, or from an explicit Metadata_ImageID if the table has one.
An object is identified by Metadata_ImageID, Metadata_ObjectType and Metadata_ObjectNumber.
adata = mt.io.from_dataframe(df, resolution="object", object_type="cell")
A table from cp_measure uses different feature names.
Say so with convention; the default is "cellprofiler".
adata = mt.io.from_dataframe(df, convention="cp_measure", object_type="cell")
Numeric columns that match neither convention, such as proprietary or learned features, are kept as features with feature_kind="embedding", never dropped.
object_type is also an argument of stamp().
Check it#
report = mt.io.validate(adata)
validate returns a report of what is wrong and what is only worth a warning.
Stamping already runs it, so a stamped object passes.
Run it again after you edit obs or X by hand.
See the data model for every field and the stamp() reference for the arguments.