Download Plotly using downloadHandler - r

i got stuck at some point while trying to use downloadHandler to download Plotly images. I just cannot figure out further how to get the image from temp directory...
Here is a sample code:
library(shiny)
library(plotly)
library(rsvg)
library(ggplot2)
d <- data.frame(X1=rnorm(50,mean=50,sd=10),X2=rnorm(50,mean=5,sd=1.5),Y=rnorm(50,mean=200,sd=25))
ui <-fluidPage(
title = 'Download Plotly',
sidebarLayout(
sidebarPanel(
helpText(),
downloadButton('download'),
tags$script('
document.getElementById("download").onclick = function() {
var plotly_svg = Plotly.Snapshot.toSVG(
document.querySelectorAll(".plotly")[0]
);
Shiny.onInputChange("plotly_svg", plotly_svg);
};
')
),
mainPanel(
plotlyOutput('regPlot'),
plotlyOutput('regPlot2')
)
)
)
server <- function(input, output, session) {
output$regPlot <- renderPlotly({
p <- plot_ly(d, x = d$X1, y = d$X2,mode = "markers")
p
})
output$regPlot2 <- renderPlotly({
p <- plot_ly(d, x = d$X1, y = d$X2,mode = "markers")
p
})
observeEvent(input$plotly_svg, priority = 10, {
png_gadget <- tempfile(fileext = ".png")
png_gadget <- "out.png"
print(png_gadget)
rsvg_png(charToRaw(input$plotly_svg), png_gadget)
})
output$download <- downloadHandler(
filename = function(){
paste(paste("test",Sys.Date(),sep=""), ".png",sep="")},
content = function(file) {
temp_dir <- tempdir()
tempImage <- file.path(temp_dir, 'out.png')
file.copy('out.png', tempImage, overwrite = TRUE)
png(file, width = 1200, height = 800, units = "px", pointsize = 12, bg = "white", res = NA)
dev.off()
})
}
shinyApp(ui = ui, server = server)
Additionally i am not sure how can i choose which of the plotly images should be downloaded. Thanks for any tips and help!
Info:
--> I have tried using webshot, however if I zoom or filter in any way plot, unfortunatelly webshot does not mirror it
--> i am not using the available plotly panel for download, because it is not working using IE

The OP has edited his/her post to add a requirement:
--> I have tried using webshot, however if I zoom or filter in any way plot, unfortunatelly webshot does not mirror it
Below is a Javascript solution, which doesn't need additional libraries. I'm not fluent in Javascript and I'm not sure the method is the most direct one: I'm under the impression that this method creates a file object from a url and then it creates a url from the file object. I will try to minimize the code.
library(shiny)
library(plotly)
d <- data.frame(X1 = rnorm(50,mean=50,sd=10),
X2 = rnorm(50,mean=5,sd=1.5),
Y = rnorm(50,mean=200,sd=25))
ui <-fluidPage(
title = 'Download Plotly',
sidebarLayout(
sidebarPanel(
helpText(),
actionButton('download', "Download")
),
mainPanel(
plotlyOutput('regPlot'),
plotlyOutput('regPlot2'),
tags$script('
function download(url, filename, mimeType){
return (fetch(url)
.then(function(res){return res.arrayBuffer();})
.then(function(buf){return new File([buf], filename, {type:mimeType});})
);
}
document.getElementById("download").onclick = function() {
var gd = document.getElementById("regPlot");
Plotly.Snapshot.toImage(gd, {format: "png"}).once("success", function(url) {
download(url, "plot.png", "image/png")
.then(function(file){
var a = window.document.createElement("a");
a.href = window.URL.createObjectURL(new Blob([file], {type: "image/png"}));
a.download = "plot.png";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
});
}
')
)
)
)
server <- function(input, output, session) {
regPlot <- reactive({
plot_ly(d, x = d$X1, y = d$X2, mode = "markers")
})
output$regPlot <- renderPlotly({
regPlot()
})
regPlot2 <- reactive({
plot_ly(d, x = d$X1, y = d$X2, mode = "markers")
})
output$regPlot2 <- renderPlotly({
regPlot2()
})
}
shinyApp(ui = ui, server = server)
EDIT
I was right. There's a shorter and cleaner solution:
tags$script('
document.getElementById("download").onclick = function() {
var gd = document.getElementById("regPlot");
Plotly.Snapshot.toImage(gd, {format: "png"}).once("success", function(url) {
var a = window.document.createElement("a");
a.href = url;
a.type = "image/png";
a.download = "plot.png";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
}
')
EDIT
To select the plot to download, you can do:
sidebarLayout(
sidebarPanel(
helpText(),
selectInput("selectplot", "Select plot to download", choices=list("plot1","plot2")),
actionButton('download', "Download")
),
mainPanel(
plotlyOutput('regPlot'),
plotlyOutput('regPlot2'),
tags$script('
document.getElementById("download").onclick = function() {
var plot = $("#selectplot").val();
if(plot == "plot1"){
var gd = document.getElementById("regPlot");
}else{
var gd = document.getElementById("regPlot2");
}
Plotly.Snapshot.toImage(gd, {format: "png"}).once("success", function(url) {
var a = window.document.createElement("a");
a.href = url;
a.type = "image/png";
a.download = "plot.png";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
}
')
)
)

1) Install the webshot package.
2) Install phantom.js:
library(webshot)
install_phantomjs()
See ?install_phantomjs for the details.
3) Now you can use the export function of the plotly package:
library(shiny)
library(plotly)
d <- data.frame(X1 = rnorm(50,mean=50,sd=10),
X2 = rnorm(50,mean=5,sd=1.5),
Y = rnorm(50,mean=200,sd=25))
ui <-fluidPage(
title = 'Download Plotly',
sidebarLayout(
sidebarPanel(
helpText(),
downloadButton('download')
),
mainPanel(
plotlyOutput('regPlot'),
plotlyOutput('regPlot2')
)
)
)
server <- function(input, output, session) {
regPlot <- reactive({
plot_ly(d, x = d$X1, y = d$X2, mode = "markers")
})
output$regPlot <- renderPlotly({
regPlot()
})
regPlot2 <- reactive({
plot_ly(d, x = d$X1, y = d$X2, mode = "markers")
})
output$regPlot2 <- renderPlotly({
regPlot2()
})
output$download <- downloadHandler(
filename = function(){
paste0(paste0("test", Sys.Date()), ".png")
},
content = function(file) {
export(regPlot(), file=file)
})
}
shinyApp(ui = ui, server = server)
You can save to the svg format. See ?export for the explanations.

Instead of using webshot, you should consider to try webshot2. See my detailed answer to the similar case.
# Webshot and phantomjs have been previously installed.
library(webshot2)

Related

Shiny module for downloading all plots from dashboard works locally but not in Docker

Here's a Shiny module that I'm using to download all plots from a dashboard. You should be able to run it by copy-pasting the code and calling the function mod_download_plots_app.
mod_download_plots_ui <- function(id){
ns <- NS(id)
tagList(
shinyjs::useShinyjs(), # we need this to be able to keep the button disabled until input changes
shinyjs::disabled(
downloadButton(
ns("download_all_plots"),
"Download all plots",
style = "color: #333; margin: 15px;" # default style doesn't work well in the sidebar
)
)
)
}
mod_download_plots_server <- function(id, analysis, plots_info) {
stopifnot(is.reactive(analysis), is.list(plots_info))
moduleServer(id, function(input, output, session) {
observe(
if (analysis() != "empty_choice") {
shinyjs::enable("download_all_plots")
} else {
shinyjs::disable("download_all_plots")
}
)
save_plot <- function(plot_info, plot_name, prefix, increment) {
incProgress(increment)
pixels_per_inch <- 100
file_path <- file.path(tempdir(), paste0(prefix, "_", plot_name, ".png"))
ggsave(
filename = file_path, plot = plot_info$plot(),
width = plot_info$width() / pixels_per_inch, height = plot_info$height() / pixels_per_inch
)
}
name_zip_file <- function() {
paste0(analysis(), "-", Sys.Date(), ".zip")
}
zip_all_plots <- function(file) {
withProgress(message = "Exporting plots to png files", {
increment <- 1 / length(plots_info)
plot_files <- purrr::imap_chr(plots_info, save_plot, prefix = analysis(), increment = increment)
zip::zip(file, files = plot_files, mode = "cherry-pick")
})
}
output$download_all_plots <- downloadHandler(
filename = name_zip_file,
content = zip_all_plots
)
})
}
mod_download_plots_app <- function() {
library(shiny)
library(ggplot2)
ui <- fluidPage(
mod_download_plots_ui("zip")
)
server <- function(input, output, session) {
plot1 <- list(plot = reactive(qplot(x = cyl, y = mpg, data = mtcars)), width = reactive(100), height = reactive(200))
plot2 <- list(plot = reactive(qplot(x = am, y = mpg, data = mtcars)), width = reactive(800), height = reactive(400))
mod_download_plots_server(
"zip",
reactive("selected_analysis"),
tibble::lst(plot1, plot2)
)
}
shinyApp(ui, server)
}
When I run it locally, it works as it should. But when I run it on Docker, I get:
Warning: Error in : Result 1 must be a single string, not NULL of length 0
[No stack trace available]
that appears when running the line:
plot_files <- purrr::imap_chr(plots_info, save_plot, prefix = analysis(), increment = increment)
Our docker library versions are not completely the same as my local ones - they are half a year old but I don't believe this would cause a problem.
Create a new directory with these two files:
Dockerfile
FROM rocker/shiny-verse:4.1
RUN R -e "install.packages('shinyjs')"
COPY app.R /srv/shiny-server/app.R
app.R
mod_download_plots_ui <- function(id) {
ns <- NS(id)
tagList(
shinyjs::useShinyjs(), # we need this to be able to keep the button disabled until input changes
shinyjs::disabled(
downloadButton(
ns("download_all_plots"),
"Download all plots",
style = "color: #333; margin: 15px;" # default style doesn't work well in the sidebar
)
)
)
}
mod_download_plots_server <- function(id, analysis, plots_info) {
stopifnot(is.reactive(analysis), is.list(plots_info))
moduleServer(id, function(input, output, session) {
observe(
if (analysis() != "empty_choice") {
shinyjs::enable("download_all_plots")
} else {
shinyjs::disable("download_all_plots")
}
)
save_plot <- function(plot_info, plot_name, prefix, increment) {
incProgress(increment)
pixels_per_inch <- 100
file_path <- file.path(tempdir(), paste0(prefix, "_", plot_name, ".png"))
ggsave(
filename = file_path, plot = plot_info$plot(),
width = plot_info$width() / pixels_per_inch, height = plot_info$height() / pixels_per_inch
)
}
name_zip_file <- function() {
paste0(analysis(), "-", Sys.Date(), ".zip")
}
zip_all_plots <- function(file) {
withProgress(message = "Exporting plots to png files", {
increment <- 1 / length(plots_info)
plot_files <- purrr::imap_chr(plots_info, save_plot, prefix = analysis(), increment = increment)
zip::zip(file, files = plot_files, mode = "cherry-pick")
})
}
output$download_all_plots <- downloadHandler(
filename = name_zip_file,
content = zip_all_plots
)
})
}
mod_download_plots_app <- function() {
library(shiny)
library(ggplot2)
ui <- fluidPage(
mod_download_plots_ui("zip")
)
server <- function(input, output, session) {
plot1 <- list(plot = reactive(qplot(x = cyl, y = mpg, data = mtcars)), width = reactive(100), height = reactive(200))
plot2 <- list(plot = reactive(qplot(x = am, y = mpg, data = mtcars)), width = reactive(800), height = reactive(400))
mod_download_plots_server(
"zip",
reactive("selected_analysis"),
tibble::lst(plot1, plot2)
)
}
shinyApp(ui, server)
}
# This script must both define and call this function
mod_download_plots_app()
Then go to the directory and build and run the app in bash:
cd my_project_dir
docker build --tag shiny_docker_downlaod_app .
docker run -p 3838:3838 shiny_docker_downlaod_app
Go to localhost:3838 to view your app.

Download button auto clear by any input change

I have two input selection and an action button to generate a plot and download the data. I would like to clear the output contents (plot and download button) any time there is a change in the input selection. The code below will only clear the plot and not the download button. Not sure if the reactiveValuesunder the downloadhandleris correct.
library(shiny)
library(ggplot2)
library(openxlsx)
ui = fluidPage(
textInput("textT", label = "Title", value = ""),
textInput("textX", label = "X-Axis Label", value = ""),
actionButton("Btn", "Run", icon=icon("play-circle")),
plotOutput('plot1'),
conditionalPanel(condition = "input.Btn>0", downloadButton("dwload", "Download"))
)
server = function(input, output, session) {
v <- reactiveValues(clearAll = TRUE)
observeEvent(c(input$textT, input$textX), {
v$clearAll <- TRUE
}, priority = 10)
observeEvent(input$Btn, {
output$plot1 = renderPlot({
if (v$clearAll)
return()
else
ggplot(mtcars, aes(x= gear, y= carb)) + geom_line() +ggtitle(input$textT) + xlab(input$textX)
})
output$dwload <- downloadHandler(
filename = function() {
paste0("Checks-", gsub(" ", "_", gsub(":", ".", Sys.time())), ".xlsx")
},
content = function(file) {
if (v$clearAll)
return()
else
quick_xlsx(mtcars, file=file)
}
)
v$clearAll <- FALSE
}, priority = 10)
}
shinyApp(ui, server)
I'd appreciate any help.
Thank you!
Here is a solution using renderUI and req:
library(shiny)
library(ggplot2)
library(openxlsx)
ui <- fluidPage(
textInput("textT", label = "Title", value = ""),
textInput("textX", label = "X-Axis Label", value = ""),
actionButton("Btn", "Run", icon=icon("play-circle")),
uiOutput("widgets")
)
server <- function(input, output, session) {
hideAll <- reactiveVal(TRUE)
observeEvent(list(input$textT, input$textX), {
hideAll(TRUE)
})
observeEvent(input$Btn, {
req(input$textT)
req(input$textX)
hideAll(FALSE)
})
output$plot1 <- renderPlot({
ggplot(mtcars, aes(x= gear, y= carb)) + geom_line() +
ggtitle(input$textT) + xlab(input$textX)
})
output$dwload <- downloadHandler(
filename = function() {
paste0("Checks-", gsub(" ", "_", gsub(":", ".", Sys.time())), ".xlsx")
},
content = function(file) {
quick_xlsx(mtcars, file=file)
}
)
output$widgets <- renderUI({
req(!hideAll())
tagList(
plotOutput('plot1'),
downloadButton("dwload", "Download")
)
})
}
shinyApp(ui, server)

Removing traces by name using plotlyProxy (or accessing output schema in reactive context)

I am attempting to use the plotlyProxy() functionality (Documented here) to allow users of a shiny application to add and remove traces with minimal latency.
Adding traces proves to be relatively simple, but I'm having difficulty figuring out how to remove traces by name (I'm only seeing documented examples that remove by trace number).
Is there a way to remove traces by name using plotlyProxy()?
If not, is there a way that I can parse through the output object to derive what trace numbers are associated with a given name?
I can determine the associated trace number of a given name in an interactive R session using the standard schema indices, but when I attempt to apply the same logic in a shiny application I get an error: "Error in $.shinyoutput: Reading objects from shinyoutput object not allowed."
A minimal example is below. Neither observer watching the Remove button actually works, but they should give an idea for the functionality I'm trying to achieve.
library(shiny)
library(plotly)
ui <- fluidPage(
textInput("TraceName", "Trace Name"),
actionButton("Add","Add Trace"),
actionButton("Remove","Remove Trace"),
plotlyOutput("MyPlot")
)
server <- function(input,output,session) {
## Creaing the plot
output$MyPlot <- renderPlotly({
plot_ly() %>%
layout(showlegend = TRUE)
})
## Adding traces is smooth sailing
observeEvent(input$Add,{
plotlyProxy("MyPlot", session) %>%
plotlyProxyInvoke("addTraces", list(x = rnorm(10),y = rnorm(10),
type = "scatter",mode = "markers",
name = input$TraceName))
})
## Ideal Solution (that does not work)
observeEvent(input$Remove,{
plotlyProxy("MyPlot", session) %>%
plotlyProxyInvoke("deleteTraces", input$TraceName)
})
## Trying to extract tracenames throws an error:
## Warning: Error in $.shinyoutput: Reading objects from shinyoutput object not allowed.
observeEvent(input$Remove,{
TraceNames <- unlist(lapply(seq_along(names(output$MyPlot$x$attrs)),
function(x) output$MyPlot$x$attrs[[x]][["name"]]))
ThisTrace <- which(TraceNames == input$TraceName)
plotlyProxy("MyPlot", session) %>%
plotlyProxyInvoke("deleteTraces", ThisTrace)
})
}
shinyApp(ui, server)
Edit using plotlyProxy:
Update #SeGa, thanks for adding support to delete traces with duplicated names!
Finally, I found a solution to realize the expected behaviour by adapting this answer. I'm receiving the trace.name / trace.index mapping by using onRender from library(htmlwidgets) after the remove-button is clicked:
library(shiny)
library(plotly)
library(htmlwidgets)
js <- "function(el, x, inputName){
var id = el.getAttribute('id');
var d3 = Plotly.d3;
$(document).on('shiny:inputchanged', function(event) {
if (event.name === 'Remove') {
var out = [];
d3.select('#' + id + ' g.legend').selectAll('.traces').each(function(){
var trace = d3.select(this)[0][0].__data__[0].trace;
out.push([name=trace.name, index=trace.index]);
});
Shiny.setInputValue(inputName, out);
}
});
}"
ui <- fluidPage(
textInput("TraceName", "Trace Name"),
verbatimTextOutput("PrintTraceMapping"),
actionButton("Add", "Add Trace"),
actionButton("Remove", "Remove Trace"),
plotlyOutput("MyPlot")
)
server <- function(input, output, session) {
output$MyPlot <- renderPlotly({
plot_ly(type = "scatter", mode = "markers") %>%
layout(showlegend = TRUE) %>% onRender(js, data = "TraceMapping")
})
output$PrintTraceMapping <- renderPrint({unlist(input$TraceMapping)})
observeEvent(input$Add, {
req(input$TraceName)
plotlyProxy("MyPlot", session) %>%
plotlyProxyInvoke("addTraces", list(x = rnorm(10),y = rnorm(10),
type = "scatter",mode = "markers",
name = input$TraceName))
})
observeEvent(input$Remove, {
req(input$TraceName, input$TraceMapping)
traces <- matrix(input$TraceMapping, ncol = 2, byrow = TRUE)
indices <- as.integer(traces[traces[, 1] == input$TraceName, 2])
plotlyProxy("MyPlot", session) %>%
plotlyProxyInvoke("deleteTraces", indices)
})
}
shinyApp(ui, server)
Result:
Useful articles in this context:
shiny js-events
plotly addTraces
plotly deleteTraces
Solution for Shiny Modules using plotlyProxy:
library(shiny)
library(plotly)
library(htmlwidgets)
js <- "function(el, x, data){
var id = el.getAttribute('id');
var d3 = Plotly.d3;
$(document).on('shiny:inputchanged', function(event) {
if (event.name.indexOf('Remove') > -1) {
var out = [];
d3.select('#' + id + ' g.legend').selectAll('.traces').each(function(){
var trace = d3.select(this)[0][0].__data__[0].trace;
out.push([name=trace.name, index=trace.index]);
});
Shiny.setInputValue(data.ns + data.x, out);
}
});
}"
plotly_ui_mod <- function(id) {
ns <- NS(id)
tagList(
textInput(ns("TraceName"), "Trace Name"),
verbatimTextOutput(ns("PrintTraceMapping")),
actionButton(ns("Add"), "Add Trace"),
actionButton(ns("Remove"), "Remove Trace"),
plotlyOutput(ns("MyPlot"))
)
}
plotly_server_mod <- function(input, output, session) {
sessionval <- session$ns("")
output$MyPlot <- renderPlotly({
plot_ly(type = "scatter", mode = "markers") %>%
layout(showlegend = TRUE) %>% onRender(js, data = list(x = "TraceMapping",
ns = sessionval))
})
output$PrintTraceMapping <- renderPrint({unlist(input$TraceMapping)})
observeEvent(input$Add, {
req(input$TraceName)
plotlyProxy("MyPlot", session) %>%
plotlyProxyInvoke("addTraces", list(x = rnorm(10),y = rnorm(10),
type = "scatter",mode = "markers",
name = input$TraceName))
})
observeEvent(input$Remove, {
req(input$TraceName, input$TraceMapping)
traces <- matrix(input$TraceMapping, ncol = 2, byrow = TRUE)
indices <- as.integer(traces[traces[, 1] == input$TraceName, 2])
plotlyProxy("MyPlot", session) %>%
plotlyProxyInvoke("deleteTraces", indices)
})
}
ui <- fluidPage(
plotly_ui_mod("plotly_mod")
)
server <- function(input, output, session) {
callModule(plotly_server_mod, "plotly_mod")
}
shinyApp(ui, server)
Previous Solution avoiding plotlyProxy:
I came here via this question.
You were explicitly asking for plotlyProxy() so I'm not sure if this is helpful to you, but here is a workaround to realize the expected behaviour via updating the data provided to plot_ly() instead of using plotlyProxy():
library(shiny)
library(plotly)
ui <- fluidPage(
selectizeInput(inputId="myTraces", label="Trace names", choices = NULL, multiple = TRUE, options = list('plugins' = list('remove_button'), 'create' = TRUE, 'persist' = TRUE, placeholder = "...add or remove traces")),
plotlyOutput("MyPlot")
)
server <- function(input, output, session){
myData <- reactiveVal()
observeEvent(input$myTraces, {
tmpList <- list()
for(myTrace in input$myTraces){
tmpList[[myTrace]] <- data.frame(name = myTrace, x = rnorm(10),y = rnorm(10))
}
myData(do.call("rbind", tmpList))
return(NULL)
}, ignoreNULL = FALSE)
output$MyPlot <- renderPlotly({
if(is.null(myData())){
plot_ly(type = "scatter", mode = "markers")
} else {
plot_ly(myData(), x = ~x, y = ~y, color = ~name, type = "scatter", mode = "markers") %>%
layout(showlegend = TRUE)
}
})
}
shinyApp(ui, server)
I couldn't find the names attributes of the traces, and I think the deleteTrace function is not able to delete by name. Based on the reference it just deletes based on index.
I tried to implement something for Shiny, which records the added traces in a dataframe and adds an index to them. For deletion, it matches the given names with the dataframe and gives those indeces to the delete method of plotlyProxyInvoke, but it is not working correctly. Maybe someone could add some insight into why this is happening?
One problem seems to be the legend, which is showing wrong labels after deletion and I dont think that plotly and R/shiny are keeping the same indices of the traces, which leads to strange behaviour. So this code definitly needs some fixing.
--
I included a small JQuery snippet, which records all the traces of the plot and sends them to a reactiveVal(). Interestingly, it differs from the data.frame, that listens to the AddTraces event. There will always be one remaining trace in the plot.
library(shiny)
library(plotly)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
tags$head(tags$script(HTML(
"$(document).on('shiny:value', function(event) {
var a = $('.scatterlayer.mlayer').children();
if (a.length > 0) {
var text = [];
for (var i = 0; i < a.length; i++){
text += a[i].className.baseVal + '<br>';
}
Shiny.onInputChange('plotlystr', text);
}
});"
))),
textInput("TraceName", "Trace Name"),
actionButton("Add","Add Trace"),
actionButton("Remove","Remove Trace by Name"),
plotlyOutput("MyPlot"),
splitLayout(
verbatimTextOutput("printplotly"),
verbatimTextOutput("printreactive")
)
)
server <- function(input,output,session) {
## Reactive Plot
plt <- reactive({
plot_ly() %>%
layout(showlegend = T)
})
## Reactive Value for Added Traces
addedTrcs <- reactiveValues(tr = NULL, id = NULL, df = NULL)
## Creaing the plot
output$MyPlot <- renderPlotly({
plt()
})
## Adding traces is smooth sailing
observeEvent(input$Add,{
req(input$TraceName)
plotlyProxy("MyPlot", session) %>%
plotlyProxyInvoke("addTraces", list(x = rnorm(10),y = rnorm(10),
type = "scatter",mode = "markers", colors ="blue",
name = input$TraceName))
})
## Adding trace to reactive
observeEvent(input$Add, {
req(input$TraceName)
x <- input$TraceName
addedTrcs$id <- c(addedTrcs$id, length(addedTrcs$id))
addedTrcs$tr <- c(addedTrcs$tr, x)
addedTrcs$df <- data.frame(id=addedTrcs$id, tr=addedTrcs$tr, stringsAsFactors = F)
})
## Remove Trace from Proxy by NAME
observeEvent(input$Remove,{
req(input$TraceName %in% addedTrcs$tr)
ind = which(addedTrcs$df$tr == input$TraceName)
ind = addedTrcs$df[ind,"id"]
plotlyProxy("MyPlot", session) %>%
plotlyProxyInvoke("deleteTraces", as.integer(ind))
})
## Remove Trace from Reactive
observeEvent(input$Remove, {
req(input$TraceName %in% addedTrcs$df$tr)
whichInd <- which(addedTrcs$tr == input$TraceName)
addedTrcs$df <- addedTrcs$df[-whichInd,]
addedTrcs$id <- addedTrcs$id[-whichInd]
addedTrcs$tr <- addedTrcs$tr[-whichInd]
req(nrow(addedTrcs$df)!=0)
addedTrcs$df$id <- 0:(nrow(addedTrcs$df)-1)
})
tracesReact <- reactiveVal()
observe({
req(input$plotlystr)
traces <- data.frame(traces=strsplit(input$plotlystr, split = "<br>")[[1]])
tracesReact(traces)
})
output$printplotly <- renderPrint({
req(tracesReact())
tracesReact()
})
## Print Reactive Value (added traces)
output$printreactive <- renderPrint({
req(addedTrcs$df)
addedTrcs$df
})
}
shinyApp(ui, server)
It appears the Plotly.D3 method has been depreciated and no longer works in the above code. I was able to replicate a simple solution with the below code.
library(shiny)
library(plotly)
library(htmlwidgets)
js <- "function(el){
$(document).on('shiny:inputchanged', function(event) {
if (event.name === 'Remove') {
var traceName = document.getElementById('TraceName').value
var plotlyData = document.getElementById('MyPlot').data
plotlyData.forEach(function (item, index) {
if (item.name === traceName){
Plotly.deleteTraces('MyPlot', index);
}
});
}
});
}"
ui <- fluidPage(
textInput("TraceName", "Trace Name"),
actionButton("Remove", "Remove Trace"),
plotlyOutput("MyPlot")
)
server <- function(input, output, session) {
output$MyPlot <- renderPlotly({
print("renderPlotlyRan")
plot_ly(type = "scatter", mode = "markers") %>%
add_markers(x = rnorm(10),y = rnorm(10), name = "Trace1") %>%
add_markers(x = rnorm(10),y = rnorm(10), name = "Trace2") %>%
add_markers(x = rnorm(10),y = rnorm(10), name = "Trace3") %>%
add_markers(x = rnorm(10),y = rnorm(10), name = "Trace4") %>%
layout(showlegend = TRUE) %>%
htmlwidgets::onRender(x = ., jsCode = js)
})
}
shinyApp(ui, server)

