Composed Plots

Combine transcript structure diagrams with quantitative visualizations in a single coordinated figure.

LegendPanelBuilder


def LegendPanelBuilder(
    ax:Optional[plt.Axes]
):

Builder for creating consistent legend panels across different composed plots.

Automatically stacks legend elements vertically with proper spacing: - Categorical legends (group colors) - Colorbars (PSI, GEX, etc.) - Dot size legends (prevalence)


DotSizeSlot


def DotSizeSlot(
    sizes:List[float]=None, labels:List[str]=None, title:str='Prevalence\n(dot size)'
)->None:

Slot for dot size legend.


ColorbarSlot


def ColorbarSlot(
    norm:mpl.colors.Normalize, cmap:mpl.colors.Colormap, label:str=''
)->None:

Slot for continuous colorbar.


CategoricalSlot


def CategoricalSlot(
    groups:List[str], color_map:Dict[str, str], title:str='Groups'
)->None:

Slot for categorical legend (group colors).


make_aligned_transcript_panel_layout


def make_aligned_transcript_panel_layout(
    tp:TranscriptPlots, transcripts_ids:List[str], n_panel_cols:int, fig_width:float=None, draw_cds:bool=True,
    show_ruler:bool=True, bands_frac_top:float=0.0, bands_frac_bottom:float=0.0
)->PanelLayout:

Create a transcript panel layout with PERFECT alignment.

This wrapper around make_transcript_panel_layout fixes: 1. Panel bounds so dots/cells align exactly with transcript intron lines 2. Band positions (top/bottom) to attach to the realigned panel 3. Legend panel height to match the actual content height

Examples

Composed plots combining transcript structures with quantitative visualizations

# Load spatial mouse data
import scanpy as sc

# Load the actual spatial mouse data
spatial_mouse_data = sc.read_h5ad('/data/analysis/data_mcandrew/00_allos_0.6_TAB/data/mouse_cbs/mouse_sit/two_mouse_cbs.h5ad')



# Rename spatial coordinates to X_spatial for consistency
if "spatial" in spatial_mouse_data.obsm:
    spatial_mouse_data.obsm["X_spatial"] = spatial_mouse_data.obsm["spatial"]

print(spatial_mouse_data)
print(f"Spatial coordinates shape: {spatial_mouse_data.obsm['X_spatial'].shape}")

API reference


plot_isoform_heatmap_composed


def plot_isoform_heatmap_composed(
    transcript_data, # Transcript annotation data
    adata, # Annotated data object with transcript counts
    gene_id:str, # Gene ID to plot
    group_col:str, # Column in adata.obs defining groups (e.g., 'cell_type')
    top_n:int=2, # Number of top isoforms to show
    estimator:str='pseudobulk', # PSI estimator
    dirichlet_alpha:float=0.5, # Dirichlet alpha parameter
    epsilon:float=1e-06, # Small value to avoid division by zero
    visible_groups:Optional[List[str]]=None, # Subset of groups to display
    cmap:str='magma', # Colormap for PSI heatmap
    colorbar_label:str='PSI', # Label for PSI colorbar
    fig_width:float=20.0, # Figure width in inches
    draw_cds:bool=True, # Whether to draw CDS regions
    show_ticks:bool=True, # Whether to show ruler ticks
    add_gex_band:bool=False, # Whether to add gene expression band
    add_group_color_band:bool=False, # Whether to add group color band
    group_color_map:Optional[Dict[str, str]]=None, # Custom color map for groups
    gex_band_position:str='top', # Position of GEX band ("top" or "bottom")
    group_band_position:str='bottom', # Position of group color band ("top" or "bottom")
    show_panel_colorbar:bool=False, # default off: use legend instead
    show_group_legend:bool=False, # default off: group labels on x-axis are sufficient
    legend_pad:float=0.02, # horizontal padding between plot and legend
    label_offset_h:float=0, # horizontal offset for x-axis labels (positive = right)
    label_offset_v:float=0, # vertical offset for x-axis labels (positive = down)
    row_pitch:float=0.45, # vertical spacing between transcript rows (smaller = tighter)
    intron_scale:float=0.15, # intron compression (smaller = more compressed)
    color_offset:int=0, # rotate transcript color palette by this many steps
)->Tuple[plt.Figure, List[str], List[str], np.ndarray]: # The matplotlib figure

