import tempfile
import scanpy as sc
import tiledbsoma
import tiledbsoma.io
Add New Measurements to an Existing SOMA Experiment
This feature is currently limited to Python and requires TileDB-SOMA version 1.16.2 or later.
Introduction
TileDB-SOMA supports storing multiple measurements from the same set of observations (typically cells) within a single experiment. This makes it possible to manage multi-modal datasets or any scenario where you have a different set (or a different number) of features measured across the same observations. This tutorial shows the recommended workflow for adding a new SOMA Measurement
to an existing SOMA Experiment
.
As a practical example, you will process the same single-cell RNA-seq dataset with two different methods for selecting highly variable genes. Each method will store its output as a separate Measurement
within the same Experiment
.
Setup
Import necessary libraries. Then, load the standard pbmc3k
dataset and simulate two different processing outputs.
Define a URI for the SOMA Experiment.
Load and preprocess the base dataset.
Select a specific set of highly variable genes for approach A.
Select a different set of highly variable genes for approach B.
Create the initial Experiment
Create the SOMA Experiment
and ingest the output from Approach A.
Now, you have an experiment containing a single measurement (ApproachA_RNA
). The next steps focus on adding the ApproachB_RNA
data as a new, distinct measurement.
Define the new Measurement
’s schema on disk
This is a critical step. Before ingesting data for ApproachB_RNA
, define its SOMA structure (including its unique var
DataFrame and X
array) on disk.
Use tiledbsoma.io.from_anndata()
with ingest_mode='schema_only'
, referencing adata_b
.
This creates the necessary SOMA arrays (experiment.ms['ApproachB_RNA'].var
, experiment.ms['ApproachB_RNA'].X['data']
) with their schemas derived from adata_b
, but without writing the actual data yet.
Register the AnnData for the new Measurement
Create a registration_mapping
for adata_b
. This maps the cell barcodes in adata_b.obs
to the existing soma_joinid
s in experiment.obs
(since the cells are the same as in AlignerA_RNA
). It also establishes mappings for the new set of features in adata_b.var
.
Prepare the Experiment
for ingestion
With the registration_mapping
created (linking the new AnnData’s obs
and var
to the SOMA Experiment
), call registration_mapping.prepare_experiment(experiment_uri)
.
This function updates the SOMA experiment’s structure before writing any new data. It performs two main operations based on all registered AnnData objects (in this case, just adata_b
for the new measurement):
- Dimension Resizing: It checks if the existing SOMA arrays need to be resized to accommodate the dimensions of the new data.
- Enum Schema Evolution: For any categorical columns in your
adata_b.obs
oradata_b.var
(which SOMA stores as enumerations),prepare_experiment
updates the SOMA array schemas. It adds any new categories present inadata_b
to the existing SOMA enumerations.
This step is important for data integrity and ensures the safety of future data writes, even if multiple processes write data concurrently.
After this step, the SOMA experiment (including the schema-defined AlignerB_RNA
measurement) is fully prepared to receive the actual data.
Ingest data into the new Measurement
Now that you created and prepared the experiment, you can ingest the actual data from adata_b
into the new measurement.
Inspect the updated SOMA Experiment
Open the SOMA experiment again (this time in read mode 'r'
) and verify that the new measurement is present and contains the expected data.
Conclusion
Adding new measurements to an existing SOMA experiment is a powerful way to organize datasets that share the same observations but differ in their features or modalities. By following the workflow outlined in this tutorial, you can build your SOMA objects correctly.