
Calibrated histology measurements, traceable review and transparent reporting.
bloodspottR brings red-positive tissue area and image-derived event candidates into an explicit physical-slide workflow. It preserves measurement support, missing values, quality decisions and provenance while keeping image readers, annotation clients and model execution behind defined interfaces.
Experimental software. Numerical and software checks do not establish biological accuracy. A candidate event is not necessarily one erythrocyte. Native whole-slide inference, QuPath project writeback and portable DNN training are not yet qualified end-to-end package features. The preserved study pipeline and the reusable R package have separate validation histories.
install.packages("remotes")
# remotes::install_github("CTTIR/bloodspottR")
install.packages("bloodspottR", repos = c('https://cttir.r-universe.dev', 'https://cloud.r-project.org'))
install.packages("shiny") # Optional results application
Required runtime dependencies are cli, digest and jsonlite.
R 4.2 or newer is required. The package itself has no compiled code; optional
spatial dependencies may need system libraries on Linux. To build the tutorials,
install knitr and rmarkdown, make Pandoc available (included with RStudio),
then reinstall with build_vignettes = TRUE. Install
openxlsx2 for workbook export. For the optional candidate-exchange adapter,
install cellspecR from CTTIR/cellspecR. No GPU software is needed to explore
existing results. The package is a development version and is not on CRAN.
library(bloodspottR)
results <- bs_example() # Deterministic synthetic data, never study results
bs_validate(results)
results$groups <- bs_summarize(results, strata = c("organ", "stratum"))
results$groups
# Local read-only explorer; no inference service starts.
if (interactive()) bs_app(results)
The demonstration deliberately includes missing values and zero tissue support. Pooled summaries propagate missing measurements. A zero numerator over known positive tissue gives a measured zero; an unknown or zero denominator gives a missing rate. Group rates divide sums, rather than averaging slide percentages.
The Shiny app displays existing slide images, annotations and measurements. It supports arbitrary organ labels and configurable grouping metadata. Use the synthetic four-tissue example to try image navigation, zoom/pan and annotation selection:
demo <- bs_viewer_example()
if (interactive()) bs_app(demo$results, images = demo$images,
title = "My slide collection")
# When the app has stopped:
unlink(demo$directory, recursive = TRUE)

