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

Refactor #992

Merged
merged 43 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e7ab218
904 teal_data in teal_module (#924)
chlebowa Nov 22, 2023
2ad80bd
Merge branch 'main' into refactor
gogonzo Nov 22, 2023
11a786a
remove unnecessary
gogonzo Nov 22, 2023
a9e7902
Merge remote-tracking branch 'origin/main' into refactor
gogonzo Nov 23, 2023
990d2a2
docs: corrects teal_data_module example and updated documentation
averissimo Nov 23, 2023
e9b3b7e
fix vignette
Nov 24, 2023
14df20d
`get_code` to return concatenated code string (#976)
kartikeyakirar Nov 29, 2023
49eca09
vignette themes (#978)
chlebowa Nov 30, 2023
5bea317
vignette filter panel (#981)
chlebowa Nov 30, 2023
8a7b24f
vignette reporting (#979)
chlebowa Nov 30, 2023
e88f47d
Merge 8a7b24f1606b2f8ada45847f77b31aba7eb82ea8 into 8ab74927a9a603ea1…
gogonzo Nov 30, 2023
6afeae7
[skip actions] Restyle files
github-actions[bot] Nov 30, 2023
021678d
fix r cmd check (except vignettes)
gogonzo Nov 30, 2023
28e1972
update example module (#991)
chlebowa Nov 30, 2023
b617482
deprecations
gogonzo Nov 30, 2023
e0ce9f4
vignette introduction (#977)
chlebowa Nov 30, 2023
c9c841f
vignette data (#990)
chlebowa Nov 30, 2023
5f651a1
Merge c9c841f71bbb680ba83e190e2b3893d1b423c4ca into 8ab74927a9a603ea1…
gogonzo Nov 30, 2023
6b05039
[skip actions] Restyle files
github-actions[bot] Nov 30, 2023
dda004d
vignette custom modules (#980)
chlebowa Nov 30, 2023
3674a5e
Merge dda004d5f5fa35c9dccfe63f3add679b7940d40c into 8ab74927a9a603ea1…
gogonzo Nov 30, 2023
4842338
[skip actions] Restyle files
github-actions[bot] Nov 30, 2023
51d2ebf
update example modules in vignettes (#993)
chlebowa Nov 30, 2023
4432294
Merge 51d2ebfde6cda66835339c3c795d0a817a33509a into 8ab74927a9a603ea1…
gogonzo Nov 30, 2023
b0fc5d9
[skip actions] Restyle files
github-actions[bot] Nov 30, 2023
b06a96a
trigger
Nov 30, 2023
77ade74
fix checks
Nov 30, 2023
8c79531
tweak NEWS
chlebowa Nov 30, 2023
3d7692f
modify error message
chlebowa Nov 30, 2023
e95ba8f
removed additional line break from code. (#989)
kartikeyakirar Dec 1, 2023
f424cd4
Update R/modules.R
averissimo Dec 1, 2023
5000351
fix unnecessary conversion from teal_data_module to teal_data
gogonzo Dec 4, 2023
a73700b
Merge remote-tracking branch 'origin/main' into refactor
gogonzo Dec 5, 2023
e01b322
remove remaining TealData artefacts
gogonzo Dec 6, 2023
17384b2
[skip actions] Roxygen Man Pages Auto Update
dependabot-preview[bot] Dec 6, 2023
3be159f
remove leftover `tdata` mentions (#998)
chlebowa Dec 6, 2023
9f8cbb9
remove unnecessary packages
gogonzo Dec 7, 2023
5a397d8
shorten example
gogonzo Dec 7, 2023
cb7a88f
984 refactor blueprint (#997)
chlebowa Dec 7, 2023
1f99e5a
- bump up teal.slice and teal.data
gogonzo Dec 8, 2023
25b06ca
vbump teal.transform dependency
gogonzo Dec 8, 2023
70cee9b
empty
gogonzo Dec 8, 2023
58282cb
empty
gogonzo Dec 8, 2023
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ tmp.*
vignettes/*.R
vignettes/*.html
vignettes/*.md
inst/doc
12 changes: 5 additions & 7 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ BugReports: https://github.com/insightsengineering/teal/issues
Depends:
R (>= 4.0),
shiny (>= 1.7.0),
teal.data (>= 0.3.0.9011),
teal.slice (>= 0.4.0.9023),
teal.transform (>= 0.4.0.9007)
teal.data (>= 0.3.0.9017),
teal.slice (>= 0.4.0.9027),
teal.transform (>= 0.4.0.9010)
Imports:
checkmate (>= 2.1.0),
jsonlite,
Expand All @@ -51,8 +51,6 @@ Imports:
utils
Suggests:
bslib,
covr,
dplyr (>= 1.0.5),
knitr (>= 1.42),
MultiAssayExperiment,
R6,
Expand All @@ -70,8 +68,8 @@ Config/Needs/verdepcheck: rstudio/shiny, insightsengineering/teal.data,
mllg/checkmate, jeroen/jsonlite, r-lib/lifecycle, daroczig/logger,
tidyverse/magrittr, r-lib/rlang, daattali/shinyjs,
insightsengineering/teal.logger, insightsengineering/teal.reporter,
insightsengineering/teal.widgets, rstudio/bslib, r-lib/covr,
tidyverse/dplyr, yihui/knitr, bioc::MultiAssayExperiment, r-lib/R6,
insightsengineering/teal.widgets, rstudio/bslib,
yihui/knitr, bioc::MultiAssayExperiment, r-lib/R6,
rstudio/rmarkdown, rstudio/shinyvalidate,
insightsengineering/teal.code, r-lib/testthat, r-lib/withr,
yaml=vubiostat/r-yaml
Expand Down
4 changes: 2 additions & 2 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Generated by roxygen2: do not edit by hand

S3method(c,teal_slices)
S3method(get_code,tdata)
S3method(get_metadata,default)
S3method(get_metadata,tdata)
S3method(join_keys,tdata)
Expand All @@ -19,6 +18,7 @@ S3method(within,teal_data_module)
export("%>%")
export(TealReportCard)
export(as.teal_slices)
export(as_tdata)
export(example_module)
export(get_code_tdata)
export(get_metadata)
Expand Down Expand Up @@ -48,7 +48,7 @@ import(shiny)
import(teal.data)
import(teal.slice)
import(teal.transform)
importFrom(lifecycle,deprecate_soft)
importFrom(lifecycle,badge)
importFrom(magrittr,"%>%")
importFrom(methods,setMethod)
importFrom(stats,setNames)
Expand Down
7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
* `data` argument in `init` now accepts `teal_data` and `teal_data_module`.
* Added `landing_popup_module` function which creates a module that will display a popup when the app starts. The popup will block access to the app until it is dismissed.
* Filter state snapshots can now be uploaded from file. See `?snapshot`.
* Added `as_tdata` function to facilitate migration of modules to the new `teal_data` class.

### Breaking changes

* `tdata` has been deprecated and replaced with `teal_data`. Support for `tdata` passed to the `data` argument in `module(server)` will be removed in the next release.
* `module(ui)` argument no longer accepts `data` and `datasets` arguments. All data dependent logic should be set in the `server` function.
* `module(server)` argument deprecated `datasets` argument. `teal_module`s' `server` functions should accept `data` (`teal_data`) instead.

### Miscellaneous

Expand Down
20 changes: 11 additions & 9 deletions R/dummy_functions.R
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,7 @@ example_datasets <- function() { # nolint
#' @return A `teal` module which can be included in the `modules` argument to [teal::init()].
#' @examples
#' app <- init(
#' data = teal_data(
#' dataset("IRIS", iris),
#' dataset("MTCARS", mtcars)
#' ),
#' data = teal_data(IRIS = iris, MTCARS = mtcars),
#' modules = example_module()
#' )
#' if (interactive()) {
Expand All @@ -93,22 +90,27 @@ example_module <- function(label = "example teal module", datanames = "all") {
module(
label,
server = function(id, data) {
checkmate::assert_class(data, "tdata")
checkmate::assert_class(data(), "teal_data")
moduleServer(id, function(input, output, session) {
output$text <- renderPrint(data[[input$dataname]]())
ns <- session$ns
updateSelectInput(session, "dataname", choices = isolate(teal.data::datanames(data())))
output$text <- renderPrint({
req(input$dataname)
data()[[input$dataname]]
})
teal.widgets::verbatim_popup_srv(
id = "rcode",
verbatim_content = attr(data, "code")(),
verbatim_content = reactive(teal.code::get_code(data())),
title = "Association Plot"
)
})
},
ui = function(id, data) {
ui = function(id) {
ns <- NS(id)
teal.widgets::standard_layout(
output = verbatimTextOutput(ns("text")),
encoding = div(
selectInput(ns("dataname"), "Choose a dataset", choices = names(data)),
selectInput(ns("dataname"), "Choose a dataset", choices = NULL),
teal.widgets::verbatim_popup_ui(ns("rcode"), "Show R code")
)
)
Expand Down
43 changes: 21 additions & 22 deletions R/get_rcode_utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -38,39 +38,38 @@ get_rcode_str_install <- function() {
#' @param datasets (`FilteredData`) object
#' @param hashes named (`list`) of hashes per dataset
#'
#' @return `character(3)` containing the following elements:
#' @return Character string concatenated from the following elements:
#' - data pre-processing code (from `data` argument in `init`)
#' - hash check of loaded objects
#' - filter code
#' - filter code (if any)
#'
#' @keywords internal
get_datasets_code <- function(datanames, datasets, hashes) {
# preprocessing code
str_prepro <- teal.data:::get_code_dependency(attr(datasets, "preprocessing_code"), names = datanames)
if (length(str_prepro) == 0) {
str_prepro <- "message('Preprocessing is empty')"
} else if (length(str_prepro) > 0) {
str_prepro <- paste0(str_prepro, "\n\n")
} else {
str_prepro <- paste(str_prepro, collapse = "\n")
}

str_hash <- paste(
paste0(
vapply(
datanames,
function(dataname) {
sprintf(
"stopifnot(%s == %s)",
deparse1(bquote(rlang::hash(.(as.name(dataname))))),
deparse1(hashes[[dataname]])
)
},
character(1)
),
collapse = "\n"
),
"\n\n"
)
# hash checks
str_hash <- vapply(datanames, function(dataname) {
sprintf(
"stopifnot(%s == %s)",
deparse1(bquote(rlang::hash(.(as.name(dataname))))),
deparse1(hashes[[dataname]])
)
}, character(1))
str_hash <- paste(str_hash, collapse = "\n")

# filter expressions
str_filter <- teal.slice::get_filter_expr(datasets, datanames)
if (str_filter == "") {
str_filter <- character(0)
}

c(str_prepro, str_hash, str_filter)
# concatenate all code
str_code <- paste(c(str_prepro, str_hash, str_filter), collapse = "\n\n")
sprintf("%s\n", str_code)
}
50 changes: 21 additions & 29 deletions R/init.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,10 @@
#' End-users: This is the most important function for you to start a
#' teal app that is composed out of teal modules.
#'
#' @param data (`TealData` or `TealDataset` or `TealDatasetConnector` or `list` or `data.frame`
#' or `MultiAssayExperiment`, `teal_data`, `teal_data_module`)\cr
#' `R6` object as returned by [teal.data::cdisc_data()], [teal.data::teal_data()],
#' [teal.data::cdisc_dataset()], [teal.data::dataset()], [teal.data::dataset_connector()] or
#' [teal.data::cdisc_dataset_connector()] or [teal_data_module()] or a single `data.frame` or
#' a `MultiAssayExperiment`
#' or a list of the previous objects or function returning a named list.
#' NOTE: teal does not guarantee reproducibility of the code when names of the list elements
#' do not match the original object names. To ensure reproducibility please use [teal.data::teal_data()]
#' or [teal.data::cdisc_data()] with `check = TRUE` enabled.
#' @param data (`teal_data`, `teal_data_module`, `named list`)\cr
#' `teal_data` object as returned by [teal.data::teal_data()] or
#' `teal_data_modules` or simply a list of a named list of objects
#' (`data.frame` or `MultiAssayExperiment`).
#' @param modules (`list`, `teal_modules` or `teal_module`)\cr
#' nested list of `teal_modules` or `teal_module` objects or a single
#' `teal_modules` or `teal_module` object. These are the specific output modules which
Expand Down Expand Up @@ -50,13 +44,10 @@
#' @include modules.R
#'
#' @examples
#' new_iris <- transform(iris, id = seq_len(nrow(iris)))
#' new_mtcars <- transform(mtcars, id = seq_len(nrow(mtcars)))
#'
#' app <- init(
#' data = teal_data(
#' dataset("new_iris", new_iris),
#' dataset("new_mtcars", new_mtcars),
#' new_iris = transform(iris, id = seq_len(nrow(iris))),
#' new_mtcars = transform(mtcars, id = seq_len(nrow(mtcars))),
#' code = "
#' new_iris <- transform(iris, id = seq_len(nrow(iris)))
#' new_mtcars <- transform(mtcars, id = seq_len(nrow(mtcars)))
Expand All @@ -74,7 +65,7 @@
#' "Iris Sepal.Length histogram",
#' server = function(input, output, session, data) {
#' output$hist <- renderPlot(
#' hist(data[["new_iris"]]()$Sepal.Length)
#' hist(data()[["new_iris"]]$Sepal.Length)
#' )
#' },
#' ui = function(id, ...) {
Expand Down Expand Up @@ -111,11 +102,22 @@ init <- function(data,
footer = tags$p(),
id = character(0)) {
logger::log_trace("init initializing teal app with: data ({ class(data)[1] }).")
if (!inherits(data, c("TealData", "teal_data", "teal_data_module"))) {
data <- teal.data::to_relational_data(data = data)
if (is.list(data) && !inherits(data, "teal_data_module")) {
checkmate::assert_list(data, names = "named")
data <- do.call(teal.data::teal_data, data)
}
if (inherits(data, "TealData")) {
lifecycle::deprecate_stop(
when = "0.99.0",
what = "init(data)",
paste(
"TealData is no longer supported. Use teal_data() instead.",
"Please follow migration instructions https://github.com/insightsengineering/teal/discussions/988."
)
)
}

checkmate::assert_multi_class(data, c("TealData", "teal_data", "teal_data_module"))
checkmate::assert_multi_class(data, c("teal_data", "teal_data_module"))
checkmate::assert_multi_class(modules, c("teal_module", "list", "teal_modules"))
checkmate::assert_string(title, null.ok = TRUE)
checkmate::assert(
Expand Down Expand Up @@ -147,12 +149,6 @@ init <- function(data,
as.list(hashables$data@env)
} else if (inherits(data, "teal_data_module")) {
body(data$server)
} else if (hashables$data$is_pulled()) {
sapply(get_dataname(hashables$data), simplify = FALSE, function(dn) {
hashables$data$get_dataset(dn)$get_raw_data()
})
} else {
hashables$data$get_code()
}

attr(filter, "app_id") <- rlang::hash(hashables)
Expand Down Expand Up @@ -218,10 +214,6 @@ init <- function(data,
landing_module <- landing[[1L]]
do.call(landing_module$server, c(list(id = "landing_module_shiny_id"), landing_module$server_args))
}
if (inherits(data, "TealDataAbstract")) {
# copy TealData so that load won't be shared between the session
data <- data$copy(deep = TRUE)
}
filter <- deep_copy_filter(filter)
srv_teal_with_splash(id = id, data = data, modules = modules, filter = filter)
}
Expand Down
61 changes: 15 additions & 46 deletions R/module_nested_tabs.R
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,6 @@ ui_nested_tabs.teal_module <- function(id, modules, datasets, depth = 0L, is_mod
args <- isolate(teal.transform::resolve_delayed(modules$ui_args, datasets))
args <- c(list(id = ns("module")), args)

if (is_arg_used(modules$ui, "datasets")) {
args <- c(args, datasets = datasets)
}

if (is_arg_used(modules$ui, "data")) {
data <- .datasets_to_data(modules, datasets)
args <- c(args, data = list(data))
}

teal_ui <- tags$div(
id = id,
class = "teal_module",
Expand Down Expand Up @@ -243,7 +234,7 @@ srv_nested_tabs.teal_module <- function(id, datasets, modules, is_module_specifi
}

if (is_arg_used(modules$server, "data")) {
data <- .datasets_to_data(modules, datasets, trigger_data)
data <- eventReactive(trigger_data(), .datasets_to_data(modules, datasets))
args <- c(args, data = list(data))
}

Expand All @@ -252,13 +243,6 @@ srv_nested_tabs.teal_module <- function(id, datasets, modules, is_module_specifi
args <- c(args, filter_panel_api = filter_panel_api)
}

if (is_arg_used(modules$server, "datasets") && is_arg_used(modules$server, "data")) {
warning(
"Module '", modules$label, "' has `data` and `datasets` arguments in the formals.",
"\nIt's recommended to use `data` to work with filtered objects."
)
}

# observe the trigger_module above to induce the module once the renderUI is triggered
observeEvent(
ignoreNULL = TRUE,
Expand All @@ -277,25 +261,20 @@ srv_nested_tabs.teal_module <- function(id, datasets, modules, is_module_specifi
})
}

#' Convert `FilteredData` to reactive list of datasets of the `tdata` type.
#' Convert `FilteredData` to reactive list of datasets of the `teal_data` type.
#'
#' Converts `FilteredData` object to `tdata` object containing datasets needed for a specific module.
#' Converts `FilteredData` object to `teal_data` object containing datasets needed for a specific module.
#' Please note that if module needs dataset which has a parent, then parent will be also returned.
#' A hash per `dataset` is calculated internally and returned in the code.
#'
#' @param module (`teal_module`) module where needed filters are taken from
#' @param datasets (`FilteredData`) object where needed data are taken from
#' @param trigger_data (`reactiveVal`) to trigger getting the filtered data
#' @return list of reactive datasets with following attributes:
#' - `code` (`character`) containing datasets reproducible code.
#' - `join_keys` (`join_keys`) containing relationships between datasets.
#' - `metadata` (`list`) containing metadata of datasets.
#' @return A `teal_data` object.
#'
#' @keywords internal
.datasets_to_data <- function(module, datasets, trigger_data = reactiveVal(1L)) {
.datasets_to_data <- function(module, datasets) {
checkmate::assert_class(module, "teal_module")
checkmate::assert_class(datasets, "FilteredData")
checkmate::assert_class(trigger_data, "reactiveVal")

datanames <- if (is.null(module$datanames) || identical(module$datanames, "all")) {
datasets$datanames()
Expand All @@ -304,29 +283,19 @@ srv_nested_tabs.teal_module <- function(id, datasets, modules, is_module_specifi
}

# list of reactive filtered data
data <- sapply(
datanames,
function(x) eventReactive(trigger_data(), datasets$get_data(x, filtered = TRUE)),
simplify = FALSE
)
data <- sapply(datanames, function(x) datasets$get_data(x, filtered = TRUE), simplify = FALSE)

hashes <- calculate_hashes(datanames, datasets)
metadata <- sapply(datanames, datasets$get_metadata, simplify = FALSE)

new_tdata(
data,
eventReactive(
trigger_data(),
{
c(
get_rcode_str_install(),
get_rcode_libraries(),
get_datasets_code(datanames, datasets, hashes)
)
}
),
datasets$get_join_keys(),
metadata
code <- c(
get_rcode_str_install(),
get_rcode_libraries(),
get_datasets_code(datanames, datasets, hashes)
)

do.call(
teal.data::teal_data,
args = c(data, code = list(code), join_keys = list(datasets$get_join_keys()[datanames]))
)
}

Expand Down
Loading