Download table as image r

I want to be able to download a table as an image(PNG or JPEG). Let's assume that my dataframe is df
output$statsTable <- renderTable({
#Printing the table
df
})
output$downloadStatsTable <- downloadHunter(
filename = function() {
paste(getwd(), '/test.png', sep = '')
},
content = function(con) {
p <- grid.table(df)
device <- function(..., width, height) grDevices::png(..., width = 12, height = 9, res = 300, units = "in")
ggsave(file, plot = p, device = device)
}
)
To download table as image you can use grid.table function from library gridExtra. Here is a code which you could use as a template:
library(gridExtra)
library(shiny)
df <- head(datasets::iris)
ui <- fluidPage(
tableOutput("statsTable"),
downloadButton('downloadStatsTable ', 'Download')
)
server <- function(input, output) {
output$statsTable <- renderTable({
#Printing the table
df
})
output$downloadStatsTable <- downloadHandler(
# Create the download file name
filename = function() {
paste("data-", Sys.Date(), ".jpeg", sep="")
},
content = function(file) {
grid.table(df)
jpeg(file=file)
grid.table(df) #Create image of the data frame
dev.off()
})
}
runApp(list(ui = ui, server = server), launch.browser = TRUE)
Hope it helps!

Print category name on clicking the column of the plot in rCharts

I am trying to get the category name on clicking the column. I have implemented the following code but it does not seem to work. What am I doing wrong?
library(shiny)
library(rCharts)
ui <- fluidPage(
showOutput("chart", lib="highcharts"),
textOutput("check")
)
server <- function(input, output){
output$chart <- renderChart2({
p1 <- rCharts:::Highcharts$new()
p1$chart(type = "column", width = 400, height = 400)
p1$title(text = "Iris")
p1$xAxis(categories = colnames(t(iris[1:4])), title = list(text = "Categories"))
p1$yAxis(title = list(text = "Length"))
p1$data(as.data.frame(iris[2,1:4]))
p1$plotOptions(events = list(click = "#! function() {Shiny.onInputChange('click', {
x: this.data[1]
})
} !#" ))
return(p1)
})
output$check <- renderText(paste0(input$hcClicked$x))
}
shinyApp(ui =ui, server = server)

Resources