问题
I would like to combine the richness of html widgets (mainly plotly and networkD3), with the possibility of arranging them as plots in a grid in R, to export them as pdf graphic for a publication. However, if I create some html widget objects in R and try to arrange them with gridExtra::grid.arrange() (see minimal example below) I get the following error:
Error in gList(list(x = list(links = list(source = c(0, 0), target = c(1, :
only 'grobs' allowed in "gList"
I searched for “converting html widgets to grobs or plots” to be able to arrange them in a grid, but could not find any relevant information. I could go the long manual way of first saving the html widget as a website with htmlwidgets::saveWidget(), then converting it to a pdf with webshot::webshot() and arranging the graphics manually with a vector graphic editor (such as Inkscape). But despite the manual effort, all the conversion steps might results in a decrease in quality.
Maybe I could somehow arrange the graphics in LaTeX R-Markdown document with tables or columns and specify the paper dimension to fit my plot. But somehow that feels neither like an ideal solution, since I might want to arrange my graphs dynamically in several columns and rows, add titles, ect., which would make the arrangement quite complex in LaTeX/knitr.
So before I embark on the journey of knitting everything manually together, I would like to ask whether you know a better way to arrange some html widgets plots and export them to pdf within R?
Minimal example
Here is a little minimal example to reproduce my problem. Let’s say my aim is a graph which compares the energy flow of two different processes with each other (Sankey diagrams with networkD3), by arranging them next to each other in a grid, like so: Exemplary arranged Sankey plots
This would be my code:
library(networkD3)
library(grid)
library(gridExtra)
## Create simplified Data
dfSankey <- list()
dfSankey$nodes <- data.frame(Name = c("Final Energy","Conversion Losses","Useful Energy"))
#1st process
dfSankey$links1 <- data.frame(Source = c(0,0),Target=c(1,2),Value=c(30,70))
#2nd process
dfSankey$links2 <- data.frame(Source = c(0,0),Target=c(1,2),Value=c(10,60))
## Draw Sankeys
plSankey1 <- sankeyNetwork(Links = dfSankey$links1, Nodes = dfSankey$nodes, Source = 'Source',
Target = 'Target', Value = 'Value', NodeID = 'Name')
plSankey2 <- sankeyNetwork(Links = dfSankey$links2, Nodes = dfSankey$nodes, Source = 'Source',
Target = 'Target', Value = 'Value', NodeID = 'Name')
#Arrange them next to each other
grid.arrange(plSankey1,plSankey2)
This results in the error message mentioned in the beginning.
Windows 7, R-Studio 0.99.903, R version 3.2.3, grid 3.2.3, gridExtra 2.2.1, networkD3 0.2.13
回答1:
After the inspiration of Amit Kohli I started experimenting with flexdashboard, all kinds of Rmarkdown formats (html, pdf, isolides, ...), Rpresentations - but all of them had some drawbacks compared to my target.
In my opinion the best visual results can be achieved with a shiny app. Then saving the resulting website as pdf with chrome and finally croping the pdf with briss.
library(networkD3)
## Create simplified Data
dfSankey <- list()
dfSankey$nodes <- data.frame(Name = c("Final Energy","Conversion Losses","Useful Energy"))
#1st process
dfSankey$links1 <- data.frame(Source = c(0,0),Target=c(1,2),Value=c(30,70))
#2nd process
dfSankey$links2 <- data.frame(Source = c(0,0),Target=c(1,2),Value=c(10,60))
# Define UI for application that draws two Sankeys in columns
ui <- shinyUI(fluidPage(column(6,
h2("Process 1", align = "center"),
uiOutput("plot1.ui")
),
column(6,
h2("Process 2", align = "center"),
uiOutput("plot2.ui")
)
))
# Define server logic required to draw the sankeys
server <- shinyServer(function(input, output) {
#Render plot area relative to flow height
output$plot1.ui <- renderUI({
sankeyNetworkOutput("Plot1", height = "400px")
})
output$plot2.ui <- renderUI({
sankeyNetworkOutput("Plot2", height=paste0(400*(70/100),"px"))
})
#Render Sankeys
output$Plot1 <- renderSankeyNetwork({
sankeyNetwork(Links = dfSankey$links1, Nodes = dfSankey$nodes, Source = 'Source',
Target = 'Target', Value = 'Value', NodeID = 'Name', fontSize = 15, nodeWidth = 10)
})
output$Plot2 <- renderSankeyNetwork({
sankeyNetwork(Links = dfSankey$links2, Nodes = dfSankey$nodes, Source = 'Source',
Target = 'Target', Value = 'Value', NodeID = 'Name', fontSize = 15, nodeWidth = 10)
})
})
# Run the application
shinyApp(ui = ui, server = server)
Still feels a bit like a overkill to write a shiny app and doing all this manual converting just for arranging two html widget figures in a pdf, but at least the resulting pdf picture looks very pleasing.
I hope this might help others too.
来源:https://stackoverflow.com/questions/40089207/how-to-arrange-html-widget-plots-in-a-grid-for-export-as-pdf