-
-
-
+flippers. This tiny dashboard is composed of 4 steps: import the data,
+filter, create the plot and chose the geometry (points). Within each
+step (block), the user can change inputs and see the changes propagate
+in real time. Notice that the filter step requires to press a submit
+button before moving forward, which prevents the plot from appearing
+first. This is to prevent long running task from being run unecessarily.
+You can find more in other vignettes.
+
+
+You can of course start with a totally empty dashboard and create your
+own analysis from scratch.
+
+2. On the other hand, it provides **developers** with a set of tools to
+ seamlessly create new blocks, thereby enhancing the entire framework
+ and fostering **collaboration** within organizations teams. For
+ instance, regarding the previous example, below is what it takes to
+ create such dashboard.
+
``` r
library(blockr)
library(palmerpenguins)
@@ -126,6 +103,41 @@ stack <- new_stack(
serve_stack(stack)
```
+Note that the `{blockr.ggplot2}`
+[package](https://github.com/BristolMyersSquibb/blockr.ggplot2) exposes
+some ready to use blocks as shown above.
+
+## How to get started?
+
+To get started, we invite you to read this
+[vignette](https://bristolmyerssquibb.github.io/blockr/articles/blockr.html).
+
+To get a better idea of `{blockr}` capabilities in various data context,
+you can look at this
+[vignette](https://bristolmyerssquibb.github.io/blockr/articles/blockr_examples.html).
+
+## Key features
+
+1. **User-Friendly Interface**: Build data pipelines with intuitive
+ interface.
+2. **Flexibility**: Easily add, remove, or rearrange blocks in your
+ pipeline.
+3. **Extensibility**: Developers can create custom blocks to extend
+ functionality.
+4. **Reproducibility**: Pipelines created with `blockr` are easily
+ shareable and reproducible, with exportable code.
+5. **Interactivity**: Real-time feedback as you build and modify your
+ pipeline.
+
+## Installation
+
+You can install the development version of blockr from
+[GitHub](https://github.com/) with:
+
+``` r
+pak::pak("BristolMyersSquibb/blockr")
+```
+
## Contribute
Easiest is to run `make`, otherwise:
diff --git a/inst/shinylive/apps/ae-forest-plot/app.R b/inst/shinylive/apps/ae-forest-plot/app.R
new file mode 100644
index 00000000..c778c670
--- /dev/null
+++ b/inst/shinylive/apps/ae-forest-plot/app.R
@@ -0,0 +1,159 @@
+webr::install("blockr", repos = c("https://bristolmyerssquibb.github.io/webr-repos", "https://repo.r-wasm.org"))
+webr::install("blockr.pharmaverseadam", repos = c("https://bristolmyerssquibb.github.io/webr-repos", "https://repo.r-wasm.org"))
+
+library(blockr)
+library(dplyr)
+library(tidyr)
+library(forestplot)
+library(blockr.pharmaverseadam)
+
+# Function to create adverse event forest plot
+create_ae_forest_plot <- function(data, usubjid_col, arm_col, aedecod_col, n_events) {
+ data <- data |> filter(.data[[arm_col]] != "Placebo")
+ # Convert column names to strings
+ usubjid_col <- as.character(substitute(usubjid_col))
+ arm_col <- as.character(substitute(arm_col))
+ aedecod_col <- as.character(substitute(aedecod_col))
+
+ # Calculate the total number of subjects in each arm
+ n_subjects <- data |>
+ select(all_of(c(usubjid_col, arm_col))) |>
+ distinct() |>
+ group_by(across(all_of(arm_col))) |>
+ summarise(n = n(), .groups = "drop")
+
+ # Calculate AE frequencies and proportions
+ ae_summary <- data |>
+ group_by(across(all_of(c(arm_col, aedecod_col)))) |>
+ summarise(n_events = n_distinct(.data[[usubjid_col]]), .groups = "drop") |>
+ left_join(n_subjects, by = arm_col) |>
+ mutate(proportion = n_events / n)
+
+ # Select top N most frequent AEs across all arms
+ top_aes <- ae_summary |>
+ group_by(across(all_of(aedecod_col))) |>
+ summarise(total_events = sum(n_events), .groups = "drop") |>
+ top_n(n_events, total_events) |>
+ pull(all_of(aedecod_col))
+
+ # Get unique treatment arms
+ arms <- unique(data[[arm_col]])
+ if (length(arms) != 2) {
+ stop("This plot requires exactly two treatment arms.")
+ }
+ active_arm <- arms[1]
+ control_arm <- arms[2]
+
+ # Filter for top AEs and calculate relative risk
+ ae_rr <- ae_summary |>
+ filter(.data[[aedecod_col]] %in% top_aes) |>
+ pivot_wider(
+ id_cols = all_of(aedecod_col),
+ names_from = all_of(arm_col),
+ values_from = c(n_events, n, proportion)
+ ) |>
+ mutate(
+ RR = .data[[paste0("proportion_", active_arm)]] / .data[[paste0("proportion_", control_arm)]],
+ lower_ci = exp(log(RR) - 1.96 * sqrt(
+ 1 / .data[[paste0("n_events_", active_arm)]] +
+ 1 / .data[[paste0("n_events_", control_arm)]] -
+ 1 / .data[[paste0("n_", active_arm)]] -
+ 1 / .data[[paste0("n_", control_arm)]]
+ )),
+ upper_ci = exp(log(RR) + 1.96 * sqrt(
+ 1 / .data[[paste0("n_events_", active_arm)]] +
+ 1 / .data[[paste0("n_events_", control_arm)]] -
+ 1 / .data[[paste0("n_", active_arm)]] -
+ 1 / .data[[paste0("n_", control_arm)]]
+ ))
+ )
+
+ # Prepare data for forest plot
+ forest_data <- ae_rr |>
+ mutate(
+ label = paste0(
+ .data[[aedecod_col]], " (",
+ .data[[paste0("n_events_", active_arm)]], "/", .data[[paste0("n_", active_arm)]], " vs ",
+ .data[[paste0("n_events_", control_arm)]], "/", .data[[paste0("n_", control_arm)]], ")"
+ )
+ )
+
+ # Create forest plot
+ forestplot(
+ labeltext = cbind(
+ forest_data$label,
+ sprintf("%.2f (%.2f-%.2f)", forest_data$RR, forest_data$lower_ci, forest_data$upper_ci)
+ ),
+ mean = forest_data$RR,
+ lower = forest_data$lower_ci,
+ upper = forest_data$upper_ci,
+ align = c("l", "r"),
+ graphwidth = unit(60, "mm"),
+ cex = 0.9,
+ lineheight = unit(8, "mm"),
+ boxsize = 0.35,
+ col = fpColors(box = "royalblue", line = "darkblue", summary = "royalblue"),
+ txt_gp = fpTxtGp(label = gpar(cex = 0.9), ticks = gpar(cex = 0.9), xlab = gpar(cex = 0.9)),
+ xlab = paste("Relative Risk (", active_arm, " / ", control_arm, ")"),
+ zero = 1,
+ lwd.zero = 2,
+ lwd.ci = 2,
+ xticks = c(0.5, 1, 2, 4),
+ grid = TRUE,
+ title = paste("Relative Risk of Adverse Events (", active_arm, " vs ", control_arm, ")")
+ )
+}
+
+new_forest_plot_block <- function(...) {
+ new_block(
+ fields = list(
+ usubjid_col = new_select_field(
+ "USUBJID",
+ function(data) colnames(data),
+ multiple = FALSE,
+ title = "Subject ID Column"
+ ),
+ arm_col = new_select_field(
+ "ACTARM",
+ function(data) colnames(data),
+ multiple = FALSE,
+ title = "Treatment Arm Column"
+ ),
+ aedecod_col = new_select_field(
+ "AEDECOD",
+ function(data) colnames(data),
+ multiple = FALSE,
+ title = "AE Term Column"
+ ),
+ n_events = new_numeric_field(
+ 10,
+ min = 5, max = 20, step = 1,
+ title = "Number of Top AEs to Display"
+ )
+ ),
+ expr = substitute({
+ my_fun(data, .(usubjid_col), .(arm_col), .(aedecod_col), .(n_events))
+ }, list(my_fun = create_ae_forest_plot)),
+ class = c("adverse_event_plot_block", "plot_block"),
+ ...
+ )
+}
+
+# Register the custom block
+register_block(
+ new_forest_plot_block,
+ name = "Adverse Event Forest Plot",
+ description = "Create a forest plot of adverse events comparing two treatment arms",
+ classes = c("adverse_event_plot_block", "plot_block"),
+ input = "data.frame",
+ output = "plot"
+)
+
+# Create the stack
+clinical_trial_stack <- new_stack(
+ new_adam_block(selected = "adae"),
+ # filter_in_block(),
+ new_forest_plot_block()
+)
+
+serve_stack(clinical_trial_stack)
diff --git a/inst/shinylive/apps/custom-field/app.R b/inst/shinylive/apps/custom-field/app.R
new file mode 100644
index 00000000..808d7ea2
--- /dev/null
+++ b/inst/shinylive/apps/custom-field/app.R
@@ -0,0 +1,98 @@
+webr::install("blockr", repos = c("https://bristolmyerssquibb.github.io/webr-repos", "https://repo.r-wasm.org"))
+
+library(blockr)
+
+new_slider_field <- function(
+ value = numeric(),
+ min = numeric(),
+ max = numeric(),
+ step = numeric(),
+ ...) {
+ blockr::new_field(
+ value = value,
+ min = min,
+ max = max,
+ step = step,
+ ...,
+ class = "slider_field"
+ )
+}
+
+ui_input.slider_field <- function(x, id, name) {
+ shiny::sliderInput(
+ blockr::input_ids(x, id),
+ name,
+ value = blockr::value(x, "value"),
+ min = blockr::value(x, "min"),
+ max = blockr::value(x, "max"),
+ step = blockr::value(x, "step")
+ )
+}
+
+validate_field.slider_field <- function(x) {
+ val <- value(x)
+ min <- value(x, "min")
+ max <- value(x, "max")
+ step <- value(x, "step")
+
+ validate_number(val)
+
+ if (length(min)) {
+ validate_number(min, "min")
+ }
+
+ if (length(max)) {
+ validate_number(max, "max")
+ }
+
+ if (length(step)) {
+ validate_number(step, "step")
+ }
+
+ NextMethod()
+}
+
+ui_update.slider_field <- function(x, session, id, name) {
+ updateSliderInput(
+ session,
+ blockr::input_ids(x, id),
+ name,
+ blockr::value(x),
+ blockr::value(x, "min"),
+ blockr::value(x, "max"),
+ blockr::value(x, "step")
+ )
+}
+
+registerS3method("ui_input", "slider_field", ui_input.slider_field)
+registerS3method("ui_update", "slider_field", ui_update.slider_field)
+
+new_slice_block <- function(from = 0, ...) {
+
+ n_rows <- \(data) nrow(data)
+
+ fields <- list(
+ rows = new_slider_field(
+ value = from,
+ min = 0,
+ max = n_rows,
+ step = 1,
+ title = "Select rows"
+ )
+ )
+
+ new_block(
+ fields = fields,
+ expr = quote(dplyr::slice(seq_len(.(rows)))),
+ name = "Slider slice block",
+ ...,
+ class = c("slice_block", "transform_block")
+ )
+}
+
+serve_stack(
+ new_stack(
+ new_dataset_block("iris"),
+ new_slice_block(5)
+ )
+)
diff --git a/inst/shinylive/apps/dataset-block/app.R b/inst/shinylive/apps/dataset-block/app.R
new file mode 100644
index 00000000..2b56aeb8
--- /dev/null
+++ b/inst/shinylive/apps/dataset-block/app.R
@@ -0,0 +1,16 @@
+webr::install("blockr", repos = c("https://bristolmyerssquibb.github.io/webr-repos", "https://repo.r-wasm.org"))
+
+library(blockr)
+custom_data_block <- function(...) {
+ new_dataset_block(
+ selected = "lab",
+ package = "blockr.data",
+ ...
+ )
+}
+
+stack <- new_stack(
+ custom_data_block,
+ new_select_block
+)
+serve_stack(stack)
diff --git a/inst/shinylive/apps/empty-stack/app.R b/inst/shinylive/apps/empty-stack/app.R
new file mode 100644
index 00000000..00d69061
--- /dev/null
+++ b/inst/shinylive/apps/empty-stack/app.R
@@ -0,0 +1,11 @@
+webr::install("blockr", repos = c("https://bristolmyerssquibb.github.io/webr-repos/", "https://repo.r-wasm.org")) #nolint
+
+library(blockr)
+library(blockr.data)
+library(blockr.ggplot2)
+library(blockr.cardinal)
+library(blockr.pharmaverseadam)
+library(blockr.pharmaversesdtm)
+library(blockr.ggstatsplot)
+library(blockr.clinical.timelines)
+serve_stack(new_stack(), id = "mystack")
diff --git a/inst/shinylive/apps/filesbrowser-block/app.R b/inst/shinylive/apps/filesbrowser-block/app.R
new file mode 100644
index 00000000..4e8689b7
--- /dev/null
+++ b/inst/shinylive/apps/filesbrowser-block/app.R
@@ -0,0 +1,13 @@
+webr::install("blockr", repos = c("https://bristolmyerssquibb.github.io/webr-repos", "https://repo.r-wasm.org"))
+
+## file: app.R
+library(blockr)
+
+stack <- new_stack(
+ new_filesbrowser_block,
+ new_csv_block,
+ new_select_block
+)
+serve_stack(stack)
+
+## file: penguins.csv
diff --git a/inst/shinylive/apps/filesbrowser-block/penguins.csv b/inst/shinylive/apps/filesbrowser-block/penguins.csv
new file mode 100644
index 00000000..03e2c584
--- /dev/null
+++ b/inst/shinylive/apps/filesbrowser-block/penguins.csv
@@ -0,0 +1,345 @@
+"species","island","bill_length_mm","bill_depth_mm","flipper_length_mm","body_mass_g","sex","year"
+"Adelie","Torgersen",39.1,18.7,181,3750,"male",2007
+"Adelie","Torgersen",39.5,17.4,186,3800,"female",2007
+"Adelie","Torgersen",40.3,18,195,3250,"female",2007
+"Adelie","Torgersen",NA,NA,NA,NA,NA,2007
+"Adelie","Torgersen",36.7,19.3,193,3450,"female",2007
+"Adelie","Torgersen",39.3,20.6,190,3650,"male",2007
+"Adelie","Torgersen",38.9,17.8,181,3625,"female",2007
+"Adelie","Torgersen",39.2,19.6,195,4675,"male",2007
+"Adelie","Torgersen",34.1,18.1,193,3475,NA,2007
+"Adelie","Torgersen",42,20.2,190,4250,NA,2007
+"Adelie","Torgersen",37.8,17.1,186,3300,NA,2007
+"Adelie","Torgersen",37.8,17.3,180,3700,NA,2007
+"Adelie","Torgersen",41.1,17.6,182,3200,"female",2007
+"Adelie","Torgersen",38.6,21.2,191,3800,"male",2007
+"Adelie","Torgersen",34.6,21.1,198,4400,"male",2007
+"Adelie","Torgersen",36.6,17.8,185,3700,"female",2007
+"Adelie","Torgersen",38.7,19,195,3450,"female",2007
+"Adelie","Torgersen",42.5,20.7,197,4500,"male",2007
+"Adelie","Torgersen",34.4,18.4,184,3325,"female",2007
+"Adelie","Torgersen",46,21.5,194,4200,"male",2007
+"Adelie","Biscoe",37.8,18.3,174,3400,"female",2007
+"Adelie","Biscoe",37.7,18.7,180,3600,"male",2007
+"Adelie","Biscoe",35.9,19.2,189,3800,"female",2007
+"Adelie","Biscoe",38.2,18.1,185,3950,"male",2007
+"Adelie","Biscoe",38.8,17.2,180,3800,"male",2007
+"Adelie","Biscoe",35.3,18.9,187,3800,"female",2007
+"Adelie","Biscoe",40.6,18.6,183,3550,"male",2007
+"Adelie","Biscoe",40.5,17.9,187,3200,"female",2007
+"Adelie","Biscoe",37.9,18.6,172,3150,"female",2007
+"Adelie","Biscoe",40.5,18.9,180,3950,"male",2007
+"Adelie","Dream",39.5,16.7,178,3250,"female",2007
+"Adelie","Dream",37.2,18.1,178,3900,"male",2007
+"Adelie","Dream",39.5,17.8,188,3300,"female",2007
+"Adelie","Dream",40.9,18.9,184,3900,"male",2007
+"Adelie","Dream",36.4,17,195,3325,"female",2007
+"Adelie","Dream",39.2,21.1,196,4150,"male",2007
+"Adelie","Dream",38.8,20,190,3950,"male",2007
+"Adelie","Dream",42.2,18.5,180,3550,"female",2007
+"Adelie","Dream",37.6,19.3,181,3300,"female",2007
+"Adelie","Dream",39.8,19.1,184,4650,"male",2007
+"Adelie","Dream",36.5,18,182,3150,"female",2007
+"Adelie","Dream",40.8,18.4,195,3900,"male",2007
+"Adelie","Dream",36,18.5,186,3100,"female",2007
+"Adelie","Dream",44.1,19.7,196,4400,"male",2007
+"Adelie","Dream",37,16.9,185,3000,"female",2007
+"Adelie","Dream",39.6,18.8,190,4600,"male",2007
+"Adelie","Dream",41.1,19,182,3425,"male",2007
+"Adelie","Dream",37.5,18.9,179,2975,NA,2007
+"Adelie","Dream",36,17.9,190,3450,"female",2007
+"Adelie","Dream",42.3,21.2,191,4150,"male",2007
+"Adelie","Biscoe",39.6,17.7,186,3500,"female",2008
+"Adelie","Biscoe",40.1,18.9,188,4300,"male",2008
+"Adelie","Biscoe",35,17.9,190,3450,"female",2008
+"Adelie","Biscoe",42,19.5,200,4050,"male",2008
+"Adelie","Biscoe",34.5,18.1,187,2900,"female",2008
+"Adelie","Biscoe",41.4,18.6,191,3700,"male",2008
+"Adelie","Biscoe",39,17.5,186,3550,"female",2008
+"Adelie","Biscoe",40.6,18.8,193,3800,"male",2008
+"Adelie","Biscoe",36.5,16.6,181,2850,"female",2008
+"Adelie","Biscoe",37.6,19.1,194,3750,"male",2008
+"Adelie","Biscoe",35.7,16.9,185,3150,"female",2008
+"Adelie","Biscoe",41.3,21.1,195,4400,"male",2008
+"Adelie","Biscoe",37.6,17,185,3600,"female",2008
+"Adelie","Biscoe",41.1,18.2,192,4050,"male",2008
+"Adelie","Biscoe",36.4,17.1,184,2850,"female",2008
+"Adelie","Biscoe",41.6,18,192,3950,"male",2008
+"Adelie","Biscoe",35.5,16.2,195,3350,"female",2008
+"Adelie","Biscoe",41.1,19.1,188,4100,"male",2008
+"Adelie","Torgersen",35.9,16.6,190,3050,"female",2008
+"Adelie","Torgersen",41.8,19.4,198,4450,"male",2008
+"Adelie","Torgersen",33.5,19,190,3600,"female",2008
+"Adelie","Torgersen",39.7,18.4,190,3900,"male",2008
+"Adelie","Torgersen",39.6,17.2,196,3550,"female",2008
+"Adelie","Torgersen",45.8,18.9,197,4150,"male",2008
+"Adelie","Torgersen",35.5,17.5,190,3700,"female",2008
+"Adelie","Torgersen",42.8,18.5,195,4250,"male",2008
+"Adelie","Torgersen",40.9,16.8,191,3700,"female",2008
+"Adelie","Torgersen",37.2,19.4,184,3900,"male",2008
+"Adelie","Torgersen",36.2,16.1,187,3550,"female",2008
+"Adelie","Torgersen",42.1,19.1,195,4000,"male",2008
+"Adelie","Torgersen",34.6,17.2,189,3200,"female",2008
+"Adelie","Torgersen",42.9,17.6,196,4700,"male",2008
+"Adelie","Torgersen",36.7,18.8,187,3800,"female",2008
+"Adelie","Torgersen",35.1,19.4,193,4200,"male",2008
+"Adelie","Dream",37.3,17.8,191,3350,"female",2008
+"Adelie","Dream",41.3,20.3,194,3550,"male",2008
+"Adelie","Dream",36.3,19.5,190,3800,"male",2008
+"Adelie","Dream",36.9,18.6,189,3500,"female",2008
+"Adelie","Dream",38.3,19.2,189,3950,"male",2008
+"Adelie","Dream",38.9,18.8,190,3600,"female",2008
+"Adelie","Dream",35.7,18,202,3550,"female",2008
+"Adelie","Dream",41.1,18.1,205,4300,"male",2008
+"Adelie","Dream",34,17.1,185,3400,"female",2008
+"Adelie","Dream",39.6,18.1,186,4450,"male",2008
+"Adelie","Dream",36.2,17.3,187,3300,"female",2008
+"Adelie","Dream",40.8,18.9,208,4300,"male",2008
+"Adelie","Dream",38.1,18.6,190,3700,"female",2008
+"Adelie","Dream",40.3,18.5,196,4350,"male",2008
+"Adelie","Dream",33.1,16.1,178,2900,"female",2008
+"Adelie","Dream",43.2,18.5,192,4100,"male",2008
+"Adelie","Biscoe",35,17.9,192,3725,"female",2009
+"Adelie","Biscoe",41,20,203,4725,"male",2009
+"Adelie","Biscoe",37.7,16,183,3075,"female",2009
+"Adelie","Biscoe",37.8,20,190,4250,"male",2009
+"Adelie","Biscoe",37.9,18.6,193,2925,"female",2009
+"Adelie","Biscoe",39.7,18.9,184,3550,"male",2009
+"Adelie","Biscoe",38.6,17.2,199,3750,"female",2009
+"Adelie","Biscoe",38.2,20,190,3900,"male",2009
+"Adelie","Biscoe",38.1,17,181,3175,"female",2009
+"Adelie","Biscoe",43.2,19,197,4775,"male",2009
+"Adelie","Biscoe",38.1,16.5,198,3825,"female",2009
+"Adelie","Biscoe",45.6,20.3,191,4600,"male",2009
+"Adelie","Biscoe",39.7,17.7,193,3200,"female",2009
+"Adelie","Biscoe",42.2,19.5,197,4275,"male",2009
+"Adelie","Biscoe",39.6,20.7,191,3900,"female",2009
+"Adelie","Biscoe",42.7,18.3,196,4075,"male",2009
+"Adelie","Torgersen",38.6,17,188,2900,"female",2009
+"Adelie","Torgersen",37.3,20.5,199,3775,"male",2009
+"Adelie","Torgersen",35.7,17,189,3350,"female",2009
+"Adelie","Torgersen",41.1,18.6,189,3325,"male",2009
+"Adelie","Torgersen",36.2,17.2,187,3150,"female",2009
+"Adelie","Torgersen",37.7,19.8,198,3500,"male",2009
+"Adelie","Torgersen",40.2,17,176,3450,"female",2009
+"Adelie","Torgersen",41.4,18.5,202,3875,"male",2009
+"Adelie","Torgersen",35.2,15.9,186,3050,"female",2009
+"Adelie","Torgersen",40.6,19,199,4000,"male",2009
+"Adelie","Torgersen",38.8,17.6,191,3275,"female",2009
+"Adelie","Torgersen",41.5,18.3,195,4300,"male",2009
+"Adelie","Torgersen",39,17.1,191,3050,"female",2009
+"Adelie","Torgersen",44.1,18,210,4000,"male",2009
+"Adelie","Torgersen",38.5,17.9,190,3325,"female",2009
+"Adelie","Torgersen",43.1,19.2,197,3500,"male",2009
+"Adelie","Dream",36.8,18.5,193,3500,"female",2009
+"Adelie","Dream",37.5,18.5,199,4475,"male",2009
+"Adelie","Dream",38.1,17.6,187,3425,"female",2009
+"Adelie","Dream",41.1,17.5,190,3900,"male",2009
+"Adelie","Dream",35.6,17.5,191,3175,"female",2009
+"Adelie","Dream",40.2,20.1,200,3975,"male",2009
+"Adelie","Dream",37,16.5,185,3400,"female",2009
+"Adelie","Dream",39.7,17.9,193,4250,"male",2009
+"Adelie","Dream",40.2,17.1,193,3400,"female",2009
+"Adelie","Dream",40.6,17.2,187,3475,"male",2009
+"Adelie","Dream",32.1,15.5,188,3050,"female",2009
+"Adelie","Dream",40.7,17,190,3725,"male",2009
+"Adelie","Dream",37.3,16.8,192,3000,"female",2009
+"Adelie","Dream",39,18.7,185,3650,"male",2009
+"Adelie","Dream",39.2,18.6,190,4250,"male",2009
+"Adelie","Dream",36.6,18.4,184,3475,"female",2009
+"Adelie","Dream",36,17.8,195,3450,"female",2009
+"Adelie","Dream",37.8,18.1,193,3750,"male",2009
+"Adelie","Dream",36,17.1,187,3700,"female",2009
+"Adelie","Dream",41.5,18.5,201,4000,"male",2009
+"Gentoo","Biscoe",46.1,13.2,211,4500,"female",2007
+"Gentoo","Biscoe",50,16.3,230,5700,"male",2007
+"Gentoo","Biscoe",48.7,14.1,210,4450,"female",2007
+"Gentoo","Biscoe",50,15.2,218,5700,"male",2007
+"Gentoo","Biscoe",47.6,14.5,215,5400,"male",2007
+"Gentoo","Biscoe",46.5,13.5,210,4550,"female",2007
+"Gentoo","Biscoe",45.4,14.6,211,4800,"female",2007
+"Gentoo","Biscoe",46.7,15.3,219,5200,"male",2007
+"Gentoo","Biscoe",43.3,13.4,209,4400,"female",2007
+"Gentoo","Biscoe",46.8,15.4,215,5150,"male",2007
+"Gentoo","Biscoe",40.9,13.7,214,4650,"female",2007
+"Gentoo","Biscoe",49,16.1,216,5550,"male",2007
+"Gentoo","Biscoe",45.5,13.7,214,4650,"female",2007
+"Gentoo","Biscoe",48.4,14.6,213,5850,"male",2007
+"Gentoo","Biscoe",45.8,14.6,210,4200,"female",2007
+"Gentoo","Biscoe",49.3,15.7,217,5850,"male",2007
+"Gentoo","Biscoe",42,13.5,210,4150,"female",2007
+"Gentoo","Biscoe",49.2,15.2,221,6300,"male",2007
+"Gentoo","Biscoe",46.2,14.5,209,4800,"female",2007
+"Gentoo","Biscoe",48.7,15.1,222,5350,"male",2007
+"Gentoo","Biscoe",50.2,14.3,218,5700,"male",2007
+"Gentoo","Biscoe",45.1,14.5,215,5000,"female",2007
+"Gentoo","Biscoe",46.5,14.5,213,4400,"female",2007
+"Gentoo","Biscoe",46.3,15.8,215,5050,"male",2007
+"Gentoo","Biscoe",42.9,13.1,215,5000,"female",2007
+"Gentoo","Biscoe",46.1,15.1,215,5100,"male",2007
+"Gentoo","Biscoe",44.5,14.3,216,4100,NA,2007
+"Gentoo","Biscoe",47.8,15,215,5650,"male",2007
+"Gentoo","Biscoe",48.2,14.3,210,4600,"female",2007
+"Gentoo","Biscoe",50,15.3,220,5550,"male",2007
+"Gentoo","Biscoe",47.3,15.3,222,5250,"male",2007
+"Gentoo","Biscoe",42.8,14.2,209,4700,"female",2007
+"Gentoo","Biscoe",45.1,14.5,207,5050,"female",2007
+"Gentoo","Biscoe",59.6,17,230,6050,"male",2007
+"Gentoo","Biscoe",49.1,14.8,220,5150,"female",2008
+"Gentoo","Biscoe",48.4,16.3,220,5400,"male",2008
+"Gentoo","Biscoe",42.6,13.7,213,4950,"female",2008
+"Gentoo","Biscoe",44.4,17.3,219,5250,"male",2008
+"Gentoo","Biscoe",44,13.6,208,4350,"female",2008
+"Gentoo","Biscoe",48.7,15.7,208,5350,"male",2008
+"Gentoo","Biscoe",42.7,13.7,208,3950,"female",2008
+"Gentoo","Biscoe",49.6,16,225,5700,"male",2008
+"Gentoo","Biscoe",45.3,13.7,210,4300,"female",2008
+"Gentoo","Biscoe",49.6,15,216,4750,"male",2008
+"Gentoo","Biscoe",50.5,15.9,222,5550,"male",2008
+"Gentoo","Biscoe",43.6,13.9,217,4900,"female",2008
+"Gentoo","Biscoe",45.5,13.9,210,4200,"female",2008
+"Gentoo","Biscoe",50.5,15.9,225,5400,"male",2008
+"Gentoo","Biscoe",44.9,13.3,213,5100,"female",2008
+"Gentoo","Biscoe",45.2,15.8,215,5300,"male",2008
+"Gentoo","Biscoe",46.6,14.2,210,4850,"female",2008
+"Gentoo","Biscoe",48.5,14.1,220,5300,"male",2008
+"Gentoo","Biscoe",45.1,14.4,210,4400,"female",2008
+"Gentoo","Biscoe",50.1,15,225,5000,"male",2008
+"Gentoo","Biscoe",46.5,14.4,217,4900,"female",2008
+"Gentoo","Biscoe",45,15.4,220,5050,"male",2008
+"Gentoo","Biscoe",43.8,13.9,208,4300,"female",2008
+"Gentoo","Biscoe",45.5,15,220,5000,"male",2008
+"Gentoo","Biscoe",43.2,14.5,208,4450,"female",2008
+"Gentoo","Biscoe",50.4,15.3,224,5550,"male",2008
+"Gentoo","Biscoe",45.3,13.8,208,4200,"female",2008
+"Gentoo","Biscoe",46.2,14.9,221,5300,"male",2008
+"Gentoo","Biscoe",45.7,13.9,214,4400,"female",2008
+"Gentoo","Biscoe",54.3,15.7,231,5650,"male",2008
+"Gentoo","Biscoe",45.8,14.2,219,4700,"female",2008
+"Gentoo","Biscoe",49.8,16.8,230,5700,"male",2008
+"Gentoo","Biscoe",46.2,14.4,214,4650,NA,2008
+"Gentoo","Biscoe",49.5,16.2,229,5800,"male",2008
+"Gentoo","Biscoe",43.5,14.2,220,4700,"female",2008
+"Gentoo","Biscoe",50.7,15,223,5550,"male",2008
+"Gentoo","Biscoe",47.7,15,216,4750,"female",2008
+"Gentoo","Biscoe",46.4,15.6,221,5000,"male",2008
+"Gentoo","Biscoe",48.2,15.6,221,5100,"male",2008
+"Gentoo","Biscoe",46.5,14.8,217,5200,"female",2008
+"Gentoo","Biscoe",46.4,15,216,4700,"female",2008
+"Gentoo","Biscoe",48.6,16,230,5800,"male",2008
+"Gentoo","Biscoe",47.5,14.2,209,4600,"female",2008
+"Gentoo","Biscoe",51.1,16.3,220,6000,"male",2008
+"Gentoo","Biscoe",45.2,13.8,215,4750,"female",2008
+"Gentoo","Biscoe",45.2,16.4,223,5950,"male",2008
+"Gentoo","Biscoe",49.1,14.5,212,4625,"female",2009
+"Gentoo","Biscoe",52.5,15.6,221,5450,"male",2009
+"Gentoo","Biscoe",47.4,14.6,212,4725,"female",2009
+"Gentoo","Biscoe",50,15.9,224,5350,"male",2009
+"Gentoo","Biscoe",44.9,13.8,212,4750,"female",2009
+"Gentoo","Biscoe",50.8,17.3,228,5600,"male",2009
+"Gentoo","Biscoe",43.4,14.4,218,4600,"female",2009
+"Gentoo","Biscoe",51.3,14.2,218,5300,"male",2009
+"Gentoo","Biscoe",47.5,14,212,4875,"female",2009
+"Gentoo","Biscoe",52.1,17,230,5550,"male",2009
+"Gentoo","Biscoe",47.5,15,218,4950,"female",2009
+"Gentoo","Biscoe",52.2,17.1,228,5400,"male",2009
+"Gentoo","Biscoe",45.5,14.5,212,4750,"female",2009
+"Gentoo","Biscoe",49.5,16.1,224,5650,"male",2009
+"Gentoo","Biscoe",44.5,14.7,214,4850,"female",2009
+"Gentoo","Biscoe",50.8,15.7,226,5200,"male",2009
+"Gentoo","Biscoe",49.4,15.8,216,4925,"male",2009
+"Gentoo","Biscoe",46.9,14.6,222,4875,"female",2009
+"Gentoo","Biscoe",48.4,14.4,203,4625,"female",2009
+"Gentoo","Biscoe",51.1,16.5,225,5250,"male",2009
+"Gentoo","Biscoe",48.5,15,219,4850,"female",2009
+"Gentoo","Biscoe",55.9,17,228,5600,"male",2009
+"Gentoo","Biscoe",47.2,15.5,215,4975,"female",2009
+"Gentoo","Biscoe",49.1,15,228,5500,"male",2009
+"Gentoo","Biscoe",47.3,13.8,216,4725,NA,2009
+"Gentoo","Biscoe",46.8,16.1,215,5500,"male",2009
+"Gentoo","Biscoe",41.7,14.7,210,4700,"female",2009
+"Gentoo","Biscoe",53.4,15.8,219,5500,"male",2009
+"Gentoo","Biscoe",43.3,14,208,4575,"female",2009
+"Gentoo","Biscoe",48.1,15.1,209,5500,"male",2009
+"Gentoo","Biscoe",50.5,15.2,216,5000,"female",2009
+"Gentoo","Biscoe",49.8,15.9,229,5950,"male",2009
+"Gentoo","Biscoe",43.5,15.2,213,4650,"female",2009
+"Gentoo","Biscoe",51.5,16.3,230,5500,"male",2009
+"Gentoo","Biscoe",46.2,14.1,217,4375,"female",2009
+"Gentoo","Biscoe",55.1,16,230,5850,"male",2009
+"Gentoo","Biscoe",44.5,15.7,217,4875,NA,2009
+"Gentoo","Biscoe",48.8,16.2,222,6000,"male",2009
+"Gentoo","Biscoe",47.2,13.7,214,4925,"female",2009
+"Gentoo","Biscoe",NA,NA,NA,NA,NA,2009
+"Gentoo","Biscoe",46.8,14.3,215,4850,"female",2009
+"Gentoo","Biscoe",50.4,15.7,222,5750,"male",2009
+"Gentoo","Biscoe",45.2,14.8,212,5200,"female",2009
+"Gentoo","Biscoe",49.9,16.1,213,5400,"male",2009
+"Chinstrap","Dream",46.5,17.9,192,3500,"female",2007
+"Chinstrap","Dream",50,19.5,196,3900,"male",2007
+"Chinstrap","Dream",51.3,19.2,193,3650,"male",2007
+"Chinstrap","Dream",45.4,18.7,188,3525,"female",2007
+"Chinstrap","Dream",52.7,19.8,197,3725,"male",2007
+"Chinstrap","Dream",45.2,17.8,198,3950,"female",2007
+"Chinstrap","Dream",46.1,18.2,178,3250,"female",2007
+"Chinstrap","Dream",51.3,18.2,197,3750,"male",2007
+"Chinstrap","Dream",46,18.9,195,4150,"female",2007
+"Chinstrap","Dream",51.3,19.9,198,3700,"male",2007
+"Chinstrap","Dream",46.6,17.8,193,3800,"female",2007
+"Chinstrap","Dream",51.7,20.3,194,3775,"male",2007
+"Chinstrap","Dream",47,17.3,185,3700,"female",2007
+"Chinstrap","Dream",52,18.1,201,4050,"male",2007
+"Chinstrap","Dream",45.9,17.1,190,3575,"female",2007
+"Chinstrap","Dream",50.5,19.6,201,4050,"male",2007
+"Chinstrap","Dream",50.3,20,197,3300,"male",2007
+"Chinstrap","Dream",58,17.8,181,3700,"female",2007
+"Chinstrap","Dream",46.4,18.6,190,3450,"female",2007
+"Chinstrap","Dream",49.2,18.2,195,4400,"male",2007
+"Chinstrap","Dream",42.4,17.3,181,3600,"female",2007
+"Chinstrap","Dream",48.5,17.5,191,3400,"male",2007
+"Chinstrap","Dream",43.2,16.6,187,2900,"female",2007
+"Chinstrap","Dream",50.6,19.4,193,3800,"male",2007
+"Chinstrap","Dream",46.7,17.9,195,3300,"female",2007
+"Chinstrap","Dream",52,19,197,4150,"male",2007
+"Chinstrap","Dream",50.5,18.4,200,3400,"female",2008
+"Chinstrap","Dream",49.5,19,200,3800,"male",2008
+"Chinstrap","Dream",46.4,17.8,191,3700,"female",2008
+"Chinstrap","Dream",52.8,20,205,4550,"male",2008
+"Chinstrap","Dream",40.9,16.6,187,3200,"female",2008
+"Chinstrap","Dream",54.2,20.8,201,4300,"male",2008
+"Chinstrap","Dream",42.5,16.7,187,3350,"female",2008
+"Chinstrap","Dream",51,18.8,203,4100,"male",2008
+"Chinstrap","Dream",49.7,18.6,195,3600,"male",2008
+"Chinstrap","Dream",47.5,16.8,199,3900,"female",2008
+"Chinstrap","Dream",47.6,18.3,195,3850,"female",2008
+"Chinstrap","Dream",52,20.7,210,4800,"male",2008
+"Chinstrap","Dream",46.9,16.6,192,2700,"female",2008
+"Chinstrap","Dream",53.5,19.9,205,4500,"male",2008
+"Chinstrap","Dream",49,19.5,210,3950,"male",2008
+"Chinstrap","Dream",46.2,17.5,187,3650,"female",2008
+"Chinstrap","Dream",50.9,19.1,196,3550,"male",2008
+"Chinstrap","Dream",45.5,17,196,3500,"female",2008
+"Chinstrap","Dream",50.9,17.9,196,3675,"female",2009
+"Chinstrap","Dream",50.8,18.5,201,4450,"male",2009
+"Chinstrap","Dream",50.1,17.9,190,3400,"female",2009
+"Chinstrap","Dream",49,19.6,212,4300,"male",2009
+"Chinstrap","Dream",51.5,18.7,187,3250,"male",2009
+"Chinstrap","Dream",49.8,17.3,198,3675,"female",2009
+"Chinstrap","Dream",48.1,16.4,199,3325,"female",2009
+"Chinstrap","Dream",51.4,19,201,3950,"male",2009
+"Chinstrap","Dream",45.7,17.3,193,3600,"female",2009
+"Chinstrap","Dream",50.7,19.7,203,4050,"male",2009
+"Chinstrap","Dream",42.5,17.3,187,3350,"female",2009
+"Chinstrap","Dream",52.2,18.8,197,3450,"male",2009
+"Chinstrap","Dream",45.2,16.6,191,3250,"female",2009
+"Chinstrap","Dream",49.3,19.9,203,4050,"male",2009
+"Chinstrap","Dream",50.2,18.8,202,3800,"male",2009
+"Chinstrap","Dream",45.6,19.4,194,3525,"female",2009
+"Chinstrap","Dream",51.9,19.5,206,3950,"male",2009
+"Chinstrap","Dream",46.8,16.5,189,3650,"female",2009
+"Chinstrap","Dream",45.7,17,195,3650,"female",2009
+"Chinstrap","Dream",55.8,19.8,207,4000,"male",2009
+"Chinstrap","Dream",43.5,18.1,202,3400,"female",2009
+"Chinstrap","Dream",49.6,18.2,193,3775,"male",2009
+"Chinstrap","Dream",50.8,19,210,4100,"male",2009
+"Chinstrap","Dream",50.2,18.7,198,3775,"female",2009
diff --git a/inst/shinylive/apps/ggplot-block/app.R b/inst/shinylive/apps/ggplot-block/app.R
new file mode 100644
index 00000000..372d6fd6
--- /dev/null
+++ b/inst/shinylive/apps/ggplot-block/app.R
@@ -0,0 +1,46 @@
+webr::install("blockr", repos = c("https://bristolmyerssquibb.github.io/webr-repos", "https://repo.r-wasm.org"))
+
+library(blockr)
+library(palmerpenguins)
+library(ggplot2)
+
+new_ggplot_block <- function(col_x = character(), col_y = character(), ...) {
+
+ data_cols <- function(data) colnames(data)
+
+ new_block(
+ fields = list(
+ x = new_select_field(col_x, data_cols, type = "name"),
+ y = new_select_field(col_y, data_cols, type = "name")
+ ),
+ expr = quote(
+ ggplot(mapping = aes(x = .(x), y = .(y)))
+ ),
+ class = c("ggplot_block", "plot_block"),
+ ...
+ )
+}
+
+new_geompoint_block <- function(color = character(), shape = character(), ...) {
+
+ data_cols <- function(data) colnames(data$data)
+
+ new_block(
+ fields = list(
+ color = new_select_field(color, data_cols, type = "name"),
+ shape = new_select_field(shape, data_cols, type = "name")
+ ),
+ expr = quote(
+ geom_point(aes(color = .(color), shape = .(shape)), size = 2)
+ ),
+ class = c("plot_layer_block", "plot_block"),
+ ...
+ )
+}
+
+stack <- new_stack(
+ data_block = new_dataset_block("penguins", "palmerpenguins"),
+ plot_block = new_ggplot_block("flipper_length_mm", "body_mass_g"),
+ layer_block = new_geompoint_block("species", "species")
+)
+serve_stack(stack)
diff --git a/inst/shinylive/apps/ode-demo/app.R b/inst/shinylive/apps/ode-demo/app.R
new file mode 100644
index 00000000..768d025d
--- /dev/null
+++ b/inst/shinylive/apps/ode-demo/app.R
@@ -0,0 +1,51 @@
+webr::install("blockr", repos = c("https://bristolmyerssquibb.github.io/webr-repos", "https://repo.r-wasm.org"))
+webr::install("blockr.ggplot2", repos = c("https://bristolmyerssquibb.github.io/webr-repos", "https://repo.r-wasm.org"))
+
+library(blockr)
+library(pracma)
+library(blockr.ggplot2)
+
+new_ode_block <- function(...) {
+
+ lorenz <- function(t, y, parms) {
+ c(
+ X = parms[1] * y[1] + y[2] * y[3],
+ Y = parms[2] * (y[2] - y[3]),
+ Z = -y[1] * y[2] + parms[3] * y[2] - y[3]
+ )
+ }
+
+ fields <- list(
+ a = new_numeric_field(-8 / 3, -10, 20),
+ b = new_numeric_field(-10, -50, 100),
+ c = new_numeric_field(28, 1, 100)
+ )
+
+ new_block(
+ fields = fields,
+ expr = substitute(
+ as.data.frame(
+ ode45(
+ fun,
+ y0 = c(X = 1, Y = 1, Z = 1),
+ t0 = 0,
+ tfinal = 100,
+ parms = c(.(a), .(b), .(c))
+ )
+ ),
+ list(fun = lorenz)
+ ),
+ ...,
+ class = c("ode_block", "data_block")
+ )
+}
+
+stack <- new_stack(
+ new_ode_block,
+ new_ggplot_block(
+ func = c("x", "y"),
+ default_columns = c("y.1", "y.2")
+ ),
+ new_geompoint_block
+)
+serve_stack(stack)
diff --git a/inst/shinylive/apps/palmer-penguins/app.R b/inst/shinylive/apps/palmer-penguins/app.R
new file mode 100644
index 00000000..3fdffe4b
--- /dev/null
+++ b/inst/shinylive/apps/palmer-penguins/app.R
@@ -0,0 +1,47 @@
+webr::install("blockr", repos = c("https://bristolmyerssquibb.github.io/webr-repos/", "https://repo.r-wasm.org")) #nolint
+
+library(blockr)
+library(palmerpenguins)
+library(ggplot2)
+
+new_ggplot_block <- function(col_x = character(), col_y = character(), ...) {
+
+ data_cols <- function(data) colnames(data)
+
+ new_block(
+ fields = list(
+ x = new_select_field(col_x, data_cols, type = "name"),
+ y = new_select_field(col_y, data_cols, type = "name")
+ ),
+ expr = quote(
+ ggplot(mapping = aes(x = .(x), y = .(y)))
+ ),
+ class = c("ggplot_block", "plot_block"),
+ ...
+ )
+}
+
+new_geompoint_block <- function(color = character(), shape = character(), ...) {
+
+ data_cols <- function(data) colnames(data$data)
+
+ new_block(
+ fields = list(
+ color = new_select_field(color, data_cols, type = "name"),
+ shape = new_select_field(shape, data_cols, type = "name")
+ ),
+ expr = quote(
+ geom_point(aes(color = .(color), shape = .(shape)), size = 2)
+ ),
+ class = c("plot_layer_block", "plot_block"),
+ ...
+ )
+}
+
+stack <- new_stack(
+ data_block = new_dataset_block("penguins", "palmerpenguins"),
+ filter_block = new_filter_block("sex", "female"),
+ plot_block = new_ggplot_block("flipper_length_mm", "body_mass_g"),
+ layer_block = new_geompoint_block("species", "species")
+)
+serve_stack(stack)
diff --git a/inst/shinylive/apps/registry-demo/app.R b/inst/shinylive/apps/registry-demo/app.R
new file mode 100644
index 00000000..2601680c
--- /dev/null
+++ b/inst/shinylive/apps/registry-demo/app.R
@@ -0,0 +1,29 @@
+webr::install("blockr", repos = c("https://bristolmyerssquibb.github.io/webr-repos", "https://repo.r-wasm.org"))
+
+library(blockr)
+
+new_tail_block <- function(data, n_rows = numeric(), ...) {
+
+ n_rows_max <- function(data) nrow(data)
+
+ new_block(
+ fields = list(
+ n_rows = new_numeric_field(n_rows, 1L, n_rows_max)
+ ),
+ expr = quote(tail(n = .(n_rows))),
+ class = c("tail_block", "transform_block"),
+ ...
+ )
+}
+
+register_block(
+ constructor = new_tail_block,
+ name = "tail block",
+ description = "return last n rows",
+ classes = c("tail_block", "transform_block"),
+ input = "data.frame",
+ output = "data.frame"
+)
+
+stack <- new_stack(new_dataset_block)
+serve_stack(stack)
diff --git a/inst/shinylive/apps/result-block/app.R b/inst/shinylive/apps/result-block/app.R
new file mode 100644
index 00000000..0f751fee
--- /dev/null
+++ b/inst/shinylive/apps/result-block/app.R
@@ -0,0 +1,14 @@
+webr::install("blockr", repos = c("https://bristolmyerssquibb.github.io/webr-repos", "https://repo.r-wasm.org"))
+
+library(blockr)
+library(blockr.data)
+
+serve_workspace(
+ stack1 = new_stack(
+ new_dataset_block("lab", "blockr.data"),
+ new_select_block(c("STUDYID", "USUBJID"))
+ ),
+ stack2 = new_stack(new_result_block),
+ stack3 = new_stack(new_dataset_block("ae", "blockr.data")),
+ title = "My workspace"
+)
diff --git a/inst/shinylive/apps/upload-block/app.R b/inst/shinylive/apps/upload-block/app.R
new file mode 100644
index 00000000..513580ca
--- /dev/null
+++ b/inst/shinylive/apps/upload-block/app.R
@@ -0,0 +1,10 @@
+webr::install("blockr", repos = c("https://bristolmyerssquibb.github.io/webr-repos", "https://repo.r-wasm.org"))
+
+library(blockr)
+
+stack <- new_stack(
+ new_upload_block,
+ new_csv_block,
+ new_select_block
+)
+serve_stack(stack)
diff --git a/inst/shinylive/apps/workspace-kitchen-sink/app.R b/inst/shinylive/apps/workspace-kitchen-sink/app.R
new file mode 100644
index 00000000..61f271ff
--- /dev/null
+++ b/inst/shinylive/apps/workspace-kitchen-sink/app.R
@@ -0,0 +1,7 @@
+webr::install("blockr", repos = c("https://bristolmyerssquibb.github.io/webr-repos/", "https://repo.r-wasm.org")) #nolint
+
+library(blockr)
+
+do.call(set_workspace, args = list(title = "My workspace"))
+
+serve_workspace(clear = FALSE)
diff --git a/inst/shinylive/tools.R b/inst/shinylive/tools.R
new file mode 100644
index 00000000..05a2e9c0
--- /dev/null
+++ b/inst/shinylive/tools.R
@@ -0,0 +1,22 @@
+pak::pak("parmsam/r-shinylive@feat/encode-decode-url") #nolint start
+
+create_shinylive_links <- function(path) {
+
+ dirs <- list.dirs(path)[-1]
+
+ vapply(
+ dirs,
+ shinylive:::url_encode_dir,
+ FUN.VALUE = character(1)
+ )
+}
+
+create_vignettes_links <- function() {
+ apps_path <- "inst/shinylive/apps"
+ links <- create_shinylive_links(apps_path)
+ names(links) <- gsub(sprintf("%s/", apps_path), "", names(links))
+ links
+}
+
+shinylive_links <- create_vignettes_links()
+usethis::use_data(shinylive_links, internal = TRUE, overwrite = TRUE) #nolint end
\ No newline at end of file
diff --git a/man/create_app_link.Rd b/man/create_app_link.Rd
index ffcf2611..f5587016 100644
--- a/man/create_app_link.Rd
+++ b/man/create_app_link.Rd
@@ -4,17 +4,16 @@
\alias{create_app_link}
\title{Create shinylive iframe}
\usage{
-create_app_link(app_code, mode = c("app", "editor"), header = TRUE)
+create_app_link(url, mode = c("app", "editor"), header = TRUE)
}
\arguments{
-\item{app_code}{base64 app code. You can create it from https://shinylive.io/r
-by writing code and click on share and copy the link. The code is located at
-the end of the url.}
+\item{url}{app url. A shinylive link.}
\item{mode}{How to display the shinylive app. Default to app mode.}
\item{header}{Whether to display the shinylive header. Default to TRUE.}
}
\description{
-Create shinylive iframe
+Useful for pkgdown website
}
+\keyword{internal}
diff --git a/man/figures/README-unnamed-chunk-2-1.png b/man/figures/README-unnamed-chunk-2-1.png
index 8a47c897..a4809bfe 100644
Binary files a/man/figures/README-unnamed-chunk-2-1.png and b/man/figures/README-unnamed-chunk-2-1.png differ
diff --git a/man/figures/README-unnamed-chunk-3-1.png b/man/figures/README-unnamed-chunk-3-1.png
new file mode 100644
index 00000000..a4809bfe
Binary files /dev/null and b/man/figures/README-unnamed-chunk-3-1.png differ
diff --git a/man/figures/README-unnamed-chunk-4-1.png b/man/figures/README-unnamed-chunk-4-1.png
new file mode 100644
index 00000000..a4809bfe
Binary files /dev/null and b/man/figures/README-unnamed-chunk-4-1.png differ
diff --git a/vignettes/blockr_examples.Rmd b/vignettes/blockr-examples.Rmd
similarity index 59%
rename from vignettes/blockr_examples.Rmd
rename to vignettes/blockr-examples.Rmd
index b0077590..2162b02c 100644
--- a/vignettes/blockr_examples.Rmd
+++ b/vignettes/blockr-examples.Rmd
@@ -1,8 +1,8 @@
---
-title: "Case studies"
+title: "5: Case studies"
output: rmarkdown::html_vignette
vignette: >
- %\VignetteIndexEntry{Case studies}
+ %\VignetteIndexEntry{5: Case studies}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
@@ -15,7 +15,7 @@ knitr::opts_chunk$set(echo = TRUE)
## blockr Across Industries
-The flexibility of `blockr` makes it valuable across various industries. Let's explore how it can be applied in different sectors with detailed examples. Somex examples require to create a new field such as the `new_slider_field` described in the corresponding vignette.
+The __flexibility__ of `blockr` makes it valuable across various __industries__. Let's explore how it can be applied in different sectors with detailed examples. Some examples require to create a new field such as the `new_slider_field` described in the corresponding [vignette](https://bristolmyerssquibb.github.io/blockr/articles/new-field.html).
```{r slider_block, include=FALSE}
# Provided by John, new_range_field not working
@@ -209,9 +209,10 @@ This forest plot visualizes the relative risk of adverse events between two trea
```{r, eval=TRUE, echo=FALSE}
card(
- create_app_link(
- "NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAdzgCMAnRRASwgGdSoAbbgCgA6YOtyIEA1gyG4ABAzioi7GQF4ZBQWAAWpUqnaIA9IZFjJAWiIMA5hmstSWgK50MLIodqNz8xe2kyQjp6Bsa+RBgM5tRQ7DAYVtZCAJTJAhBeTKwcXLyaphIMGKhaUAwwUABucAzscFAAJrAB4cpqGkG6+kYmooWWNnYOzq7unvRRrQGdIT3hkdGx8YkpaRDp3CyMZQCefAWSa5vbDHsNqNw7DEdbDLt8pCwNVzcnewBmVnCcF0Skr3dTvs+pJiqVylUanVGrA1ukAMQyABiTggBEeJBkpCI6nkUHIMka1VqcBkcGqZBkn3knBkv1I6QIePIAH0oHAWdTvqQWfSZAAecxU1Ho9wQPhNLiyJzsFwAKyeLOI3FkZRgSqIKsJcAacGIDQ1WogLPJFFI7GSMhA6RkMklUAFQvtMgAPgA+KksbjkBh8DD24DANWGgC6IZkAEI1EIAArcKAEehEFI2mSIgDCJGJpHUmqcMAgMmg8GU2JknAYbGs-kLMhl8sVysdhPYGAI4ITPr4sronAcTnIfHrdAVBuVqVTwabgpbbY76Jq3ZcfdIA7gfCnmontfZuv1hubsTnZU7i57K7XG51eqIY63cNrGZ4BCc8YJjlJ2NyRfzdBqMiId5y3lPVzRkNgyQTLRCXKVNjR7OVQOUGdnXdVNbTqbhQI3XgWUAvgNGHUdDVVcpDVSS00NrW0GhYPs0VIPhKLddCZGsBgiCcVAWToPYEw49h2Bw7g8PeDcyPHVJXRY6jgJgCpKzqPhCzUcVklkOwOK4tpAjABoONQFN1kfGR02fV98VJABBABRKl5AARycCgCBYb5CQgBo6QMqwMQ4ScOVleTdmbVCZNtW12M47jeI3JklCEngRPwjRNy1XcbzvbgKOY1igoUuj12NU0yB041aPo9E-QDYAiMbTUw3UmRNOinShH0ohDLAXLZKw94eTlIg2GUlkEKQ2ReNUGD1XHaTWJgAdLL4VAfIYPypuKikwMMIsH1tREAGU4Cw9EsU6mQADkZBgJQc3eRznMpWzlH4hLCV4aaa1tbFuPZZChXZUb8wUnY5tkqKuJ4vj4sE4TRKvPdb3IqSqIiuSCqUr8eBNLadKCkaSvNJqWu0qb2oMlIwbRn6WXFTazXYWQsZEwmLSpiLUFffgkvhjL90k9JU0RABxOAc1RFgnM-Zl4EpNUvs+5sJaliV8SgQM0sa1MWCAvgsIgaxHHEmA2ajGQACZLWtWTOE6zQABUtDoulRBzB6WBpMkAA9O0uLFqBxUgZbNT6MCM20AF9J1Fao2XKQ9ynYYAAEYQ1TYgyA4kS1QTk3gHNtPjP25EvR9KkrDO1AZGejyvIIcy31JeQ3xYao5Do8QApZBgGEPQLgZC1GIveUvF39NWNevfmGvDABSNhZ8rtlvh6tHUFbv4WWoJ5F1Y216u4HSefwvmkfHXA96LWBvk5DiYCm4+xLS9TL8qHhnPYW+iHv9oCdx2QICyBWp1XyYo1ho1XhFBaXBByXywFgKa48uCBlQLEcgAAGTQwDFBrTFCyAInZW4cjVMkMMMgdpIPVsAVBnA4CYKENg0BJB8F4FzJnTUccYCkJDBfWStpRC0AYEqFgU04Be1QHrIg1g+DwMtEKZOGAACcAA2GQAAqcsDk1qCD4RFZO5Dmo1RoRgzQ9NSosNVDHYh5RuEyAANSXzRvoihRi0F0NMTjBmFi2FBw4SQsh5hHF6IMZQlBbj6GQG8YQ2O-jwyBN0U4kJrjaERONAEDOvjs42LDJfVIvC0a2i4qgGowjRHiMkdI2R9iZAKJUeozR2ignOMMRPah4SPGsyiVYzhtiHEJOCS41pxj3FCDMeabxGSs49ICUE20zTQltJSR4gh3TYkyHiQUgp8zkkmNGRMkgmTpmF02duCBgsTIxl8GUUkzpqTlxpDmekqYuScBZM6GcgMe7s1tNApal94x-m4FNYZ9D+kLNPllMMsghAyE0PkzZLTkGLN2ZEzpKzHgxOyTw3ShgAgLJBcs1h0TrFcKhbpGQlRlDSCCfi9pey0WsMmX4rF0KwC4tYbSpZez0kHKmbE1laQwC5NYntNMplmSkheY812zyvg-FdjotGALjrkC9jmdodA2ANEVQUqVby1YABJlUqkvuwFabBSBiSELPDA5tdY2rteYB17xBWyD1faA18C3Vyp5B6gRJTXLeoefqrgBqikBpYOAiKL9ZLwCgCpe53IQ1QE9VgeF-CiCCKmu6w1-qhGBtYuG3uagc2hqLcI9N70WDWATR0MA3BphgCkN1St7E0BaG3g0RwU0JaMWUeg1l8kUiVsTF7Ka6ClGVs2BAOAWg4DVp0D2iADg+AAA5B0wGHaxOgRAvbsBYAAL1JGoCdABmAArCOzU2bUCZlELUfYu6yZNqIDsHgIhnIBGnce3STQGDiA-XAAI+UQrRhfW+7ggGt2yVIGqlk1gq4ltQPbNVwsJHGqmghsoBExHjqUU1R4EgdJYd9KOvDiimpewBZh1BpHcMnvwzGtGVGoB0GBW4zQWBjr4iITILAHdYXoqIZw1lBieXsKyTAAV0G0ZHo4lNZOU7qANAwHJnEahzZKZU65KamnWJqpYERqaGgJ2XpqbITTMgAAsTGIrsSeFNe2WAACqNlK2PFIFhdjtDOPcYxaSfj7BxAASAlZBoxI6gyBsrjQTRLVnlFE5S3SsgmWSek91VMawo7GRndQTkPreSux4iCZs7wRR+T9BgDAVs4JwDywcHVtoR7HQaDpTYnBGsRTqllDadXRrHVApyNy3BtVBKEM5g6zmABCAApAAkgAEWpf0srDExSqy4JaZUxZvgbagLZzZC1vQsAuD+pEVkAAyB03NBI815sDB0QKnUW6ZPMBYhC5MrbaNKvW8uYUG81kbnW0ZCCsume2VksAAFllsIuFGtkge2tuah20Je0B2ClHceKdqa52rs3f6Xdn9Qh7bByevHO9+Z1hCt0Rj77U8z7XtUn1-76IhsteBxFUHNkFs2XTAAeSW3gIJq3RSI-R7mbgqOkdfaga+bH93kSXeu7L76DhFfc5kPbGo99KfvZpyc2XYyyp9YgPmGohn2dA6aQOoJMAIJqDMxUMdGmB3lnIIh8zt31fE7ABdX8-5AJa-OjXMsC26IXCgDsD7tORWVrEStKaTk-jrmtpspk9RWSAz1fSPbGkhwIQPsTY25F88QtL81P+DNTkRQjhjgg8ZBLGc0ESKEHJCaFc3gcRt9JitmBkxFKrYdaxZfOYiLj9haG9w-OoGU2J77d4gPISfPo+8SB1bl-Lwbe8HHhTt59YWIukmiyHJEPqZBxj+LDu03wmQnfWmB9MErCSJtpHyIPreSRkhi8QGAtGqz+yBxk45jyzX4N6xB1A6R1qf51CeJkCd48jd6sIMJFZIG2ZsCczqq-pqwYD3TXzX6cR6ADjPpPI04PgZjP4z6cAJidxojTqGbYxBwsDYzUESDNib6sHiAb59YwjqgNas7kBeRgYwhAYtpCyejeglJsBr5cG2ab456oEghMTpAPh1AMCxycEET0H1wiRMEsFcASDJBgARwhhAA", # nolint
- mode = "editor"
+ blockr:::create_app_link(
+ blockr:::shinylive_links["ae-forest-plot"],
+ "editor",
+ header = FALSE
),
full_screen = TRUE
)
@@ -231,163 +232,8 @@ Toggle code
-```r
-library(dplyr)
-library(tidyr)
-library(forestplot)
-library(blockr.pharmaverseadam)
-
-# Function to create adverse event forest plot
-create_ae_forest_plot <- function(data, usubjid_col, arm_col, aedecod_col, n_events) {
- data <- data |> filter(.data[[arm_col]] != "Placebo")
- # Convert column names to strings
- usubjid_col <- as.character(substitute(usubjid_col))
- arm_col <- as.character(substitute(arm_col))
- aedecod_col <- as.character(substitute(aedecod_col))
-
- # Calculate the total number of subjects in each arm
- n_subjects <- data |>
- select(all_of(c(usubjid_col, arm_col))) |>
- distinct() |>
- group_by(across(all_of(arm_col))) |>
- summarise(n = n(), .groups = "drop")
-
- # Calculate AE frequencies and proportions
- ae_summary <- data |>
- group_by(across(all_of(c(arm_col, aedecod_col)))) |>
- summarise(n_events = n_distinct(.data[[usubjid_col]]), .groups = "drop") |>
- left_join(n_subjects, by = arm_col) |>
- mutate(proportion = n_events / n)
-
- # Select top N most frequent AEs across all arms
- top_aes <- ae_summary |>
- group_by(across(all_of(aedecod_col))) |>
- summarise(total_events = sum(n_events), .groups = "drop") |>
- top_n(n_events, total_events) |>
- pull(all_of(aedecod_col))
-
- # Get unique treatment arms
- arms <- unique(data[[arm_col]])
- if (length(arms) != 2) {
- stop("This plot requires exactly two treatment arms.")
- }
- active_arm <- arms[1]
- control_arm <- arms[2]
-
- # Filter for top AEs and calculate relative risk
- ae_rr <- ae_summary |>
- filter(.data[[aedecod_col]] %in% top_aes) |>
- pivot_wider(
- id_cols = all_of(aedecod_col),
- names_from = all_of(arm_col),
- values_from = c(n_events, n, proportion)
- ) |>
- mutate(
- RR = .data[[paste0("proportion_", active_arm)]] / .data[[paste0("proportion_", control_arm)]],
- lower_ci = exp(log(RR) - 1.96 * sqrt(
- 1 / .data[[paste0("n_events_", active_arm)]] +
- 1 / .data[[paste0("n_events_", control_arm)]] -
- 1 / .data[[paste0("n_", active_arm)]] -
- 1 / .data[[paste0("n_", control_arm)]]
- )),
- upper_ci = exp(log(RR) + 1.96 * sqrt(
- 1 / .data[[paste0("n_events_", active_arm)]] +
- 1 / .data[[paste0("n_events_", control_arm)]] -
- 1 / .data[[paste0("n_", active_arm)]] -
- 1 / .data[[paste0("n_", control_arm)]]
- ))
- )
-
- # Prepare data for forest plot
- forest_data <- ae_rr |>
- mutate(
- label = paste0(
- .data[[aedecod_col]], " (",
- .data[[paste0("n_events_", active_arm)]], "/", .data[[paste0("n_", active_arm)]], " vs ",
- .data[[paste0("n_events_", control_arm)]], "/", .data[[paste0("n_", control_arm)]], ")"
- )
- )
-
- # Create forest plot
- forestplot::forestplot(
- labeltext = cbind(
- forest_data$label,
- sprintf("%.2f (%.2f-%.2f)", forest_data$RR, forest_data$lower_ci, forest_data$upper_ci)
- ),
- mean = forest_data$RR,
- lower = forest_data$lower_ci,
- upper = forest_data$upper_ci,
- align = c("l", "r"),
- graphwidth = unit(60, "mm"),
- cex = 0.9,
- lineheight = unit(8, "mm"),
- boxsize = 0.35,
- col = fpColors(box = "royalblue", line = "darkblue", summary = "royalblue"),
- txt_gp = fpTxtGp(label = gpar(cex = 0.9), ticks = gpar(cex = 0.9), xlab = gpar(cex = 0.9)),
- xlab = paste("Relative Risk (", active_arm, " / ", control_arm, ")"),
- zero = 1,
- lwd.zero = 2,
- lwd.ci = 2,
- xticks = c(0.5, 1, 2, 4),
- grid = TRUE,
- title = paste("Relative Risk of Adverse Events (", active_arm, " vs ", control_arm, ")")
- )
-}
-
-new_forest_plot_block <- function(...) {
- new_block(
- fields = list(
- usubjid_col = new_select_field(
- "USUBJID",
- function(data) colnames(data),
- multiple = FALSE,
- title = "Subject ID Column"
- ),
- arm_col = new_select_field(
- "ACTARM",
- function(data) colnames(data),
- multiple = FALSE,
- title = "Treatment Arm Column"
- ),
- aedecod_col = new_select_field(
- "AEDECOD",
- function(data) colnames(data),
- multiple = FALSE,
- title = "AE Term Column"
- ),
- n_events = new_numeric_field(
- 10,
- min = 5, max = 20, step = 1,
- title = "Number of Top AEs to Display"
- )
- ),
- expr = quote({
- create_ae_forest_plot(data, .(usubjid_col), .(arm_col), .(aedecod_col), .(n_events))
- }),
- class = c("adverse_event_plot_block", "plot_block"),
- ...
- )
-}
-
-# Register the custom block
-register_block(
- new_forest_plot_block,
- name = "Adverse Event Forest Plot",
- description = "Create a forest plot of adverse events comparing two treatment arms",
- category = "plot",
- classes = c("adverse_event_plot_block", "plot_block"),
- input = "data.frame",
- output = "plot"
-)
-
-# Create the stack
-clinical_trial_stack <- new_stack(
- new_adam_block(selected = "adae"),
- # filter_in_block(),
- new_forest_plot_block()
-)
-
-serve_stack(clinical_trial_stack)
+```{r, results="asis", echo=FALSE, warning=FALSE, comment = ""}
+blockr:::print_shinylive_r_code("ae-forest-plot")
```
@@ -753,9 +599,10 @@ In the below example, we implemented the Lorenz attractor and solve it with the
```{r, eval=TRUE, echo=FALSE}
card(
- create_app_link(
- "NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAdzgCMAnRRASwgGdSoAbbgCgA6YOtyIEA1gyG4ABAzioi7GQF4ZBQWAAWpUqnaIA9IZFjJAWiIMA5hmstSWgK50MLIodqNz8xe2kyQjp6Bsa+RBgM5tRQ7DAYVtZCAJTJAhBeTKwcXLyaphIMdtaooqQATAHhymoaQbr6RiaihZY2dg7Oru6e9FHVAfUhTeGR0bHxiSlpEOncLIxQDACefAWSM-OLK3yoDFAEMFCbC-s760XWJWXlM+kQcNQA+kQAJnBP6zIAPOYyAGZOCAEUjuCB8DCQ5IyEDpdIyGSieQQABePz+gOBoJIMj4pFky1kqCWMHY0NhEARCLqlKpCIAGqoZMSGKTgABGAC6MgAVDJlhzuQBqfnAcrcvkCgDMnNw8LpMgAmkyWWzxbzcQL1X9pZzknLaXSAFpM8wCrkarXC5kk9jAGWWsXcnX2znyhEzBEAXzhtP+LDg3Feyl+iJYnEEhpkUCZD2eECc8AYLAIT39gdefHMAA5DFLZOZ2QAGWTlIv690yOixx5PBNJlNpgNBrPFgsAVhLMmL5YNdIINfjibgydT6Zb5WzsnZ06L5fld1pcc+LXEkbp4+DTM37D7VLgAA89kz2C5OA4nOR1wrYhhXlAuBh-vt4NeFTI3nAACztt-vgFArIlbvssRZMhojJqDOSpMtBJpQRWUbvqQYFqCWwEKqQ-rQNwsFznu-42qyNTqBCfDHLIGBrPqMhUQQqQYR6GGIe+8wRpiTJIhQKKelSLFUpCGAEeo3CxCRdRgJ+K5mIMYD3lw0kSCkC7pD6sw5Ac4jojIy6cJp17LlJ6xAUutZXKURCkIpa6VpiA61JoB6ycsKQmXS7z-FATjcFZxDcImHDgZoywYOyzkYJUYC8TR8rLtYcBEDAihsFZ6zpDM7AjgAbh8ekSHweXiMkYBepyQA", # nolint
- mode = "editor"
+ blockr:::create_app_link(
+ blockr:::shinylive_links["ode-demo"],
+ "editor",
+ header = FALSE
),
full_screen = TRUE
)
@@ -775,55 +622,7 @@ Toggle code
-```r
-library(blockr)
-library(pracma)
-library(blockr.ggplot2)
-
-new_ode_block <- function(...) {
-
- lorenz <- function (t, y, parms) {
- c(
- X = parms[1] * y[1] + y[2] * y[3],
- Y = parms[2] * (y[2] - y[3]),
- Z = -y[1] * y[2] + parms[3] * y[2] - y[3]
- )
- }
-
- fields <- list(
- a = new_numeric_field(-8/3, -10, 20),
- b = new_numeric_field(-10, -50, 100),
- c = new_numeric_field(28, 1, 100)
- )
-
- new_block(
- fields = fields,
- expr = substitute(
- as.data.frame(
- ode45(
- fun,
- y0 = c(X = 1, Y = 1, Z = 1),
- t0 = 0,
- tfinal = 100,
- parms = c(.(a), .(b), .(c))
- )
- ),
- list(fun = lorenz)
- ),
- ...,
- class = c("ode_block", "data_block")
- )
-}
-
-stack <- new_stack(
- new_ode_block,
- # Coming from blockr.ggplot2
- new_ggplot_block(
- func = c("x", "y"),
- default_columns = c("y.1", "y.2")
- ),
- new_geompoint_block
-)
-serve_stack(stack)
+```{r, results="asis", echo=FALSE, warning=FALSE, comment = ""}
+blockr:::print_shinylive_r_code("ode-demo")
```
diff --git a/vignettes/blockr.Rmd b/vignettes/blockr.Rmd
index 4bd31f29..1bb39e68 100644
--- a/vignettes/blockr.Rmd
+++ b/vignettes/blockr.Rmd
@@ -31,12 +31,71 @@ note_box <- function(..., color) {
```
```{r echo=FALSE}
-knitr::include_url("https://blockr-org.github.io/useR2024")
+knitr::include_url("https://bristolmyerssquibb.github.io/useR2024")
```
-## Get started
+# Get started
-`{blockr}` provides plug and play blocks which can be used to import, transform and visualize data.
+`{blockr}` provides plug and play __blocks__ which can be used to import, transform and visualize data. This guide provides an entry point for end users without extensive coding skills, as well as developers.
+
+## {blockr} for non coders
+
+In that case, you likely just want to get started to create your first data pipeline.
+
+### The user interface
+
+This is what the `{blockr}` interface looks. We designed it to be like a cooking __recipie__, where blocks correspond to the different __steps__.
+Within each block are some __inputs__ that allow you to change parameters. For instance, when you import the data, you may want to select a given dataset or specify a file from your computer or on a server. In figure \@ref(fig:blockr-ui),
+the `airquality` dataset is imported. On the top center of the block, you can see information about the number of rows and columns. Then, a filter block is added and target the `Ozone` column. Notice the __validation__ message as the value is missing. The submit button can't be clicked as long as the input is empty, which prevents from triggering errors in downstream blocks. Each block can be collapsed/uncollapsed and removed with the corresponding buttons located on the top right corner. As you can see, we group all related blocks inside a common container, the __stack__, which can also be collapse and removed.
+
+```{r blockr-ui, echo=FALSE, fig.cap='User Interface Overview', fig.align = 'center', out.width='100%'}
+knitr::include_graphics("figures/blockr-ui.png")
+```
+
+### Starting from scratch
+
+When you start from scratch, there are actually no blocks in the interface and you have to add them one by one.
+To add a new block, you can click on the `+` icon on the stack top right corner. This opens a sidebar on the left side, where it is possible to search for blocks. To make things easier, all the suggested blocks are compatible with the current state of the pipeline. For instance, when the stack is empty, only entry point blocks are suggested, so you can import data. Then, after clicking on the block, the suggestion list changes so you can, for instance, filter data or select only a subset of columns, and more.
+
+```{r, echo=FALSE}
+# shinylive container
+card(
+ blockr:::create_app_link(
+ blockr:::shinylive_links["empty-stack"],
+ "app",
+ header = FALSE
+ ),
+ full_screen = TRUE
+)
+```
+
+### Toward a dashboard
+
+What if you aim at creating a more ambitious pipeline? In that case, you don't need one cooking recipie but multiple, so you can organise your own dinner party. Below is a slightly more complex application, where you can add multiple stacks and connect them together. This are the following step to connect 2 stacks together:
+
+- Click on "Add stack".
+- Add a new dataset block with the default BOD dataset.
+- Add a filter block. Target the Time column with values between 1 and 2, then click "submit". You should get only 2 rows.
+- Click on "Add stack".
+- Add a new result block in this second stack. You should see the same result as in the first stack.
+
+Doing so, you can build you analysis step by step in a modular way.
+
+```{r, echo=FALSE}
+# shinylive container
+card(
+ blockr:::create_app_link(
+ blockr:::shinylive_links["workspace-kitchen-sink"],
+ "app",
+ header = FALSE
+ ),
+ full_screen = TRUE
+)
+```
+
+## {blockr} for developers
+
+In the following section, we describe the building blocks behind blockr so you can start creating your blocks.
### Introduction
@@ -75,7 +134,7 @@ mermaid("
)
```
-Under the hoods, blocks are composed of __fields__. The latter are translated into shiny inputs used to convey interactivity within the block. As you can see in the below diagram, fields are combined to compute an expression, which eventually leads to a block result after evaluation. For a data block, there is no data input.
+Under the hoods, blocks are composed of __fields__. The latter are translated into shiny inputs used to convey __interactivity__ within the block. As you can see in the below diagram, fields are combined to compute an __expression__, which eventually leads to a block __result__ after __evaluation__. For a data block, there is no data input.
```{r, echo=FALSE}
mermaid(
@@ -148,16 +207,6 @@ mermaid(
)
```
-
-### The user interface
-
-By default, only the last __stack__ block is visible, all others are collapsed.
-To preview all block you can set `options("BLOCKR_DEV" = TRUE)`.
-
-```{r blockr-ui, echo=FALSE, fig.cap='User Interface Overview', fig.align = 'center', out.width='100%'}
-knitr::include_graphics("figures/blockr-ui.png")
-```
-
### Create a stack
To create a __stack__, you call `new_stack()` and feed it all the required __blocks__.
@@ -165,6 +214,14 @@ Below is a simple stack providing a dataset selector and a filter operation. `se
wrapper to run the corresponding shiny app. Note that with `serve_stack()`, you don't need to worry about
specifying any __modules IDs__, they are automatically handled by `{blockr}`.
+blocks can be instantiated either by calling their constructor name and passed to the stack:
+
+```r
+stack <- new_stack(new_dataset_block)
+```
+
+Alternatively, it is possible to create block with specific parameter values, as shown below:
+
```r
library(blockr)
library(blockr.data)
@@ -177,112 +234,22 @@ stack <- new_stack(
serve_stack(stack)
```
-```{r, eval=TRUE, echo=FALSE}
-card(
- create_app_link(
- "NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAdzgCMAnRRASwgGdSoAbbgCgA6YOtyIEA1gyG4ABAzioi7GQF4ZBQWAAWpUqnaIA9IZFjJAWiIMA5hmstSWgK50MLIodqNz8xe2kyQjp6Bsa+RBgM5tRQ7DAYVtZCAJTJAhDcLIxQDACefKYSDGkZWQw5+YWSGAAmUFwlmdl5fKg88AyoFNZObOwl6ZxQEjIAPOYyEHDUAPpDEoIQMjJVAIyqk9MzdVzscKQzVXx73HAE5DUbQl0QPX0BbRJQ1nBXYG3cHTd3HCm46csqgAmDZTWYAMxY3HIDEOogWxG4ThgHDe7C6BBYcH8eBkADceE5sW8AII1OCZOApdIlPYMPFwOZcBbzcTJMAAXwAukA", # nolint
- "app",
- header = FALSE
- ),
- full_screen = TRUE
-)
-```
+By default, only the last __stack__ block is visible, all others are collapsed.
+To preview all block you can set `options("BLOCKR_DEV" = TRUE)`.
```{r, eval=TRUE, echo=FALSE}
note_box(
"You'll notice that some blocks, such as the `filter_block`
- have a submit button. The reason was to prevent any expansive task
- to run without explicit user approval. That said, this feature is
- still very much experimental and might change in the future.",
- color = "primary"
-)
-```
-
-
-In the next example, we'll see how to create an which can dynamically add or remove blocks.
-
-### Dynamically add a block
-
-The stack exposes a helper button to add a block in the top right corner of the card header.
-It triggers an [offcanvas](https://getbootstrap.com/docs/5.3/components/offcanvas/)
-UI panel, that basically allows one to select any block available in the
-registered blocks [vignette](https://blockr-org.github.io/blockr/articles/registry.html).
-
-As a side note, there's another mechanism that works to add blocks, which we describe in the
-following. It is more verbose but allows you to
-bring your own custom UI. On the UI side, we call `generate_ui()`,
-which is nothing more than calling the stack module UI and `generate_server()` in the Shiny server function. If you leave `id` NULL,
-the namespace is automatically handled. To get the list of available blocks, we leverage the `{blockr}` registry namely `available_blocks()` which exposes the
-currently registered blocks. You can learn more about the registry in the dedicated
-[vignette](https://blockr-org.github.io/blockr/articles/registry.html).
-`add_block_ui()` is a UI helper to show a button as well
-as the necessary interface to contain the new block choice.
-Within an `observer` we listen to the "add block" button. Then, we pass the new block in the `new_block` slot of the `generate_server()` function.
-It accepts the name of the block to insert as well as its position in the stack (here we append and leave `NULL`).
-
-```{r, eval=TRUE, echo=FALSE}
-note_box(
- "Note that `{blockr.demo}` (https://github.com/blockr-org/block.demo)
- utilises `{masonry}` (https://github.com/blockr-org/masonry) to provide
- a better user experience, allowing one to drag and drop blocks
- within the stack.",
+ have a submit button. This is to prevent any expansive task
+ from running without explicit user approval.",
color = "primary"
)
```
-```r
-library(shiny)
-library(blockr)
-
-stack <- new_stack(new_dataset_block)
-shinyApp(
- ui = bslib::page_fluid(
- add_block_ui(),
- generate_ui(stack, id = "mystack")
- ),
- server = function(input, output, session) {
- vals <- reactiveValues(new_block = NULL)
- stack <- generate_server(
- stack,
- id = "mystack",
- new_block = reactive(vals$new_block)
- )
-
- observeEvent(input$add, {
- block <- available_blocks()[[input$selected_block]]
- # add_block expect the current stack, the block to add and its position
- # (NULL is fine for the position, in that case the block will
- # go at the end)
- vals$new_block <- list(block = block)
- })
- }
-)
-```
-
-Blocks can be removed in any context. Keep in mind that a stack can't contain 2 data blocks.
-
-```{r, eval=TRUE, echo=FALSE}
-note_box(
- "At the moment, we don't check whether removing a block breaks the pipeline.",
- color = "danger"
-)
-```
-
-```{r, eval=TRUE, echo=FALSE}
-card(
- create_app_link(
- "NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAdzgCMAnRRASwgGdSoAbbgCgA6YOtyIEA1gyG4ABAzioi7GQF4ZBQWAAWpUqnaIA9IZFjJAWiIMA5hmstSWgK50MLIodqNz8xe2kyQjp6Bsa+RBgM5tRQ7DAYVtZCAJTJAhDcLIxQDACefKYSDGkZWQw5+YWSGAAmUFwl6ZxQEjIAPOYyEHDUAPrNEnwl7HAMAG5w-VyDA+LJYAC+ALpAA", # nolint
- "app",
- header = FALSE
- ),
- full_screen = TRUE
-)
-```
-
### Example with modules
-The stack can be nested within modules. This is what we do in
-[`{blockr.demo}`](https://github.com/blockr-org/block.demo).
+This might be useful if you consider embedding blockr in your own application.
+The stack can be nested within modules.
```r
library(shiny)
@@ -328,27 +295,36 @@ shinyApp(ui, server)
### Connect stacks: the workspace
The __workspace__ allows you to create more complex analysis by connecting stacks together and get a dashboard.
-To know more about this you can read the following [article](https://blockr-org.github.io/blockr/articles/data-blocks.html#reading-data-from-another-stack).
+To know more about this you can read the following [article](https://bristolmyerssquibb.github.io/blockr/articles/data-blocks.html#reading-data-from-another-stack).
-```{r, echo=FALSE}
-mermaid(
- "flowchart TD
- subgraph s1[Stack 1]
- direction TB
- input_s1(Data)
- transform_s1(Transform)
- input_s1 --> |data| transform_s1
- end
- transform_s1 --> |data| input_s2
- subgraph s2[Stack 2]
- direction TB
- input_s2(Data)
- transform_s2(Transform)
- output_s2(Visualize)
- input_s2 --> |data| transform_s2 --> |data| output_s2
+```{r, echo=FALSE, message=FALSE}
+mermaid("
+ flowchart TD
+ subgraph LR workspace[Workspace]
+ subgraph stack1[Stack]
+ direction LR
+ subgraph input_block[Block 1]
+ input(Data: dataset, browser, ...)
+ end
+ subgraph transform_block[Block 2]
+ transform(Transform block: filter, select ...)
+ end
+ subgraph output_block[Block 3]
+ output(Result/transform: plot, filter, ...)
+ end
+ input_block --> |data| transform_block --> |data| output_block
+ end
+ subgraph stack2[Stack 2]
+ stack1_data[Stack 1 data] --> |data| transform2[Transform]
+ end
+ stack1 --> |data| stack2
+ subgraph stackn[Stack n]
+ stacki_data[Stack i data] --> |data| transformn[Transform] --> |data| Visualize
+ end
+ stack2 ---> |... data| stackn
end
",
- height = "600px"
+ width = "100%"
) |>
htmlwidgets::onRender(
"function(el, x) {
diff --git a/vignettes/data-blocks.Rmd b/vignettes/data-blocks.Rmd
index 126a9718..d2e02710 100644
--- a/vignettes/data-blocks.Rmd
+++ b/vignettes/data-blocks.Rmd
@@ -50,32 +50,18 @@ new_dataset_block <- function(
The `new_dataset_block()` function defaults to using the base R `datasets` package, but you can supply any valid package containing one or multiple data sets. Here, we use the `{blockr.data}` package to select the `"lab"` data set:
-```r
-# Define the custom data block
-custom_data_block <- function(...) {
- new_dataset_block(
- selected = "lab",
- package = "blockr.data",
- ...
- )
-}
-
-stack <- new_stack(
- custom_data_block,
- new_select_block
-)
-serve_stack(stack)
-```
-
-```{r, eval=TRUE, echo=FALSE}
+```{r, results="asis", echo=FALSE, warning=FALSE, comment = ""}
+# shinylive container
card(
- create_app_link(
- "NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAdzgCMAnRRASwgGdSoAbbgCgA6YOtyIEA1gyG4ABAzioi7GQF4ZBQWAAWpUqnaIA9IZFjJAWiIMA5hmstSWgK50MLIodqNz8xe2kyQjp6Bsa+RBgM5tRQ7DAYVtZCAJTJAhDcLIxQDACefKYSDGkQBE6cRDAA+gAmUFxVheIyADzmMgBmTqWk7hB8GIPJMiDpMjIQcNS19bFwpI2iEoIQ4+PscNxwBOQ1qoFg3FB00mNrqFASUNZw+0JNDBh1XKera4MYZyUAvunpnJdmm0JlMqgDlmcyhVqs8oIszLIzpNphstjt4RJ0iUNgwAG5wMFcZbg8TJMDfAC6QA", # nolint
+ blockr:::create_app_link(
+ blockr:::shinylive_links["dataset-block"],
"app",
header = FALSE
),
full_screen = TRUE
)
+
+blockr:::print_shinylive_r_code("dataset-block")
```
```{r, eval=TRUE, echo=FALSE}
@@ -101,26 +87,18 @@ of the four following data __parser__ blocks:
If you want to load data from any location on your computer, `new_upload_block()` is what you need.
Since the `new_upload_block()` temporarily moves data into a custom location, for security reasons, it might not be always possible.
-```r
-library(blockr)
-
-stack <- new_stack(
- new_upload_block,
- new_csv_block,
- new_select_block
-)
-serve_stack(stack)
-```
-
-```{r, eval=TRUE, echo=FALSE}
+```{r, results="asis", echo=FALSE, warning=FALSE, comment = ""}
+# shinylive container
card(
- create_app_link(
- "NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAdzgCMAnRRASwgGdSoAbbgCgA6YOtyIEA1gyG4ABAzioi7GQF4ZBQWAAWpUqnaIA9IZFjJAWiIMA5hmstSWgK50MLIodqNz8xe2kyQjp6Bsa+RBgM5tRQ7DAYVtZCAJTJAhDcLIxQDACefKYSDGkQ6ZxQEjIAPOYyEHDUAPrlEoIQMnUNjU6oolAAJo2F4rjpHfVNBOwAbkOiEqPtnU3scNxwBKRzZuklqwzTcM1crS3iyWAAvgC6QA", # nolint
+ blockr:::create_app_link(
+ blockr:::shinylive_links["upload-block"],
"app",
header = FALSE
),
full_screen = TRUE
)
+
+blockr:::print_shinylive_r_code("upload-block")
```
#### Files browser block
@@ -143,26 +121,18 @@ In the following demonstration, dummy dataset has been uploaded to the webR file
the block. But, you can also upload your own data thanks to the corresponding
shinylive feature (upload button).
-```r
-library(blockr)
-
-stack <- new_stack(
- new_filesbrowser_block,
- new_csv_block,
- new_select_block
-)
-serve_stack(stack)
-```
-
-```{r, eval=TRUE, echo=FALSE}
+```{r, results="asis", echo=FALSE, warning=FALSE, comment = ""}
+# shinylive container
card(
- create_app_link(
- "NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAdzgCMAnRRASwgGdSoAbbgCgA6YOtyIEA1gyG4ABAzioi7GQF4ZBQWAAWpUqnaIA9IZFjJAWiIMA5hmstSWgK50MLIodqNz8xe2kyQjp6Bsa+RBgM5tRQ7DAYVtZCAJTJAhDcLIxQDACefKYSDGkQ6ZxQEjIAPOYyEHDUAPrlEoIQMnUNjQBmLNxw7IxE1OxwDI2F4rjpHfVNBOwAbhOiEtPtnU2j-QSkK2bpJaMMi3DNXK0t4slgAL644NDwVKgU1k5s7BgLi3iEJORKMghOxXgQWANpEIWOxuFAIAATKHCPrcRr9CDWRyNGAwZF0VGNBEKbG45HdTLoMbot6kvF4IR0IgI3I42LsRpJBlgUYAD2RuTgOSE6SEAEFiZk4MiACqJMajUp4ADMAE4MABGXAagAcGAA7NqdVrlfqAKwABmmYBgPGleAATBaLfrRWAJXApbL5QxFdI1Rgzdr9RgACxGgBsuGVOud1u6cFt-WkTpdbo9Xu5cpsCoo0lDFowyqN2tVQeVDst8cTdpTztdSozEO9Od9ebwADkxbguz3u73e6mG+LJc2sz6-SqIwbS0XS8XlaGq0IE0n7bgh+nR+uhNnrLmldH1cWnRgoxrVVblRHlzba4761vPWPrXuD-69argxgdUaTRHK2rNc6zTRttxbfc20PAMHVnc8y1wUMI3Na1gIfUCR2fHcwDfKD-VDTUjUIi8F1DFDB0fMCsIg988FDWDT1gi8rXoqsKIw91wPHVtJ2jENfw1EMtV1KNlWVON2OHTjqO4yDeNNH9v2LXUr31CTu03KjM1fCd20QjViJDc8dVgis4xXGtk3QqSm2w3D5L1KMHQMpjVRNWMrSENCN0ozDtN3XToIIpyDOE1Vf1DAtPLvKyfI42yaLwqcz2-ASdXLNTotXe84psridJ4vSYxnC9S3LJcsss9dNL8l8AsKw96MDHyStVQ0Kui7yauk-ycMC-CwyI8NdXDMTAIsrrfJ6uq+oa-MQuai9w3o8yYuqqaEu5AAhGFiHXBS0rnQTRqioCcu6zbrR29g9v9ENDV1ErY2jCNVsm+L8qEa7bpVM0MC-C8MCYnUvxjVbstii7PrAb6iH2vVgeI9Kj1vd68pkq7drhj9FMEoGjSvDzUPOjbodh-a-uUz8jUNMHKrRp9evJ-NC2MlLdQXM1UZJj6Ma+rH1wLRaQwBnVadTM7IdJvmYYFu7-qI899VMjVbwh9beaZuW6MLINHtFq8y06nn0d6gAReRYH9dU9enB79V-Cs1aqkDTZmi2hXpPj8ce4SHaPN6TcZ93La9gM9f4o1HfE+mg60kPPZZhX9aNUbL2NqXNYTq3kuGh6ELGoMJrj2rsI9nOj3x5ziNVKNQ1VjONbdsvQ5x38nVLQ3ucz5vkXLr2msRvXnuVLnY574OW8TlUjNnKmTRjyWm8nvvW5VdUBPVYSdWWm9G9dlfuX7-1p2Ho0Vedhn46niuhcO4aC-T4mJ+v1fp5eojh9EjVwZd6zD+tMfOiBEwqtTrqdLyJdpo3zDg9acotyzOnHsvV+R816VzZpvFir197-1QYA9B9ca7n2jKxZ+KDS5vwrgpYeyd9RfgdG1IMkkAFCCAR-PGANLykMvlAy6bDCEOjnNXVyWp67dwodA5EzN17s3upGaMlpkEgR1Kw2WN1sY6yRsnHUEVF6QMzqo-B-MNEU2-Fwq8FUl4qLUTIxCrlmoSwLBImxxj1E-VIYtPU29DSMN-u9IxlDtra30oNR68ETSZXIa4oJmNTHW2-F-RRvDDG2JCULTB85oxEwMRrQJUjgnxOSrbdmxoNzpWUehfJ-D3GaO9vBGuo1zS4LitUsmITR4lXgUacsDdrFVLSUU0JJ5QplUQhAtaMSClxI8QpJWPSXr+J5m0mWdiiHbx9qqWCziWmphWVrIZ14wlCVTuUlJeTBkeKIcZUspkjbRIGW4uxnSSmuXLKPSprTLl1PWbObeEUf67OdPsma9kip-QBtOeCV4LTnKmTUsFjUDKbzCeFcZLjHmxPqnJIqypFoWMWZ8vZajEXWyeqiw2gdUluNJbIpWmzRJj36V8ml-U6J-UOlw9qfTcnwuhrSxRwt8WqSWdSrFs0cWNSEYdPWCFWJAotCCuybLEKFkhbjNyfFRUXNZXNGemywk7wDgqpViV5LTiYtOHxySiXApJSqpqoCwpBiiia+1erPH0uBqDCWxcxXTOxbRexdD2a10QlE3lmKA0SqDUch6eo0q0xyWAdWfKZYCs6aAh+xYVpurcewhSylI4XgXnCqNNT2FEJPIWZSqpRpMsjSy8VBbpy1uFdkqlOrm3oKOaLUpoMlHMuJfmnteo23epRnm7t79ip9qwYSoddqR0zr+vGnypkG0pr-k26NlbRm+x8i6-Rkzy3QwLXnJG5VtVpvNj29UbNt7gIxTuitPaLVKRptGY9qbT0y0rYWTlPk9GdpvdnMO3jFady1baxVaj-1HT1LKuuHyHkvrPT2vFwkrXBnbk-P1Xbd2ELxUPW5+kQO-oObMiOyctl8XGlu96qpvmCy1B3J0OblZFxPXFJjTyOnyI1MZBcLouM-p48x+W7crTMXsc+1MvHxXPJFpBkiG4tmie3fJiTsj406PrXJ50Cno3PMct+VyoNmmLotEZmpJmq7Se4Wqcj4m+OHIg4JP80ZBIacY9pxCxHSylnavqFCjatOudme50+pZHYmR8zzGz7ShlLhSqeWtYicGofC4pjp6p7atQXL6hjCW-OD1nLK9qDpQvcey8Z3LqXCz5xNHh4rmdEurPSUI3Tta64iay4Z91kqcbzN1Lh696F2u9QzSGat+KLPVd87qobv0SrxtBih-DIFJugodfu0zup1v0cW+KjN768bA1pjy1rGttvKo9QpfOGrHaDrCwNpbQahZMXtqJKxm2JuDY+wZYaiH13ZIWyV97SVBVMQhQo8SZaXMnYdazQLF4vyuv69ZgHUPioCVniW6MVX4ttex7xIhtDa1Huc7VhFKq1TfjCiaWFMHbtmr0pFJGG4f6qup29pH92QecKg4XKzrPZIfcw7OVytMXs1b54Rmd04ZVZI+SzuDPaQy0NlejsiXHjsK+oe5-HYtSH0bEzT9D79fl41lZShVYuCErrkfik03nRfq6t4WBihZWNxjVODkny7qFwK8VetXQew55fMVk+VmOHcCM9z7E5qnFzjcRwbgeKPzufsXAHm7HvqFCOEn9Yejtmfu4j0ne2wvONx4L7Ao6SvSMx3D9O6hfb43lj3nXyvsjEbQtk-b+vJ9SmGpOtV838vX2K9SmMxcCOLd-o17jdzqoFyWde1j3vHDk8m9NGnxft6rcGS1z5MRSCe9CAAOIUFIEQIg0j0nYY1AF5yYjZeT44jfsg9-H9DKrIJsIuJLgGaBGnLl-rfr-oUlcnqA9CAlzixL9tdgfEqN-nfg-tAXUgAX9AxLqCAWAVfNfpARgTMj8vjgREGM5EGGaBMoQWAGgVAaQYLNFi-o4tzkuAvlNAwSQSYlcn9MNMFFzmIsmp-lJNwX-lcnbNqJTFzl+GaEVnQeIZgYLHispHiuGE6DrgflwcQRIT8k3qrINFQSAVdoobocoUnADHir4hqLvJwRAT-jwbUoLOqqxoJiAZumYY4XoYLCXtqNYVznYTBmIeYUwfmHqAIali-iARUpjiEd4RYeyrjIIc5CxEVqIW6EoWEXRMeNITOM5IaGaLEZvvEegT4fmExHipQewVdhkagaEbwT8uqDDlXM5LgBGMel4WUYkYhGdhQT5OjiIZpjoQkdkYhLAXkaxg6LBGaBtuAaUYwY0euJaD7ARCMr+KAbzg4d0WMSlsJP0cYUosEZkQ0c4fNItAcdEZFNodsYsWcXRK2nke3KrCAeXiUScaMUsRUcnJLocRfn9rlB8TsV8Q8cRH9G4dQYCnEUCXcWsv0bYcIu4fXOpICfUZ8fceGrjNUdQd3u8WicCRiaGAjNqGsQgb0TcQsU4XYtgcIh3FzAZrcVSekjNnkSeNMSAZWAqpSeUXRNKiSfZujmAXUUQeiWsuCfyZQS6K8fYdyT0WaPesGBuMAa9AybKbsVvPye3HSbUcMbBvibCekhEdqI8dMVaDQVsfklkSCcGueAEc5DmvcgCcOiKQSXCccoiXIZyZjpaacXCf4Q1novYT6aKYaSVKukBiAXMQEjCUycll1v6b4oqpOlZsGa6ekgqe4dMdQQQcsjGTyYhDIawTYSxN+rqamQaclhmdUXXBvuAeWbGR4isXrLDtMTMZ4bmfqQ2T8niraQrAUYhC1p-vWfmSlnrHigwuwekWWXmXKbrHkQwoBOaVOvQb6ekgRFYYicWGaFCU6Uui6RWXwT7BylztQZ0R2fuV2cwezARLgSxMUcgVGlaYSYLvAaaZGRaTObseKQiRoewRMkOZ+daSscXhuIuf8XWYBYSSwQRL+e1IOdOZ2SOc2UYXSW8RBYhT0aGHigJOORGVhTccOZhX4S8W+Ucd6ZBWsgFgiZKRFEgQBRhWMSscNDIdMeGPScuU+WKUdNhXhVOdGQxdaUhKsX2W0bMR+QJYSeGawROctP+QhRefmTQUdOGQ6MqFqGaLiehQpURckVXKVGRARRRembjE3qpWaTmf6pxU-sJb+UEX2DulZZWYtO+tMXIcmvxdpbsVUfyQxB3AZTBoRYxY1tIaBVue2ZZauclgJtWeGkGUZcltOMxalqJeBR5SuSGclsSYYU5KJTuVpelWmQlRcYpP2fIYZRJWsolSFc5DWeVZ5YJftk5MAUUeJfVYSZrj5QMeSQFfFY2fuiaR3DghxZFYeZUSVS8brj1RVekjgcaShVuY6flY5VchqdRVztsgBMTvntNf-kIshTlepUgfrstWQWEikRqNsrXruVvm1dSdJi2Q6GxVGRDrdWuT8eNZdfYUZidcsQBh+tMRsZlpvt9SNd2WdUYXgUhDcSDRlX1UdDeVzhsWeYHq9VFRceteMRPrqTDYVY2UXoqWZR4QyTjQeadc2YjQOV9b1VgUIl9oRADSAbQS9QVaTb4cVdUZ9a3izZefmDbHNVMWxZpcdaDYLPCQRDYctPeZ-iTTzXgCsQJCpQ6FGGVUPjtStWEseTVQOUdszT9ecQDCkeyUSVjcLbDT8kaT+T5DmptRXqjXDVho4ouV6cDdTYLILtUYMVTWrVgbDh5gzRpVsTLSOSGC0diQOSbbrSLbzWCaBRsbLqbbjadWoeNTWYBOxEHZhQYdhocfHZHWbSxiVOLWSf5bbdzYpeoU8bIR4YHa7fmKoSSXhaAVtVtrXXRO5uKZodXarXbVgXOYYbgcreBdLa3QOViSJXIYtQnazXXYtLNfab0V7T3csSfnNSeM1bnSjWXZncJW4e1KaM3f9t7csd+U1WafeVPbLeMrPfkR5sbcwhpPLnrW3SZa0bBENZflvbsSHQmYEdrQfenk-fZQOP2CAwA1HaCQJKScYUSYvZ-UBYWElb4uyU3d3XA5JcJc8TMXxXnYnS4cnNndEUuR-QAMJaCfCkAMBoBUIDwsHKYXgboUluikPkOUOoDUPSAAF80XiiQtZ0HMMcAUNUNoLvzblHTNEq5C1QL8OcCsPsNJHA5PTPZm66lSTSOCNsPCMVzyGtQaq0xXXzFMNkMCOyOaMDyzV4ybyOyLXClgBqMmOO63zP5ZX+xOzHFKh2NCMONeyiNUybJ6OqmGMsOeMJ6ONERcIuo6l8NGMyPBNgDsI+OzhcKOwWWSIeMaNePnH0qbwLhDFRNBPpMhPeMGSJliNNJ54oFCBpNyPhofq6gZSMPuPRPqPVPyFES+7n4BONP5PVMpYAzJ6OZN1WaqNNP2OFMcN90KlOgdNcmBPGOxPxM1o+RBZfpbHDPdOmMcN44r6RINOVMjPzOEJVXhLC50UqOzMxMFNxOELiOPRvLjKrPnPNMbO8nunzwLrXVrNzOXOVqC4dUE6p4zNdNfM9NUVQqfp+JuN7PrMZNy1Z7qjZodqAtQvAvPO9GrY0bvK7O2P7PfPoKtOlQXjcqdPIsXMtN91GkSwAspmPOjNXNW5cMMJ+7uXnnYvQtjOgkXqbw7NTUktPMwscklVWhOgurhUEZVOotCzqrGTix1Wssov8tKXe6CtiLI1is4s9N7VzXxq0xzH0W8u0vxMbJSY5p5VpXiv8uhhR7HMXhd6tVyuksSt-MGGqigzwVmvquOuj6U7ZJxVAsOsKtKvFnjF2vmvstotSukZVayuht0taPeWAyMsishsesWtcJsFdzLkxuVpnZ-N76aV6v2t8thsrFpthSMoMn5JZuELEX5yMrRspvFtqrR7cMvQR2b1VsiN-WPSSliJHXM0dtaM+7NuOZyX64DsDxpshTbKqst1+tFuxtFNeJPTizE00sHP0u4wskXiOzIT-21bjvhHERHMutfrKNjsNsLscNA6BZTPJku1zsGvVvou1oLhA0Pnp4Huws6OJk5poXntsuXsvPUZUw6uwOfsCuIyby0x9vtsXuVrmNgv-PO3vv7twfXNiN9kWi-ursPvruDs+wJqg50wkNodW5-QNIPz1pnv9ukdaMGRpuSk8M4f6t4c0Mv3Dygz5vY1ru4tkerZz5cf-vyvFvHmAxSbtSpU0cAeVrxsQZOimSjtSfCeAej1syuTr7lOH0se8f4ebzF2mtKf+uNsEetTJNtvbV3AAC6QAA", # nolint
+ blockr:::create_app_link(
+ blockr:::shinylive_links["filesbrowser-block"],
"app",
header = FALSE
),
full_screen = TRUE
)
+
+blockr:::print_shinylive_r_code("filesbrowser-block")
```
Note that in a later release, we plan to merge `filesbrowser_block()` and `upload_block()` into
@@ -176,28 +146,16 @@ a `new_dataset_block()` from which we can select some columns with `new_select_b
we can reuse this smaller dataset. If you dynamically add a third stack, you can also select the third stack's
output as input to the second stack (it appears in the result block select input).
-```r
-library(blockr)
-library(blockr.data)
-
-serve_workspace(
- stack1 = new_stack(
- new_dataset_block("lab", "blockr.data"),
- new_select_block(c("STUDYID", "USUBJID"))
- ),
- stack2 = new_stack(new_result_block),
- stack3 = new_stack(new_dataset_block("ae", "blockr.data")),
- title = "My workspace"
-)
-```
-
-```{r, eval=TRUE, echo=FALSE}
+```{r, results="asis", echo=FALSE, warning=FALSE, comment = ""}
+# shinylive container
card(
- create_app_link(
- "NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAdzgCMAnRRASwgGdSoAbbgCgA6YOtyIEA1gyG4ABAzioi7GQF4ZBQWAAWpUqnaIA9IZFjJAWiIMA5hmstSWgK50MLIodqNz8xe2kyQjp6Bsa+RBgM5tRQ7DAYVtZCAJTJAhDcLIxQDACefKYSDGkZWQw5+YWSGAAmUFwl6exwDABucAD61Fbi7KhQBHCCEDIynAPiAIyqMhBw1B3jEsOjo3MLdVzNpB1VmtxQdAFCVQy19VApuOmrs-OLcNxwBDt7GkIAygAqAKoAIgBNACSf2OYB+Hx+ACEAFIglIlUbJa4jMZcCQAJhm60W6PEfBx8nYTm4r1EEmRNzREwAzNj7kt8TjNrE4GSzJooHAwadzlwESjRqQHE8ZkIALK5GTdBi9fqDITpZJgAC+AF0gA", # nolint
+ blockr:::create_app_link(
+ blockr:::shinylive_links["result-block"],
"app",
header = FALSE
),
full_screen = TRUE
)
+
+blockr:::print_shinylive_r_code("result-block")
```
diff --git a/vignettes/developer-guide.Rmd b/vignettes/internals.Rmd
similarity index 98%
rename from vignettes/developer-guide.Rmd
rename to vignettes/internals.Rmd
index 6be8b159..65072a57 100644
--- a/vignettes/developer-guide.Rmd
+++ b/vignettes/internals.Rmd
@@ -1,8 +1,8 @@
---
-title: "Developer guide"
+title: "6: Internals"
output: rmarkdown::html_vignette
vignette: >
- %\VignetteIndexEntry{Developer guide}
+ %\VignetteIndexEntry{6: Internals}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
diff --git a/vignettes/new-field.Rmd b/vignettes/new-field.Rmd
index 17f84ebd..b970b6cd 100644
--- a/vignettes/new-field.Rmd
+++ b/vignettes/new-field.Rmd
@@ -108,11 +108,13 @@ ui_update.slider_field <- function(x, session, id, name) {
We can test our newly created field in a custom block.
-```{r, eval=TRUE, echo=FALSE}
+```{r, echo=FALSE}
+# shinylive container
card(
- create_app_link(
- "NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAdzgCMAnRRASwgGdSoAbbgCgA6YOtyIEA1gyG4ABAzioi7GQF4ZBQWAAWpUqnaIA9IZFjJAWiIMA5hmstSWgK50MLIodqNz8xe2kyQjp6Bsa+RBgM5tRQ7DAYVtZCAJTJAhDp3CyMUAwAnnymEgxpGRAQcNQA+uxZACZwDFUAZixw3HUyADzmMs1OEASk7hCCEDITMgBuPE5wqjIQTvAMLBrJuOmTMjBsC0sra3wbW5MwUAAe+8uNRyfjk5wK14frmw8TGF-JMiCnRZJmBVqq12nUxtsZtw5gsoXN3ttduM1EiEWdLgtzhc0RMnqgFnicTIvhgiQRuLFlGohLUWA0mqCOkJTqUAL7pdJOFhVNioJykDC0+ktNodbq9fqDYYkPjYmR02TQeA-P4PdhaNh5ZhCxoASQgfNIEMmAKYrAN-J5dXYstkdPu2yVcCJcPmalNzFdtsCYFdKSJSIWHsQXrlQiR-tOEyxQdExU9szg3vDl0jHxkeNjZjNodkNPIqBSLPS7LKULpUHIIrBgvqjWrYp6fQGQxGspVpyh4umifbp0DTdzPojYFK0Yxg97YbAWKLaoL3aH+YUc87PArVYOdEafChpVOLGaMj43Ao1kcfCRqV+UZ79UrcCqW53qOHbDnE1LB6PJ7PF6x16qpC651A+T7LNuDCXpceYzqmo6nF+DyHsep4QOeWh8HigG3uWoGbhBO6Ej6eIfjISETAAcnAFykAAsnAjhEOCbIcks3JOKg+FwLWdL1oynRNpKrYynK7BwOw7AjHadSKrAcAdg8nHcQAynWDD6oaxq4hJUkkESwa8padI2nK9pEk6BlxoCIZTg6JrWTmU6wSO9kTMGS5wRcabbB5zkkQWZGsWU8j2E8DAqQAzPATHgkIXI8hapABDS6kNnUAQJUZAo6gyop1KUoUsOFUUxVozGaAlykPilYC5elmUcVxD68cKAn7uUlQ1FkBCPgC3bCdKozNAwRAwAsAAMsgkoppwQFUo3UMoTYCAIfD4VAPwQIt62VptbETAJy29FknDaXIRBLfsXX1QJ50TK6CwjWNRLRnsahTbe45XGo82Lewr0ZguagAIyA8MpCngsQgqe0cBDBdS3MumY4yB1EzAlUALnUdT35QDt40agDALAAjk4RDkOtqDcHkZq0r1WFwKTVRoXwGB8P9qSpBZ8nQ2Aal8STDPzAC0i3iSZIUpJCwaKlax9dZtWkAwUAcM0VgwFjSsIQ8wXpOJDBTI+nBQBIxqY6b5u3pjG3iaQ2tmJoLCrP4o4WTdPWK07ACsqOlMkYCsgAukAA", # nolint
- mode = "editor"
+ blockr:::create_app_link(
+ blockr:::shinylive_links["custom-field"],
+ "app",
+ header = FALSE
),
full_screen = TRUE
)
@@ -122,7 +124,7 @@ card(
@@ -131,36 +133,7 @@ Toggle code
-
-```r
-new_slice_block <- function(from = 0, ...) {
-
- n_rows <- \(data) nrow(data)
-
- fields <- list(
- rows = new_slider_field(
- value = from,
- min = 0,
- max = n_rows,
- step = 1,
- title = "Select rows"
- )
- )
-
- new_block(
- fields = fields,
- expr = quote(dplyr::slice(seq_len(.(rows)))),
- name = "Slider slice block",
- ...,
- class = c("slice_block", "transform_block")
- )
-}
-
-serve_stack(
- new_stack(
- new_dataset_block("iris"),
- new_slice_block(5)
- )
-)
+```{r, results="asis", echo=FALSE, warning=FALSE, comment = ""}
+blockr:::print_shinylive_r_code("custom-field")
```
diff --git a/vignettes/plot-block.Rmd b/vignettes/plot-block.Rmd
index afe0021f..26812058 100644
--- a/vignettes/plot-block.Rmd
+++ b/vignettes/plot-block.Rmd
@@ -389,8 +389,8 @@ serve_stack(stack)
```{r, eval=TRUE, echo=FALSE}
card(
- create_app_link(
- "NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAdzgCMAnRRASwgGdSoAbbgCgA6YOtyIEA1gyG4ABAzioi7GQF4ZBQWAAWpUqnaIA9IZFjJAWiIMA5hmstSWgK50MLIodqNz8xe2kyQjp6Bsa+RBgM5tRQ7DAYVtZCAJTJAhDcLIxQDACefKYSDGkZWQw5+ag88AyoFNZObOwlmdl5fNbWqKKkAEwl6RBw1AD6nd1EpCOF4jIAPOYyAGZOEASk7hB8xNwjAB6q6lo5UOtwDHzJsjsjuYcEx+VnF1cyGO-JMiDp6TIyACZQLgjHbKBbLVbrTZ8QFcT47aDwdgwoFQAYQP5DUYzQQYv7LFhwbj-ZRqTKcXH4-EHNRYkbsIlwdYjJaE4nbIi7PayWFQEGc9iyUi5OqHISIuApXC-KkyO604b0xnM1lE-4c3a5Hmo-ncQUyYWitTi2CSsAlKlXGV-OB7VAMQ4ARyckzglNl4x6fBgaFQbGshygcGRNLefD2r3lYdyqQt+KteL+BG4sVJ6k0nsm01EEgCQgmUxmUutb3eMpKAF8fhA6dY4EQYIo2IWc7NwSs1hsSBqrPdHqdyC9ZOxjkajidnpdZO8MJ9vhAZbzdWDFh2od3efDORLkbyACSb6uYxU4kuq4lp8mkd1Una9hWjBncJlTc-qu8MbXA0FCkVwMWQKaxaJviI5oP+D5Ks+KpsuqYF1F+fI-gaf4ARKKQlgmVK2vaTouuQN74nWDYjE2ZB8EGyIfocGA9sUw6jhBYbwXAqTDiwABeTH9Jh0ogcmqb3JoBYjCmuTnNmZh5mAIlFuafFUjO5bpFWC4cFwEjzIsdKcKc4jukuMyHHSvIMi2ZjCfUjQcNJVTcDUdQQA0TRSoEeKya2xmKpm5kSJoSyZOgEnPk5jgjDAMDSXQRD-Lk4WpmMwF-GJElGZBxGNkQzaSX5QjsHUBCEv4eCBGA+VMkVGEQCUDIMAAbnA9IafpukSMkYAVgAukAA", # nolint
+ blockr:::create_app_link(
+ blockr:::shinylive_links["ggplot-block"],
"app",
header = FALSE
),
diff --git a/vignettes/registry.Rmd b/vignettes/registry.Rmd
index 74a41dfe..6ed103f0 100644
--- a/vignettes/registry.Rmd
+++ b/vignettes/registry.Rmd
@@ -32,15 +32,6 @@ note_box <- function(..., color) {
## Introduction
-```{r, eval=TRUE, echo=FALSE}
-note_box(
- "This part is likely more dedicated to developers than users. However,
- it might be useful whenever you design custom blocks and want to register
- them in `{blockr}`.",
- color = "primary"
-)
-```
-
The __registry__ is a __environment__ which provides access to multiple __blocks__ as well as some
metadata:
@@ -187,8 +178,8 @@ visible in the new choices:
```{r, eval=TRUE, echo=FALSE}
card(
- create_app_link(
- "NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAdzgCMAnRRASwgGdSoAbbgCgA6YOtyIEA1gyG4ABAzioi7GQF4ZBQWAAWpUqnaIA9IZFjJAWiIMA5hmstSWgK50MLIodqNz8xe2kyQjp6Bsa+RBgM5tRQ7DAYVtZCAJTJAhDcLIxQDACefKYSDGkQ6RBw1AD6XCzclYXiMgA85jIAZk4QBKTuEHwAJlBcshCVDETUymoQTvAMLBrJshgryTIg6ekyMqPjk5UwUAAeza0dXT0kA0NQaxB711wl21s7FfWiEoIQ29ttLHBuP0pjJMpxvr9frsJiDylUZnMFpV-oD+nxoZNZABGAAyIzGMIOx2evyWr22cCOqAYqhkAEcnERyHwavwfmoMOiCZNUmSfr8CNxYiCNEJWR8zAExQwoBw2lYYBKJClcOSZCsMK8SgBfTb3OD2ThwBhK8QQ9QkTgMJzdKy0uHVKC1U2q-nQeC0sVO7gyBrSV79ODsAjzVCXdmBMDyUhOBg-IWcHZyGH+-mC4VB2misDiv14SOkGVyhWmlWvNioJykT1gQZcDBtGXwVPbIhVyvVtRCOtQBtNuBCdIldKcKASU5vKqjr4OnvsOCkU0lecMABucEq07NW+SYG1AF0gA", # nolint
+ blockr:::create_app_link(
+ blockr:::shinylive_links["registry-demo"],
"app",
header = FALSE
),