Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add decorators to all TMG modules #1370

Closed
15 tasks done
gogonzo opened this issue Oct 9, 2024 · 2 comments
Closed
15 tasks done

Add decorators to all TMG modules #1370

gogonzo opened this issue Oct 9, 2024 · 2 comments
Assignees
Labels

Comments

@gogonzo
Copy link
Contributor

gogonzo commented Oct 9, 2024

Blocked by #1368

  • Assign yourself to a single module by adding your name next to the item.
  • add the decorator functionality to the module and update relevant documentation by including the decorator
  • Keep consistent output names - table, listing, graph
  • PR link should be added next to the item
  • once merged ✔️ the item

Items:

@gogonzo gogonzo added the core label Oct 9, 2024
@gogonzo gogonzo transferred this issue from insightsengineering/teal Oct 9, 2024
@gogonzo gogonzo transferred this issue from insightsengineering/teal.modules.general Oct 9, 2024
@gogonzo gogonzo added this to the Decorate modules' output milestone Oct 9, 2024
@averissimo averissimo self-assigned this Nov 18, 2024
@m7pr m7pr self-assigned this Nov 18, 2024
@m7pr
Copy link
Contributor

m7pr commented Nov 18, 2024

@averissimo do you think we should go with graph name, or with plot name for plot objects?
tm_a_regression would a review of the names as it uses g and p. I also think that documentation should contain an information on what are the possible names of objects to be decorated as we have in teal::example_module() https://github.com/insightsengineering/teal/pull/1357/files#diff-30b1b14a6fc7f2b6907f241d0f5d2e780dea7396ded16caffc8147b3d0fdf5a7R5-R9

m7pr added a commit to insightsengineering/teal.modules.general that referenced this issue Nov 21, 2024
Part of insightsengineering/teal#1370

<details><summary> Working Example </summary>

```r
devtools::load_all("../teal")
devtools::load_all(".")
library(ggplot2)
interactive_decorator <- teal_transform_module(
  ui = function(id) {
    ns <- NS(id)
    div(
      textInput(ns("x_axis_title"), "X axis title", value = "x axis")
    )
  },
  server = function(id, data) {
    moduleServer(id, function(input, output, session) {
      reactive({
        req(data())
        within(data(),
               {
                 plot <- plot +
                   xlab(my_title)
               },
               my_title = input$x_axis_title
        )
      })
    })
  }
)
# general data example
data <- teal_data()
data <- within(data, {
  require(nestcolor)
  CO2 <- data.frame(CO2)
})

app <- init(
  data = data,
  modules = tm_g_bivariate(
    x = data_extract_spec(
      dataname = "CO2",
      select = select_spec(
        label = "Select variable:",
        choices = variable_choices(data[["CO2"]]),
        selected = "conc",
        fixed = FALSE
      )
    ),
    y = data_extract_spec(
      dataname = "CO2",
      select = select_spec(
        label = "Select variable:",
        choices = variable_choices(data[["CO2"]]),
        selected = "uptake",
        multiple = FALSE,
        fixed = FALSE
      )
    ),
    row_facet = data_extract_spec(
      dataname = "CO2",
      select = select_spec(
        label = "Select variable:",
        choices = variable_choices(data[["CO2"]]),
        selected = "Type",
        fixed = FALSE
      )
    ),
    col_facet = data_extract_spec(
      dataname = "CO2",
      select = select_spec(
        label = "Select variable:",
        choices = variable_choices(data[["CO2"]]),
        selected = "Treatment",
        fixed = FALSE
      )
    ),
    decorators = list(interactive_decorator)
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}
```

</details>

---------

Signed-off-by: Marcin <[email protected]>
Co-authored-by: André Veríssimo <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.general that referenced this issue Nov 21, 2024
Part of insightsengineering/teal#1370

<details><summary> Working Example </summary>