Plot composed figure with transcript structures and heatmap.


plot_isoform_dot_composed


def plot_isoform_dot_composed(
    transcript_data, adata, gene_id:str, group_col:str, top_n:int=2, estimator:str='pseudobulk',
    dirichlet_alpha:float=0.5, epsilon:float=1e-06, visible_groups:Optional[List[str]]=None,
    size_mode:str='prevalence', psi_threshold:float=0.05, cmap:str='magma', colorbar_label:str='PSI',
    fig_width:float=20.0, draw_cds:bool=True, show_ticks:bool=True, add_gex_band:bool=False,
    add_group_color_band:bool=False, group_color_map:Optional[Dict[str, str]]=None, gex_band_position:str='top',
    group_band_position:str='bottom', show_panel_colorbar:bool=False, # use legend instead
    label_offset_h:float=0.0, # horizontal offset for x-axis labels (positive = right)
    label_offset_v:float=0.0, # vertical offset for x-axis labels (positive = down)
    row_pitch:float=0.45, # vertical spacing between transcript rows (smaller = tighter)
    intron_scale:float=0.15, # intron compression (smaller = more compressed)
    color_offset:int=0, # rotate transcript color palette by this many steps
)->Tuple[plt.Figure, List[str], List[str], np.ndarray, np.ndarray]:

Call self as a function.


plot_isoform_violin_composed


def plot_isoform_violin_composed(
    transcript_data, # TranscriptData object for gene/transcript lookups
    adata, # Annotated data object with transcript counts
    gene_id:str, # Gene ID to plot
    group_col:str, # Column in adata.obs defining groups (e.g., 'cell_type')
    gene_col:str='geneId', # Column in adata.var mapping transcripts to genes
    layer:str | None=None, # Layer in adata.layers to use. If None, uses adata.X
    top_n:int | None=None, # Number of top isoforms to plot by mean expression.
Mutually exclusive with `transcripts`.
    transcripts:List[str] | None=None, # Specific transcript IDs to plot.
Mutually exclusive with `top_n`.
    log1p:bool=True, # Apply log1p transformation to counts
    drop_zeros:bool=False, # Remove zero values before plotting
    min_cells_per_group:int=10, # Minimum cells required per group to include
    fig_width:float=20.0, # Overall figure width in inches
    draw_cds:bool=True, # Draw CDS regions on transcript structures
    show_ticks:bool=True, # Show genomic coordinate ruler
    palette:str | list='tab10', # Color palette for groups (used if group_color_map is not provided)
    stripplot:bool=True, # Overlay scatter points on violins
    point_size:float=2.0, # Size of scatter points
    point_alpha:float=0.4, # Alpha transparency of points
    jitter:float=0.25, # Horizontal jitter width for points
    sharey:bool=False, # Share y-axis across all violin panels (default False for better visibility)
    visible_groups:Optional[List[str]]=None, # Subset of groups to display. If None, all groups are shown.
    add_gex_band:bool=False, # Add a gene-expression (CP10k) quantitative band above the panel.
    add_group_color_band:bool=False, # Add colored band showing group categories
    group_color_map:Optional[Dict[str, str]]=None, # Custom color mapping for groups. If provided, overrides palette for
both violin colors and group color band.
    row_pitch:float=0.45, # vertical spacing between transcript rows
    intron_scale:float=0.15, # intron compression (smaller = more compressed)
    color_offset:int=0, # rotate transcript color palette by this many steps
    panel_x0:float=1.15, # horizontal gap between transcripts and violin panel
)->Tuple[plt.Figure, List[str], List[str]]: # The matplotlib figure

Plot violin plots showing isoform expression with transcript structures.

Creates a multi-panel layout with transcript structures on the left and violin plots for each isoform-group combination on the right.


plot_isoform_replicates_composed


