Create a static shiny app
export_static_app.Rmd
Introduction
This vignette shows how to create static Shiny apps using
the OmopViewer
package. These static shiny apps are
separated projects with their own ui
, server
,
global
and files to pre-process the results that later can
easily later be customised and deployed. This functionality is adequate
if what you are willing is to deploy a shiny, customise it later and/or
be able to access this shiny app in the future. If what you want is to
visualise the data briefly and you do not need to access to the shiny in
the future, edit it or deploy it maybe the Dynamic app functionality is what are you
searching for.
Loading Necessary Libraries and Data
In this vignette we will use simply to packages:
library(OmopViewer)
library(omopgenerics, warn.conflicts = FALSE)
library(shiny)
We’ll use the omopViewerResults
mock data from this
package for illustration:
# Inspect the structure of the sample data
summary(omopViewerResults)
#> A summarised_result object with 39307 rows, 96 different result_id, 1 different
#> cdm names, and 44 settings.
#> CDM names: synthea-covid19-200k.
#> Settings: result_type, package_name, package_version, group, strata,
#> additional, min_cell_count, analysis, analysis_censor_cohort_name,
#> analysis_complete_database_intervals, analysis_full_contribution,
#> analysis_outcome_washout, analysis_repeated_events, analysis_type, censor_date,
#> cohort_definition_id, cohort_table_name, denominator_age_group, …, type, and
#> unknown_indication_table.
Subsetting the Data
For this example, we’ll use a subset of the data containing specific result types:
result <- omopViewerResults |>
filterSettings(
result_type %in% c("summarise_omop_snapshot", "summarise_characteristics", "incidence")
)
This filters the omopViewerResults
data to include only
entries where result_type is one of “summarise_omop_snapshot”,
“summarise_characteristics”, or “incidence”.
summary(result)
#> A summarised_result object with 1245 rows, 20 different result_id, 1 different
#> cdm names, and 20 settings.
#> CDM names: synthea-covid19-200k.
#> Settings: result_type, package_name, package_version, group, strata,
#> additional, min_cell_count, analysis_censor_cohort_name,
#> analysis_complete_database_intervals, analysis_outcome_washout,
#> analysis_repeated_events, denominator_age_group,
#> denominator_days_prior_observation, denominator_end_date,
#> denominator_requirements_at_entry, denominator_sex, denominator_start_date,
#> denominator_target_cohort_name, denominator_time_at_risk, and table_name.
Generating the Shiny App
The exportStaticApp function generates a Shiny app from the prepared
data. Using the default parameters, it only requires a directory to save
the app and the processed data (a
dir <- tempdir()
exportStaticApp(result = result, directory = dir)
#> ℹ Processing data
#> ✔ Data processed: 3 panels idenfied: `summarise_omop_snapshot`,
#> `summarise_characteristics`, and `incidence`.
#> ℹ Creating shiny from provided data
#> ✔ Shiny created in: /tmp/Rtmperk6FQ/shiny
Note that by default if executed in an interactive environment like
R Studio the project will be opened in a separated window. Use
open = FALSE
if you do not wish to open the shiny app after
generating it.
Generated shiny app
See that this created a new project shiny in the specified directory along with some files:
cat(list.files(path = here::here(dir, "shiny"), recursive = TRUE), sep = "\n")
#> background.md
#> data/preprocess.R
#> data/results.csv
#> functions.R
#> global.R
#> server.R
#> shiny.Rproj
#> ui.R
#> www/hds_logo.svg
#> www/ohdsi_logo.svg
background.R
is only generated if background argument is set toTRUE
and is used to customise the landing page of the shiny app.data
folder contains the raw result objectresults.csv
and the script to process the datapreprocess.R
.funcitons.R
contains several functions that are used internally in the shiny app.global.R
,ui.R
, andserver.R
define the shiny app itself.www
contains images and logos used in the shiny app, by defaulthds_logo.svg
andohdsi_logo.svg
.
Panels generated (panelDetails)
The shiny generated contained a total of 3 panels, this was
determined by the argument panelDetails
. Each element in
panelDetails
will be used to create a different panel in
the shiny app. The package contains in total 28 predefined panels:
omopViewerPanels
#> $summarise_omop_snapshot
#> Snapshot (OmopViewer panel)
#> • icon: clipboard-list
#> • data: result_type: <summarise_omop_snapshot>
#> • filters: 1 filters + 1 automatic filters
#> • content: Tidy (DT); Table Snapshot (gt)
#>
#> $summarise_observation_period
#> Observation period (OmopViewer panel)
#> • icon: eye
#> • data: result_type: <summarise_observation_period>
#> • filters: 1 filters + 4 automatic filters
#> • content: Tidy (DT); Table Observation period (gt); Plot Observation period (ui)
#>
#> $summarise_clinical_records
#> Clinical records (OmopViewer panel)
#> • icon: bars-staggered
#> • data: result_type: <summarise_clinical_records>
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Table Clinical records (gt)
#>
#> $summarise_record_count
#> Record count (OmopViewer panel)
#> • icon: signal
#> • data: result_type: <summarise_record_count>
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Plot record count (ui)
#>
#> $summarise_missing_data
#> Missing data (OmopViewer panel)
#> • icon: circle-exclamation
#> • data: result_type: <summarise_missing_data>
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Table Missing data (gt)
#>
#> $summarise_in_observation
#> In Observation (OmopViewer panel)
#> • icon: explosion
#> • data: result_type: <summarise_in_observation>
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Plot in observation (ui)
#>
#> $orphan_code_use
#> Orphan codes (OmopViewer panel)
#> • icon: magnifying-glass-arrow-right
#> • data: result_type: <orphan_code_use>
#> • filters: 1 filters + 4 automatic filters
#> • content: Tidy (DT); Table Orphan codes (gt)
#>
#> $cohort_code_use
#> Cohort code use (OmopViewer panel)
#> • icon: chart-column
#> • data: result_type: <cohort_code_use>
#> • filters: 1 filters + 4 automatic filters
#> • content: Tidy (DT); Table Cohort code use (gt)
#>
#> $code_use
#> Code use (OmopViewer panel)
#> • icon: chart-column
#> • data: result_type: <code_use>
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Table Code use (gt)
#>
#> $achilles_code_use
#> Achilles code use (OmopViewer panel)
#> • icon: chart-column
#> • data: result_type: <achilles_code_use>
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Table Achilles code use (gt)
#>
#> $unmapped_codes
#> Unmapped codes (OmopViewer panel)
#> • icon: chart-column
#> • data: result_type: <unmapped_codes>
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Table Unmapped codes (gt)
#>
#> $summarise_cohort_overlap
#> Cohort Overlap (OmopViewer panel)
#> • icon: circle-half-stroke
#> • data: result_type: <summarise_cohort_overlap>
#> • filters: 1 filters + 5 automatic filters
#> • content: Tidy (DT); Table Overlap (gt); Plot Overlap (ui)
#>
#> $summarise_cohort_count
#> Cohort Count (OmopViewer panel)
#> • icon: users
#> • data: result_type: <summarise_cohort_count>
#> • filters: 1 filters + 4 automatic filters
#> • content: Tidy (DT); Table Counts (gt); Plot Counts (ui)
#>
#> $summarise_cohort_attrition
#> Cohort Attrition (OmopViewer panel)
#> • icon: layer-group
#> • data: result_type: <summarise_cohort_attrition>
#> • filters: 1 filters + 2 automatic filters
#> • content: Tidy (DT); Table Attrition (gt); Diagram (grViz)
#>
#> $summarise_cohort_timing
#> Cohort Timing (OmopViewer panel)
#> • icon: chart-simple
#> • data: result_type: <summarise_cohort_timing>
#> • filters: 1 filters + 2 automatic filters
#> • content: Tidy (DT); Table Timing (gt); Plot Timing (ui)
#>
#> $summarise_characteristics
#> Cohort Characteristics (OmopViewer panel)
#> • icon: users-gear
#> • data: result_type: <summarise_characteristics>
#> • filters: 1 filters + 4 automatic filters
#> • content: Tidy (DT); Table Characteristics (gt); Plot Characteristics (ui)
#>
#> $summarise_large_scale_characteristics
#> Large Scale Characteristics (OmopViewer panel)
#> • icon: arrow-up-right-dots
#> • data: result_type: <summarise_large_scale_characteristics>
#> • filters: 1 filters + 4 automatic filters
#> • content: Table (reactable); Most common codes (gt); Plot Compared (plotly)
#>
#> $incidence
#> Incidence (OmopViewer panel)
#> • icon: chart-line
#> • data: result_type: <incidence>
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Table Incidence (gt); Plot Incidence (ui); Plot population (ui)
#>
#> $incidence_attrition
#> Incidence Attrition (OmopViewer panel)
#> • icon: layer-group
#> • data: result_type: <incidence_attrition>
#> • filters: 1 filters + 2 automatic filters
#> • content: Tidy (DT); Table Incidence Attrition (gt)
#>
#> $prevalence
#> Prevalence (OmopViewer panel)
#> • icon: chart-column
#> • data: result_type: <prevalence>
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Table Prevalence (gt); Plot Prevalence (ui); Plot population (ui)
#>
#> $prevalence_attrition
#> Prevalence Attrition (OmopViewer panel)
#> • icon: layer-group
#> • data: result_type: <prevalence_attrition>
#> • filters: 1 filters + 2 automatic filters
#> • content: Tidy (DT); Table Prevalence Attrition (gt)
#>
#> $summarise_dose_coverage
#> Dose coverage (OmopViewer panel)
#> • icon: pills
#> • data: result_type: <summarise_dose_coverage>
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Table Dose coverage (gt)
#>
#> $summarise_proportion_of_patients_covered
#> Proportion of patients covered (OmopViewer panel)
#> • icon: chart-gantt
#> • data: result_type: <summarise_proportion_of_patients_covered>
#> • filters: 1 filters + 3 automatic filters
#> • content: Tidy (DT); Table PPC (gt); Plot PPC (ui)
#>
#> $summarise_drug_restart
#> Drug Restart (OmopViewer panel)
#> • icon: chart-gantt
#> • data: result_type: <summarise_drug_restart>
#> • filters: 1 filters + 3 automatic filters
#> • content: Tidy (DT); Table Drug Restart (gt); Plot Drug Restart (ui)
#>
#> $summarise_drug_utilisation
#> Drug Utilisation (OmopViewer panel)
#> • icon: capsules
#> • data: result_type: <summarise_drug_utilisation>
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Table Drug Utilisation (gt); Plot Drug Utilisation (ui)
#>
#> $summarise_indication
#> Indication (OmopViewer panel)
#> • icon: disease
#> • data: result_type: <summarise_indication>
#> • filters: 1 filters + 7 automatic filters
#> • content: Tidy (DT); Table Indication (gt); Plot Indication (ui)
#>
#> $summarise_treatment
#> Treatments (OmopViewer panel)
#> • icon: disease
#> • data: result_type: <summarise_treatment>
#> • filters: 1 filters + 7 automatic filters
#> • content: Tidy (DT); Table Treatments (gt); Plot Treatment (ui)
#>
#> $default
#> <result_type> (OmopViewer panel)
#> • icon: folder
#> • data: -no data-
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Table (gt)
Each panel is associated with a determined result_type
as showed in the print. By default, the function
panelDetailsFromResult()
groups the results by
result_type
and displays each result_type
in a
separate panel, if a pre-build panel does not exist for that
result_type
then the default panel is used. In our
case we have pre-build panels that are:
panelDetailsFromResult(result = result)
#> $summarise_omop_snapshot
#> Snapshot (OmopViewer panel)
#> • icon: clipboard-list
#> • data: result_type: <summarise_omop_snapshot>
#> • filters: 1 filters + 1 automatic filters
#> • content: Tidy (DT); Table Snapshot (gt)
#>
#> $summarise_characteristics
#> Cohort Characteristics (OmopViewer panel)
#> • icon: users-gear
#> • data: result_type: <summarise_characteristics>
#> • filters: 1 filters + 4 automatic filters
#> • content: Tidy (DT); Table Characteristics (gt); Plot Characteristics (ui)
#>
#> $incidence
#> Incidence (OmopViewer panel)
#> • icon: chart-line
#> • data: result_type: <incidence>
#> • filters: 1 filters + 6 automatic filters
#> • content: Tidy (DT); Table Incidence (gt); Plot Incidence (ui); Plot population (ui)
Understanding Panel Details (panelDetails)
Each panel’s entry contains key information:
Icon: Defines the icon displayed next to the panel, helping to visually distinguish between the different types of panels (e.g., clipboard-list, chart-line …).
Data: the fields used in data will be passed to
filterSettings()
function to determine the data that will be included in that panel. Usuallyresult_type
is the most common way (e.g.panelDetails$data <- list(result_type = "incidence")
), but other fields can be used for example:panelDetails$data <- list(result_type = "incidence", denominator_age_group = c("0 to 19", "20 to 39"))
would only include the results obtained by the following code:
result |>
filterSettings(
result_type == "incidence" &
denominator_age_group %in% c("0 to 19", "20 to 39")
)
Filters: Filters (filters + automatic_filters) that allow users to refine the results within each panel. Each panel has its own defaults. For example, the default incidence panel includes automatic_filters: “settings”, “variable_name” and filters: “cdm_name”. This means that there will be a field for any column in settings, and variable_name and cdm_name columns.
Content: Defines the types of content displayed in the panel, such as tables (DT, gt, reactable, …) and plots (ui, ggplot2, plotly, …). For example, the
summarise_omop_snapshot
panel includes a table displaying the snapshot data and a gt table generated from that snapshot data.
All of these elements - icon, data, filters, and content - can be customised by the user if needed. See more details in the customised_panels vignette.
Panel Structure (omopViewerPanels)
The arrangement of panels within the app is controlled by the
panelStructure
variable. This variable determines how
panels are grouped into logical sections or tabs within the Shiny app.
By default, the different panels are grouped by the package the produced
the result object. In this case OmopSketch,
CohortCharacteristics and IncidencePrevalence
respectively.
Customise panelStructure
ps1 <- list(
grp_1 = c("summarise_omop_snapshot", "incidence"),
grp_2 = c("summarise_characteristics")
)
exportStaticApp(result = result, directory = tempdir(), panelStructure = ps1)
This custom panelStructure
groups the
“summarise_omop_snapshot” and “incidence” result types together in
grp_1, while placing the “summarise_characteristics” result type in
grp_2. You can pass this custom structure to
exportStaticApp
to organize the panels according to your
preference.