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
1 change: 1 addition & 0 deletions SQANTI-sc_env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ dependencies:
- r-e1071=1.7_16
- r-forcats=1.0.0
- r-ggdist
- r-ggiraph=0.8.12
- r-ggplot2>=3.4.0
- r-ggplotify=0.1.2
- r-gridbase=0.4_7
Expand Down
10 changes: 10 additions & 0 deletions scripts/generate_multisample_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ def parse_args():
"--report", default="both", choices=["pdf", "html", "both"],
help="Report format to generate (default: both).",
)
parser.add_argument(
"--pca_features", default=None,
help=(
"Optional file with one cell-summary column name per line, replacing the "
"curated feature set used for the QC overview and PCA. Blank lines and "
"lines starting with '#' are ignored."
),
)
parser.add_argument(
"--rscript", default="Rscript",
help="Path to the Rscript executable (default: Rscript).",
Expand Down Expand Up @@ -164,6 +172,8 @@ def main():
]
if len(class_files) >= 2:
cmd.extend(["--class_files", ",".join(class_files)])
if args.pca_features:
cmd.extend(["--pca_features", str(Path(args.pca_features).resolve())])

# Pass group annotation vectors if any non-empty values were provided
if any(v for v in color_groups):
Expand Down
4 changes: 4 additions & 0 deletions src/qc_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ def build_parser(version_str: str = '1.2.0'):
help='Generate a multisample cohort report from per-sample cell summaries.')
apsc.add_argument('--multisample_report_prefix', default='SQANTI_sc_multisample_report',
help='Output prefix for the multisample report (default: SQANTI_sc_multisample_report).')
apsc.add_argument('--pca_features', default=None,
help='Optional file with one cell-summary column name per line, replacing the curated '
'feature set used for the multisample QC overview and PCA. Blank lines and '
'lines starting with # are ignored.')
apsc.add_argument('--write_per_cell_outputs', action='store_true', default=False,
help='When set, writes per-cell gene_counts.csv, ujc_counts.csv, and cv.csv for each sample.')
apsc.add_argument('--export_h5ad', action='store_true', default=False,
Expand Down
7 changes: 6 additions & 1 deletion src/qc_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ def generate_multisample_report(args, df):
if len(class_files) >= 2:
class_files_flag = f' --class_files "{",".join(class_files)}"'

pca_features_flag = ""
pca_features = getattr(args, 'pca_features', None)
if pca_features:
pca_features_flag = f' --pca_features "{os.path.abspath(pca_features)}"'

group_flags = ""
if color_groups and any(v for v in color_groups):
group_flags += f' --color_group "{",".join(color_groups)}"'
Expand All @@ -125,7 +130,7 @@ def generate_multisample_report(args, df):
f"Rscript {reportAssetsPath}/SQANTI-sc_multisample_report.R "
f"--files \"{files_arg}\" --out_dir \"{out_dir}\" "
f"--mode {mode} --report {report_fmt} --prefix \"{prefix}\""
f"{class_files_flag}{group_flags}"
f"{class_files_flag}{pca_features_flag}{group_flags}"
)

print("**** Generating multisample SQANTI-sc report...", file=sys.stdout)
Expand Down
657 changes: 640 additions & 17 deletions src/report_assets/SQANTI-sc_multisample_report.R

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions src/report_assets/SQANTI-sc_multisample_report.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,37 @@ if (exists("multi_structural_category_violin_plots", envir = .GlobalEnv)) {
<div class="section-spacer-xl"></div>
```

# Sample QC Overview

```{r qc-overview-dims}
# The canvas has to grow with the sample count, so the static fallback below
# takes its fig.width/fig.height from the dimensions the report script computed.
.qc_dims <- if (exists("multi_qc_overview_dims", envir = .GlobalEnv)) {
get("multi_qc_overview_dims", envir = .GlobalEnv)
} else {
list(width = 12, height = 13)
}
# The interactive widget sizes itself to the container, so it only runs the
# static chunk when ggiraph was unavailable.
.qc_widget <- exists("multi_qc_overview_widget", envir = .GlobalEnv)
```

```{r qc-overview-interactive, eval=.qc_widget}
get("multi_qc_overview_widget", envir = .GlobalEnv)
```

```{r qc-overview-static, eval=!.qc_widget, fig.width=.qc_dims$width, fig.height=.qc_dims$height}
if (exists("multi_qc_overview_plot", envir = .GlobalEnv)) {
print(get("multi_qc_overview_plot", envir = .GlobalEnv))
} else {
cat("The per-sample QC overview is not available.")
}
```

```{=html}
<div class="section-spacer-xl"></div>
```

# PCA Analysis {.tabset .tabset-fade}

## PCA Plot
Expand Down
17 changes: 17 additions & 0 deletions src/report_assets/style-multisample.css
Original file line number Diff line number Diff line change
Expand Up @@ -455,3 +455,20 @@ p.date {
display: block !important;
}
}

/* ---------------------------------------------------------------
Per-sample QC overview (ggiraph widget)

girafe(opts_sizing(rescale = TRUE)) scales the SVG to the container
WIDTH only, so on a wide screen a tall figure still runs past the fold.
An inline SVG carrying a viewBox honours max-height and rescales
proportionally, so this caps the figure at the viewport instead and
leaves the aspect ratio alone.
--------------------------------------------------------------- */
.girafe_container_std > svg,
.girafe_container_std svg.girafe_svg {
max-height: 82vh;
max-width: 100%;
width: auto !important;
height: auto;
}
Loading