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

feat: allow html content to be added to a report #294

Merged
merged 7 commits into from
Dec 17, 2024
Merged

Conversation

vedhav
Copy link
Contributor

@vedhav vedhav commented Dec 13, 2024

Closes #129

It turns out that interactive plots can be rendered by saving them in an RDS file and fetching them just like how we do the reports for table objects.

Example app to test interactive plots in a report. Note that not all HTML content can be rendered in static documents like pdf, pptx, and word. But popular plotting packages that use have the ability for static render.
I don't know yet if all htmlwidget objects can do this, but I am inclined to believe this is the case as echarts4r package is a light htmlwidgets wrapper over the apache echarts JS library.

library(teal)
library(plotly)
library(echarts4r)
devtools::load_all("teal.reporter")

interactive_module <- function(label = "example teal module", transformators = list()) {
  checkmate::assert_string(label)
  module(
    label,
    server = function(id, data, filter_panel_api, reporter) {
      moduleServer(id, function(input, output, session) {
        plot_q <- reactive({
          data() |>
            within({
              library(plotly)
              library(echarts4r)
              data <- data.frame(
                x = 1:100,
                y = rnorm(100)
              )
              g <- ggplot(data, aes(x = x, y = y)) +
                geom_line() +
                geom_point() +
                labs(
                  title = "Sample Plot",
                  x = "X axis",
                  y = "Y axis"
                ) +
                theme_minimal()
              p <- ggplotly(g)
              e <- data |>
                e_charts(x) |>
                e_line(y) |>
                e_scatter(y) |>
                e_tooltip(trigger = "axis") |>
                e_animation(duration = 0)
              h <- shiny::div(
                style = "background: teal; color: white;",
                "HTML Content"
              )
            })
        })
        output$plotly_plot <- renderPlotly({
          plot_q()[["p"]]
        })
        output$echarts_plot <- renderEcharts4r({
          plot_q()[["e"]]
        })
        output$custom_html <- renderUI({
          plot_q()[["h"]]
        })
        teal.widgets::verbatim_popup_srv(
          id = "rcode",
          verbatim_content = reactive(teal.code::get_code(plot_q())),
          title = "Example Code"
        )
        card_fun <- function(comment, label) {
          card <- teal::report_card_template(
            title = "Plotly plot",
            label = label,
            with_filter = FALSE,
            filter_panel_api = filter_panel_api
          )
          card$append_text("HTML content", style = "header3")
          card$append_html(plot_q()[["h"]])
          card$append_text("plotly plot", style = "header3")
          card$append_html(plot_q()[["p"]])
          card$append_text("echarts4r plot", style = "header3")
          card$append_html(plot_q()[["e"]])
          card$append_src(teal.code::get_code(plot_q()))
          card
        }
        simple_reporter_srv("simple_reporter", reporter = reporter, card_fun = card_fun)
      })
    },
    ui = function(id) {
      ns <- NS(id)
      teal.widgets::standard_layout(
        output = tags$div(
          uiOutput(ns("custom_html")),
          plotlyOutput(ns("plotly_plot")),
          echarts4rOutput(ns("echarts_plot"))
        ),
        encoding = tags$div(
          teal.widgets::verbatim_popup_ui(ns("rcode"), "Show R code"),
          simple_reporter_ui(ns("simple_reporter"))
        )
      )
    },
    datanames = "all",
    transformators = transformators
  )
}

app <- teal::init(
  data = teal_data(IRIS = iris, MTCARS = mtcars),
  modules = interactive_module()
)

shinyApp(app$ui, app$server)

@gogonzo gogonzo self-assigned this Dec 13, 2024
Copy link
Contributor

github-actions bot commented Dec 13, 2024

Unit Tests Summary

  1 files   19 suites   28s ⏱️
197 tests 159 ✅ 38 💤 0 ❌
273 runs  235 ✅ 38 💤 0 ❌

Results for commit fa72347.

♻️ This comment has been updated with latest results.

Copy link
Contributor

github-actions bot commented Dec 13, 2024

badge

Code Coverage Summary

