I’m hosting a shiny
app written in R
on a cloud server. Its purpose is to allow users to interactively visualize spatial gene expression data from fibrosing interstitial lung disease patients. Such interactivity is useful here because there are too many possible logical comparisons between groups than what can reasonably fit in a manuscript.
At one point, I was losing track of how inputs were being processed into intermediate/final outputs. I wrote down a pen and paper version before, but it’s gotten even more complicated than that.
Nextflow
introduced me to mermaid
flowcharts. I wrote down the following on the live editor:
flowchart
input$anno_type_select -->|reactive| ROIs
ROIs --> reactiveRun
input$run --> |eventReactive| reactiveRun
reactiveRun --> |renderUI| output$customization
output$customization --> |reactive| pcaPlot
reactiveRun --> |eventReactive| contrast
contrast --> |reactive| efit
input$lfc --> |reactive| lfc
lfc --> |reactive| topTableDF
efit --> |reactive| topTableDF
contrast --> |reactive| topTableDF
topTableDF --> |downloadHandler| output$downloadTable
topTableDF --> |renderUI| output$table
efit --> |reactive| volcano
contrast --> |reactive| plotHeight
plotHeight --> |reactive| volcano
contrast --> |reactive| volcano
reactiveRun --> |eventReactive| spe_ruv_subset
spe_ruv_subset --> |eventReactive| pca_ruv_results_subset
spe_ruv_subset --> |reactive| pcaPlot
input$shapes_n --> |reactive| pcaPlot
input$colours_n --> |reactive| pcaPlot
pca_ruv_results_subset --> |reactive| pcaPlot
pcaPlot --> |renderUI| output$pca
pcaPlot --> |downloadHandler| output$downloadPCA
input$toggle_PCAcustom --> |observeEvent| toggle::PCAcustom
toggle::PCAcustom --> |uiOutput| output$customization
input$shapes_n --> |renderUI| output$customization
input$colours_n --> |renderUI| output$customization
input$toggle_customRange --> |observeEvent| toggle::show_customRange
toggle::show_customRange --> |uiOutput| output$customRange
input$customX --> |renderUI| output$customRange
input$customY --> |renderUI| output$customRange
input$customX --> |reactive| customX
input$customY --> |reactive| customY
customY --> |reactive| volcano
customX --> |reactive| volcano
input$maxOverlap --> |reactive| maxOverlap
maxOverlap --> |reactive| volcano
volcano --> |reactive| volcanoPlots
volcano --> |renderUI| output$volcanoUI
volcanoPlots --> |downloadHandler| output$downloadVolcano
input$top_n_genes --> |reactive| top_n_genes
input$heatmap_col --> |reactive| heatmap_col
input$heatmap_range --> |reactive| heatmap_range
input$heatmap_size --> |reactive| heatmap_size
input$heatmap_fontsize --> |reactive| heatmap_fontsize
reactiveRun --> |reactive| lcpm_subset_scale
spe_ruv_subset --> |reactive| lcpm_subset_scale
reactiveRun --> |reactive| colnames4heatmap
spe_ruv_subset --> |reactive| colnames4heatmap
colnames4heatmap --> |reactive| heatmap
lcpm_subset_scale --> |reactive| lcpm_subset_scale_topGenes
topTableDF --> |reactive| lcpm_subset_scale_topGenes
top_n_genes --> |reactive| lcpm_subset_scale_topGenes
heatmap_range --> |reactive| heatmap
heatmap_col --> |reactive| heatmap
heatmap_fontsize --> |reactive| heatmap
heatmap_size --> |reactive| heatmap
lcpm_subset_scale_topGenes --> |reactive| heatmap
heatmap --> |renderUI| output$heatmapUI
lcpm_subset_scale_topGenes --> |downloadHandler| output$downloadHeatmap heatmap --> |downloadHandler| output$downloadHeatmap
flowchart input$anno_type_select -->|reactive| ROIs ROIs --> reactiveRun input$run --> |eventReactive| reactiveRun reactiveRun --> |renderUI| output$customization output$customization --> |reactive| pcaPlot reactiveRun --> |eventReactive| contrast contrast --> |reactive| efit input$lfc --> |reactive| lfc lfc --> |reactive| topTableDF efit --> |reactive| topTableDF contrast --> |reactive| topTableDF topTableDF --> |downloadHandler| output$downloadTable topTableDF --> |renderUI| output$table efit --> |reactive| volcano contrast --> |reactive| plotHeight plotHeight --> |reactive| volcano contrast --> |reactive| volcano reactiveRun --> |eventReactive| spe_ruv_subset spe_ruv_subset --> |eventReactive| pca_ruv_results_subset spe_ruv_subset --> |reactive| pcaPlot input$shapes_n --> |reactive| pcaPlot input$colours_n --> |reactive| pcaPlot pca_ruv_results_subset --> |reactive| pcaPlot pcaPlot --> |renderUI| output$pca pcaPlot --> |downloadHandler| output$downloadPCA input$toggle_PCAcustom --> |observeEvent| toggle::PCAcustom toggle::PCAcustom --> |uiOutput| output$customization input$shapes_n --> |renderUI| output$customization input$colours_n --> |renderUI| output$customization input$toggle_customRange --> |observeEvent| toggle::show_customRange toggle::show_customRange --> |uiOutput| output$customRange input$customX --> |renderUI| output$customRange input$customY --> |renderUI| output$customRange input$customX --> |reactive| customX input$customY --> |reactive| customY customY --> |reactive| volcano customX --> |reactive| volcano input$maxOverlap --> |reactive| maxOverlap maxOverlap --> |reactive| volcano volcano --> |reactive| volcanoPlots volcano --> |renderUI| output$volcanoUI volcanoPlots --> |downloadHandler| output$downloadVolcano input$top_n_genes --> |reactive| top_n_genes input$heatmap_col --> |reactive| heatmap_col input$heatmap_range --> |reactive| heatmap_range input$heatmap_size --> |reactive| heatmap_size input$heatmap_fontsize --> |reactive| heatmap_fontsize reactiveRun --> |reactive| lcpm_subset_scale spe_ruv_subset --> |reactive| lcpm_subset_scale reactiveRun --> |reactive| colnames4heatmap spe_ruv_subset --> |reactive| colnames4heatmap colnames4heatmap --> |reactive| heatmap lcpm_subset_scale --> |reactive| lcpm_subset_scale_topGenes topTableDF --> |reactive| lcpm_subset_scale_topGenes top_n_genes --> |reactive| lcpm_subset_scale_topGenes heatmap_range --> |reactive| heatmap heatmap_col --> |reactive| heatmap heatmap_fontsize --> |reactive| heatmap heatmap_size --> |reactive| heatmap lcpm_subset_scale_topGenes --> |reactive| heatmap heatmap --> |renderUI| output$heatmapUI lcpm_subset_scale_topGenes --> |downloadHandler| output$downloadHeatmap heatmap --> |downloadHandler| output$downloadHeatmap
Nodes represent input, data and/or output variables. Curves represent reactive expressions or rendering functions.
Some takeaways:
- the whole thing really depends on
input$anno_type_select
andinput$run
, which are user-selected biological groups and pressing run, respectively - visual outputs (PCA, table, volcano, or heatmap) are created using
renderUI
while their downloadable counterparts are created usingdownloadHandler
- I don’t think whatever has been
renderUI
-ed can be converted into downloadable image files
- I don’t think whatever has been
- mostly straightforward except for
toggle::*
- these open customization panels that are not enabled by default
- if enabled, they have to take additional input from users
- input through
input$toggle_*
activatestoggle::*
- this activates
output$*
throughuiOutput
- since this is an
output
, this is shown to users
- since this is an
input
s are baked into theseoutput
s!!- reactive expressions take these
input
s downstream
- flowchart is written by hand, so there can be some mistakes and omissions
- but, writing it out could be helpful for really getting down to the nitty-gritty of what is exactly happening
- is there a package that can automatically generate a flowchart?
There are many other things that I could document about this app. Hosting it online for free through the Digital Alliance of Canada’s cloud was a bit of a journey. The how and why might be the topic for a part 2. In a part 3, I might document some cute tricks in R
to process data with reactivity.
You can find the entire app’s code here. The raw and processed data underpinning the app are under embargo at this time.
\ (•◡•) /