For your data, pass an image manifest with image_id, slide_id, path and
optional annotations and label columns. PNG/JPEG previews and saved overlays
work directly. Native whole-slide images use an optional OpenSlide Python reader;
QuPath GeoJSON supplies selectable points and polygons with their recorded
measurements. Multiple images or regions may link to one slide. group_by and
group_label customize the tissue filter; title customizes the heading.
Passing a result file path enables refresh of saved measurements; Watch saved files also refreshes exported annotations. It never edits the source project or reruns analysis. See the viewer tutorial for coordinate transforms, Python setup, format limits and complete examples.
# Adapt a preserved study summary, or use profile = "canonical" for a canonical CSV.
# results <- bs_import_legacy("path/to/analysis.json")
results <- bs_example()
results$groups <- bs_summarize(results, strata = "organ")
# New destinations only: existing deliveries are never overwritten.
delivery <- tempfile("bloodspottr-report-")
report <- bs_report(
results, delivery, author = "RH",
background = "Synthetic demonstration of calibrated slide reporting."
)
report
list.files(delivery)
bs_report() writes self-contained HTML, CSV tables, canonical JSON and a
SHA-256 manifest. Supplied comparisons also receive a Comparison.csv table.
Canonical JSON preserves their run names and excluded-slide IDs in
comparison_context; reimport restores these attributes and the HTML report
states the comparison direction. Standalone comparison CSVs need this context
alongside them.
bs_export_results() writes the table bundle without HTML;
xlsx = TRUE adds a workbook when openxlsx2 is installed. Large images,
individual annotation geometry and training weights remain separate artifacts.
The initial package renderer does not recreate the study-specific TeX/PDF image
supplement; its HTML can be printed from a browser.
| Area | Implemented interface |
|---|---|
| Project metadata |
bs_project(), bs_status()
|
| Preserved measurements |
bs_import_legacy(), bs_validate(), bs_summarize()
|
| Paired comparison |
bs_compare() with explicit shared-support checks |
| Review records | Saved-artifact review plans and confirmation receipts |
| Backend boundary | Versioned requests and explicit executable invocation |
| Suite reuse |
bs_cttir_inventory(), calibrated bs_as_cellspec() exchange |
| Results |
bs_export_results(), bs_report(), bs_app()
|
| Existing measurement core |
measure_burden(), aggregate_burden(), measure_event_burden(), aggregate_event_burden()
|
| Color and profile shape |
bs_color_features(), bs_profile_extent()
|
| Optional spatial geometry |
tissue_window(), cell_pattern()
|
The package inventories source metadata across a chosen CTTIR suite directory without loading or installing those packages. Runtime compatibility is tested for the implemented cellspecR exchange; other adapters require qualification within their respective scopes.
After installation with vignettes:
vignette("bloodspottr-workflow", package = "bloodspottR")
vignette("cttir-interoperability", package = "bloodspottR")
vignette("review-and-backends", package = "bloodspottR")
vignette("shiny-results-explorer", package = "bloodspottR")
| Tutorial | Start here when you want to… |
|---|---|
| Measurements to a report | Import, pool, compare and export slide measurements |
| Shiny results explorer | Upload data, filter slides and interpret missing values |
| CTTIR interoperability | Exchange calibrated candidates with cellspecR |
| Review and backends | Record saved reviews and invoke a trusted external worker |
The vignettes use runnable synthetic examples and state each interface's limits. Function help documents the implemented interfaces. Example data are synthetic.
The test suite covers exact-count boundaries, missing support, pooled rates, transactional exports, review receipts, worker failures and calibrated exchange. CI calls the shared CTTIR package-check, coverage and house-lint workflows. Check the linked workflow results for the current commit; a configured workflow alone does not establish cross-platform qualification. Software checks and visual inspection do not establish biological accuracy.
The Shiny application inspects recorded results, preview images and OpenSlide-supported whole-slide images. Native inference, portable DNN training, QuPath project writeback and generic slide image PDF supplements remain separate work. Configured external workers are trusted code, not a security sandbox. Missing measurements remain unknown, and low-signal slides are not inferred controls. Worker execution requires processx and ps. The runner tracks process ancestry and verifies termination of observed descendants before committing output. Workers must join helpers before successful exit; intentionally detached processes are unsupported. Captured logs are limited to 10 MiB per stream.
Slide IDs are nonempty character strings; keep leading zeros. Areas use mm² and
densities use counts/mm². The explicit unit suffixes in the existing measurement
API are retained for compatibility. Missing measurements use NA; zero denotes
an observed zero. Counts must be whole and at most 2^53, including pooled
counts. Use canonical results.json for lossless metadata exchange; presentation
CSVs escape formula-like text for spreadsheet safety.
Package validation failures inherit from bloodspottr_error, so callers can
handle them with tryCatch(..., bloodspottr_error = function(e) ...). Errors from
external dependencies may retain their own classes. Report reproducible issues
through GitHub issues, using synthetic
or de-identified examples.
MIT. Copyright 2026 R. Heller. See LICENSE.md. The bundled OpenSeadragon viewer retains its BSD-3-Clause license. OpenSlide is an optional external dependency and is not bundled.
Where applicable, LLM tools were used for narrowly defined, non-authorial tasks: copyediting, prose refinement, Markdown/LaTeX formatting, boilerplate scaffolding (such as CI configurations and build scripts), and code refactoring. Tools included Chat AI, the KISSKI (GWDG) service, and self-hosted Mistral Small (24B, Apache-2.0) served through a local vLLM architecture on an Ubuntu Linux workstation with Intel processors and NVIDIA GPUs. The self-hosted model ran locally, with no data sent to third parties.
All scientific claims, methodological choices, analyses, interpretations and conclusions remain the authors' own. Where applicable, LLM-generated material must be reviewed and revised before inclusion, and references must be verified against their DOI, arXiv ID or ISBN.
Local software setup: vLLM with Python/PyTorch, plus R and RStudio.
Editable R sources and regeneration instructions are in tools/branding.