Filename                  Stmts    Miss  Cover    Missing
----------------------  -------  ------  -------  -----------------------------------------------------------------------------------------------------
R/AddCardModule.R           146       2  98.63%   170, 207
R/ContentBlock.R             15       2  86.67%   43-49
R/DownloadModule.R          238      67  71.85%   98-104, 152, 183-188, 197-202, 205-210, 219-224, 227-232, 240-245, 248-253, 260-265, 268-273, 312-316
R/FileBlock.R                13       0  100.00%
R/HTMLBlock.R                 9       0  100.00%
R/LoadReporterModule.R      103      19  81.55%   100-105, 108-113, 119-124, 136
R/NewpageBlock.R              2       0  100.00%
R/PictureBlock.R             30       2  93.33%   20, 118
R/Previewer.R               374      97  74.06%   96-98, 101-102, 184-213, 217-219, 222, 289, 304, 306-309, 312, 315-325, 439-483
R/RcodeBlock.R               18       0  100.00%
R/Renderer.R                121      37  69.42%   99-114, 218, 228, 237, 239-260
R/ReportCard.R               86       3  96.51%   250, 255, 280
R/Reporter.R                107       6  94.39%   273-278
R/ResetModule.R              53       0  100.00%
R/SimpleReporter.R           32       0  100.00%
R/TableBlock.R                9       0  100.00%
R/TextBlock.R                15       0  100.00%
R/utils.R                   126      86  31.75%   7, 38-97, 99, 102-109, 137, 161-169, 206-215
R/yaml_utils.R               81       2  97.53%   78, 289
R/zzz.R                      14      10  28.57%   2-13, 19
TOTAL                      1592     333  79.08%

Diff against main

Filename            Stmts    Miss  Cover
----------------  -------  ------  --------
R/ContentBlock.R       -3       0  -2.22%
R/HTMLBlock.R          +9       0  +100.00%
R/Previewer.R          +2      +2  -0.40%
R/RcodeBlock.R         +3       0  +100.00%
R/Renderer.R           +8       0  +2.16%
R/ReportCard.R         +2       0  +0.08%
R/TextBlock.R          +2       0  +100.00%
TOTAL                 +23      +2  +0.18%

Results for commit: fa72347

Minimum allowed coverage is 80%

♻️ This comment has been updated with latest results

R/HTMLBlock.R Show resolved Hide resolved
R/HTMLBlock.R Outdated Show resolved Hide resolved
R/Renderer.R Outdated Show resolved Hide resolved
Signed-off-by: Vedha Viyash <[email protected]>
Copy link
Contributor

@gogonzo gogonzo left a comment

Choose a reason for hiding this comment

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

I accept this solution as proposed conversion plotly -> html to include to include directly in md is not sufficient for pdf (there is no way to convert html in md to static image in pdf). Please add tests of the:

  • htmlBlock class
  • ReportCars$append_html
  • Renderer$htmlBlock2md

Copy link
Contributor

github-actions bot commented Dec 17, 2024

Unit Test Performance Difference

Test Suite $Status$ Time on main $±Time$ $±Tests$ $±Skipped$ $±Failures$ $±Errors$
HTMLBlock 👶 $+0.06$ $+8$ $+3$ $0$ $0$
Additional test case details
Test Suite $Status$ Time on main $±Time$ Test Case
ContentBlock 👶 $+0.00$ get_content_returns_NULL_on_a_newly_initialized_ContentBlock
ContentBlock 💀 $0.00$ $-0.00$ get_content_returns_character_0_on_a_newly_initialized_ContentBlock
ContentBlock 👶 $+0.03$ set_content_accepts_a_list_object
ContentBlock 💀 $0.04$ $-0.04$ set_content_asserts_the_argument_is_character
HTMLBlock 👶 $+0.01$ HTMLBlock_object_can_be_created
HTMLBlock 👶 $+0.00$ from_list_creates_a_HTMLBlock
HTMLBlock 👶 $+0.00$ get_content_returns_a_html_content_asis
HTMLBlock 👶 $+0.00$ new_accepts_a_shiny.tag
HTMLBlock 👶 $+0.01$ new_accepts_a_shiny.tag.list
HTMLBlock 👶 $+0.01$ new_doesn_t_accept_character
HTMLBlock 👶 $+0.01$ new_returns_an_object_of_type_HTMLBlock
HTMLBlock 👶 $+0.00$ to_list_returns_a_list_containing_a_content_asis_

Results for commit 51e2c6b

♻️ This comment has been updated with latest results.

@gogonzo gogonzo enabled auto-merge (squash) December 17, 2024 11:18
@gogonzo gogonzo merged commit 81b6103 into main Dec 17, 2024
29 checks passed
@gogonzo gogonzo deleted the 129-allow-html@main branch December 17, 2024 11:18
@github-actions github-actions bot locked and limited conversation to collaborators Dec 17, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature Request]: Allow htmlwidgets Plots in Report
2 participants