Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add two example apps to showcase DDL and Custom transformation #177

Open
wants to merge 15 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ on:
paths:
- RNA-seq/**
- basic-teal/**
- delayed-data/**
- custom-transform/**
- efficacy/**
- exploratory/**
- longitudinal/**
Expand Down Expand Up @@ -45,6 +47,8 @@ jobs:
directory:
- RNA-seq
- basic-teal
- delayed-data
- custom-transform
- efficacy
- exploratory
- longitudinal
Expand All @@ -63,6 +67,15 @@ jobs:
echo "BRANCH_NAME=main" >> $GITHUB_ENV
fi

- name: Check if deployment should be skipped
id: skip_check
run: |
if [[ "${{ matrix.channel }}" == "dev" && ("${{ matrix.directory }}" == "delayed-data" || "${{ matrix.directory }}" == "custom-transform") ]]; then
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "skip=false" >> $GITHUB_OUTPUT
fi

- name: Setup job token 🔑
id: github-token
run: |
Expand Down Expand Up @@ -150,6 +163,7 @@ jobs:

- name: Install R packages using renv and update the renv snapshot
shell: Rscript {0}
if: steps.skip_check.outputs.skip == 'false'
working-directory: ${{ matrix.directory }}
run: |
options(renv.config.cache.symlinks = FALSE)
Expand All @@ -164,7 +178,7 @@ jobs:
run: cat renv.lock

- name: Front end test to check if the app works fine
if: steps.find-cypress.outputs.has-cypress-tests == 'true'
if: steps.find-cypress.outputs.has-cypress-tests == 'true' && steps.skip_check.outputs.skip == 'false'
uses: cypress-io/github-action@v6
with:
build: npm install cypress --save-dev
Expand All @@ -175,12 +189,14 @@ jobs:

- name: Install deployment-related R package dependencies
shell: Rscript {0}
if: steps.skip_check.outputs.skip == 'false'
working-directory: ${{ matrix.directory }}
run: |
install.packages(c("BiocManager", "rsconnect"))

- name: Deploy 🖨 ${{ matrix.directory }} 🎨
shell: Rscript {0}
if: steps.skip_check.outputs.skip == 'false'
working-directory: ${{ matrix.directory }}
run: |
rsconnect::setAccountInfo(
Expand All @@ -201,6 +217,7 @@ jobs:
)

- name: Commit and push changes 📌
if: steps.skip_check.outputs.skip == 'false'
run: |
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions"
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,9 @@ rsconnect/

# Markdown generated files
*/README.html

# Node modules
*/tests/node_modules