def plot_isoform_replicates_composed(
    transcript_data, # Transcript data object for structure plots
    adata, # Annotated data object
    gene_id:str, # Gene ID to plot
    group_col:str, # Column in adata.obs defining groups (e.g., 'cell_type')
    replicate_col:str, # Column in adata.obs defining replicates (e.g., 'batch', 'sample_id')
    top_n:int=2, # Number of top isoforms to plot
    estimator:str='pseudobulk', # PSI estimator ('pseudobulk', 'dirichlet', 'cell-mean', 'cell-median', 'coverage-weighted')
    dirichlet_alpha:float=0.5, # Dirichlet alpha parameter
    epsilon:float=1e-06, # Small value to avoid division by zero
    visible_groups:Optional[List[str]]=None, # Subset of groups to display
    fig_width:float=20.0, # Figure width in inches
    draw_cds:bool=True, # If True, draw CDS regions in transcript structures
    show_ticks:bool=True, # If True, show ruler ticks
    add_gex_band:bool=False, # If True, add GEX band
    add_group_color_band:bool=False, # If True, add group color band
    group_color_map:Optional[Dict[str, str]]=None, # Custom color map for groups
    box_overlay:bool=True, # If True, overlay boxplots on scatter points
    point_size:float=4.0, # Size of scatter points
    point_alpha:float=0.85, # Alpha transparency of points
    jitter_width:float=0.12, # Width of horizontal jitter for points
    label_wrap:int=14, # Width for wrapping x-axis labels
    label_rot:int=35, # Rotation angle for x-axis labels
    row_pitch:float=0.45, # vertical spacing between transcript rows
    intron_scale:float=0.15, # intron compression (smaller = more compressed)
    color_offset:int=0, # rotate transcript color palette by this many steps
)->Tuple[plt.Figure, List[str], List[str], Dict[Tuple[int, int], np.ndarray]]: # The matplotlib figure

Composed plot: transcript structures + replicate PSI variability.

Left: Transcript structure glyphs Right: Replicate plots showing PSI variability across biological replicates


plot_isoform_stacked_bar_composed


def plot_isoform_stacked_bar_composed(
    transcript_data, # Transcript annotation data
    adata, # Annotated data object with transcript counts
    gene_id:str, # Gene ID to plot
    group_col:str, # Column in adata.obs defining groups (e.g., 'cell_type')
    top_n:Optional[int]=None, # Number of top isoforms to show separately. Others grouped as "Other".
If None, shows all isoforms.
    estimator:str='pseudobulk', # PSI estimator ('pseudobulk', 'dirichlet', 'cell-mean', 'cell-median', 'coverage-weighted')
    dirichlet_alpha:float=0.5, # Dirichlet alpha parameter
    epsilon:float=1e-06, # Small value to avoid division by zero
    compute_on_selection_only:bool=False, # If True, compute PSI only on selected top_n isoforms (rescaled to sum to 100%).
If False, compute PSI on all isoforms and show remaining as "Other" category.
    visible_groups:Optional[List[str]]=None, # Subset of groups to display. If None, all groups are shown.
    fig_width:float=16.0, # Figure width in inches
    draw_cds:bool=True, # Whether to draw CDS regions in transcript structures
    show_ticks:bool=True, # Whether to show ruler ticks
    label_wrap:int=14, # Width for wrapping x-axis labels
    label_rot:int=45, # Rotation angle for x-axis labels
    show_values:bool=False, # Whether to show percentage values on bars
    show_title:bool=False, # Whether to show the figure title
    add_group_color_band:bool=False, # Add a categorical color band above the panel showing group identity.
    group_color_map:Optional[Dict[str, str]]=None, # Custom color mapping for groups used in the color band.
    add_gex_band:bool=False, # Add a gene-expression (CP10k) quantitative band above the panel.
    add_gex_bar:bool=False, # Whether to add gene expression bar above stacked bars
    gex_bar_height:float=0.003, # Fixed height of gene expression bar as fraction of main plot height
    gex_legend_width:float=0.35, # Width of the GEX legend colorbar (as fraction, 0-1)
    gex_legend_x:float=0.15, # Horizontal position of GEX legend colorbar (0=left, 1=right)
    row_pitch:float=0.45, # vertical spacing between transcript rows
    intron_scale:float=0.15, # intron compression (smaller = more compressed)
    color_offset:int=0, # rotate transcript color palette by this many steps
)->Tuple[plt.Figure, List[str], List[str], np.ndarray]: # The matplotlib figure

Plot composed figure with transcript structures and stacked bar chart.

Creates a two-panel figure showing: - Left: Transcript structures for isoforms - Right: Stacked bar chart showing isoform composition per group

Colors are matched between transcript structures and bar segments.


plot_isoform_umap_composed


