Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ Parameters are settings that live exclusively in `config/config.yaml` and determ
| `integration.integrate_key` | **Mandatory** | Variable Harmony corrects over during integration (e.g. `sample`). |
| `extra_annotations.columns` | **Optional** | `core_samples.tsv` columns to surface in downstream plots (e.g. `[patient, batch]`). All sample-sheet columns are carried into `obs` and can be used by pseudobulk models whether or not they are plotted. |
| `analysis.pseudobulk.analyses` | Pseudobulk | Named aggregation/model specifications containing the comparison variables, explicit contrasts, exclusions, optional pairing/covariates, and optional LRT. |
| `analysis.umap_point_size` | **Optional** | Marker size for ordinary UMAP embedding plots (default: `2`). Highlight and split UMAPs remain at least size `10`. |
| `analysis.spatial_point_size` | **Optional** | Marker size for spatial maps (default: `20`). This is independent of the UMAP marker size; coordinate-only spatial-niche maps are scaled proportionally. |

## 4. Color scale customization

Expand Down
3 changes: 3 additions & 0 deletions config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ per_sample_qc: ''
analysis:
# qc thresholds
plot_dpi: 300
# marker sizes for UMAP embeddings and spatial maps, respectively
umap_point_size: 2
spatial_point_size: 20
min_counts: 1
min_cells: 3
min_genes: 100
Expand Down
2 changes: 2 additions & 0 deletions workflow/rules/annotate_cells.smk
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ rule annotate_cells:
annotation_colors=config.get("annotation_colors", {}),
region_colors=ANALYSIS.get("region_colors", {}),
dpi=ANALYSIS.get("plot_dpi", 300),
umap_point_size=ANALYSIS.get("umap_point_size", 2),
spatial_point_size=ANALYSIS.get("spatial_point_size", 20),
niche_column=GENE_EXPLORATION.get("niche_column", ""),
script:
"../scripts/annotate_cells.py"
2 changes: 2 additions & 0 deletions workflow/rules/explore_genes.smk
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ rule explore_genes_integrated:
aucell_fraction=GENE_EXPLORATION.get("aucell_max_rank_fraction", 0.05),
niche_column=GENE_EXPLORATION.get("niche_column", ""),
dpi=GENE_EXPLORATION.get("dpi", ANALYSIS.get("plot_dpi", 300)),
umap_point_size=ANALYSIS.get("umap_point_size", 2),
annotation_colors=config.get("annotation_colors", {}),
region_colors=ANALYSIS.get("region_colors", {}),
extra_annot_columns=EXTRA_ANNOT_COLUMNS,
Expand Down Expand Up @@ -71,6 +72,7 @@ rule explore_genes_sample:
niche_column=GENE_EXPLORATION.get("niche_column", ""),
aucell_fraction=GENE_EXPLORATION.get("aucell_max_rank_fraction", 0.05),
dpi=GENE_EXPLORATION.get("dpi", ANALYSIS.get("plot_dpi", 300)),
spatial_point_size=ANALYSIS.get("spatial_point_size", 20),
annotation_colors=config.get("annotation_colors", {}),
region_colors=ANALYSIS.get("region_colors", {}),
script:
Expand Down
2 changes: 2 additions & 0 deletions workflow/rules/ingest_ref.smk
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ rule ingest_ref:
ref_label_key=config.get("ingest_ref_label_key", "cell_type"),
de_n_genes=ANALYSIS.get("de_n_genes", 10),
annotation_colors=config.get("annotation_colors", {}),
umap_point_size=ANALYSIS.get("umap_point_size", 2),
spatial_point_size=ANALYSIS.get("spatial_point_size", 20),
script:
"../scripts/ingest_ref.py"
1 change: 1 addition & 0 deletions workflow/rules/integrate_samples.smk
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ rule integrate_samples:
annotation_colors=config.get("annotation_colors", {}),
region_colors=ANALYSIS.get("region_colors", {}),
dpi=ANALYSIS.get("plot_dpi", 300),
umap_point_size=ANALYSIS.get("umap_point_size", 2),
niche_column=GENE_EXPLORATION.get("niche_column", ""),
extra_annot_columns=EXTRA_ANNOT_COLUMNS,
sample_colors=SAMPLE_COLORS,
Expand Down
2 changes: 2 additions & 0 deletions workflow/rules/leiden_analysis.smk
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ rule leiden_analysis:
resolution_scan_step=ANALYSIS.get("resolution_scan_step", 0.1),
annotation_colors=config.get("annotation_colors", {}),
region_colors=ANALYSIS.get("region_colors", {}),
umap_point_size=ANALYSIS.get("umap_point_size", 2),
spatial_point_size=ANALYSIS.get("spatial_point_size", 20),
script:
"../scripts/leiden_analysis.py"
1 change: 1 addition & 0 deletions workflow/rules/preprocess_umap.smk
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ rule preprocess_umap:
"keep_unannotated", True
),
region_colors=ANALYSIS.get("region_colors", {}),
spatial_point_size=ANALYSIS.get("spatial_point_size", 20),
script:
"../scripts/preprocess_umap.py"
1 change: 1 addition & 0 deletions workflow/rules/qc_sweep.smk
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ rule qc_sweep:
ref_label_key=config.get("ingest_ref_label_key", "cell_type"),
region_colors=config.get("analysis", {}).get("region_colors", {}),
region_levels=config.get("analysis", {}).get("region_levels", []),
spatial_point_size=config.get("analysis", {}).get("spatial_point_size", 20),
script:
"../scripts/qc_sweep.py"
2 changes: 2 additions & 0 deletions workflow/rules/sample_report.smk
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ rule sample_report:
annotation_colors=config.get("annotation_colors", {}),
region_colors=ANALYSIS.get("region_colors", {}),
dpi=ANALYSIS.get("plot_dpi", 300),
umap_point_size=ANALYSIS.get("umap_point_size", 2),
spatial_point_size=ANALYSIS.get("spatial_point_size", 20),
niche_column=GENE_EXPLORATION.get("niche_column", ""),
script:
"../scripts/sample_report.py"
2 changes: 2 additions & 0 deletions workflow/rules/spatial_niches.smk
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,7 @@ rule spatial_niches:
annotation_colors=config.get("annotation_colors", {}),
region_colors=ANALYSIS.get("region_colors", {}),
dpi=ANALYSIS.get("plot_dpi", 300),
umap_point_size=ANALYSIS.get("umap_point_size", 2),
spatial_point_size=ANALYSIS.get("spatial_point_size", 20),
script:
"../scripts/spatial_niches.py"
1 change: 1 addition & 0 deletions workflow/rules/subcluster.smk
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ rule subcluster:
region_colors=ANALYSIS.get("region_colors", {}),
region_levels=REGION_LEVELS,
dpi=ANALYSIS.get("plot_dpi", 300),
umap_point_size=ANALYSIS.get("umap_point_size", 2),
niche_column=GENE_EXPLORATION.get("niche_column", ""),
extra_annot_columns=EXTRA_ANNOT_COLUMNS,
sample_colors=SAMPLE_COLORS,
Expand Down
10 changes: 10 additions & 0 deletions workflow/schemas/config.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,16 @@ properties:
type: integer
minimum: 1
description: Default figure DPI.
umap_point_size:
type: number
exclusiveMinimum: 0
default: 2
description: Marker size for ordinary UMAP embedding plots.
spatial_point_size:
type: number
exclusiveMinimum: 0
default: 20
description: Marker size for spatial maps.

