--- title: "Visualizing pathway-level data with wikiprofiler" format: html execute: warning: false message: false vignette: > %\VignetteIndexEntry{Visualizing pathway-level data with wikiprofiler} %\VignetteEngine{quarto::html} %\VignetteEncoding{UTF-8} --- ```{r} #| include: false knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 11, fig.height = 7, dpi = 144, warning = FALSE, message = FALSE ) ``` ## Overview `wikiprofiler` is designed around a pipe-friendly grammar for pathway graphics. The core idea is simple: start with a pathway plot, add a data-mapping layer, and then add optional visual refinements. The newer APIs extend that same design upstream and downstream: `wp_map()` prepares data before plotting, `wp_comparefill()` adds a comparison layer, and `wp_render()` scales the workflow to pathway batches. This vignette walks through the current workflow in English, with the `wp_*` functions written in a pipe-oriented style whenever composition makes sense. ## Setup ```{r} library(wikiprofiler) library(clusterProfiler) library(DOSE) library(org.Hs.eg.db) library(knitr) ``` ## A minimal input object The example below uses `DOSE::geneList` together with `clusterProfiler::enrichWP()` so that the same objects can be reused across the basic plotting, comparison plotting, and batch rendering sections. ```{r} data(geneList, package = "DOSE") de <- names(geneList)[1:100] wp_res <- enrichWP(de, organism = "Homo sapiens") wp_tbl <- as.data.frame(wp_res) de_symbol <- bitr( de, fromType = "ENTREZID", toType = "SYMBOL", OrgDb = "org.Hs.eg.db" ) value <- stats::setNames(geneList[de_symbol[, 1]], de_symbol[, 2]) pathway_id <- wp_tbl$ID[1] kable(head(wp_tbl[, c("ID", "Description", "p.adjust")], 5), digits = 4) ``` ## Build a single pathway plot with pipes The most direct workflow starts with `wpplot()`, adds a fill layer with `wp_bgfill()`, and then improves label readability with `wp_shadowtext()`. ```{r} wpplot(pathway_id) |> wp_bgfill( value = value, low = "darkgreen", high = "firebrick", legend_x = 0.88, legend_y = 0.95 ) |> wp_shadowtext(bg.r = 2, bg.col = "white") ``` If you want to save the final plot, keep the piped object and pass it to `wpsave()`. ```{r} p_single <- wpplot(pathway_id) |> wp_bgfill( value = value, low = "darkgreen", high = "firebrick", legend_x = 0.88, legend_y = 0.95 ) |> wp_shadowtext() single_png <- file.path(tempdir(), "wikiprofiler-single-demo.png") wpsave(p_single, single_png, width = 11, height = 7) single_png ``` ## Prepare plotting values with `wp_map()` `wp_bgfill()` expects a named numeric vector keyed by gene symbol. In real analyses, that is often not the format you start with. `wp_map()` fills that gap by: - mapping identifiers such as `ENTREZID` to `SYMBOL` - aggregating duplicated rows that end up at the same symbol The next example intentionally duplicates part of the table so that the aggregation step is visible. ```{r} expr_tbl <- de_symbol[1:40, c("ENTREZID", "SYMBOL")] expr_tbl$score <- unname(geneList[expr_tbl$ENTREZID]) expr_tbl_dup <- expr_tbl[1:10, ] expr_tbl_dup$score <- expr_tbl_dup$score * 0.5 expr_tbl2 <- rbind(expr_tbl, expr_tbl_dup) mapped_value <- wp_map( expr_tbl2, value_col = "score", id_col = "ENTREZID", mapping = de_symbol[, c("ENTREZID", "SYMBOL")], mapping_from = "ENTREZID", mapping_to = "SYMBOL", aggregator = "mean" ) head(mapped_value, 10) ``` `wp_map()` also stores a mapping table as an attribute so that you can inspect how each symbol-level value was produced. ```{r} mapping_table <- attr(mapped_value, "mapping_table") kable(head(mapping_table, 10), digits = 4) ``` Once the values are prepared, they drop directly into the same pipe-oriented plotting workflow. ```{r} wpplot(pathway_id) |> wp_bgfill( value = mapped_value, low = "navy", high = "goldenrod", legend_x = 0.88, legend_y = 0.95 ) |> wp_shadowtext() ``` ## Compare two conditions with `wp_comparefill()` When both conditions are already represented as named numeric vectors keyed by symbol, `wp_comparefill()` computes the comparison values and reuses the same plotting grammar. Here the second condition is simulated from `mapped_value` only to illustrate the API. The point is the workflow shape, not the biology of this toy example. ```{r} control_value <- mapped_value case_value <- mapped_value + rep(c(-0.6, 0.9), length.out = length(mapped_value)) p_compare <- wpplot(pathway_id) |> wp_comparefill( value = case_value, control = control_value, mode = "difference", low = "steelblue4", high = "darkorange2", legend_x = 0.88, legend_y = 0.95 ) |> wp_shadowtext() p_compare ``` The comparison table is stored on the returned `wpplot` object. ```{r} kable(head(p_compare$comparison, 10), digits = 4) ``` If you prefer ratio-based contrasts, switch the mode to `log2_ratio`. ```{r} #| eval: false wpplot(pathway_id) |> wp_comparefill( value = case_value, control = control_value, mode = "log2_ratio", pseudocount = 1 ) |> wp_shadowtext() ``` ## Render multiple pathways with `wp_render()` `wp_render()` is the batch entry point. It accepts pathway IDs directly, a `data.frame`, or an enrichment-like S4 object with a `result` slot. It can return a named list of `wpplot` objects, write files to disk, or do both. The example below renders the top two enriched pathways and writes them with a filename template that combines rank, pathway ID, and pathway name. ```{r} batch_dir <- file.path(tempdir(), "wikiprofiler-batch-demo") if (dir.exists(batch_dir)) { unlink(batch_dir, recursive = TRUE) } batch_plots <- wp_render( pathway = wp_tbl[, c("ID", "Description")], value = mapped_value, n = 2, name_col = "Description", dir = batch_dir, file_ext = "png", filename_template = "{index}_{id}_{name}", shadowtext = TRUE, width = 11, height = 7 ) batch_files <- list.files(batch_dir, full.names = TRUE) batch_files ``` The returned object is still useful even when you also export files. ```{r} names(batch_plots) ``` To work entirely in memory, omit `dir`. ```{r} #| eval: false plots <- wp_render( pathway = wp_res, value = mapped_value, n = 6, shadowtext = TRUE ) ``` ## A typical analysis pattern In practice, the workflow often looks like this: ```{r} #| eval: false wp_res <- enrichWP(gene_ids, organism = "Homo sapiens") mapped_value <- wp_map( expr_table, value_col = "logFC", id_col = "ENTREZID", mapping = id_map, mapping_from = "ENTREZID", mapping_to = "SYMBOL", aggregator = "mean" ) plots <- wp_render( pathway = wp_res, value = mapped_value, n = 6, dir = "wp_batch", name_col = "Description", filename_template = "{index}_{id}_{name}", shadowtext = TRUE ) ``` For two-condition analyses, pass both `value` and `control`. ```{r} #| eval: false plots <- wp_render( pathway = wp_res, value = case_value, control = control_value, n = 6, dir = "wp_compare_batch", name_col = "Description", filename_template = "{index}_{id}_{name}", shadowtext = TRUE ) ``` ## Summary The package now exposes a clearer layered workflow: - `wpplot()` starts a pathway graphic - `wp_bgfill()` and `wp_shadowtext()` add visual layers - `wp_map()` prepares data for plotting - `wp_comparefill()` adds condition-to-condition contrasts - `wp_render()` scales the same grammar to pathway batches The important part is that the plotting grammar still reads from left to right. The newer APIs do not replace that design; they make the same modular approach easier to use in real analysis pipelines.