def plot_isoform_umap_composed(
    transcript_data, adata, gene_id:str, group_col:str, top_n:int=2, estimator:str='pseudobulk',
    dirichlet_alpha:float=0.5, epsilon:float=1e-06, visible_groups:Optional[List[str]]=None,
    show_individual_colorbars:bool=False, # If True, show a small colorbar for each UMAP plot panel.
    use_per_panel_scale:bool=False, # If True, each panel has its own colorbar scale based on its data.
If False (default), all panels share a global scale.
    fig_width:float=20.0, draw_cds:bool=True, show_ticks:bool=True, add_gex_band:bool=False,
    add_group_color_band:bool=False, group_color_map:Optional[Dict[str, str]]=None, umap_basis:str='umap',
    umap_cmaps:Optional[List[str]]=None, umap_max_cols:int=2, umap_size:float=5.0, umap_alpha:float=0.9,
    use_global_vmin_vmax:bool=True, vmin:Optional[float]=None, vmax:Optional[float]=None,
    use_density:bool=False, # If True, show KDE-based density instead of raw expression.
    density_adjust:float=1.0, # Bandwidth adjustment for KDE (only used if use_density=True).
    row_pitch:float=0.45, # vertical spacing between transcript rows
    intron_scale:float=0.15, # intron compression (smaller = more compressed)
)->Tuple[plt.Figure, List[str], List[str]]:

Composed plot: transcript structures + UMAP embeddings.

Left: Transcript structure glyphs Right: Tiled UMAP plots (one per isoform)


plot_isoform_density_composed


def plot_isoform_density_composed(
    transcript_data, adata, gene_id:str, group_col:str, top_n:int=2, estimator:str='pseudobulk',
    dirichlet_alpha:float=0.5, epsilon:float=1e-06, visible_groups:Optional[List[str]]=None,
    show_individual_colorbars:bool=False, # If True, show a small colorbar for each density plot panel.
    use_per_panel_scale:bool=False, # If True, each panel has its own colorbar scale based on its data.
If False (default), all panels share a global scale.
    fig_width:float=20.0, draw_cds:bool=True, show_ticks:bool=True, add_gex_band:bool=False,
    add_group_color_band:bool=False, group_color_map:Optional[Dict[str, str]]=None, density_basis:str='umap',
    density_cmaps:Optional[List[str]]=None, density_max_cols:int=2, density_size:float=5.0, density_alpha:float=0.9,
    density_adjust:float=1.0, use_global_vmin_vmax:bool=True, vmin:Optional[float]=None, vmax:Optional[float]=None,
    row_pitch:float=0.45, # vertical spacing between transcript rows
    intron_scale:float=0.15, # intron compression (smaller = more compressed)
)->Tuple[plt.Figure, List[str], List[str]]:

Composed plot: transcript structures + density (KDE) embeddings.

Left: Transcript structure glyphs Right: Tiled density plots (one per isoform, showing spatial density via KDE)


plot_isoform_spatial_composed


def plot_isoform_spatial_composed(
    transcript_data, adata, gene_id:str, group_col:str, top_n:int=2, estimator:str='pseudobulk',
    dirichlet_alpha:float=0.5, epsilon:float=1e-06, visible_groups:Optional[List[str]]=None,
    show_individual_colorbars:bool=True, use_per_panel_scale:bool=False, fig_width:float=20.0, draw_cds:bool=True,
    show_ticks:bool=True, add_gex_band:bool=False, add_group_color_band:bool=False,
    group_color_map:Optional[Dict[str, str]]=None, spatial_basis:str='spatial', spatial_cmap:Optional[str]=None,
    spatial_cmaps:Optional[List[str]]=None, spatial_max_cols:int=2, spatial_size:float=5.0, spatial_alpha:float=0.9,
    use_global_vmin_vmax:bool=True, vmin:Optional[float]=None, vmax:Optional[float]=None, invert_y:bool=True,
    use_density:bool=False, density_adjust:float=1.0, aspect_equal:bool=True, color_offset:int=0,
    intron_scale:float=0.15, # intron compression (smaller = more compressed)
)->Tuple[plt.Figure, List[str], List[str]]:

Composed plot: transcript structures + spatial embeddings.

Left: Transcript structure glyphs Right: Tiled spatial plots (one per isoform)

If use_density=False (default): colour = raw isoform expression. If use_density=True: colour = KDE-based spatial density of that isoform.