ingest_ref:
type: string
Expand Down
12 changes: 7 additions & 5 deletions workflow/scripts/annotate_cells.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,15 @@ def generate_annotation_plots(adata, annot_key, label, plots_dir, sample_id,

# UMAP
log.info(" [%s] UMAP …", label)
sc.pl.umap(adata, color=[annot_key], size=2, wspace=0.25, frameon=False,
sc.pl.umap(adata, color=[annot_key], size=UMAP_POINT_SIZE, wspace=0.25, frameon=False,
title=f"Cell types ({label})")
plt.savefig(os.path.join(subdir, f"UMAP_{label}_{sample_id}.png"),
dpi=DPI, bbox_inches="tight")
plt.close()

# Spatial overview
try:
sc.pl.spatial(adata, color=annot_key, spot_size=20, frameon=False,
sc.pl.spatial(adata, color=annot_key, spot_size=SPATIAL_POINT_SIZE, frameon=False,
title=f"Spatial – {label}", library_id=library_id)
plt.savefig(os.path.join(subdir, f"spatial_all_{label}_{sample_id}.png"),
dpi=DPI, bbox_inches="tight")
Expand All @@ -119,7 +119,7 @@ def generate_annotation_plots(adata, annot_key, label, plots_dir, sample_id,
lambda x, c=ct: c if x == c else "Other"
)
try:
sc.pl.spatial(adata, color="_hl", spot_size=20, frameon=False,
sc.pl.spatial(adata, color="_hl", spot_size=SPATIAL_POINT_SIZE, frameon=False,
palette={"Other": "#d3d3d3", ct: "#000000"},
title=ct, library_id=library_id)
safe = ct.replace("/", "_").replace(" ", "_")
Expand Down Expand Up @@ -179,6 +179,8 @@ def generate_annotation_plots(adata, annot_key, label, plots_dir, sample_id,
ANNOTATION_COLORS = snakemake.params.annotation_colors
REGION_COLORS = snakemake.params.region_colors
DPI = int(getattr(snakemake.params, "dpi", 300))
UMAP_POINT_SIZE = float(getattr(snakemake.params, "umap_point_size", 2))
SPATIAL_POINT_SIZE = float(getattr(snakemake.params, "spatial_point_size", 20))
NICHE_COLUMN = getattr(snakemake.params, "niche_column", "")

adata_path = str(snakemake.input.adata)
Expand Down Expand Up @@ -397,7 +399,7 @@ def generate_annotation_plots(adata, annot_key, label, plots_dir, sample_id,
fig, axes = plt.subplots(1, n_panels, figsize=(8 * n_panels, 6),
gridspec_kw={"wspace": 0.5})
for ax, col in zip(axes, annot_cols_present):
sc.pl.umap(adata, color=col, size=2, frameon=False,
sc.pl.umap(adata, color=col, size=UMAP_POINT_SIZE, frameon=False,
title=col.replace("cell_type_", ""), ax=ax, show=False,
legend_fontsize=6, na_in_legend=False)
plt.savefig(os.path.join(plots_dir, f"UMAP_comparison_{sample_id}.png"),
Expand All @@ -410,7 +412,7 @@ def generate_annotation_plots(adata, annot_key, label, plots_dir, sample_id,
fig, axes = plt.subplots(1, n_panels, figsize=(8 * n_panels, 6),
gridspec_kw={"wspace": 0.5})
for ax, col in zip(axes, annot_cols_present):
sc.pl.spatial(adata, color=col, spot_size=20, frameon=False,
sc.pl.spatial(adata, color=col, spot_size=SPATIAL_POINT_SIZE, frameon=False,
title=col.replace("cell_type_", ""),
library_id=library_id, ax=ax, show=False,
legend_fontsize=6, na_in_legend=False)
Expand Down
11 changes: 6 additions & 5 deletions workflow/scripts/explore_genes_integrated.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,14 @@ def generate_umap_composite(adata, color_col, annot_key, has_regions, out_path,
gridspec_kw={"wspace": 0.5})

try:
sc.pl.umap(adata, color=color_col, size=2, frameon=False,
sc.pl.umap(adata, color=color_col, size=UMAP_POINT_SIZE, frameon=False,
vmin=vmin, vmax=vmax, cmap="viridis",
title=title, ax=axes[0], show=False)
except Exception as e:
log.warning(" UMAP %s failed: %s", title, e)

try:
sc.pl.umap(adata, color=annot_key, size=2, frameon=False,
sc.pl.umap(adata, color=annot_key, size=UMAP_POINT_SIZE, frameon=False,
title="Cell types", legend_fontsize=6,
na_in_legend=False,
ax=axes[1], show=False)
Expand All @@ -223,7 +223,7 @@ def generate_umap_composite(adata, color_col, annot_key, has_regions, out_path,
idx = 2
if has_regions:
try:
sc.pl.umap(adata, color="region_annotation", size=2, frameon=False,
sc.pl.umap(adata, color="region_annotation", size=UMAP_POINT_SIZE, frameon=False,
title="Regions", legend_fontsize=6,
na_in_legend=False,
ax=axes[idx], show=False)
Expand All @@ -239,7 +239,7 @@ def generate_umap_composite(adata, color_col, annot_key, has_regions, out_path,
if niche_palette:
adata.uns[f"{niche_col}_colors"] = [
niche_palette.get(str(c), "#cccccc") for c in cats]
sc.pl.umap(adata, color=niche_col, size=2, frameon=False,
sc.pl.umap(adata, color=niche_col, size=UMAP_POINT_SIZE, frameon=False,
title="Spatial niches", legend_fontsize=5,
na_in_legend=False, ax=axes[idx], show=False)
_compact_legend(axes[idx], title="Niche")
Expand All @@ -261,6 +261,7 @@ def generate_umap_composite(adata, color_col, annot_key, has_regions, out_path,
AUCELL_FRACTION = float(snakemake.params.aucell_fraction)
NICHE_COLUMN = str(snakemake.params.niche_column) if snakemake.params.niche_column else ""
DPI = int(snakemake.params.dpi)
UMAP_POINT_SIZE = float(getattr(snakemake.params, "umap_point_size", 2))
ANNOTATION_COLORS = snakemake.params.annotation_colors
REGION_COLORS = snakemake.params.region_colors
EXTRA_ANNOT_COLUMNS = list(getattr(snakemake.params, "extra_annot_columns", []) or [])
Expand Down Expand Up @@ -299,7 +300,7 @@ def generate_umap_composite(adata, color_col, annot_key, has_regions, out_path,
adata.uns[f"{_dc}_colors"] = [pal.get(str(c), "#cccccc") for c in cats]
_dd = os.path.join(base_dir, "_design")
os.makedirs(_dd, exist_ok=True)
sc.pl.umap(adata, color=[_dc], size=2, frameon=False,
sc.pl.umap(adata, color=[_dc], size=UMAP_POINT_SIZE, frameon=False,
title=f"Integrated – by {_dc}", show=False)
plt.savefig(os.path.join(_dd, f"UMAP_by_{_dc}.png"),
dpi=DPI, bbox_inches="tight")
Expand Down
9 changes: 5 additions & 4 deletions workflow/scripts/explore_genes_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def generate_spatial_composite(adata, color_col, annot_key, has_regions,

# (1) Expression / AUCell
try:
sc.pl.spatial(adata, color=color_col, spot_size=20, frameon=False,
sc.pl.spatial(adata, color=color_col, spot_size=SPATIAL_POINT_SIZE, frameon=False,
vmin=vmin, vmax=vmax, cmap="viridis",
title=title, library_id=library_id,
ax=axes[0], show=False)
Expand All @@ -88,7 +88,7 @@ def generate_spatial_composite(adata, color_col, annot_key, has_regions,

# (2) Cell type
try:
sc.pl.spatial(adata, color=annot_key, spot_size=20, frameon=False,
sc.pl.spatial(adata, color=annot_key, spot_size=SPATIAL_POINT_SIZE, frameon=False,
title="Cell types", library_id=library_id,
legend_fontsize=6, na_in_legend=False,
ax=axes[1], show=False)
Expand All @@ -100,7 +100,7 @@ def generate_spatial_composite(adata, color_col, annot_key, has_regions,
# (3) Region
if has_regions:
try:
sc.pl.spatial(adata, color="region_annotation", spot_size=20,
sc.pl.spatial(adata, color="region_annotation", spot_size=SPATIAL_POINT_SIZE,
frameon=False, title="Regions",
library_id=library_id,
legend_fontsize=6, na_in_legend=False,
Expand All @@ -120,7 +120,7 @@ def generate_spatial_composite(adata, color_col, annot_key, has_regions,
if niche_palette:
adata.uns[f"{niche_col}_colors"] = [
niche_palette.get(str(c), "#cccccc") for c in cats]
sc.pl.spatial(adata, color=niche_col, spot_size=20, frameon=False,
sc.pl.spatial(adata, color=niche_col, spot_size=SPATIAL_POINT_SIZE, frameon=False,
title="Spatial niches", library_id=library_id,
legend_fontsize=5, na_in_legend=False,
ax=axes[idx], show=False)
Expand Down Expand Up @@ -235,6 +235,7 @@ def generate_dotplot_composite(adata, var_names, annot_key, has_regions,
ANNOT_KEY = str(snakemake.params.annot_key)
AUCELL_FRACTION = float(snakemake.params.aucell_fraction)
DPI = int(snakemake.params.dpi)
SPATIAL_POINT_SIZE = float(getattr(snakemake.params, "spatial_point_size", 20))
ANNOTATION_COLORS = snakemake.params.annotation_colors
REGION_COLORS = snakemake.params.region_colors
NICHE_COLUMN = str(getattr(snakemake.params, "niche_column", "") or "")
Expand Down
10 changes: 6 additions & 4 deletions workflow/scripts/ingest_ref.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
ref_label_key = snakemake.params.ref_label_key
DE_N_GENES = int(snakemake.params.de_n_genes)
ANNOTATION_COLORS = snakemake.params.annotation_colors
UMAP_POINT_SIZE = float(getattr(snakemake.params, "umap_point_size", 2))
SPATIAL_POINT_SIZE = float(getattr(snakemake.params, "spatial_point_size", 20))

adata_path = str(snakemake.input.adata)
ref_path = str(snakemake.input.ingest_ref)
Expand Down Expand Up @@ -139,7 +141,7 @@
library_id = list(adata.uns["spatial"].keys())[0]

# UMAP (original embedding) coloured by ingest labels
sc.pl.umap(adata, color=["cell_type_ingest"], size=2, frameon=False,
sc.pl.umap(adata, color=["cell_type_ingest"], size=UMAP_POINT_SIZE, frameon=False,
title="Ingest annotation (original UMAP)")
plt.savefig(os.path.join(plots_dir, f"UMAP_ingest_{sample_id}.png"),
dpi=300, bbox_inches="tight")
Expand All @@ -148,7 +150,7 @@
# UMAP from ingest projection
adata.obsm["X_umap_orig"] = adata.obsm["X_umap"].copy()
adata.obsm["X_umap"] = adata.obsm["X_umap_ingest"]
sc.pl.umap(adata, color=["cell_type_ingest"], size=2, frameon=False,
sc.pl.umap(adata, color=["cell_type_ingest"], size=UMAP_POINT_SIZE, frameon=False,
title="Ingest annotation (projected UMAP)")
plt.savefig(os.path.join(plots_dir, f"UMAP_ingest_projected_{sample_id}.png"),
dpi=300, bbox_inches="tight")
Expand All @@ -159,7 +161,7 @@

# Spatial overview
try:
sc.pl.spatial(adata, color="cell_type_ingest", spot_size=20,
sc.pl.spatial(adata, color="cell_type_ingest", spot_size=SPATIAL_POINT_SIZE,
frameon=False, title="Ingest – spatial",
library_id=library_id)
plt.savefig(os.path.join(plots_dir, f"spatial_ingest_{sample_id}.png"),
Expand All @@ -176,7 +178,7 @@
lambda x, c=ct: c if x == c else "Other"
)
try:
sc.pl.spatial(adata, color="_hl", spot_size=20, frameon=False,
sc.pl.spatial(adata, color="_hl", spot_size=SPATIAL_POINT_SIZE, frameon=False,
palette={"Other": "#d3d3d3", ct: "#e41a1c"},
title=ct, library_id=library_id)
safe = ct.replace("/", "_").replace(" ", "_")
Expand Down
Loading
Loading