Plotting System

Table of contents

  1. TOC

All canonical plots are generated through the genecircuitry/plotting/ subpackage. This replaces the legacy inline plotting code that was scattered across preprocessing.py, grn_deep_analysis.py, and hotspot_processing.py.

genecircuitry/plotting/
├── __init__.py          # Re-exports all public plot functions
├── qc_plots.py          # QC violin and scatter plots
├── grn_plots.py         # GRN network graphs, centrality heatmaps, rank plots
├── hotspot_plots.py     # Hotspot local correlation heatmaps, module plots
└── utils.py             # Shared helpers: save_plot(), plot_exists()

Shared utilities (plotting/utils.py)

save_plot(fig, filepath, plot_type, metadata, skip_existing, save_pdf)

Saves a matplotlib figure to disk in PNG and vector PDF formats, creates parent directories automatically, logs the save event, and returns True on success.

from genecircuitry.plotting.utils import save_plot

saved = save_plot( fig=fig, filepath=”results/figures/grn/my_network.png”, plot_type=”grn”, # label for logging metadata={“cluster”: “0”}, skip_existing=True, # skip if file already exists save_pdf=True, # also save .pdf alongside .png (default: config.SAVE_PDF) )

plot_exists(filepath, skip_existing, check_pdf)

Returns True if the file already exists (including its PDF counterpart when check_pdf=True) and skip_existing=True. Used internally in every plot function to avoid re-generating expensive plots.

from genecircuitry.plotting.utils import plot_exists
if not plot_exists("results/figures/grn/my_plot.png", skip_existing=True):
    # generate and save

QC plots (plotting/qc_plots.py)

plot_qc_violin_pre_filter(adata, save_name, figsize, skip_existing)

Three-panel violin plot showing genes per cell, total counts, and mitochondrial % before QC filtering.

from genecircuitry.plotting.qc_plots import plot_qc_violin_pre_filter

plot_qc_violin_pre_filter(
    adata,
    save_name="run1",          # appended to filename: violin_pre_filter_run1.png
    figsize=None,              # config.PLOT_FIGSIZE_LARGE if None
    skip_existing=True,
)
# Saved to: config.FIGURES_DIR_QC/violin_pre_filter_run1.png

plot_qc_violin_post_filter(adata, save_name, figsize, skip_existing)

Same three-panel violin plot after QC filtering — for before/after comparison.

from genecircuitry.plotting.qc_plots import plot_qc_violin_post_filter

plot_qc_violin_post_filter(adata, save_name="run1")
# Saved to: config.FIGURES_DIR_QC/violin_post_filter_run1.png

plot_qc_scatter_pre_filter(adata, save_name, figsize, skip_existing)

Scatter plots: counts vs genes, counts vs MT%, genes vs MT% — useful for spotting doublets and dying cells.

from genecircuitry.plotting.qc_plots import plot_qc_scatter_pre_filter

plot_qc_scatter_pre_filter(adata, save_name="run1")
# Saved to: config.FIGURES_DIR_QC/scatter_pre_filter_run1.png

GRN plots (plotting/grn_plots.py)

Convenience function that generates the full suite of GRN plots for a given Links object:

  • Network graphs (one per cluster)
  • Centrality score heatmaps
  • TF rank plots
  • Cross-cluster score comparisons
from genecircuitry.plotting.grn_plots import generate_all_grn_plots

generate_all_grn_plots(
    links=links,
    oracle=oracle,
    output_dir="results/figures/grn/",
    stratification="all_cells",    # label for filenames
)

plot_network_graph_single(graph, cluster, stratification, ...)

Plots a single cluster’s regulatory network as a directed graph using NetworkX.

from genecircuitry.plotting.grn_plots import plot_network_graph_single
import networkx as nx

g = nx.DiGraph()  # your GRN graph
plot_network_graph_single(
    graph=g,
    cluster="0",
    stratification="TypeA",
    top_n_nodes=30,        # show top N hubs
    figsize=None,          # config.PLOT_FIGSIZE_SQUARED_LARGE
)

Network graph where TF nodes are annotated with their top enriched pathway term (requires gseapy).

Bipartite network showing TFs and targets shared between two clusters — useful for comparing regulatory states.


Hotspot plots (plotting/hotspot_plots.py)

plot_hotspot_local_correlations(hotspot_obj, skip_existing)

Heatmap of pairwise local correlation z-scores between significant genes, with genes ordered by module.

from genecircuitry.plotting.hotspot_plots import plot_hotspot_local_correlations

plot_hotspot_local_correlations(hs, skip_existing=True)
# Saved to: config.FIGURES_DIR_HOTSPOT/hotspot_local_correlations.png

plot_module_scores_violin(hotspot_obj, adata, cluster_key, figsize, skip_existing)

Violin plots of per-module scores split by cell cluster — shows which clusters are enriched for each gene module.

from genecircuitry.plotting.hotspot_plots import plot_module_scores_violin

plot_module_scores_violin(
    hotspot_obj=hs,
    adata=adata,
    cluster_key="leiden",
    skip_existing=True,
)
# Saved to: config.FIGURES_DIR_HOTSPOT/module_scores_violin.png

Comparative & aggregation plots (plotting/comparative_plots.py)

Visualizations for cross-cluster and cross-stratification integration:

plot_comparative_module_activity(activity_df, save_name, skip_existing)

Row-standardized Z-score heatmap (cmap="viridis") comparing Hotspot co-expression module activation across clusters or stratifications.

plot_cross_stratification_module_overlap(jaccard_df, alignment_summary_df, save_name, skip_existing)

Heatmap (cmap="viridis") of gene-set Jaccard similarity across modules from different stratifications to align homologous programs and prevent numeric module name collisions.

plot_tf_module_regulatory_matrix(tf_mod_matrix, save_name, skip_existing)

Heatmap (cmap="inferno") showing target gene overlap counts between top transcription factors and co-expression modules.

plot_tf_module_concordance(concordance_df, save_name, skip_existing)

Bubble matrix (cmap="inferno") cross-referencing module expression scores (color) and top driver TF target coverage percentages (bubble size).

plot_gene_selection_sankey(provenance_df, save_name, skip_existing)

4-stage alluvial flow diagram (pastel) tracing genes from Hotspot significance to module assignment, GRN master driver role, cluster specificity, and pathway enrichment.

plot_comparative_tf_centrality(tf_pivot_df, tf_summary_df, save_name, skip_existing)

Heatmap (cmap="inferno") of TF degree centralities across groups with automatic $\bigstar$ Global Master Regulator and $\blacklozenge$ Group-Specific Regulator classifications.

plot_differential_tf_targets(diff_targets_df, save_name, skip_existing)

Stacked horizontal bar chart partitioning TF targets into Conserved (pastel blue) and Condition-Specific / Rewired (pastel coral) sets.

plot_cross_cluster_regulatory_comparison(reg_summary_df, save_name, skip_existing)

2x2 multi-panel comparison of network scale, active TFs/modules, top central TFs, and dominant regulatory circuits per cluster.

plot_integrated_regulatory_dashboard(comparative_results, save_name, skip_existing)

6-panel publication-ready composite dashboard summarizing all comparative metrics.


Figure sizing and DPI

All plot functions accept a figsize parameter; when None, they fall back to a config preset:

Config key Default Use
PLOT_FIGSIZE_SMALL (6, 4) Inline/thumbnail plots
PLOT_FIGSIZE_MEDIUM (10, 7) Standard single plots
PLOT_FIGSIZE_LARGE (20, 15) QC panels with many subplots
PLOT_FIGSIZE_WIDE (20, 8) Landscape / wide figures
PLOT_FIGSIZE_SQUARED (6, 6) Square (network graphs)
PLOT_FIGSIZE_SQUARED_LARGE (10, 10) Large square (network graphs)
PLOT_DPI 200 Screen rendering DPI
SAVE_DPI 600 File save DPI for publication quality
PLOT_FORMAT 'png' Output format
SAVE_PDF True Automatically save PDF alongside PNG

Override globally:

from genecircuitry import config config.update_config(SAVE_DPI=300, SAVE_PDF=True, PLOT_FORMAT=”png”)


---


All plot functions accept `skip_existing=True` (default). When a file already exists at the target path, the function returns `False` without regenerating the plot. Set `skip_existing=False` to force regeneration:

```python
plot_qc_violin_pre_filter(adata, skip_existing=False)  # always regenerate

This is integrated with the checkpoint system — completed plot steps are not re-run on pipeline resume.


Adding new plots

New plot functions must live in the appropriate genecircuitry/plotting/ module (not in preprocessing.py or other analysis modules). Follow this template:

# In genecircuitry/plotting/qc_plots.py (or grn_plots.py / hotspot_plots.py)

def plot_my_new_figure(adata, save_name="default", figsize=None, skip_existing=True):
    from .. import config
    from .utils import save_plot, plot_exists

    filepath = f"{config.FIGURES_DIR_QC}/my_figure_{save_name}.png"
    if plot_exists(filepath, skip_existing):
        return False

    if figsize is None:
        figsize = config.PLOT_FIGSIZE_MEDIUM

    fig, ax = plt.subplots(figsize=figsize)
    # ... plotting code ...

    return save_plot(fig, filepath, plot_type="qc", metadata={"save_name": save_name})

Then export it from genecircuitry/plotting/__init__.py.