spatial_cmap: single colormap name applied to all panels (e.g. “Reds”, “magma”). Overrides the per-mode default. spatial_cmaps takes precedence if also provided. spatial_cmaps: per-isoform colormap list; overrides spatial_cmap. aspect_equal: if True (default), each spatial subplot uses equal x/y scaling, preserving true tissue geometry. Set False to fill the available cell area. use_per_panel_scale: if True, each panel has its own colorbar scale based on its data. If False (default), all panels share a global scale. color_offset: rotate transcript color palette by this many steps.


make_group_color_map


def make_group_color_map(
    groups:List[str], cmap_name:str='tab20'
)->Dict[str, str]:

Create a color map for categorical groups.


plot_isoform_spatial_composed_HD


def plot_isoform_spatial_composed_HD(
    transcript_data, adata, gene_id:str,
    top_n:int=2, # Number of top-expressed isoforms to show (by total expression).
    fig_width:float=20.0, draw_cds:bool=True, show_ticks:bool=True, show_individual_colorbars:bool=True,
    spatial_cmap:Optional[str]=None, # Single colormap applied to all panels (e.g. "Reds", "magma").
spatial_cmaps takes precedence if also provided.
    spatial_cmaps:Optional[List[str]]=None, # Per-isoform colormap list; overrides spatial_cmap.
    spatial_max_cols:int=2, spatial_size:float=5.0, spatial_alpha:float=0.9, invert_y:bool=True,
    aspect_equal:bool=True, # If True (default), each spatial subplot uses equal x/y scaling,
preserving true tissue geometry.
    color_offset:int=0, # Rotate transcript color palette by this many steps.
    row_pitch:float=0.45, intron_scale:float=0.15, # intron compression (smaller = more compressed)
    layer:Optional[str]=None, # Layer to read expression from. Defaults to 'counts' if present.
    transcripts:Optional[List[str]]=None, # Explicit transcript IDs — bypasses top_n selection.
    log_scale:bool=True, # Use LogNorm colorscale. Default True for visium_like style.
    norm_per_spot:bool=False, # Normalise by per-spot library size before plotting.
    norm_target:float=10000.0, # CPM target when norm_per_spot=True (default 1e4).
    hd_marker:str='s', hd_bg_color:str='#E6E6E6', hd_bg_alpha:float=0.35, hd_bg_size_factor:float=1.0,
    bin_factor:Optional[int]=None, rotate:float=0
)->Tuple[plt.Figure, List[str]]:

Composed plot for Visium HD: transcript structure glyphs + spatial scatter panels.

Renders square-bin scatter on a white background (visium_like style), using array_col/array_row from adata.obs for spatial coordinates.


plot_isoform_heatmap_percell_composed


def plot_isoform_heatmap_percell_composed(
    transcript_data, # Transcript annotation data
    adata, # Annotated data object with transcript counts
    gene_id:str, # Gene ID to plot
    group_col:str, # Column in adata.obs for grouping/sorting cells (e.g., 'cell_type')
    top_n:int=2, # Number of top isoforms to include
    epsilon:float=1e-06, # Small value to avoid division by zero
    cell_subset:Optional[List[str]]=None, # Specific cell IDs to include
    max_cells:Optional[int]=500, # Maximum number of cells to plot
    cluster_within_groups:bool=True, # Whether to hierarchically cluster cells within each group
    cmap:str='magma', # Colormap name
    colorbar_label:str='PSI', # Label for colorbar
    fig_width:float=20.0, # Figure width in inches
    draw_cds:bool=True, # Whether to draw CDS regions
    show_ticks:bool=True, # Whether to show ruler ticks
    add_group_color_band:bool=False, # Add group color band
    group_color_map:Optional[Dict[str, str]]=None, # Custom color map for groups
    group_band_position:str='bottom', # Position of group color band ("top" or "bottom")
    show_panel_colorbar:bool=False, # Whether to show panel colorbar
    show_group_boundaries:bool=True, # Whether to show vertical lines between groups
    row_pitch:float=0.45, # vertical spacing between transcript rows
    intron_scale:float=0.15, # intron compression (smaller = more compressed)
    color_offset:int=0, # rotate transcript color palette by this many steps
)->Tuple[plt.Figure, List[str], List[str], np.ndarray]: # The matplotlib figure

Plot a composed per-cell heatmap with transcript structure.

This function combines transcript structure visualization with a per-cell heatmap of isoform PSI values. Cells are sorted by group and optionally clustered within each group.