feat(cell_metrics): move per-cell gene metrics into the cell summary, drop report re-derivation - #36
Merged
Merged
Conversation
Compute the annotated/novel read counts and gene read-count bins once in
cell_metrics.py (both modes) and store them as cell-summary columns, then
have the report read them instead of re-loading and re-deriving from the
classification. Plot outputs are unchanged.
- Add Annotated_genes_reads / Novel_genes_reads and gene bin counts
{anno,novel}_gene_reads_bin_{1,2_5,6_9,10plus} to the summary in reads
and isoforms modes. Store raw COUNTS, not percentages: the report derives
all three views (grouped annotated/novel, all-genes, annotated-only).
- Rewire SQANTI-sc_report.R to read these columns and delete its own
re-derivations: the isoforms CB/FL explosion (an OOM source), the
reads-mode groupby, and the expand_isoform_counts / gene_bin_label
helpers. Removes the isoforms report-side memory blowup and the redundant
reprocessing in both modes.
- Retire the old {anno,novel}_bin*_perc columns: never read by the report
and mis-binned (2-4/5-9) vs the plots' boundaries (2-5/6-9).
The gene columns added in the previous commit used the _reads suffix in both modes. Align them with the tool's existing mode-dependent convention (Reads_in_cell vs Transcripts_in_cell): keep _reads in reads mode, and in isoforms mode use _transcripts, since the per-cell counter there is transcript-level (sum of FL).
CarlosBlancoGo
added a commit
that referenced
this pull request
Jul 16, 2026
…que-isoform counts (#37) Replace the 4 gene abundance bins (1 / 2-5 / 6-9 / >=10) with 11 gapless half-open bins (0,1]..(9,10],(10,inf). The old boundaries had gaps between each value so non-integer abundances silently fell through and the gene vanished from the panel. These float non-integer abundances can come from non-exact isoform quantification approaches like EM or deterministic approaches to resolve ambiguities. Integer counts bin as before. - Add anno_gene_isoforms_bin_* (isoforms mode): distinct models per gene per cell, from the COO group sizes in the existing sparse pass, so it costs no extra explosion. - Fix the gene-bin percentage, which used ifelse(sum(n) > 0, 100*n/sum(n), 0) in a mutate grouped by CB. ifelse() returns a result the length of its test; the test is scalar here, so it yielded only bin_1's percentage and dplyr recycled it across every bin. Introduced in 6f1f8de (#36), so main is affected. Now computed in wide form (rowSums over a cells x nbin matrix, then stacked) -- order-safe, no grouped ifelse. - Figures: drop grouped Known/Novel violins. Annotated-only in both modes with labels adapting to integer vs fractional quantification; rebuild Unique Isoform Count plot. One shared build_gene_bin_violin() helper. - Stop computing novel-gene bin columns; no plot consumes them. Co-authored-by: CarlosBlancoGo <carblan@NGC224>
CarlosBlancoGo
added a commit
that referenced
this pull request
Jul 20, 2026
…cating rows (#42) The per-cluster length-distribution violins re-derived their data by exploding the classification CB/FL lists to per-(transcript, cell) rows and then replicating each row FL times (rep(seq_len(n), times = FL)) so every read became a literal row. In isoforms mode the replicated frame is the number of reads -- the same per-read explosion that #35, #36, #40 and #41 removed elsewhere by moving metrics off the report's on-the-fly re-derivation. Aggregate instead to per-(transcript, cluster) with weight = sum(FL), and drive the violin with the native geom_violin weight aesthetic, plus a weighted mean and a weighted five-number box summary computed from a small weighted-quantile helper. This reproduces the FL-replicated distribution exactly at a fraction of the rows: on the test set the weighted mean matches the replicated mean to full precision and the quantiles to within interpolation noise (invisible on the log-length axis); the rendered violins are indistinguishable in both modes. The weighted-quantile helper also handles clusters/category subsets with fewer than two points (a single transcript collapses to a degenerate box) so sparse per-category panels no longer abort the whole length-by-cluster block via the outer tryCatch.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cell_metrics.py._perccolumns.Details
Reads_in_cell/Transcripts_in_cell):Annotated_genes_reads,Novel_genes_reads,{anno,novel}_gene_reads_bin_{1,2_5,6_9,10plus}_transcriptsSQANTI-sc_report.Rnow always reads the columns; deletedexpand_isoform_counts, bothgenes_by_cbpaths, andgene_bin_label.{anno,novel}_bin*_perccolumns were never read by the report and used boundaries (2-4 / 5-9) that disagreed with the plotted boundaries (2-5 / 6-9). Replaced by the counts columns with correct boundaries.Out of scope