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.
In this vignette we will use simply to packages:
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.
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.
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:
#> /var/folders/pl/k11lm9710hlgl02nvzx4z9wr0000gp/T//RtmpnCIQ1o/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.
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 to TRUE
and is used to customise the
landing page of the shiny app.
data
folder contains the raw result object
results.csv
and the script to process the data
preprocess.R
.
funcitons.R
contains several functions that are used
internally in the shiny app.
global.R
, ui.R
, and
server.R
define the shiny app itself.
www
contains images and logos used in the shiny app,
by default hds_logo.svg
and
ohdsi_logo.svg
.
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
#> [34mSnapshot[0m (OmopViewer panel)
#> • [1m icon:[0m clipboard-list
#> • [1m data:[0m result_type: <summarise_omop_snapshot>
#> • [1m filters:[0m 1 filters + 1 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Snapshot[0m ([3mgt[0m)
#>
#> $summarise_observation_period
#> [34mObservation period[0m (OmopViewer panel)
#> • [1m icon:[0m eye
#> • [1m data:[0m result_type: <summarise_observation_period>
#> • [1m filters:[0m 1 filters + 4 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Observation period[0m ([3mgt[0m); [1;34mPlot Observation period[0m ([3mui[0m)
#>
#> $summarise_clinical_records
#> [34mClinical records[0m (OmopViewer panel)
#> • [1m icon:[0m bars-staggered
#> • [1m data:[0m result_type: <summarise_clinical_records>
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Clinical records[0m ([3mgt[0m)
#>
#> $summarise_record_count
#> [34mRecord count[0m (OmopViewer panel)
#> • [1m icon:[0m signal
#> • [1m data:[0m result_type: <summarise_record_count>
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mPlot record count[0m ([3mui[0m)
#>
#> $summarise_missing_data
#> [34mMissing data[0m (OmopViewer panel)
#> • [1m icon:[0m circle-exclamation
#> • [1m data:[0m result_type: <summarise_missing_data>
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Missing data[0m ([3mgt[0m)
#>
#> $summarise_in_observation
#> [34mIn Observation[0m (OmopViewer panel)
#> • [1m icon:[0m explosion
#> • [1m data:[0m result_type: <summarise_in_observation>
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mPlot in observation[0m ([3mui[0m)
#>
#> $orphan_code_use
#> [34mOrphan codes[0m (OmopViewer panel)
#> • [1m icon:[0m magnifying-glass-arrow-right
#> • [1m data:[0m result_type: <orphan_code_use>
#> • [1m filters:[0m 1 filters + 4 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Orphan codes[0m ([3mgt[0m)
#>
#> $cohort_code_use
#> [34mCohort code use[0m (OmopViewer panel)
#> • [1m icon:[0m chart-column
#> • [1m data:[0m result_type: <cohort_code_use>
#> • [1m filters:[0m 1 filters + 4 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Cohort code use[0m ([3mgt[0m)
#>
#> $code_use
#> [34mCode use[0m (OmopViewer panel)
#> • [1m icon:[0m chart-column
#> • [1m data:[0m result_type: <code_use>
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Code use[0m ([3mgt[0m)
#>
#> $achilles_code_use
#> [34mAchilles code use[0m (OmopViewer panel)
#> • [1m icon:[0m chart-column
#> • [1m data:[0m result_type: <achilles_code_use>
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Achilles code use[0m ([3mgt[0m)
#>
#> $unmapped_codes
#> [34mUnmapped codes[0m (OmopViewer panel)
#> • [1m icon:[0m chart-column
#> • [1m data:[0m result_type: <unmapped_codes>
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Unmapped codes[0m ([3mgt[0m)
#>
#> $summarise_cohort_overlap
#> [34mCohort Overlap[0m (OmopViewer panel)
#> • [1m icon:[0m circle-half-stroke
#> • [1m data:[0m result_type: <summarise_cohort_overlap>
#> • [1m filters:[0m 1 filters + 5 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Overlap[0m ([3mgt[0m); [1;34mPlot Overlap[0m ([3mui[0m)
#>
#> $summarise_cohort_count
#> [34mCohort Count[0m (OmopViewer panel)
#> • [1m icon:[0m users
#> • [1m data:[0m result_type: <summarise_cohort_count>
#> • [1m filters:[0m 1 filters + 4 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Counts[0m ([3mgt[0m); [1;34mPlot Counts[0m ([3mui[0m)
#>
#> $summarise_cohort_attrition
#> [34mCohort Attrition[0m (OmopViewer panel)
#> • [1m icon:[0m layer-group
#> • [1m data:[0m result_type: <summarise_cohort_attrition>
#> • [1m filters:[0m 1 filters + 2 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Attrition[0m ([3mgt[0m); [1;34mDiagram[0m ([3mgrViz[0m)
#>
#> $summarise_cohort_timing
#> [34mCohort Timing[0m (OmopViewer panel)
#> • [1m icon:[0m chart-simple
#> • [1m data:[0m result_type: <summarise_cohort_timing>
#> • [1m filters:[0m 1 filters + 2 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Timing[0m ([3mgt[0m); [1;34mPlot Timing[0m ([3mui[0m)
#>
#> $summarise_characteristics
#> [34mCohort Characteristics[0m (OmopViewer panel)
#> • [1m icon:[0m users-gear
#> • [1m data:[0m result_type: <summarise_characteristics>
#> • [1m filters:[0m 1 filters + 4 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Characteristics[0m ([3mgt[0m); [1;34mPlot Characteristics[0m ([3mui[0m)
#>
#> $summarise_large_scale_characteristics
#> [34mLarge Scale Characteristics[0m (OmopViewer panel)
#> • [1m icon:[0m arrow-up-right-dots
#> • [1m data:[0m result_type: <summarise_large_scale_characteristics>
#> • [1m filters:[0m 1 filters + 4 automatic filters
#> • [1m content:[0m [1;34mTable[0m ([3mreactable[0m); [1;34mMost common codes[0m ([3mgt[0m); [1;34mPlot Compared[0m ([3mplotly[0m)
#>
#> $incidence
#> [34mIncidence[0m (OmopViewer panel)
#> • [1m icon:[0m chart-line
#> • [1m data:[0m result_type: <incidence>
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Incidence[0m ([3mgt[0m); [1;34mPlot Incidence[0m ([3mui[0m); [1;34mPlot population[0m ([3mui[0m)
#>
#> $incidence_attrition
#> [34mIncidence Attrition[0m (OmopViewer panel)
#> • [1m icon:[0m layer-group
#> • [1m data:[0m result_type: <incidence_attrition>
#> • [1m filters:[0m 1 filters + 2 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Incidence Attrition[0m ([3mgt[0m)
#>
#> $prevalence
#> [34mPrevalence[0m (OmopViewer panel)
#> • [1m icon:[0m chart-column
#> • [1m data:[0m result_type: <prevalence>
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Prevalence[0m ([3mgt[0m); [1;34mPlot Prevalence[0m ([3mui[0m); [1;34mPlot population[0m ([3mui[0m)
#>
#> $prevalence_attrition
#> [34mPrevalence Attrition[0m (OmopViewer panel)
#> • [1m icon:[0m layer-group
#> • [1m data:[0m result_type: <prevalence_attrition>
#> • [1m filters:[0m 1 filters + 2 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Prevalence Attrition[0m ([3mgt[0m)
#>
#> $summarise_dose_coverage
#> [34mDose coverage[0m (OmopViewer panel)
#> • [1m icon:[0m pills
#> • [1m data:[0m result_type: <summarise_dose_coverage>
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Dose coverage[0m ([3mgt[0m)
#>
#> $summarise_proportion_of_patients_covered
#> [34mProportion of patients covered[0m (OmopViewer panel)
#> • [1m icon:[0m chart-gantt
#> • [1m data:[0m result_type: <summarise_proportion_of_patients_covered>
#> • [1m filters:[0m 1 filters + 3 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable PPC[0m ([3mgt[0m); [1;34mPlot PPC[0m ([3mui[0m)
#>
#> $summarise_drug_restart
#> [34mDrug Restart[0m (OmopViewer panel)
#> • [1m icon:[0m chart-gantt
#> • [1m data:[0m result_type: <summarise_drug_restart>
#> • [1m filters:[0m 1 filters + 3 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Drug Restart[0m ([3mgt[0m); [1;34mPlot Drug Restart[0m ([3mui[0m)
#>
#> $summarise_drug_utilisation
#> [34mDrug Utilisation[0m (OmopViewer panel)
#> • [1m icon:[0m capsules
#> • [1m data:[0m result_type: <summarise_drug_utilisation>
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Drug Utilisation[0m ([3mgt[0m); [1;34mPlot Drug Utilisation[0m ([3mui[0m)
#>
#> $summarise_indication
#> [34mIndication[0m (OmopViewer panel)
#> • [1m icon:[0m disease
#> • [1m data:[0m result_type: <summarise_indication>
#> • [1m filters:[0m 1 filters + 7 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Indication[0m ([3mgt[0m); [1;34mPlot Indication[0m ([3mui[0m)
#>
#> $summarise_treatment
#> [34mTreatments[0m (OmopViewer panel)
#> • [1m icon:[0m disease
#> • [1m data:[0m result_type: <summarise_treatment>
#> • [1m filters:[0m 1 filters + 7 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Treatments[0m ([3mgt[0m); [1;34mPlot Treatment[0m ([3mui[0m)
#>
#> $default
#> [34m<result_type>[0m (OmopViewer panel)
#> • [1m icon:[0m folder
#> • [1m data:[0m -no data-
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable[0m ([3mgt[0m)
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
#> [34mSnapshot[0m (OmopViewer panel)
#> • [1m icon:[0m clipboard-list
#> • [1m data:[0m result_type: <summarise_omop_snapshot>
#> • [1m filters:[0m 1 filters + 1 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Snapshot[0m ([3mgt[0m)
#>
#> $summarise_characteristics
#> [34mCohort Characteristics[0m (OmopViewer panel)
#> • [1m icon:[0m users-gear
#> • [1m data:[0m result_type: <summarise_characteristics>
#> • [1m filters:[0m 1 filters + 4 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Characteristics[0m ([3mgt[0m); [1;34mPlot Characteristics[0m ([3mui[0m)
#>
#> $incidence
#> [34mIncidence[0m (OmopViewer panel)
#> • [1m icon:[0m chart-line
#> • [1m data:[0m result_type: <incidence>
#> • [1m filters:[0m 1 filters + 6 automatic filters
#> • [1m content:[0m [1;34mTidy[0m ([3mDT[0m); [1;34mTable Incidence[0m ([3mgt[0m); [1;34mPlot Incidence[0m ([3mui[0m); [1;34mPlot population[0m ([3mui[0m)
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. Usually result_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.
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.
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.