Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Visualization: Every Plot with a Purpose

A plot should answer a stated question. Save the table or cell-level values behind it, because the figure is a view rather than the complete result.

Prepare one object

The examples in this chapter use one clustered object:

Requires CLI: this example imports the package and reads local files.

Requires CLI: this example imports the package.

import "singlecell" as sc

let obj = sc.standard(
    sc.load("ctrl_raw"),
    resolution: 0.5, n_hvg: 100, k: 15,
    min_genes: 20, max_genes: 2500, max_pct_mito: 5.0,
    min_cells: 3, target: 10000.0, quiet: true
)

QC distributions

Before filtering, inspect totals, detected genes, and mitochondrial percentage. The current package provides QC tables; BioLang’s general plotting builtins render their columns:

Requires CLI: this example imports the package and reads local files.

let with_qc = sc.load("ctrl_raw") |> sc.qc()

println("Total counts")
println(hist(col(with_qc.cell_qc_table, "total_counts"), 20))
println("Genes detected")
println(hist(col(with_qc.cell_qc_table, "n_genes"), 20))
println("Mitochondrial percentage")
println(hist(col(with_qc.cell_qc_table, "pct_mito"), 20))

These ASCII histograms are useful in logs and remote jobs. For multiple samples, split metrics by sample rather than hiding differences in one pooled distribution.

For a connected SVG inspection surface:

Requires CLI: this example imports the package and writes a local file.

write_text("qc-dashboard.svg", sc.plot_qc_dashboard(sc.load("ctrl_raw")))

plot_qc_violin() and plot_qc_scatter() provide the two component views when they are needed separately.

PCA plot

Requires CLI: this example imports the package and writes a local file.

write_text("pca.svg", sc.plot_pca(obj, "PCA: major linear variation"))

Use PCA to inspect dominant linear structure and technical separation. A sample forming its own region can indicate biology, batch, or quality. PCA axes have a global mathematical meaning that UMAP axes do not, but their signs can flip between implementations.

Elbow plot

Requires CLI: this example imports the package.

write_text("elbow.svg", sc.plot_elbow(obj, 15))

The ordered ASCII bars show variance explained by each principal component. Look for a gradual leveling rather than pretending there is always one exact cutoff. Check whether later PCs contain coherent biology or mostly noise.

UMAP cluster map

Requires CLI: this example imports the package and writes a local file.

write_text("umap.svg", sc.plot_umap(obj, "UMAP by Leiden cluster"))

Use UMAP to inspect local neighborhoods, mixing, and outliers. Do not interpret axis values, island area, or long-range distance as calibrated biology. Label the plot with the representation and parameters used.

Use arbitrary per-cell labels for condition, donor, cell type, batch, or phase. The teaching fixture has one sample, so stand-in labels show the mechanism:

Requires CLI: this example imports the package and writes a local file.

# In a real analysis these come from your sample sheet, aligned to obj.barcodes.
let condition_labels = range(0, obj.n_cells)
    |> map(|i| if i % 2 == 0 { "control" } else { "treated" })

write_text(
    "umap-by-condition.svg",
    sc.plot_embedding(obj, condition_labels, "UMAP by condition")
)

Feature plot

Requires CLI: this example imports the package and writes a local file.

write_text(
    "feature-LYZ.svg",
    sc.plot_feature(obj, "LYZ", "LYZ normalized expression")
)

A feature plot colors each UMAP point by one gene’s expression. Use several positive and negative markers. A few isolated high cells can be ambient RNA, doublets, or genuine rare expression.

When comparing conditions, keep one colour scale across panels:

Requires CLI: this example imports the package and writes a local file.

write_text(
    "feature-split.svg",
    sc.plot_feature_split(obj, "LYZ", condition_labels)
)

Violin plot

Requires CLI: this example imports the package and writes a local file.

write_text("violin-LYZ.svg", sc.plot_violin(obj, "LYZ"))

The violin compares a gene’s normalized expression distribution across clusters. Check both the expressing fraction and magnitude: a broad low signal and a narrow high signal can have similar means.

Marker heatmap

Requires CLI: this example imports the package and writes a local file.

write_text("marker-heatmap.svg", sc.plot_markers(obj, 5))

The heatmap selects genes with high cluster-vs-rest mean differences and shows mean expression by cluster. It is a compact overview, not a formal replicate-aware differential-expression result.

plot_group_heatmap() accepts any per-cell grouping and a chosen gene panel, so the same view can compare cell types, conditions, donors, or cell-cycle phases.

Expression dot plot

Requires CLI: this example imports the package and writes a local file.

write_text(
    "marker-dotplot.svg",
    sc.expr_dotplot(
        obj,
        ["LYZ", "MS4A1", "CD3D", "GNLY"],
        "Candidate population markers"
    )
)

Circle size represents the fraction of cells expressing the gene; color represents mean expression among expressing cells. This separates prevalence from intensity. BioLang’s general dotplot builtin is a sequence-comparison plot and is unrelated.

Proportion plot

Requires CLI: this example imports the package.

write_text("proportions.svg", sc.plot_proportions(obj))

This ordered ASCII chart counts cells per cluster or supplied group. Raw cell fractions can be affected by capture, filtering, and sampling. Perform sample-level compositional analysis before making population claims.

Export all SVG plots

Every plot_* function returns an SVG string, with no exceptions — pass the result to write_text to save it, or to save_png to rasterise it. The advanced gallery and complete export workflow are in Advanced Analysis and Diagnostic Plots.

Every exported figure should be accompanied by:

  • the BioLang source and version;
  • input identity and filtering summary;
  • plot title, groups, genes, and transformations;
  • the values or assignments behind the figure;
  • a caption stating what the plot can and cannot establish.