What does Matisse do?
Genes can be spliced in different ways – certain exons may be included in some transcripts but skipped in others. This is called alternative splicing, and it means one gene can produce multiple protein variants with different functions.
Matisse measures alternative splicing one cell at a time. For each cell it calculates a PSI value (Percent Spliced In) for each splicing event:
- PSI = 1 – every transcript in that cell includes the exon
- PSI = 0 – every transcript skips the exon
- PSI = 0.5 – half include, half skip
By comparing PSI values across cell types, clusters, or conditions you can find which populations splice genes differently – and by how much. Matisse sits on top of your existing Seurat workflow. Your gene expression data, UMAP, and cluster labels stay intact; splicing information is added alongside them.
Two entry points
Matisse supports two data types via a single constructor. What you pass in determines the mode:
| Data type | How to create | When to use |
|---|---|---|
| Long-read / transcript quantification (Bagpiper, FLAMES, LIQA) | CreateMatisseObject(transcript_counts=..., ioe_files=...) |
You have a transcripts x cells count matrix and SUPPA2 IOE files |
| Short-read 10x Chromium (STARsolo junction counts) | CreateMatisseObject(junction_counts=..., event_data=...) |
You have a cells x junctions count matrix from STARsolo
--soloFeatures SJ
|
Once the object is built, all downstream functions – QC, filtering, normalisation, visualisation – are identical for both data types.
Quick-start (long reads)
library(Matisse)
obj <- CreateMatisseObject(
seurat = seu,
transcript_counts = tx_counts, # transcripts x cells from Bagpiper/FLAMES
ioe_files = "events_SE.ioe",
min_coverage = 5L
)
# PSI is computed at construction; summarise before clustering
obj <- SummarizePSI(obj)
obj <- ComputeIsoformQC(obj)
# Normalise transcript counts and cluster
obj <- SCTransform(obj)
obj <- RunUMAP(obj, dims = 1:50)
obj <- FindNeighbors(obj, dims = 1:50)
obj <- FindClusters(obj, resolution = 0.5)
PlotUMAP(obj, feature = "SE:chr18:3433647-3436055:+")-> Full walkthrough: Long-read workflow
Quick-start (short reads)
library(Matisse)
obj <- CreateMatisseObject(
seurat = seu, # your existing Seurat object
junction_counts = jxn_counts, # cells x junctions from STARsolo
event_data = event_df # splice event annotation
)
obj <- CalculatePSI(obj, min_coverage = 5)
obj <- ComputeIsoformQC(obj)
PlotUMAP(obj, feature = "PTBP1:SE:chr18:3433647-3436055")-> Full walkthrough: Short-read workflow
Session info
sessionInfo()
#> R version 4.5.3 (2026-03-11)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.4 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8
#> [4] LC_COLLATE=C.UTF-8 LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8
#> [7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C
#> [10] LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> loaded via a namespace (and not attached):
#> [1] digest_0.6.39 desc_1.4.3 R6_2.6.1 fastmap_1.2.0
#> [5] xfun_0.57 cachem_1.1.0 knitr_1.51 htmltools_0.5.9
#> [9] rmarkdown_2.31 lifecycle_1.0.5 cli_3.6.6 sass_0.4.10
#> [13] pkgdown_2.2.0 textshaping_1.0.5 jquerylib_0.1.4 systemfonts_1.3.2
#> [17] compiler_4.5.3 tools_4.5.3 ragg_1.5.2 bslib_0.10.0
#> [21] evaluate_1.0.5 yaml_2.3.12 otel_0.2.0 jsonlite_2.0.0
#> [25] rlang_1.2.0 fs_2.1.0 htmlwidgets_1.6.4