1

I am searching to include plotly charts in a column of a DT table in R, similar to sparkline package.

I can't get the plotly objects to render. My current trials give empty column or having the html displayed as character.

library(DT)
library(plotly)
library(htmltools)

plot_list <- lapply(1:5, function(i) {
  plot_ly(y = rnorm(10), type = "scatter", mode = "lines") %>%
    layout(xaxis = list(showticklabels = FALSE, ticks = ""),
           margin = list(l = 1, r = 0, t = 0, b = 0))
})

plot_html <- lapply(plot_list, function(p) {
  as.character(tagList(p))
})
df <- data.frame(
  ID = 1:5,
  Preview = I(plot_html)
)

DT::datatable(df, escape = FALSE)

I have tried to play with tagList, I and HTML functions.

Thanks for any clue!

1 Answer 1

1

In Shiny you can solve it like this.

Without Shiny you can add divs inside your data.frame where your plots should go. Then we need to load the plotly dependency inside the DT-widget. Otherwise, plotly commands such as Plotly.newPlot will be unknown. Finally, if the widget is loaded DOMContentLoaded, you can add the plotly plots and layout to the empty divs using JS.

library(DT)
library(plotly)
library(htmltools)
library(htmlwidgets)
library(jsonlite)

plot_json <- lapply(1:5, \(i) {
  p <- plot_ly(x = 1:10, y = 1:10 * i, type = "scatter", mode = "lines")
  plotly_build(p)$x[c("data", "layout")]
})

plot_height <- 80

df <- data.frame(
  ID = seq_along(plot_json),
  Preview = sprintf(
    '<div id="plot_%s" style="height: %spx;"></div>',
    seq_along(plot_json),
    plot_height
  )
)

datatable(df, escape = FALSE,
          options = list(
            # prevent known problem, that plots don't fit the whole column width
            # column 2 is the one holding the plotlys
            columnDefs = list(list(targets = 2, width = '50%')) 
          )) |> 
  prependContent(
    tagList(
      htmlDependency(
        name = "plotly-binding",
        version = "1",
        src = system.file("htmlwidgets/lib/plotlyjs", package = "plotly"),
        script = "plotly-latest.min.js"
      )
    )
  ) |>
  appendContent(
    tags$script(HTML(sprintf("
      document.addEventListener('DOMContentLoaded', function() {
        var plots = %s;
        plots.forEach(function(plot, i) {
          Plotly.newPlot('plot_' + (i+1), plot.data, plot.layout, {displayModeBar: false});
        });
      });
    ", toJSON(plot_json, auto_unbox = TRUE)))
    )
  )

res

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot for this precise answer, works perfectly! I was thinking answer would be more straightforward. Sincere thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.