insitro cp-POSH#
cp_posh() serves the 124-gene proof-of-concept dataset from insitro/cp-posh, A549 cells carrying a pooled CRISPR-knockout library, stained with a six-channel Cell Painting panel and read by in-situ sequencing of the guide barcodes. Every cell gets a broad, untargeted profile of about 1,278 morphology features, so it is the broad-morphology complement to the nine hand-picked readouts of scallops_arv471(). The features are already well-normalized by the authors, so normalize() is not needed first.
The genes whose knockout is expected to move cells away from the controls are KIF18A, the proteasome (PSMB1, PSMD4), the mitochondrial ribosome (MRPL43, MRPS5), the ARP2/3 complex (ARPC4, ACTR6) and COPI (COPE, ARCN1), scored against the non-targeting and intergenic guides.
Use it if your own data is a single-cell optical pooled CRISPR screen with a broad morphology readout, or any per-cell profile you aggregate to a perturbation. No tutorial is built on it; CRISPR knockouts runs the knockout workflow on the arrayed jump_crispr() screen, and the same calls apply once cells here are aggregated to guides.
import numpy as np
import pandas as pd
import plotly.express as px
import scanpy as sc
import mantispy as mt
This page uses the guide-level aggregate, one median profile per guide.
adata = mt.ds.cp_posh(aggregated=True)
adata
AnnData object with n_obs × n_vars = 1551 × 1278
obs: 'Metadata_Gene', 'Metadata_sgRNA', 'Metadata_CellCount', 'Metadata_Perturbation', 'Metadata_Plate', 'Metadata_Control', 'Metadata_Perturbation_Type'
var: 'object', 'feature_group', 'feature', 'channel', 'scale', 'angle', 'gray_levels', 'radial_bin', 'params', 'is_feature'
uns: 'mantispy'
layers: None (.X)
Known mechanisms in profile space#
On the first two principal components each point is a guide. The controls and the known-mechanism genes are coloured apart from the rest, and the known-mechanism guides should sit away from the controls.
mechanism = {"KIF18A", "PSMB1", "PSMD4", "MRPL43", "MRPS5", "ARPC4", "ACTR6", "COPE", "ARCN1"}
controls = {"nontargeting", "intergenic"}
scaled = adata.copy()
sc.pp.scale(scaled)
scaled.X = np.nan_to_num(scaled.X)
sc.pp.pca(scaled, n_comps=10)
coords = pd.DataFrame(scaled.obsm["X_pca"][:, :2], columns=["PC1", "PC2"])
gene = adata.obs["Metadata_Gene"].astype(str)
coords["gene"] = gene.to_numpy()
coords["kind"] = np.where(
gene.isin(controls),
"control",
np.where(gene.isin(mechanism), "known mechanism", "other"),
)
fig = px.scatter(
coords,
x="PC1",
y="PC2",
color="kind",
hover_name="gene",
category_orders={"kind": ["other", "control", "known mechanism"]},
title="cp-POSH guides in profile space",
opacity=0.6,
)
fig.show()