# Teal lock file
*/teal_app.lock
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ A gallery of sample apps based on the [`teal`](https://github.com/insightsengine

The Stable version of the apps use the latest released packages while the dev version of the apps use the development packages which are installed from the `main` branch of the respective package repository. The specific versions used can be seen in the `Session Info` of the deployed app.


| Stable version | Dev version |
|---------------------------------------------------|-------------------------------------------------|
| [basic-teal](https://genentech.shinyapps.io/NEST_basic-teal_stable/) | [basic-teal](https://genentech.shinyapps.io/NEST_basic-teal_dev/) |
| [exploratory](https://genentech.shinyapps.io/NEST_exploratory_stable/) | [exploratory](https://genentech.shinyapps.io/NEST_exploratory_dev/) |
| [safety](https://genentech.shinyapps.io/NEST_safety_stable/) | [safety](https://genentech.shinyapps.io/NEST_safety_dev/) |
| [efficacy](https://genentech.shinyapps.io/NEST_efficacy_stable/) | [efficacy](https://genentech.shinyapps.io/NEST_efficacy_dev/) |
| [patient-profile](https://genentech.shinyapps.io/NEST_patient-profile_stable/) | [patient-profile](https://genentech.shinyapps.io/NEST_patient-profile_dev/)|
| [early-dev](https://genentech.shinyapps.io/NEST_early-dev_stable/) | [early-dev](https://genentech.shinyapps.io/NEST_early-dev_dev/) |
| [longitudinal](https://genentech.shinyapps.io/NEST_longitudinal_stable/) | [longitudinal](https://genentech.shinyapps.io/NEST_longitudinal_dev/) |
| [RNA-seq](https://genentech.shinyapps.io/NEST_RNA-seq_stable/) | [RNA-seq](https://genentech.shinyapps.io/NEST_RNA-seq_dev/) |
| [python](https://genentech.shinyapps.io/NEST_python_stable/) | [python](https://genentech.shinyapps.io/NEST_python_dev/) |

| Stable version | Dev version |
| -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| [basic-teal](https://genentech.shinyapps.io/NEST_basic-teal_stable/) | [basic-teal](https://genentech.shinyapps.io/NEST_basic-teal_dev/) |
| delayed-data - NOT DEPLOYED | [delayed-data](https://genentech.shinyapps.io/NEST_delayed-data_dev/) |
| custom-transform - NOT DEPLOYED | [custom-transform](https://genentech.shinyapps.io/NEST_custom-transform_dev/) |
| [exploratory](https://genentech.shinyapps.io/NEST_exploratory_stable/) | [exploratory](https://genentech.shinyapps.io/NEST_exploratory_dev/) |
| [safety](https://genentech.shinyapps.io/NEST_safety_stable/) | [safety](https://genentech.shinyapps.io/NEST_safety_dev/) |
| [efficacy](https://genentech.shinyapps.io/NEST_efficacy_stable/) | [efficacy](https://genentech.shinyapps.io/NEST_efficacy_dev/) |
| [patient-profile](https://genentech.shinyapps.io/NEST_patient-profile_stable/) | [patient-profile](https://genentech.shinyapps.io/NEST_patient-profile_dev/) |
| [early-dev](https://genentech.shinyapps.io/NEST_early-dev_stable/) | [early-dev](https://genentech.shinyapps.io/NEST_early-dev_dev/) |
| [longitudinal](https://genentech.shinyapps.io/NEST_longitudinal_stable/) | [longitudinal](https://genentech.shinyapps.io/NEST_longitudinal_dev/) |
| [RNA-seq](https://genentech.shinyapps.io/NEST_RNA-seq_stable/) | [RNA-seq](https://genentech.shinyapps.io/NEST_RNA-seq_dev/) |
| [python](https://genentech.shinyapps.io/NEST_python_stable/) | [python](https://genentech.shinyapps.io/NEST_python_dev/) |

## Running the apps

Expand Down Expand Up @@ -74,5 +74,5 @@ Adding a sample app involves the following steps:
#### Optional/Soft requirements

1. You can snapshot the teal app dependencies using `{renv}` but make sure to snapshot using GitHub references to the teal packages.
2. Create a GIF recording ([KAP](https://getkap.co/) is a good tool for this). Make sure that the dimensions of the GIF is 970x555 px and the size is about 1 MB. (It can be done by recording using KAP in 1470x840 px and rendering 5fps and downsizing 33%). Place the GIF inside the `_internal/quarto/assets/img` directory. Also, make sure that the name of the GIF is `APP_NAME.gif`. Also, make sure to place a static image with the name dimention called `APP_NAME.png` that will be displayed in the demo page when the card is not hovered.
2. Create a GIF recording ([LICEcap](https://www.cockos.com/licecap/) is a good tool for this). Make sure that the dimensions of the GIF is 970x555 px and the size is about 1 MB. Place the GIF inside the `_internal/quarto/assets/img` directory. Also, make sure that the name of the GIF is `APP_NAME.gif`. Also, make sure to place a static image with the name dimention called `APP_NAME.png` that will be displayed in the demo page when the card is not hovered.
3. Add front-end tests with the help of cypress. Copy the contents of the `js` directory within some other app's directory inside your app directory to get the node dependencies. Place the cypress tests inside the `tests/cypress` inside your app's directory. Please refer to an existing app's tests so that the `.github/deploy.yaml` will automaticall run the cypress tests.
Binary file added _internal/quarto/assets/img/custom-transform.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _internal/quarto/assets/img/custom-transform.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _internal/quarto/assets/img/delayed-data.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _internal/quarto/assets/img/delayed-data.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions _internal/quarto/demo-apps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
deployment_server: https://genentech.shinyapps.io/
apps:
- title: basic-teal
- title: delayed-data
- title: custom-transform
- title: exploratory
- title: safety
- title: efficacy
Expand Down
1 change: 1 addition & 0 deletions custom-transform/.Rprofile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
source("renv/activate.R")
20 changes: 20 additions & 0 deletions custom-transform/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

<!-- Generated by app_readme_template.Rmd and generate_app_readme.R: do not edit by hand-->

# custom-transform app

### Run the app yourself

source("https://raw.github.com/insightsengineering/teal.gallery/main/_internal/utils/sourceme.R")

# Run the app
restore_and_run("custom-transform", package_repo = "https://insightsengineering.r-universe.dev")

### View the deployed app

Deployed app:
<https://genentech.shinyapps.io/NEST_custom-transform_stable>

### Preview the app

![](../_internal/quarto/assets/img/custom-transform.gif)<!-- -->
137 changes: 137 additions & 0 deletions custom-transform/app.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
library(teal)

my_transformers <- list(
teal_transform_module(
label = "Keep first 6 from IRIS",
vedhav marked this conversation as resolved.
Show resolved Hide resolved
ui = function(id) {
ns <- NS(id)
div(
checkboxInput(ns("check"), label = "Toggle `head(iris)`"),
)
},
server = function(id, data) {
moduleServer(id, function(input, output, session) {
eventReactive(input$check, {
req(data())
if (input$check) {
within(data(), iris <- head(iris, 6))
} else {
data()
}
})
})
}
),
teal_transform_module(
label = "Merge datasets to get ANL",
ui = function(id) {
ns <- NS(id)
tagList(
div("Choose the two datasets to merge:"),
teal.widgets::optionalSelectInput(ns("merge_a"), "Merge A", choices = NULL),
teal.widgets::optionalSelectInput(ns("merge_b"), "Merge B", choices = NULL)
)
},
server = function(id, data) {
checkmate::assert_class(data, "reactive")
moduleServer(id, function(input, output, session) {
iv <- shinyvalidate::InputValidator$new()
iv$add_rule("merge_a", shinyvalidate::sv_required("Please select dataset A"))
iv$add_rule("merge_b", shinyvalidate::sv_required("Please select dataset B"))
iv$enable()

reactive_datanames <- reactive({
req(data())
teal.data::datanames(data())
})
observeEvent(reactive_datanames(), {
selected_a <- isolate(input$merge_a)
if (identical(selected_a, "")) selected_a <- restoreInput(session$ns("merge_a"), NULL)
teal.widgets::updateOptionalSelectInput(
session = session,
inputId = "merge_a",
choices = reactive_datanames(),
selected = restoreInput(session$ns("merge_a"), selected_a)
)

selected_b <- isolate(input$merge_b)
if (identical(selected_b, "")) selected <- restoreInput(session$ns("merge_b"), NULL)
teal.widgets::updateOptionalSelectInput(
session = session,
inputId = "merge_b",
choices = reactive_datanames(),
selected = restoreInput(session$ns("merge_b"), selected_b)
)
})

merge_a <- reactive(input$merge_a)
merge_b <- reactive(input$merge_b)
vedhav marked this conversation as resolved.
Show resolved Hide resolved

reactive({
new_data <- within(
data(),
ANL <- dplyr::left_join(merge_a, merge_b),
merge_a = tryCatch(as.name(merge_a()), error = function(e) as.name("DatasetA")),
merge_b = tryCatch(as.name(merge_b()), error = function(e) as.name("DatasetA"))
vedhav marked this conversation as resolved.
Show resolved Hide resolved
)
teal.data::datanames(new_data) <- c(teal.data::datanames(new_data), "ANL")
new_data
})
})
}
)
)

data <- teal_data() %>%
within(
{
ADSL <- teal.data::rADSL
ADTTE <- teal.data::rADTTE
iris <- iris

CO2 <- CO2
factors <- names(Filter(isTRUE, vapply(CO2, is.factor, logical(1L))))
CO2[factors] <- lapply(CO2[factors], as.character)
}
)
join_keys(data) <- default_cdisc_join_keys[c("ADSL", "ADTTE")]
teal.data::datanames(data) <- c("ADSL", "ADTTE", "iris", "CO2")

nest_logo <- "https://raw.githubusercontent.com/insightsengineering/hex-stickers/main/PNG/nest.png"
app_source <- "https://github.com/insightsengineering/teal.gallery/tree/main/basic-teal"
gh_issues_page <- "https://github.com/insightsengineering/teal.gallery/issues"

header <- tags$span(
style = "display: flex; align-items: center; justify-content: space-between; margin: 10px 0 10px 0;",
tags$span("Teal app with custom transform", style = "font-size: 30px;"),
tags$span(
style = "display: flex; align-items: center;",
tags$img(src = nest_logo, alt = "NEST logo", height = "45px", style = "margin-right:10px;"),
tags$span(style = "font-size: 24px;", "NEST @ Roche")
)
)

footer <- tags$p(
"This teal app is brought to you by the NEST Team at Roche/Genentech.
For more information, please visit:",
tags$a(href = app_source, target = "_blank", "Source Code"), ", ",
tags$a(href = gh_issues_page, target = "_blank", "Report Issues")
)
Comment on lines +95 to +114
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a comment for this PR, but all apps code is extended by 20 lines just to add a NEST logo
general issue here: #178


app <- init(
data = data,
filter = teal_slices(
teal_slice("ADSL", "SEX"),
teal_slice("ADSL", "AGE", selected = c(18L, 65L))
),
modules = modules(
example_module("Module with transformations", transformers = my_transformers),
example_module("Module with only iris transformation", transformers = my_transformers[1]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it really needed?

Suggested change
example_module("Module with only iris transformation", transformers = my_transformers[1]),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's okay to have this. Without this, we would have one module with transformers and one without it. Adding a transformation using the same object clears some misconceptions some people might have. For example, the my_transformers object can be used only once. It's an example to show that transformers are stacked and more importantly it shows that you have to pass transformers as a list and not a teal_transform_module object even when you have a single transform.

example_module("Module with no transformations")
),
title = build_app_title("Custom Transform Teal App", nest_logo),
header = header,
footer = footer
)

shinyApp(app$ui, app$server)
16 changes: 16 additions & 0 deletions custom-transform/delayed-data.Rproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Version: 1.0

RestoreWorkspace: Default
SaveWorkspace: Default
AlwaysSaveHistory: Default

EnableCodeIndexing: Yes
UseSpacesForTab: Yes
NumSpacesForTab: 2
Encoding: UTF-8

RnwWeave: Sweave
LaTeX: pdfLaTeX

AutoAppendNewline: Yes
StripTrailingWhitespace: Yes
Loading
Loading