```r
pkgload::load_all("../teal")
pkgload::load_all("../teal.modules.general")

footnote_dec <- teal_transform_module(
  label = "Footnote",
  ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = "I am a good decorator"),
  server = function(id, data) {
    moduleServer(id, function(input, output, session) {
      logger::log_info("🟢 Footnote called to action!", namespace = "teal.modules.general")
      reactive(
        within(
          data(),
          {
            footnote_str <- footnote
            plot <- plot + ggplot2::labs(caption = footnote_str)
          },
          footnote = input$footnote
        )
      )
    })
  }
)


title_plot <- teal_transform_module(
  server = make_teal_transform_server(
    expression(
      logger::log_info("🔴 Title being called to action!", namespace = "teal.modules.general"),
      plot <- plot + ggplot2::ggtitle("A title to the plot")
    )
  )
)

# CDISC data example
data <- teal_data()
data <- within(data, {
  require(nestcolor)
  ADSL <- rADSL
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

app <- init(
  data = data,
  modules = modules(
    tm_g_response(
      label = "Response Plots",
      decorators = list(footnote_dec, title_plot),
      response = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Select variable:",
          choices = variable_choices(data[["ADSL"]], c("BMRKR2", "COUNTRY")),
          selected = "BMRKR2",
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Select variable:",
          choices = variable_choices(data[["ADSL"]], c("SEX", "RACE")),
          selected = "RACE",
          multiple = FALSE,
          fixed = FALSE
        )
      )
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}
```

</details>

---------

Signed-off-by: André Veríssimo <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.general that referenced this issue Nov 21, 2024
Part of insightsengineering/teal#1370

<details><summary> Working Example </summary>

```r
pkgload::load_all("../teal")
pkgload::load_all("../teal.modules.general")

footnote_dec <- teal_transform_module(
  label = "Footnote",
  ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = "I am a good decorator"),
  server = function(id, data) {
    moduleServer(id, function(input, output, session) {
      logger::log_info("🟢 Footnote called to action!", namespace = "teal.modules.general")
      reactive(
        within(
          data(),
          {
            footnote_str <- footnote
            plot <- plot + ggplot2::labs(caption = footnote_str)
          },
          footnote = input$footnote
        )
      )
    })
  }
)

table_dup_dec <- teal_transform_module(
  server = make_teal_transform_server(
    expression(
      logger::log_info("🔴 Table dup being called to action!", namespace = "teal.modules.general"),
      summary_table <- rbind(summary_table, summary_table),
      if (exists("test_table")) test_table <- rbind(test_table, test_table, test_table) 
    )
  )
)

# CDISC data example
data <- teal_data()
data <- within(data, {
  ADSL <- rADSL
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

vars1 <- choices_selected(
  variable_choices(data[["ADSL"]], c("ARM", "COUNTRY", "SEX")),
  selected = NULL
)

app <- init(
  data = data,
  modules = modules(
    tm_g_distribution(
      decorators = list(footnote_dec, table_dup_dec),
      dist_var = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1")),
          selected = "BMRKR1",
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      strata_var = data_extract_spec(
        dataname = "ADSL",
        filter = filter_spec(
          vars = vars1,
          multiple = TRUE
        )
      ),
      group_var = data_extract_spec(
        dataname = "ADSL",
        filter = filter_spec(
          vars = vars1,
          multiple = TRUE
        )
      )
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}
```

</details>

---------

Signed-off-by: André Veríssimo <[email protected]>
m7pr added a commit to insightsengineering/teal.modules.general that referenced this issue Nov 22, 2024
Part of insightsengineering/teal#1370

<details><summary> Working Example </summary>

````r
devtools::load_all("../teal")
devtools::load_all(".")


split_by_decorator <- teal_transform_module(
  label = "Footnote",
  ui = function(id) shiny::textInput(
    shiny::NS(id, "text"), "Insert row", "Hello World!" 
  ),
  server = function(id, data) {
    moduleServer(id, function(input, output, session) {
      logger::log_info("🟢 Text called to action!", namespace = "teal.modules.general")
      reactive(
        within(
          data(),
          {
              table <- table %>% insert_rrow(rrow(text))
          },
          text = input$text
        )
      )
    })
  }
)

