A .Q-View file is a single-file binary container that
bundles a plain-text manifest, an embedded H2 SQL database with project
metadata / analyte panel / sample assignments / replicate pixel
intensities (and – when generated – a fully rendered CSV report stored
as a CLOB), and one or more LOB segments holding the raw
chemiluminescent plate images.
qviewparsR extracts everything except the raw images and
returns it as tidy tibbles. There is no Java runtime, no H2 database
driver, no compiled code – all logic is pure R.
Installation
qviewparsR is pure R – no compiled
code, no Java runtime, no H2 database driver, and no system libraries –
so it installs identically on Windows, macOS, and
Linux. The only hard prerequisite is R >=
4.1.0.
From CRAN (once released):
install.packages("qviewparsR")Development version from GitHub:
# install.packages("pak")
pak::pak("CTTIR/qviewparsR")Platform notes: on Windows no Rtools is
required (the package compiles nothing and its CRAN dependencies arrive
as binaries); on macOS nothing beyond R is needed; on
Linux the package itself is pure R, but a few
dependencies (dplyr, readr,
tidyr, openxlsx2) contain C++ and build from
source unless you use a binary repository (for example the Posit Public
Package Manager or r2u), which avoids needing a compiler.
The package depends on a small tidyverse-aligned core
(cli, dplyr, lifecycle,
openxlsx2, readr, rlang,
tibble, tidyr). Plotting requires
ggplot2; the publication overview adds
patchwork; the Shiny front-end adds shiny,
bslib, DT, withr.
A complete walk-through
library(qviewparsR)
qv <- read_qview("path/to/plate.Q-View")
qv # one-screen summary
qv$analytes # spot_number, analyte, unit, lod, lloq, uloq
qv$well_groups # one row per sample / calibrator / control
qv$pixel_intensities # long-format replicate readings
qv$summary_statistics # per-group mean / std-dev / CV rows
qv$plate_layout # one row per plate well
summary(qv) # mean / SD / CV per well type x analyteread_qview() always returns a list of class
qview with eleven slots described in
?read_qview. Empty slots are zero-row tibbles rather than
NULL, so downstream code can rely on shape stability.
The naming convention
The producing software rewrites identifiers from the original well-assignment template before storing them. The mapping is systematic and reversible:
| Template value | Stored as |
|---|---|
Cal 1 … Cal N
|
ICal 1 … ICal N
|
Low |
GLow |
High |
HHigh |
FD24277364, 1211498458, … |
NFD24277364, N1211498458, … |
strip_qview_prefix() reverses the rewrite. Pass
strip_prefix = TRUE to read_qview() to apply
it across every sample-id column at once:
qv <- read_qview("path/to/plate.Q-View", strip_prefix = TRUE)
unique(qv$well_groups$sample_id)
strip_qview_prefix(c("ICal 1", "GLow", "HHigh", "NFD24277364"))
#> [1] "Cal 1" "Low" "High" "FD24277364"Coercion and tidy-data idioms
as_tibble() returns the long-format
pixel_intensities table – the primary tabular payload – so
a parsed object drops straight into a dplyr / ggplot2 pipeline:
Visualisation
The plot.qview() method offers three quick-look views,
all coloured on the same viridis ramp the Shiny app uses:
plot(qv, type = "plate_map") # 96-well plate, fill = well type
plot(qv, type = "intensity_heatmap") # facet per analyte, fill = PI
plot(qv, type = "replicate_scatter") # rep 1 vs rep 2 per analyteEach call returns a ggplot object, so themes, scales,
and labels can be added on top:
Exporting
Three writers cover the common destinations. All return the parsed
object invisibly, so they compose with |>:
qv |>
write_qview_xlsx("plate.xlsx") |> # one sheet per parsed table
write_qview_csv ("plate_csv/") |> # one CSV per parsed table
write_qview_rds ("plate.rds") # full lossless R round-tripwrite_qview_xlsx() and write_qview_rds()
accept overwrite = TRUE to replace existing
destinations.
The legacy aliases qview_to_xlsx() and
qview_to_csv_dir() still work but emit
lifecycle::deprecate_warn(); switch to the new names.
Cross-validating against a template CSV
Every well assignment is already embedded in the .Q-View
file. If you also have the original well-assignment template CSV the
producing application imported, read_qview_template()
parses it into a tibble that aligns with
qv$plate_layout:
tmpl <- read_qview_template("path/to/template.csv")
qv$plate_layout |>
dplyr::left_join(tmpl, by = "well", suffix = c("_qview", "_template")) |>
dplyr::filter(sample_id_qview != sample_id_template)Any rows surviving the filter expose template-vs-Q-View mismatches.
Interactive front-end
For non-coding collaborators, qview_app() launches a
Shiny app in the same monochrome aesthetic (light + dark mode) with the
hex sticker in the upper-left corner:
The app accepts a .Q-View upload (and optionally a
template CSV) and exposes:
- a publication-ready 2x2 Overview figure (plate layout / pixel intensity distribution / replicate concordance / mean PI by well type) with high-DPI PNG and vector PDF export;
- every parsed table with its own xlsx download;
- one-click xlsx / rds / csv-zip of the whole project;
- a built-in dark/light toggle and per-card max/restore.
Error handling
Every exported function validates inputs early and raises a
structured cli::cli_abort() error pointing at the user’s
call rather than at internal helpers, e.g.:
Error in `read_qview()`:
! `path` must be an existing file.
x "missing.Q-View" does not exist.
Error in `read_qview()`:
! `path` is not a valid `.Q-View` project file.
x "junk.bin" is missing the expected container header.
i Expected a numeric container version followed by "Q-View Project".
The i bullet always carries an actionable hint when one
exists.
Citation
citation("qviewparsR")Heller R, Mannes M (2026). qviewparsR: Read .Q-View Multiplex ELISA Project Files. R package version 1.0.0. https://github.com/CTTIR/qviewparsR
Use of LLM tools
Portions of this package were prepared with assistance from large
language model tooling for narrowly defined, non-authorial tasks:
copyediting, prose smoothing, Markdown/LaTeX formatting, scaffolding of
boilerplate files (CI configs, build scripts), code refactoring. The
tools used were Chat AI,
the LLM service of KISSKI (GWDG), and a self-hosted Mistral
Small (24B, Apache-2.0) run locally via Ollama and the ollamar R
package — local inference only, with no data sent to third parties for
the self-hosted model.
All scientific claims, methodological choices, analyses, interpretations, and conclusions are the author’s own. No LLM-generated text was incorporated without review and revision, and every reference was verified against its DOI, arXiv ID, or ISBN.