4

I am building a Shiny app based on an HTML template and I would like to use plotly for charts. I am struggling with insertion the chart into the template.

The following code works fine:

library(shiny)
library(plotly)

shinyApp(

  ui <- fluidPage(plotlyOutput("plot1")),

  server <- function(input, output) {

    p <- plot_ly(mtcars, x = ~mpg, y = ~wt, type = 'scatter', mode = 'markers')

    output$plot1 <- renderPlotly({p})

  }
)

But when I change the app to use a template I cannot do it neither by using renderPlotly nor renderUI.

<!doctype html>
<html lang="en">
<head>
  <script src="shared/jquery.js" type="text/javascript"></script>
  <script src="shared/shiny.js" type="text/javascript"></script>
  <link rel="stylesheet" type="text/css" href="shared/shiny.css"/>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="w3.css">
</head>

<body>

  <h1>HTML Template UI</h1>
  <div id="plot1" class="shiny-plot-output" style="width: 100%; height: 300px; border: 1px solid red"></div>
  <div id="plot2" class="shiny-html-output" style="width: 100%; height: 300px; border: 1px solid blue"></div>

</body>
</html>

app.R

library(shiny)
library(plotly)

shinyApp(

  ui <- htmlTemplate("template.html"),  

  server <- function(input, output) {

    p <- plot_ly(mtcars, x = ~mpg, y = ~wt)

    output$plot1 <- renderPlotly({p})

    output$plot2 <- renderUI(HTML(paste(htmltools::tagList(list(p)))))

  }
)

Is there any way to use plotly in a Shiny app based on a HTML template?

mattino
  • 95
  • 7

2 Answers2

1

There is a more elegant and easy way to achieve this. It is well described in this RStudio article.

To include the necessary HTML & JS-dependencies you include headContent() in the header of the htmlTemplate. If you need Bootstrap components (actionButtons, tabsetPanel) you also have to include bootstrapLib() in the header. Make sure those commands are inside double curly brackets like
{{ bootstrapLib() }}.

You can also place code to generate inputs and outputs (like plotly) in such curly brackets, which will automatically create the html components and include the JavaScript dependencies for you.

This makes the template.html much cleaner.

template.html

<!doctype html>
<html lang="en">
<head>

  {{ headContent() }}

</head>
<body>
  <h1>HTML Template UI</h1>
  <div class="container-fluid">

    {{plotlyOutput("plot1") }}
    {{uiOutput("plot2") }}

  </div>
</body>
</html>

app.R

library(shiny)
library(plotly)

p <- plot_ly(mtcars, x = ~mpg, y = ~wt, type = 'scatter', mode = 'markers')

ui <- htmlTemplate("template.html")

server <- function(input, output) {
  output$plot1 <- renderPlotly({p})
  output$plot2 <- renderUI(HTML(paste(htmltools::tagList(list(p)))))
}
SeGa
  • 9,454
  • 3
  • 31
  • 70
  • 1
    Thank you SeGa, that sounds like a very good hint, especially that I have now over 2000 lines in my template. – mattino Oct 03 '18 at 08:27
0

Try using this template:

<!doctype html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <script type="application/shiny-singletons"></script>
  <script type="application/html-dependencies">json2[2014.02.04];jquery[1.12.4];shiny[1.0.5];htmlwidgets[1.0];plotly-binding[4.7.1.9000];bootstrap[3.3.7]</script>
  <script src="shared/json2-min.js"></script>
  <script src="shared/jquery.min.js"></script>
  <link href="shared/shiny.css" rel="stylesheet" />
  <script src="shared/shiny.min.js"></script>
  <script src="htmlwidgets-1.0/htmlwidgets.js"></script>
  <script src="plotly-binding-4.7.1.9000/plotly.js"></script>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <link href="shared/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
  <script src="shared/bootstrap/js/bootstrap.min.js"></script>
  <script src="shared/bootstrap/shim/html5shiv.min.js"></script>
  <script src="shared/bootstrap/shim/respond.min.js"></script>
</head>

<body>

  <h1>HTML Template UI</h1>
  <div class="container-fluid">
  <div id="plot1" class="plotly html-widget html-widget-output" style="width: 100%; height: 300px; border: 1px solid red"></div>
  <div id="plot2" class="shiny-html-output" style="width: 100%; height: 300px; border: 1px solid blue"></div>
  </div>

</body>
</html>

enter image description here

Marco Sandri
  • 23,289
  • 7
  • 54
  • 58
  • Thank you for the answer. I don't have yet these dependencies from your header (html widgets, etc.), so it not working yet on my side, but it looks very promising. I am installing it now :-) Although it would be great to know also a more "native" way of embedding the plotly in the templates, i.e. in some object with class="shiny-x-output". – mattino Feb 23 '18 at 15:14
  • @mattino Please, could you run your first R code above, click the right button in your browser, choose "visualize source code" (or something similar) and post the result ? Thank you. – Marco Sandri Feb 23 '18 at 15:21
  • The whole html body with plot1 & plot2 divs: https://imgur.com/a/qksgz – mattino Feb 23 '18 at 15:33
  • Finally I have generated it on my machine. As hinted by you it was problem with missing links in the HTML template. The solution is to generate first a page with fluidPage() and then copy its header to the template :-) – mattino Feb 26 '18 at 11:06