# CDISC data example
data <- teal_data()
data <- within(data, {
  ADSL <- rADSL
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

app <- init(
  data = data,
  modules = modules(
    tm_t_crosstable(
      label = "Cross Table",
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Select variable:",
          choices = variable_choices(data[["ADSL"]], subset = function(data) {
            idx <- !vapply(data, inherits, logical(1), c("Date", "POSIXct", "POSIXlt"))
            return(names(data)[idx])
          }),
          selected = "COUNTRY",
          multiple = TRUE,
          ordered = TRUE,
          fixed = FALSE
        )
      ),
      y = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Select variable:",
          choices = variable_choices(data[["ADSL"]], subset = function(data) {
            idx <- vapply(data, is.factor, logical(1))
            return(names(data)[idx])
          }),
          selected = "SEX",
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      decorators = list(split_by_decorator)
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}


````

</details>

---------

Signed-off-by: Marcin <[email protected]>
Co-authored-by: 27856297+dependabot-preview[bot]@users.noreply.github.com <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: André Veríssimo <[email protected]>
m7pr added a commit to insightsengineering/teal.modules.general that referenced this issue Nov 22, 2024
Part of insightsengineering/teal#1370

<details><summary> Working Example </summary>

```r

devtools::load_all("../teal")
devtools::load_all(".")
plot_title <- teal_transform_module(
  server = make_teal_transform_server(expression({
    plot <- plot + ggtitle("Custom title")
  }))
)

# general data example
data <- teal_data()
data <- within(data, {
  require(nestcolor)
  USArrests <- USArrests
})

app <- init(
  data = data,
  modules = modules(
    tm_a_pca(
      "PCA",
      dat = data_extract_spec(
        dataname = "USArrests",
        select = select_spec(
          choices = variable_choices(
            data = data[["USArrests"]], c("Murder", "Assault", "UrbanPop", "Rape")
          ),
          selected = c("Murder", "Assault"),
          multiple = TRUE
        ),
        filter = NULL
      ),
      decorators = list(plot_title)
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}

```

</details>

---------

Signed-off-by: Marcin <[email protected]>
Co-authored-by: André Veríssimo <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.general that referenced this issue Nov 22, 2024
Part of insightsengineering/teal#1370

<details><summary> Working Example </summary>

```r


pkgload::load_all("../teal")
pkgload::load_all(".")


footnote_dec <- teal_transform_module(
  label = "Footnote",
  ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = "I am a good decorator"),
  server = function(id, data) {
    moduleServer(id, function(input, output, session) {
      logger::log_info("🟢 Footnote called to action!", namespace = "teal.modules.general")
      reactive(
        within(
          data(),
          {
            plot$xlab <- footnote
          },
          footnote = input$footnote
        )
      )
    })
  }
)

# general data example
data <- teal_data()
data <- within(data, {
  countries <- data.frame(
    id = c("DE", "FR", "IT", "ES", "PT", "GR", "NL", "BE", "LU", "AT"),
    government = factor(
      c(2, 2, 2, 1, 2, 2, 1, 1, 1, 2),
      labels = c("Monarchy", "Republic")
    ),
    language_family = factor(
      c(1, 3, 3, 3, 3, 2, 1, 1, 3, 1),
      labels = c("Germanic", "Hellenic", "Romance")
    ),
    population = c(83, 67, 60, 47, 10, 11, 17, 11, 0.6, 9),
    area = c(357, 551, 301, 505, 92, 132, 41, 30, 2.6, 83),
    gdp = c(3.4, 2.7, 2.1, 1.4, 0.3, 0.2, 0.7, 0.5, 0.1, 0.4),
    debt = c(2.1, 2.3, 2.4, 2.6, 2.3, 2.4, 2.3, 2.4, 2.3, 2.4)
  )
  sales <- data.frame(
    id = 1:50,
    country_id = sample(
      c("DE", "FR", "IT", "ES", "PT", "GR", "NL", "BE", "LU", "AT"),
      size = 50,
      replace = TRUE
    ),
    year = sort(sample(2010:2020, 50, replace = TRUE)),
    venue = sample(c("small", "medium", "large", "online"), 50, replace = TRUE),
    cancelled = sample(c(TRUE, FALSE), 50, replace = TRUE),
    quantity = rnorm(50, 100, 20),
    costs = rnorm(50, 80, 20),
    profit = rnorm(50, 20, 10)
  )
})
join_keys(data) <- join_keys(
  join_key("countries", "countries", "id"),
  join_key("sales", "sales", "id"),
  join_key("countries", "sales", c("id" = "country_id"))
)

app <- init(
  data = data,
  modules = modules(
    tm_g_scatterplotmatrix(
      label = "Scatterplot matrix",
      variables = list(
        data_extract_spec(
          dataname = "countries",
          select = select_spec(
            label = "Select variables:",
            choices = variable_choices(data[["countries"]]),
            selected = c("area", "gdp", "debt"),
            multiple = TRUE,
            ordered = TRUE,
            fixed = FALSE
          )
        ),
        data_extract_spec(
          dataname = "sales",
          filter = filter_spec(
            label = "Select variable:",
            vars = "country_id",
            choices = value_choices(data[["sales"]], "country_id"),
            selected = c("DE", "FR", "IT", "ES", "PT", "GR", "NL", "BE", "LU", "AT"),
            multiple = TRUE
          ),
          select = select_spec(
            label = "Select variables:",
            choices = variable_choices(data[["sales"]], c("quantity", "costs", "profit")),
            selected = c("quantity", "costs", "profit"),
            multiple = TRUE,
            ordered = TRUE,
            fixed = FALSE
          )
        )
      ),
      decorators = list(footnote_dec)
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}
```

</details>

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: 27856297+dependabot-preview[bot]@users.noreply.github.com <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: André Veríssimo <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.general that referenced this issue Nov 22, 2024
Part of insightsengineering/teal#1370

<details><summary> Working Example </summary>

```r
pkgload::load_all("../teal")
pkgload::load_all(".")

footnote_dec <- teal_transform_module(
  label = "Footnote",
  ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = "I am a good decorator"),
  server = function(id, data) {
    moduleServer(id, function(input, output, session) {
      logger::log_info("🟢 Footnote called to action!", namespace = "teal.modules.general")
      reactive(
        within(
          data(),
          {
            footnote_str <- footnote
            plot <- plot + ggplot2::labs(caption = footnote_str)
          },
          footnote = input$footnote
        )
      )
    })
  }
)

# CDISC data example
data <- teal_data()
data <- within(data, {
  require(nestcolor)
  ADSL <- rADSL
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

app <- init(
  data = data,
  modules = modules(
    tm_g_scatterplot(
      label = "Scatterplot Choices",
      x = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Select variable:",
          choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1", "BMRKR2")),
          selected = "AGE",
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      y = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Select variable:",
          choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1", "BMRKR2")),
          selected = "BMRKR1",
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      color_by = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Select variable:",
          choices = variable_choices(
            data[["ADSL"]],
            c("AGE", "BMRKR1", "BMRKR2", "RACE", "REGION1")
          ),
          selected = NULL,
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      size_by = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Select variable:",
          choices = variable_choices(data[["ADSL"]], c("AGE", "BMRKR1")),
          selected = "AGE",
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      row_facet = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Select variable:",
          choices = variable_choices(data[["ADSL"]], c("BMRKR2", "RACE", "REGION1")),
          selected = NULL,
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      col_facet = data_extract_spec(
        dataname = "ADSL",
        select = select_spec(
          label = "Select variable:",
          choices = variable_choices(data[["ADSL"]], c("BMRKR2", "RACE", "REGION1")),
          selected = NULL,
          multiple = FALSE,
          fixed = FALSE
        )
      ),
      decorators = list(footnote_dec)
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}

```

</details>

---------

Signed-off-by: Marcin <[email protected]>
Co-authored-by: André Veríssimo <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.general that referenced this issue Nov 22, 2024
Part of insightsengineering/teal#1370

<details><summary> Working Example </summary>

```r

devtools::load_all("../teal")
devtools::load_all(".")
interactive_decorator <- teal_transform_module(
  ui = function(id) {
    ns <- NS(id)
    div(
      textInput(ns("x_axis_title_top"), "X axis title plot top", value = "x axis top"),
      textInput(ns("x_axis_title_bottom"), "X axis title plot bottom", value = "x axis bottom")
    )
  },
  server = function(id, data) {
    moduleServer(id, function(input, output, session) {
      reactive({
        req(data())
        within(data(),
               {
                 plot_bottom <- plot_bottom + xlab(my_title_bottom)
                 plot_top <- plot_top + xlab(my_title_top)
               },
               my_title_top = input$x_axis_title_top,
               my_title_bottom = input$x_axis_title_bottom
        )
      })
    })
  }
)

# general data example
data <- teal_data()
data <- within(data, {
  require(nestcolor)
  CO2 <- CO2
  factors <- names(Filter(isTRUE, vapply(CO2, is.factor, logical(1L))))
  CO2[factors] <- lapply(CO2[factors], as.character)
})

app <- init(
  data = data,
  modules = modules(
    tm_g_association(
      ref = data_extract_spec(
        dataname = "CO2",
        select = select_spec(
          label = "Select variable:",
          choices = variable_choices(data[["CO2"]], c("Plant", "Type", "Treatment")),
          selected = "Plant",
          fixed = FALSE
        )
      ),
      vars = data_extract_spec(
        dataname = "CO2",
        select = select_spec(
          label = "Select variables:",
          choices = variable_choices(data[["CO2"]], c("Plant", "Type", "Treatment")),
          selected = "Treatment",
          multiple = TRUE,
          fixed = FALSE
        )
      ),
      decorators = list(interactive_decorator)
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}

```

</details>

---------

Co-authored-by: André Veríssimo <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.general that referenced this issue Nov 22, 2024
Part of insightsengineering/teal#1370

<details><summary> Working Example </summary>

```r


devtools::load_all("../teal")
devtools::load_all(".")

# general data example
data <- teal_data()
data <- within(data, {
  require(nestcolor)
  iris <- iris
})

custom_table_decorator_interactive <- teal_transform_module(
  ui = function(id) {
    ns <- NS(id)
    div(
      selectInput(
        ns("style"), 
        "Table Style", 
        choices = c("Default", "Striped", "Hover"), 
        selected = "Default"
      )
    )
  },
  server = function(id, data) {
    moduleServer(id, function(input, output, session) {
      reactive({
        req(data(), input$style)
        within(data(), 
               {
                 if (style == "Striped") {
                   table <-
                     DT::formatStyle(
                       table,
                       columns = attr(table$x, "colnames")[-1],
                       target = 'row',
                       backgroundColor = '#f9f9f9'
                     )
                 } else if (style == "Hover") {
                   table <-
                     DT::formatStyle(
                       table,
                       columns = attr(table$x, "colnames")[-1],
                       target = 'row',
                       backgroundColor = '#f0f0f0'
                     )
                 }
               }, 
               style = input$style
        )
      })
    })
  }
)

app <- init(
  data = data,
  modules = modules(
    tm_data_table(
      variables_selected = list(
        iris = c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width", "Species")
      ),
      dt_args = list(caption = "IRIS Table Caption"),
      decorators = list(custom_table_decorator_interactive)
    )
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}
```

</details>

---------

Signed-off-by: Marcin <[email protected]>
Co-authored-by: André Veríssimo <[email protected]>
averissimo added a commit to insightsengineering/teal.modules.general that referenced this issue Nov 26, 2024
Part of insightsengineering/teal#1370

<details><summary>Updated working example</summary>

```r
# tm_missing_data

pkgload::load_all("../teal")
pkgload::load_all(".")

plot_grob_decorator <- function(default_footnote = "I am a good decorator", variable_to_replace = "summary_plot") {
  teal_transform_module(
    label = "Plot",
    ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = default_footnote),
    server = function(id, data) {
      moduleServer(id, function(input, output, session) {
        logger::log_info("🟠 plot_grob with default: {default_footnote}!", namespace = "teal.modules.general")
        reactive({
          req(data(), input$footnote)
          logger::log_info("changing the footnote {default_footnote}", namespace = "teal.modules.general")
          teal.code::eval_code(data(), substitute(
            {
            footnote_grob <- grid::textGrob(footnote, x = 0, hjust = 0, gp = grid::gpar(fontsize = 10, fontface = "italic", col = "gray50"))
            
            # Arrange the plot and footnote
            variable_to_replace <- gridExtra::arrangeGrob(
              variable_to_replace,
              footnote_grob,
              ncol = 1,
              heights = grid::unit.c(grid::unit(1, "npc") - grid::unit(1, "lines"), grid::unit(1, "lines"))
            )
          }, 
          env = list(
            footnote = input$footnote,
            variable_to_replace = as.name(variable_to_replace)
          )))
        })
      })
    }
  )
}

caption_decorator <- teal_transform_module(
  ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = "D"),
  server = make_teal_transform_server(
    expression(by_subject_plot <- by_subject_plot + ggplot2::labs(caption = footnote))
  )
)

table_decorator_interactive <- teal_transform_module(
  label = "Table",
  ui = function(id) {
    selectInput(
      NS(id, "style"), 
      "Table Style", 
      choices = c("Default", "Striped", "Hover"), 
      selected = "Default"
    )
  },
  server = function(id, data) {
    moduleServer(id, function(input, output, session) {
      logger::log_info("🔵 Footnote called to action!", namespace = "teal.modules.general")
      reactive({
        req(data(), input$style)
        within(data(), {
          style_str <- style
          table <- switch(
            style,
            "Striped" = DT::formatStyle(
              table,
              columns = attr(table$x, "colnames")[-1],
              target = 'row',
              backgroundColor = '#f9f9f9'
            ),
            "Hover" = DT::formatStyle(
              table,
              columns = attr(table$x, "colnames")[-1],
              target = 'row',
              backgroundColor = '#f0f0f0'
            ),
            table
          )
        }, style = input$style)
      })
    })
  }
)

generic_decorator <- teal_transform_module(
  ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote", value = "D"),
  server = make_teal_transform_server(
    expression({
      if (exists("by_subject_plot")) by_subject_plot <- by_subject_plot + ggplot2::labs(caption = footnote)
      if (exists("table", inherits = FALSE)) table <- DT::formatStyle(table, columns = attr(table$x, "colnames")[-1], target = 'row', backgroundColor = '#f9f9f9')
      if (exists("summary_plot")) {
        footnote_grob <- grid::textGrob(footnote, x = 0, hjust = 0, gp = grid::gpar(fontsize = 10, fontface = "italic", col = "gray50"))
        
        # Arrange the plot and footnote
        summary_plot <- gridExtra::arrangeGrob(summary_plot, footnote_grob, ncol = 1, heights = grid::unit.c(grid::unit(1, "npc") - grid::unit(1, "lines"), grid::unit(1, "lines")))
      }
      if (exists("combination_plot")) {
        footnote_grob <- grid::textGrob(footnote, x = 0, hjust = 0, gp = grid::gpar(fontsize = 10, fontface = "italic", col = "gray50"))
        
        # Arrange the plot and footnote
        combination_plot <- gridExtra::arrangeGrob(combination_plot, footnote_grob, ncol = 1, heights = grid::unit.c(grid::unit(1, "npc") - grid::unit(1, "lines"), grid::unit(1, "lines")))
      }
    })
  )
)

# CDISC example data
data <- teal_data()
data <- within(data, {
  require(nestcolor)
  ADSL <- rADSL
  ADRS <- rADRS
})
join_keys(data) <- default_cdisc_join_keys[names(data)]

app <- init(
  data = data,
  modules = modules(
    tm_missing_data(
      label = "Flat list",
      decorators = list(
        summary_plot = plot_grob_decorator("A"),
        combination_plot = plot_grob_decorator("B", "combination_plot"),
        summary_table = table_decorator_interactive,
        by_subject_plot = caption_decorator
      )
    ),
    tm_missing_data(
      label = "Complex list",
      decorators = list(
        summary_plot = list(plot_grob_decorator("A")),
        combination_plot = list(plot_grob_decorator("B", "combination_plot")),
        summary_table = list(table_decorator_interactive),
        by_subject_plot = list(caption_decorator)
      )
    ),
    tm_missing_data(
      label = "Complex list",
      decorators = list(generic_decorator)
    ),
    example_module()
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}
```

</details>

<details><summary> Old ~Working~ Example </summary>

```r
pkgload::load_all("../teal")
pkgload::load_all(".")


footnote_dec <- teal_transform_module(
  label = "Footnote",
  ui = function(id) shiny::textInput(shiny::NS(id, "footnote"), "Footnote for Combination Plot", value = "I am a good decorator"),
  server = function(id, data) {
    moduleServer(id, function(input, output, session) {
      logger::log_info("🟢 Footnote called to action!", namespace = "teal.modules.general")
      reactive(
        within(
          data(),
          {
            footnote_str <- footnote
            if (exists('combination_plot_top')) {
              combination_plot_top <- combination_plot_top + ggplot2::labs(caption = footnote_str)
            }
          },
          footnote = input$footnote
        )
      )
    })
  }
)

# general example data
data <- teal_data()
data <- within(data, {
  require(nestcolor)
  
  add_nas <- function(x) {
    x[sample(seq_along(x), floor(length(x) * runif(1, .05, .17)))] <- NA
    x
  }
  
  iris <- iris
  mtcars <- mtcars
  
  iris[] <- lapply(iris, add_nas)
  mtcars[] <- lapply(mtcars, add_nas)
  mtcars[["cyl"]] <- as.factor(mtcars[["cyl"]])
  mtcars[["gear"]] <- as.factor(mtcars[["gear"]])
})

app <- init(
  data = data,
  modules = modules(
    tm_missing_data(decorators = list(footnote_dec))
  )
)
if (interactive()) {
  shinyApp(app$ui, app$server)
}
```

</details>

---------

Co-authored-by: André Veríssimo <[email protected]>
@m7pr
Copy link
Contributor

m7pr commented Nov 29, 2024

🔥

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants