Sanity
Sampling Noise based Inference of Transcription ActivitY : Filtering of Poisson noise on a single-cell RNA-seq UMI count matrix
Single-cell RNA sequencing normalization algorithm presented in the publication Bayesian inference of gene expression states from single-cell RNA-seq data - J Breda, M Zavolan, E van Nimwegen - Nature Biotechnology, 2021.
Sanity infers the log expression levels xgc of gene g in cell c by filtering out the Poisson noise on the UMI count matrix ngc of gene g in cell c.
Reproducibility
The raw UMI count and normalized datasets mentioned in benchmarking in the associated publication are available on . Files are named
[dataset name]_UMI_counts.txt.gz and [dataset name]_[tool name]_normalization.txt.gz.
The scripts used for running the benchmarked normalization methods and for making the figures of the preprint are in the reproducibility folder.
Input
-f: UMI count matrix: (Ng x Nc) matrix with Ng the number of genes and Nc the number of cells. ('path/to/count_matrix.tsv')
| GeneID | Cell 1 | Cell 2 | Cell 3 | ... |
|---|---|---|---|---|
| Gene 1 | 1.0 | 2.0 | 0.0 | ... |
| Gene 2 | 6.0 | 3.0 | 1.0 | ... |
| ... | ... | ... | ... | ... |
The count matrix must be tab-separated (TSV).
The tab character is the only field separator Sanity accepts: comma-separated (CSV) and space-separated files are not supported and will be misread.
Convert them to TSV before running Sanity, for example with pandas.DataFrame.to_csv(path, sep='\t') or awk 'BEGIN{FS=",";OFS="\t"}{$1=$1;print}' in.csv > out.tsv.
Because tabs alone delimit fields, gene and cell names may contain spaces and commas.
The first line is the header with the cell names.
It may either start with a label for the gene-ID column (the same number of fields as a data row) or start straight away with the first cell name (one field fewer, as written by pandas.DataFrame.to_csv).
Every data row must have exactly one gene ID followed by one value per cell; Sanity stops with an error if a row has too few or too many fields.
The count matrix can be compressed with gzip (with .tsv.gz extension).
-
-f: (Alternatively) Matrix Market File Format: Sparse matrix of UMI counts. Automatically recognized by.mtxextension of the input file. Example:matrix.mtxby cellranger 2.1.0 and 3.1.0 (10x Genomics). ('path/to/text_file.mtx') Important: MTX file should be sorted by row (gene) indices! If not then you can usesort_mtx_by_row.pyscript in theSanity/scriptsfolder to sort it. See Sorting MTX file by row (gene) indices. The MTX file can be compressed with gzip (with.gzextension).-mtx_genes: (optional) Gene ID file: text file with one gene ID per line. The order of gene IDs should match the order of genes in the count matrix. Examples:genes.tsvby cellranger 2.1.0 andfeatures.tsvby cellranger 3.1.0 (10x Genomics). ('path/to/text_file')-mtx_cells: (optional) Cell ID file: text file with one cell ID per line. The order of cell IDs should match the order of cells in the count matrix. Examples:barcodes.tsvby cellranger 2.1.0 and 3.1.0 (10x Genomics). ('path/to/text_file')
-
-d: (optional) Destination folder ('path/to/output/folder', default:cwd) -
-n: (optional) Number of threads (integer, default:4). The same setting controls input indexing and inference.Uncompressed, row-sorted MTX files with nonnegative integral counts are indexed in parallel using bounded input buffers; no index cache is used. Counts written as
2.0or2e0also qualify.Fractional counts, gzip input, and counts or totals outside the exact integer range of double precision use the existing serial MTX reader. If an unsupported count is encountered during parallel indexing, the input scan restarts with that reader. The indexing log reports the reader, actual thread count and elapsed time. TSV input retains its existing reader. During inference, each worker reuses its count buffer. Plain MTX rows are read through a bounded buffer with direct numeric parsing; fractional counts are supported. TSV and gzip retain their existing numeric conversion.
-
--bonsai-output-mode: (optional flag, no value) Write only the numerical files and metadata required by Bonsai (NPY, MAP). -
-e: (optional) Print extended output (Boolean,'true', 'false', '1'or'0', default:false) -
-v_m: (optional, expert-user-only) Choose the method to estimate gene-variances $v_g$. In the MAP, EAP, MLE-options, one value for $v_g$ is fixed, and the corresponding gene expression estimates are returned, in the MARG-option, the gene expression estimates are obtained by marginalizing $v_g$. The options are:- MAP (default): Use the maximum a posteriori estimate for $v_g$.
- EAP: expected value of $v_g$ over the posterior.
- MLE: maximum likelihood estimate for $v_g$.
- MARG: (original method) The reported $v_g$ is the EAP estimate, but unlike the EAP option above, this value is not fixed when computing the gene expression estimates — instead, the gene expression estimates are obtained by marginalizing over the posterior of $v_g$.
-
-vmin/-vmax: (optional, expert-user-only) Minimal and maximal considered values of the variance in log transcription quotients (double, default: vmin=0.001vmax=50) -
-nbin: (optional, expert-user-only) Number of bins for the variance in log transcription quotients (integer, default:160) -
-no_norm: (optional, expert-user-only) Option to skip cell size normalization (Boolean,'true', 'false', '1'or'0', default:false)
For MAP, MLE and EAP, Sanity searches the complete variance grid first and calculates cell uncertainties only for the selected output bin. It retains compact fitting results for each bin and reconstructs the selected bin’s cell fractions and expression estimates, instead of storing cell-sized arrays for every bin. MARG still calculates uncertainties at every bin because it averages over the grid. The variance grid, bin selection and uncertainty formulas are unchanged. Library-size constants are computed once after the normalization setting is applied, and each gene’s digamma and trigamma values are computed once. Each worker also reuses its fitting workspace across bins and genes. These changes avoid repeated calculations and allocations without changing the fitting algorithm or its convergence tolerance.
Text output uses fixed six-decimal formatting. Each inference worker formats
one gene row, and complete rows are written in gene order. Formatting uses the
same -n worker count as inference; there is no separate writer thread setting.
The number of formatted rows held in memory is bounded by the worker count.
For zero-count cells, uncertainty is calculated from the positive displacement
e at which e*(2*delta+e)/(2*v) + n*log(1+f*(exp(e)-1)) = 0.5.
Here n is the total count for the gene and f its fitted fraction for the cell.
Sanity evaluates the full logarithm with log1p and expm1, with an overflow-safe
form for large displacements. The likelihood-drop tolerance remains 1e-7.
This changes zero-count uncertainty relative to the previous logarithm
linearization; it retains the existing Gaussian uncertainty model and does not
change the fitted means, likelihood grid or selected gene variance.
Output
-
log_transcription_quotients.txt: This file contains the estimated values of the log-transcription quotients (LTQs) for each gene in each cell. The LTQ xgc of gene g in cell c corresponds to the estimated logarithm of the fraction of mRNAs in cell c that belong to gene g. The LTQs are thus normalized such that Σg exp(xgc) = 1 for each cell c. In order to get an estimate of the number of mRNAs for gene g in cell c one would thus need to multiply exp(xgc) by the estimated total number of mRNAs M in the cell.GeneID Cell 1 Cell 2 Cell 3 ... Gene 1 -13.7227 -13.722 -13.729 ... Gene 2 -9.96744 -10.2522 -10.1453 ... ... ... ... ... ... -
ltq_error_bars.txt: Table with the error-bars on the estimates of the LTQs xgc for each gene g in each cell c.GeneID Cell 1 Cell 2 Cell 3 ... Gene 1 0.630111 0.630198 0.624802 ... Gene 2 0.315551 0.325912 0.301861 ... ... ... ... ... ...
Extended output (optional)
-
mu.txt: Estimated average LTQ μg of each gene g averaged over all cells.One value per line. Order corresponds to the order of genes in thegeneID.txtfile. -
d_mu.txt: Error bars on the inferred mean LTQs μg. One value per line. Order corresponds to the order of genes in thegeneID.txtfile. -
variance.txt: Estimated variance of the LTQs xgc across cells c for each gene g. Note that these variances are different, and generally larger, than what one would obtain when directly calculating the variance of the estimates of xgc from the filelog_transcription_quotients.txt. This is because the estimates in this file take into account the uncertainty on the estimates of the xgc. Thus, when estimates of true gene expression variability are needed, you are strongly advised to use the results in this file. Order corresponds to the order of genes in thegeneID.txtfile. -
delta.txt: Matrix of inferred log-fold changes δgc = xgc-μg for each gene g in each cell c. TSV file, columns correspond to cell IDs fromcellID.txtfile, rows correspond to gene IDs fromgeneID.txtfile. -
d_delta.txt: Matrix of error-bars for the inferred log fold-changes δgc. TSV file, columns correspond to cell IDs fromcellID.txtfile, rows correspond to gene IDs fromgeneID.txtfile. -
likelihood.txt: This file encodes the posterior distribution of each gene's true variance in log-expression. For the numerical calculation of this distribution, the variance is a priori assumed to lie in the range [vmin,vmax], and the distribution is evaluated on a grid of Nb values spaced uniformly on a logarithmic scale. The file contains a matrix with likelihoods for each gene g and each grid point b. The first line lists the grid values vb = vmin exp(b · Δv) for b = 0,...,Nb-1 with Δv = log(vmax/vmin)/(Nb-1), so the first and last values are vmin and vmax themselves; the following lines correspond to the likelihood values of genes.Variance 0.001000 0.001070 0.001146 ... Gene 1 0.018 0.019 0.020 ... Gene 2 0.0006 0.0051 0.0031 ... ... ... ... ... ...
Bonsai output mode (optional)
Use --bonsai-output-mode to write only:
delta.npyandd_delta.npy: float32 arrays of shape(genes, cells), containing deviations and their standard deviations (not variances).mu.npyandvariance.npy: float64 arrays of shape(genes, 1), containing one baseline mean and one prior variance per gene.geneID.txt,cellID.txtandsanity_command.txt: identifiers and version, method, output format and command metadata.
./bin/Sanity -f counts.tsv -d bonsai_output -n 12 --bonsai-output-mode
This flag requires MAP inference. It selects these seven files regardless of
-e; it cannot be combined with gzip or the experimental NPY output flag.
Use a folder without previous numerical text output; Sanity reports an error
if conflicting files are present. Ordinary and extended output remain text.
sanity_command.txt records # Output mode: bonsai so consumers can select
the NPY reader without another command-line option.
Arrays use NPY version 1.0, little-endian values and C order. Row order matches
geneID.txt; matrix columns match cellID.txt. Inference and uncertainty
calculations remain double precision. Workers prepare float32 matrix rows,
then write them in gene order with memory bounded by the thread count. Gene
vectors retain double precision. Unlike six-decimal text, NPY values are not
rounded to a fixed number of decimal places.
The consuming Bonsai reader must support this format; text-only readers cannot
use these outputs. In Python, arrays can be opened without loading the whole
matrix using numpy.load(path, mmap_mode="r", allow_pickle=False).
Usage
./Sanity <option(s)>
Options:
-h, --help Show this help message
-v, --version Show the current version
-f, --file Specify the input transcript count text file (.mtx for Matrix Market File Format)
-mtx_genes, --mtx_gene_name_file Specify the gene name text file (only needed if .mtx input file)
-mtx_cells, --mtx_cell_name_file Specify the cell name text file (only needed if .mtx input file)
-d, --destination Specify the destination path (default: pwd)
-n, --n_threads Specify the number of threads to be used (default: 4)
--bonsai-output-mode Write only the four numerical files and IDs/metadata required by Bonsai (NPY, MAP)
-e, --extended_output Option to print extended output (default: false, choice: false,0,true,1)
-v_m, --v_method Option to specify the method for variance estimation (default: MAP, choice: MAP, EAP, MLE, MARG)
-vmin, --variance_min Minimal value of variance in log transcription quotient (default: 0.001)
-vmax, --variance_max Maximal value of variance in log transcription quotient (default: 50)
-nbin, --number_of_variance_bins Number of bins for the variance in log transcription quotient (default: 160)
-no_norm, --no_cell_size_normalization Option to skip cell size normalization (default: false, choice: false,0,true,1)
Installation
Text formatting requires floating-point std::to_chars support in the C++17
standard library.
- Clone the GitHub repository
git clone https://github.com/jmbreda/Sanity.git
- Install OpenMP library
- On Linux
If not already installed (Check withldconfig -p | grep libgomp, no output if not installed), do
sudo apt-get update sudo apt-get install libgomp1-
On mac OS
Apple's owng++/clang++does not support OpenMP, so you need a real GCC.- Using brew (recommended)
brew install gccThe Makefile detects this automatically and picks the right
g++binary, no further changes needed.- Using macports
port install gcc13Tell the Makefile to use it by compiling with
make CC=g++-mp-13(adjust the version number to the package you installed).
- On Linux
- Move to the source code directory and compile.
cd Sanity/src
make
- The binary file is located in
Sanity/bin/Sanity
- Alternatively, pre-built binaries are published on the repository's Releases page.
Sanity_distance
Compute cell-cell distances from Sanity output files. Needs extended outputs of Sanity (-e 1 option).
Input
-f: The output folder of the Sanity run, specified with the-doption in Sanity ('path/to/folder')-s2n: (optional) The gene signal to noise ratio used as gene cut-off (double, default:1.0)-err: (optional) Compute cell-cell distance with or without error bars (boolean, default:1ortrue)-n: (optional) Number of threads (integer, default:4)
Output
- Cell-cell distance: (Nc(Nc-1)/2) vector of cell to cell distances dist(celli,cellj), i=1,...,Nc-1, j=i+1,...,Nc, with Nc the number of cells.
dist(cell1,cell2) dist(cell1,cell3) dist(cell1,cell4) ... dist(cellNc-2,cellNc-1) dist(cellNc-2,cellNc) dist(cellNc-1,cellNc)
located in the Sanity output folder (specified with -f option), named cell_cell_distance_[...].txt, depending on the -err and -s2n options.
Usage
./Sanity_distance <option(s)>
Options:
-h,--help Show this help message
-v,--version Show the current version
-f,--folder Specify the input folder with extended output from Sanity
-s2n,--signal_to_noise_cutoff Minimal signal/noise of genes to include in the distance calculation (default: 1.0)
-err,--with_error_bars Compute cell-cell distance taking the errorbar epsilon into account (default: true)
-n,--n_threads Specify the number of threads to be used (default: 4)
Installation
Same dependencies as Sanity (see above).
- Move to the source code directory and compile.
cd Sanity/src
make Sanity_distance
- The binary file is located in
Sanity/bin/Sanity_distance
Sorting MTX file by row (gene) indices
Use script sort_mtx_by_row.py in the Sanity/scripts folder to sort the MTX file by row (gene) indices. The script takes as input the MTX file. The output is a sorted MTX file by default saved as sorted_[original filename].gz in the same folder as the input file. User can specify the output file name and path with the -o option. The saved MTX file is compressed with gzip.
Requirements: Python3, sort
Example usage:
python3 sort_mtx_by_row.py -i input.mtx
Tests
A simple test comparing Sanity's output across the -v_m methods (MAP, EAP, MLE, MARG) on a small count matrix is available in the tests directory. See tests/README.md for details on running it.
Help
For any questions or assistance regarding Sanity, please post your question in the issues section.
Metadata
Release files for sanity-py 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| sanity_py-0.1.4.tar.gz | 215.8 kB | With provenance | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| sanity_py-0.1.4-cp311-abi3-win_amd64.whl | CPython 3.11 | abi3 | Windows x86-64 | Details |
| sanity_py-0.1.4-cp311-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 | Details |
| sanity_py-0.1.4-cp311-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl | CPython 3.11 | abi3 | Linux glibc 2.28+ ARM64, Linux glibc 2.26+ ARM64 | Details |
| sanity_py-0.1.4-cp311-abi3-macosx_15_0_x86_64.whl | CPython 3.11 | abi3 | macOS 15.0+ x86-64 | Details |
| sanity_py-0.1.4-cp311-abi3-macosx_14_0_arm64.whl | CPython 3.11 | abi3 | macOS 14.0+ ARM64 | Details |
Total release size: 4.8 MB
Release files / sanity_py-0.1.4.tar.gz
| Download URL | sanity_py-0.1.4.tar.gz |
|---|---|
| Size | 215.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
37d38a405250736d35d836e1f907c7e7c659d80af2c75785241b838b534702ca
|
|
BLAKE2b-256 checksum How to use checksums |
84fe1fa3dde4c6f46331f17beabcc3d1281a5f1fe530027d9c0ab13547aa4d3a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logRelease files / sanity_py-0.1.4-cp311-abi3-win_amd64.whl
| Download URL | sanity_py-0.1.4-cp311-abi3-win_amd64.whl |
|---|---|
| Size | 477.4 kB |
| Tags | CPython 3.11 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
b7bcb0e7f1f3dd3f5e30b126c51c1867b3bf47219dc43df41908b18c83bea0e1
|
|
BLAKE2b-256 checksum How to use checksums |
69ee679d367722fec6fd0b911ccc31dd87103df5b64c837f17acd528216abe1f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logRelease files / sanity_py-0.1.4-cp311-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | sanity_py-0.1.4-cp311-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 492.3 kB |
| Tags | CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
af278b957b38ceb4d5b2c12a2c84abd02c2ccc0b381db550c2ba570cdbb68cdb
|
|
BLAKE2b-256 checksum How to use checksums |
d575a4ebc741b12a3419b42202468f3596db645a5f89c22fc46f226e3a321634
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logRelease files / sanity_py-0.1.4-cp311-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl
| Download URL | sanity_py-0.1.4-cp311-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 461.8 kB |
| Tags | CPython 3.11 Linux glibc 2.26+ ARM64 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
d143d47a16aeb37d656a6e7c04e0143d58aaf041648086bb7f13d1215990e7ae
|
|
BLAKE2b-256 checksum How to use checksums |
0463dfafcf3bf83144c987f9649e538bb8f444ef9f2687bc16eca691d0c79004
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logRelease files / sanity_py-0.1.4-cp311-abi3-macosx_15_0_x86_64.whl
| Download URL | sanity_py-0.1.4-cp311-abi3-macosx_15_0_x86_64.whl |
|---|---|
| Size | 1.7 MB |
| Tags | CPython 3.11 abi3 macOS 15.0+ x86-64 |
|
SHA-256 checksum How to use checksums |
fb5ea9f93aadcf67b2070f3d1496287e3797f8cd4cd0ef96611eee7a3a7d8069
|
|
BLAKE2b-256 checksum How to use checksums |
617d29c309b3976a97089c648a856fecc1e4ef9970e48dd880e9421d81c51924
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logRelease files / sanity_py-0.1.4-cp311-abi3-macosx_14_0_arm64.whl
| Download URL | sanity_py-0.1.4-cp311-abi3-macosx_14_0_arm64.whl |
|---|---|
| Size | 1.5 MB |
| Tags | CPython 3.11 abi3 macOS 14.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
4ae833ac6dfe3e6d684ce429d60553fa9cdaf77e9377db2d212b525e26caeeb3
|
|
BLAKE2b-256 checksum How to use checksums |
073cc0a32df6a44beb595c53e3a8007e252bd8225b1a1a3c4a310c9f4d1326e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logSecurity for sanity-py 0.1.4
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 6 files in this release have been uploaded with provenance metadata.
Attestation for sanity_py-0.1.4.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.