---
title: "Interactive Analysis with the cellreportR Shiny App"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Interactive Analysis with the cellreportR Shiny App}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
resource_files:
- figures/logo.svg
- figures/logo-dark.svg
---
```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
library(cellreportR)
```
The bundled application walks the same pipeline as the package functions —
read segmented exports, specify the design, apply quality control at cell and
unit level, standardize, estimate effect sizes with confidence intervals at
both levels, export a report — in a browser rather than in a script. It is
meant for laboratory personnel without an R background, and for anyone who
wants to look at a data set before writing the script.
Every analytical step in the app delegates to an exported `cr_*` function, so
the app and a scripted analysis produce the same numbers.
## Launching
```{r launch, eval = FALSE}
library(cellreportR)
cr_run_app() # starts empty; example data is one click away
cr_run_app(experiment = my_exp) # start from an experiment already in session
```
`cr_run_app()` needs `shiny`, `bslib`, `DT` and `ggplot2`, all of which are
listed under `Suggests`; a missing one raises an error naming it. The upload
limit is raised to 512 MB for the duration of the session, because segmented
single-cell exports routinely exceed the Shiny default of 5 MB, and the
previous value is restored on exit.
```{r args}
args(cr_run_app)
```
## Layout
The page has four fixed regions:
* a **sidebar**, always visible, holding the three things every tab depends
on — where the data comes from, which marker channel the analysis targets,
and which level of the design is the control;
* a **status card** with a running log of what the app has done, so an
analysis can be reconstructed afterwards;
* the **tab strip**, in analysis order;
* an **About** card.
### The sidebar
1. **Data source** — upload one or more segmented exports, or type the path of
a directory and let the app read it with a file pattern and an optional
recursive scan. `Load example data` fills the app with a synthetic
multi-compound screen (`cr_example_screen()`) when there is nothing to
hand.
2. **Design** — upload a design table (`.csv`, `.tsv` or `.xlsx`), or build one
in the Design tab.
3. **Analysis target** — the marker channel and the control level. Every tab
downstream reads these two selectors, so changing the control level here
changes what every later tab compares against.
The whole experiment can be downloaded as an `.rds` from the sidebar at any
point, which is the bridge from the app back to a script.
### The tabs
| Tab | What it does | Backed by |
|---|---|---|
| **Data** | Cell table, the files that were read, detected channels | `cr_read_cells()`, `cr_read_exports()` |
| **Design** | Derive one design row per unit, assign treatment levels, build the experiment | `cr_build_experiment()` |
| **Quality control** | Cell filters, doublet removal, and the per-unit gate against each unit's own control | `cr_qc_filter()`, `cr_qc_doublets()`, `cr_qc_gate()`, `cr_apply_gate()` |
| **Normalisation** | Robust z-score, z-score, control ratio, background subtraction or quantile, optionally within a batch variable | `cr_normalize()`, `cr_correct_batch()` |
| **Effect sizes** | Forest plot and effect table at unit or cell level | `cr_effect_grid()`, `cr_plot_forest()` |
| **Dose-response** | 4PL / 3PL / linear fit with the fitted parameters | `cr_dose_response()`, `cr_ic50()` |
| **Figures** | Plate map, intensity by treatment, histogram, QC dashboard, spatial map | `cr_plot_plate()` and friends |
| **Report** | Pairwise comparisons, queued figures, and the exported report | `cr_report()`, `cr_render_report()` |
The Quality control tab is the one worth spending time in. Its sub-panels are
the exclusion table, the disputed verdicts (units whose verdict depends on
whether the control's median or mean is used as the threshold), the gate
figure, the area distribution and the QC log. Rows selected in the exclusion
table are dropped together with the units that fail the gate, which is the
interactive form of the reviewed exclusion list shown in
`vignette("end-to-end")`.
## Cross-tab state
The app keeps everything it knows in one `shiny::reactiveValues()` store: the
cells, the design, the assembled experiment, the state it was imported in, the
gate, the effect grid, the results and the queued figures. Quality control,
normalisation and analysis replace the experiment in that store, so every
downstream tab reacts without any tab reaching into another.
Two consequences worth knowing:
* **Reset is real.** `Reset to imported state` in the Quality control and
Normalisation tabs restores the experiment as it was imported, not the
previous step.
* **Figures are queued, not saved.** `Queue for report` adds the current
figure to the report assembly; the Report tab exports the queue.
## Deployment
The user interface, the server and every helper live inside the package
namespace, so the app can be driven in-process by `shiny::testServer()` as
well as from a browser. `inst/shiny/cellreportR/` holds only the `www/` assets
and a thin `app.R` shim for deployment on a Shiny server.
The Effect sizes tab offers **Stratify contrasts by**. Select the design column
whose groups must be analyzed separately; `compound` is selected when present.
Each stratum uses its own control observations, and tables, CSV downloads and
forest facets retain its identity. The declared `metadata$control_level` is the
initial control when valid. Changing data, channel, control, stratum, level or
confidence clears the previous effect result; press **Estimate effect sizes**
again before downloading. Selecting `(none)` explicitly pools the strata.