--- title: "From Pathology Whole-Slide Images to MOFSR" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{From Pathology Whole-Slide Images to MOFSR} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ## What MOFSR accepts MOFSR does not convert a whole-slide image into features. Its input boundary is a numeric matrix with **features in rows** and **samples in columns**. Raw WSI files such as `.svs`, `.ndpi`, `.scn`, and `.mrxs` must therefore pass through an image-analysis or representation-learning workflow first. The recommended general-purpose route is [QuPath](https://qupath.github.io/). QuPath uses OpenSlide and Bio-Formats to read many pyramidal WSI formats, but support varies between scanner variants. In particular, some MRXS variants are only partially supported. Validate pixel size, channels, focal planes, and the full-resolution image before analysis; opening a thumbnail is not sufficient. See the official [QuPath format notes](https://qupath.readthedocs.io/en/stable/docs/intro/formats.html) and [OpenSlide format list](https://openslide.org/formats/). ## Route A: QuPath measurements This route is suitable for interpretable cell, tissue, intensity, morphology, texture, and spatial summary features. 1. Create a QuPath project and import all slides. 2. Set the image type, pixel calibration, stain vectors, tissue regions, and tumor/stroma annotations consistently across the cohort. 3. Apply the same detection, classification, and measurement pipeline to every slide. Do not tune the pipeline using outcome labels. 4. Save the project, then use **Measure > Export measurements** to export the same columns for all images. QuPath documents the [Measurement Exporter](https://qupath.readthedocs.io/en/stable/docs/tutorials/exporting_measurements.html) as the preferred multi-image export route. 5. Aggregate cell- or tile-level rows into one feature vector per biological sample. If a patient has multiple slides, map slide IDs to patient IDs before the final aggregation. The following base-R helper converts a QuPath TSV export into a MOFSR pathology matrix. Replace `sample_from_image` when slide filenames are not the biological sample identifiers. ```{r, eval=FALSE} qupath_to_mofsr <- function( path, sample_column = "Image", sample_from_image = function(x) tools::file_path_sans_ext(basename(x))) { measurements <- utils::read.delim( path, check.names = FALSE, stringsAsFactors = FALSE ) if (!sample_column %in% names(measurements)) { stop(sprintf("Missing sample column: %s", sample_column)) } sample_ids <- sample_from_image(measurements[[sample_column]]) if (anyNA(sample_ids) || any(sample_ids == "")) { stop("Every exported row must map to a non-empty sample ID.") } numeric_columns <- vapply(measurements, is.numeric, logical(1)) feature_table <- measurements[, numeric_columns, drop = FALSE] if (ncol(feature_table) == 0L) { stop("No numeric QuPath measurements were found.") } aggregated <- stats::aggregate( feature_table, by = list(Sample = sample_ids), FUN = function(x) stats::median(x, na.rm = TRUE) ) pathology <- t(as.matrix(aggregated[, -1, drop = FALSE])) colnames(pathology) <- aggregated$Sample complete_features <- apply(pathology, 1, function(x) all(is.finite(x))) pathology <- pathology[complete_features, , drop = FALSE] if (nrow(pathology) == 0L) { stop("No complete pathology features remain after aggregation.") } pathology } pathology_matrix <- qupath_to_mofsr("qupath_measurements.tsv") ``` Median aggregation is a robust starting point, not a universal biological choice. Depending on the study, pre-specify additional summaries such as cell density, class proportions, quantiles, or spatial statistics. Feature definitions, magnification, stain normalization, segmentation model, and aggregation rules should remain fixed across the cohort. ## Route B: tile or patch embeddings For deep-learning representations, use QuPath's [TileExporter](https://qupath.readthedocs.io/en/stable/docs/advanced/exporting_images.html) to export calibrated, tissue-filtered tiles at a fixed physical resolution. Run the tiles through a pathology encoder, then aggregate tile embeddings to one vector per slide or patient. Save the result as the same features × samples matrix used above. Record at least the encoder name and version, weights, license, magnification or microns-per-pixel, tile size, tissue/tumor filter, normalization, aggregation method, and random seed. Do not mix embeddings from incompatible encoders or preprocessing pipelines in one modality matrix. ## Join pathology with other modalities Every modality must use the same unique biological sample IDs. MOFSR aligns matrices by column name in `RunMOFS()` and rejects missing or non-finite values. ```{r, eval=FALSE} common_samples <- Reduce( intersect, list( colnames(rna_matrix), colnames(protein_matrix), colnames(pathology_matrix) ) ) if (length(common_samples) < 3L) { stop("Too few matched samples remain for clustering.") } data_list <- list( RNA = rna_matrix[, common_samples, drop = FALSE], Protein = protein_matrix[, common_samples, drop = FALSE], Pathology = pathology_matrix[, common_samples, drop = FALSE] ) stopifnot( check_sample_alignment(data_list, strict = TRUE), all(vapply(data_list, function(x) all(is.finite(x)), logical(1))) ) result <- RunMOFS( data = data_list, methods = c("CPCA", "CIMLR"), max.clusters = 6, optimal.clusters = 3 ) ``` ## Minimum quality-control record - One immutable mapping from WSI file to slide, patient, and analysis sample ID. - Scanner, stain, pixel calibration, image type, and any format-reading caveats. - Tissue/tumor selection rule and failed-slide exclusions. - Feature or encoder version and exact aggregation rule. - Missingness and outlier checks performed before fusion. - Confirmation that feature extraction and preprocessing did not use outcome or final cluster labels.