# Create a static shiny app

## 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 55103 rows, 122 different result_id, 1, 1, and
    #> 1 different cdm names, and 53 settings.
    #> CDM names: synthea-covid19-200k, mock database, and unknown.
    #> 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_level, analysis_outcome_washout, analysis_repeated_events,
    #> analysis_type, censor_date, censor_on_cohort_exit, cohort_definition_id, …,
    #> 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 1254 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 object):

    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: C:\Users\martics\AppData\Local\Temp\RtmpI5TCEC/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")
    #> README.md
    #> _brand.yml
    #> background.md
    #> data/README.md
    #> functions.R
    #> global.R
    #> rawData/README.md
    #> rawData/preprocess.R
    #> rawData/results.csv
    #> 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`.

## 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 36 predefined panels:

    omopViewerPanels
    #> $summarise_omop_snapshot
    #> [34mSnapshot[0m (OmopViewer panel)
    #> • [1m icon:[0m camera
    #> • [1m data:[0m result_type: <summarise_omop_snapshot>
    #> • [1m filters:[0m 1 filters + 1 automatic filters
    #> • [1m content:[0m [1;34mTable Snapshot[0m ([3mgt[0m)
    #>
    #> $summarise_observation_period
    #> [34mObservation period Summary[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;34mTable Observation period[0m ([3mgt[0m); [1;34mPlot Observation period[0m ([3mui[0m)
    #>
    #> $summarise_clinical_records
    #> [34mClinical Tables Summary[0m (OmopViewer panel)
    #> • [1m icon:[0m bars-staggered
    #> • [1m data:[0m result_type: <summarise_clinical_records>
    #> • [1m filters:[0m 1 filters + 5 automatic filters
    #> • [1m content:[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;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)
    #>
    #> $summarise_trend
    #> [34mTrends[0m (OmopViewer panel)
    #> • [1m icon:[0m arrow-trend-up
    #> • [1m data:[0m result_type: <summarise_trend>
    #> • [1m filters:[0m 1 filters + 6 automatic filters
    #> • [1m content:[0m [1;34mTable Trends[0m ([3mreactable[0m); [1;34mPlot Trends[0m ([3mui[0m)
    #>
    #> $summarise_concept_id_counts
    #> [34mConcept Counts[0m (OmopViewer panel)
    #> • [1m icon:[0m database
    #> • [1m data:[0m result_type: <summarise_concept_id_counts>
    #> • [1m filters:[0m 1 filters + 6 automatic filters
    #> • [1m content:[0m [1;34mTable Concept Counts[0m ([3mreactable[0m); [1;34mTop Concept Counts[0m ([3mui[0m)
    #>
    #> $summarise_person
    #> [34mPerson Table Summary[0m (OmopViewer panel)
    #> • [1m icon:[0m person
    #> • [1m data:[0m result_type: <summarise_person>
    #> • [1m filters:[0m 1 filters + 5 automatic filters
    #> • [1m content:[0m [1;34mTable Person[0m ([3mgt[0m); [1;34mPlot Person[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;34mTable Orphan codes (reactable)[0m ([3mreactable[0m); [1;34mTable Orphan codes (gt)[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;34mTable Cohort code use (reactable)[0m ([3mreactable[0m); [1;34mTable Cohort code use (gt)[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;34mTable Code use (reactable)[0m ([3mreactable[0m); [1;34mTable Code use (gt)[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;34mTable Achilles code use (reactable)[0m ([3mreactable[0m); [1;34mTable Achilles code use (gt)[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;34mTable Unmapped codes (reactable)[0m ([3mreactable[0m); [1;34mTable Unmapped codes (gt)[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;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;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;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;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;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;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 + 4 automatic filters
    #> • [1m content:[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;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 + 4 automatic filters
    #> • [1m content:[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;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;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;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;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;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;34mTable Treatments[0m ([3mgt[0m); [1;34mPlot Treatment[0m ([3mui[0m)
    #>
    #> $measurement_summary
    #> [34mMeasurement summary[0m (OmopViewer panel)
    #> • [1m icon:[0m timeline
    #> • [1m data:[0m result_type: <measurement_summary>
    #> • [1m filters:[0m 1 filters + 4 automatic filters
    #> • [1m content:[0m [1;34mTable Measurement Summary[0m ([3mgt[0m); [1;34mPlot Measurement Summary[0m ([3mui[0m)
    #>
    #> $measurement_value_as_number
    #> [34mMeasurement value as number[0m (OmopViewer panel)
    #> • [1m icon:[0m gauge-high
    #> • [1m data:[0m result_type: <measurement_value_as_number>
    #> • [1m filters:[0m 1 filters + 4 automatic filters
    #> • [1m content:[0m [1;34mTable Measurement Number[0m ([3mgt[0m); [1;34mPlot Measurement Number[0m ([3mui[0m)
    #>
    #> $measurement_value_as_concept
    #> [34mMeasurement value as concept[0m (OmopViewer panel)
    #> • [1m icon:[0m cubes
    #> • [1m data:[0m result_type: <measurement_value_as_concept>
    #> • [1m filters:[0m 1 filters + 4 automatic filters
    #> • [1m content:[0m [1;34mTable Measurement Concept[0m ([3mgt[0m); [1;34mPlot Measurement Concept[0m ([3mui[0m)
    #>
    #> $survival
    #> [34mSurvival Analyses[0m (OmopViewer panel)
    #> • [1m icon:[0m stairs
    #> • [1m data:[0m result_type: <survival_summary>, <survival_estimates>, <survival_events>, <survival_attrition>
    #> • [1m filters:[0m 1 filters + 4 automatic filters
    #> • [1m content:[0m [1;34mTable Summary[0m ([3mgt[0m); [1;34mTable Events[0m ([3mgt[0m); [1;34mTable Attrition[0m ([3mgt[0m); [1;34mPlot Survival[0m ([3mui[0m)
    #>
    #> $summarise_log_file
    #> [34mLogs[0m (OmopViewer panel)
    #> • [1m icon:[0m clipboard-list
    #> • [1m data:[0m result_type: <summarise_log_file>
    #> • [1m filters:[0m 1 filters + 1 automatic filters
    #> • [1m content:[0m [1;34mTable Logs[0m ([3mgt[0m); [1;34mPlot Timing[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 camera
    #> • [1m data:[0m result_type: <summarise_omop_snapshot>
    #> • [1m filters:[0m 1 filters + 1 automatic filters
    #> • [1m content:[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;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;34mTable Incidence[0m ([3mgt[0m); [1;34mPlot Incidence[0m ([3mui[0m); [1;34mPlot population[0m ([3mui[0m)

### Understanding Panel Details (panelDetails)

Each panel’s entry contains key information:

1. 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 …).

2. 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")
      )

3. 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.

4. 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.