Shiny conditionalPanels just abruptly appear then disappear. Is there any way to make them slide or fade or otherwise gently transition?
Here is a way to fade the element when it is shown:
js <- "
$(document).ready(function(){
$('#plotContainer').on('show', function(event){
$(this).css('opacity', 0).animate({opacity: 1}, {duration: 1000});
});
});
"
ui <- fluidPage(
tags$head(tags$script(HTML(js))),
sidebarPanel(
actionButton("showplot", "Show")
),
mainPanel(
conditionalPanel(
condition = "input.showplot > 0",
id = "plotContainer",
plotOutput("plot")
)
)
)
server <- function(input, output) {
x <- rnorm(100)
y <- rnorm(100)
output$plot <- renderPlot({
plot(x, y)
})
}
shinyApp(ui, server)
EDIT
And also an effect on the hide event:
js <- "
$(document).ready(function(){
$('#plotContainer').on('show', function(){
$(this).css('opacity', 0).animate({opacity: 1}, {duration: 1000});
}).on('hide', function(){
var $this = $(this);
setTimeout(function(){
$this.show().hide(1000);
})
});
});
"
ui <- fluidPage(
tags$head(tags$script(HTML(js))),
sidebarPanel(
actionButton("showplot", "Show/Hide")
),
mainPanel(
conditionalPanel(
condition = "input.showplot % 2 == 1",
id = "plotContainer",
plotOutput("plot")
)
)
)
server <- function(input, output) {
x <- rnorm(100)
y <- rnorm(100)
output$plot <- renderPlot({
plot(x, y)
})
}
shinyApp(ui, server)
EDIT
Funny effects with the libraries Animate.css and jQuery-animateCSS:
js <- "
$(document).ready(function(){
$('#plotContainer').on('show', function(){
var $this = $(this);
$this.css('opacity', 0).
animate({opacity: 1}, 500, function(){
$this.animateCSS('jello', {
delay: 0,
duration: 2000
});
});
}).on('hide', function(){
var $this = $(this);
setTimeout(function(){
$this.show().animateCSS('heartBeat', {
delay: 0,
duration: 2000,
callback: function(){$this.hide(500);}
});
}, 0);
});
});
"
ui <- fluidPage(
tags$head(
tags$link(rel = "stylesheet", href = "https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.0/animate.compat.min.css"),
tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/animateCSS/1.2.2/jquery.animatecss.min.js"),
tags$script(HTML(js))
),
sidebarPanel(
actionButton("showplot", "Show/Hide")
),
mainPanel(
conditionalPanel(
condition = "input.showplot % 2 == 1",
id = "plotContainer",
plotOutput("plot")
)
)
)
server <- function(input, output) {
x <- rnorm(100)
y <- rnorm(100)
output$plot <- renderPlot({
plot(x, y)
})
}
shinyApp(ui, server)
EDIT
I've done some convenient R functions to bind these animations in a Shiny app. Here is the code:
library(shiny)
animateCSS <- function(effect, delay = 0, duration = 500, then = NULL){
effect <- match.arg(effect, c(
"bounce",
"flash",
"pulse",
"rubberBand",
"shakeX",
"shakeY",
"headShake",
"swing",
"tada",
"wobble",
"jello",
"heartBeat",
"backInDown",
"backInLeft",
"backInRight",
"backInUp",
"backOutDown",
"backOutLeft",
"backOutRight",
"backOutUp",
"bounceIn",
"bounceInDown",
"bounceInLeft",
"bounceInRight",
"bounceInUp",
"bounceOut",
"bounceOutDown",
"bounceOutLeft",
"bounceOutRight",
"bounceOutUp",
"fadeIn",
"fadeInDown",
"fadeInDownBig",
"fadeInLeft",
"fadeInLeftBig",
"fadeInRight",
"fadeInRightBig",
"fadeInUp",
"fadeInUpBig",
"fadeInTopLeft",
"fadeInTopRight",
"fadeInBottomLeft",
"fadeInBottomRight",
"fadeOut",
"fadeOutDown",
"fadeOutDownBig",
"fadeOutLeft",
"fadeOutLeftBig",
"fadeOutRight",
"fadeOutRightBig",
"fadeOutUp",
"fadeOutUpBig",
"fadeOutTopLeft",
"fadeOutTopRight",
"fadeOutBottomRight",
"fadeOutBottomLeft",
"flip",
"flipInX",
"flipInY",
"flipOutX",
"flipOutY",
"lightSpeedInRight",
"lightSpeedInLeft",
"lightSpeedOutRight",
"lightSpeedOutLeft",
"rotateIn",
"rotateInDownLeft",
"rotateInDownRight",
"rotateInUpLeft",
"rotateInUpRight",
"rotateOut",
"rotateOutDownLeft",
"rotateOutDownRight",
"rotateOutUpLeft",
"rotateOutUpRight",
"hinge",
"jackInTheBox",
"rollIn",
"rollOut",
"zoomIn",
"zoomInDown",
"zoomInLeft",
"zoomInRight",
"zoomInUp",
"zoomOut",
"zoomOutDown",
"zoomOutLeft",
"zoomOutRight",
"zoomOutUp",
"slideInDown",
"slideInLeft",
"slideInRight",
"slideInUp",
"slideOutDown",
"slideOutLeft",
"slideOutRight",
"slideOutUp"
))
js <- paste(
" $this.animateCSS('%s', {",
" delay: %d,",
" duration: %d,",
" callback: function(){",
" %s",
" }",
" });",
sep = "\n"
)
sprintf(js, effect, delay, duration, ifelse(is.null(then), "", then))
}
onShowJS <- function(animation, fadeDuration){
sprintf(paste(
"$('#%%s>div').on('show', function(){",
" var $this = $(this);",
" $this.css('opacity', 0).animate({opacity: 1}, %d, function(){",
animation,
" });",
"});",
sep = "\n"
), fadeDuration)
}
onHideJS <- function(animation, fadeDuration){
paste(
"$('#%s>div').on('hide', function(){",
" var $this = $(this);",
" setTimeout(function(){",
sub(
"^(\\s.*?\\$this\\.animateCSS)",
"$this.show().animateCSS",
sub(
"\\{\n \n \\}",
sprintf("{$this.hide(%d);}", fadeDuration),
animation
)
),
" }, 0);",
"});",
sep = "\n"
)
}
animatedConditionalPanel <-
function(condition, ..., onShow = NULL, fadeIn = 600, onHide = NULL, fadeOut = 400){
id <- paste0("animateCSS-", stringi::stri_rand_strings(1, 15))
jsShow <- ifelse(!is.null(onShow), sprintf(onShowJS(onShow, fadeIn), id), "")
jsHide <- ifelse(!is.null(onHide), sprintf(onHideJS(onHide, fadeOut), id), "")
script <- tags$script(HTML(paste(jsShow,jsHide,sep="\n")))
condPanel <- conditionalPanel(condition, ...)
tags$div(id=id, tagList(condPanel, script))
}
You have to use animateCSS and animatedConditionalPanel only. The animateCSS function defines an animation. You can chain the animations with the then argument. The animatedConditionalPanel functions replaces conditionalPanel. Here is an example:
ui <- fluidPage(
tags$head(
tags$link(rel = "stylesheet", href = "https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.0/animate.compat.min.css"),
tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/animateCSS/1.2.2/jquery.animatecss.min.js")
),
sidebarPanel(
actionButton("showplot", "Show/Hide")
),
mainPanel(
animatedConditionalPanel(
condition = "input.showplot % 2 == 0",
onShow = animateCSS("swing", duration = 1000, then = animateCSS("jello")),
fadeIn = 400,
onHide = animateCSS("pulse", then = animateCSS("bounce")),
plotOutput("plot")
)
)
)
server <- function(input, output) {
x <- rnorm(100)
y <- rnorm(100)
output$plot <- renderPlot({
plot(x, y)
})
}
shinyApp(ui, server)
UPDATE JUNE 2022
These animations will be available in the next version of the shinyGizmo package.
library(shiny)
library(shinyGizmo)
ui <- fluidPage(
sidebarPanel(
actionButton("showplot", "Show/Hide")
),
mainPanel(
fluidRow(
column(
10,
conditionalJS(
plotOutput("plot"),
condition = "input.showplot % 2 === 1",
jsCalls$animateVisibility("jello", "tada", duration = 1500)
)
),
column(2)
)
)
)
server <- function(input, output) {
x <- rnorm(100)
y <- rnorm(100)
output[["plot"]] <- renderPlot({
plot(x, y, pch = 19)
})
}
shinyApp(ui, server)
Related
I am able to use zoom on a single image, and that works well. However, in a more complex app, I have a dynamic UI that the plotting depends on a selectInput() like this:
output$all <- renderUI({
if (input$choice == 'two nodes') {
uiOutput("two")
}else{
uiOutput("three")
}
})
The problem is that when the user switches to the new visualisation, the zooming function stops working. (I have tried changing the 100ms but that's not the issue)
Here is a reproducible example:
library(shiny)
library(DiagrammeR)
library(magrittr)
js <- '
$(document).ready(function(){
var instance;
var myinterval = setInterval(function(){
var element = document.getElementById("grr");
if(element !== null){
clearInterval(myinterval);
instance = panzoom(element);
}
}, 100);
});
'
js2 <- '
$(document).ready(function(){
var instance;
var myinterval = setInterval(function(){
var element = document.getElementById("grr2");
if(element !== null){
clearInterval(myinterval);
instance = panzoom(element);
}
}, 100);
});
'
ui <- fluidPage(
selectInput('choice',
'choices:',choices = c('two nodes','three nodes')),
tags$head(
tags$script(src = "https://unpkg.com/panzoom#9.4.0/dist/panzoom.min.js"),
tags$script(HTML(js)),
tags$script(HTML(js2))
),
uiOutput("all")
)
server <- function(input, output) {
output$two_nodes <- renderUI({
div(
grVizOutput("grr", width = "100%", height = "90vh")
)
})
output$three_nodes <- renderUI({
div(
grVizOutput("grr2", width = "100%", height = "90vh")
)
})
output$all <- renderUI({
if (input$choice == 'two nodes') {
uiOutput("two_nodes")
}else{
uiOutput("three_nodes")
}
})
output$grr <- renderGrViz(render_graph(
create_graph() %>%
add_n_nodes(n = 2) %>%
add_edge(
from = 1,
to = 2,
edge_data = edge_data(
value = 4.3
)
)
))
output$grr2 <- renderGrViz(render_graph(
create_graph() %>%
add_n_nodes(n = 3) %>%
add_edge(
from = 1,
to = 2,
edge_data = edge_data(
value = 4.3
)
)
))
}
shinyApp(ui, server)
Since you used renderUI, we can add panzoom after grVizoutput, like this
library(shiny)
library(DiagrammeR)
library(magrittr)
library(shinyWidgets)
ui <- fluidPage(
selectInput('choice',
'choices:',choices = c('two nodes','three nodes')),
tags$head(
tags$script(src = "https://unpkg.com/panzoom#9.4.0/dist/panzoom.min.js"),
# tags$script(HTML(js))
),
uiOutput("all")
)
server <- function(input, output) {
output$two_nodes <- renderUI({
div(
grVizOutput("grr", width = "100%", height = "90vh"),
tags$script(HTML('panzoom($(".grViz").get(0))')),
actionGroupButtons(
inputIds = c("zoomout", "zoomin", "reset"),
labels = list(icon("minus"), icon("plus"), "Reset"),
status = "primary"
)
)
})
output$three_nodes <- renderUI({
div(
grVizOutput("grr2", width = "100%", height = "90vh"),
tags$script(HTML('panzoom($(".grViz").get(0))')),
actionGroupButtons(
inputIds = c("zoomout", "zoomin", "reset"),
labels = list(icon("minus"), icon("plus"), "Reset"),
status = "primary"
)
)
})
output$all <- renderUI({
if (input$choice == 'two nodes') {
uiOutput("two_nodes")
}else{
uiOutput("three_nodes")
}
})
output$grr <- renderGrViz(render_graph(
create_graph() %>%
add_n_nodes(n = 2) %>%
add_edge(
from = 1,
to = 2,
edge_data = edge_data(
value = 4.3
)
)
))
output$grr2 <- renderGrViz(render_graph(
create_graph() %>%
add_n_nodes(n = 3) %>%
add_edge(
from = 1,
to = 2,
edge_data = edge_data(
value = 4.3
)
)
))
}
shinyApp(ui, server)
I have used panzoom package in order to pan and zoom on my svg file in my shiny app. Is there a way to have controls like this?
library(shiny)
library(DiagrammeR)
library(magrittr)
ui <- fluidPage(
tags$head(
tags$script(src = "https://unpkg.com/panzoom#9.4.0/dist/panzoom.min.js")
),
grVizOutput("grr", width = "100%", height = "90vh"),
tags$script(
HTML('panzoom($("#grr")[0])')
)
)
server <- function(input, output) {
reactives <- reactiveValues()
observe({
reactives$graph <- render_graph(create_graph() %>%
add_n_nodes(n = 2) %>%
add_edge(
from = 1,
to = 2,
edge_data = edge_data(
value = 4.3)))
})
output$grr <- renderGrViz(reactives$graph)
}
shinyApp(ui, server)
Here is a way, but if you click too quickly on the +/- buttons, there's an undesirable effect.
library(shiny)
library(shinyWidgets)
library(DiagrammeR)
library(magrittr)
js <- '
$(document).ready(function(){
var element = document.getElementById("grr");
var instance = panzoom(element);
$("#zoomout").on("click", function(){
instance.smoothZoom(0, 0, 0.9);
});
$("#zoomin").on("click", function(){
instance.smoothZoom(0, 0, 1.1);
});
});
'
ui <- fluidPage(
tags$head(
tags$script(src = "https://unpkg.com/panzoom#9.4.0/dist/panzoom.min.js"),
tags$script(HTML(js))
),
grVizOutput("grr", width = "100%", height = "90vh"),
actionGroupButtons(
inputIds = c("zoomout", "zoomin"),
labels = list(icon("minus"), icon("plus")),
status = "primary"
)
)
server <- function(input, output) {
reactives <- reactiveValues()
observe({
reactives$graph <- render_graph(
create_graph() %>%
add_n_nodes(n = 2) %>%
add_edge(
from = 1,
to = 2,
edge_data = edge_data(
value = 4.3
)
)
)
})
output$grr <- renderGrViz(reactives$graph)
}
shinyApp(ui, server)
EDIT
Add this JavaScript to prevent the undesirable effect:
$("#zoomout").on("dblclick", function(){
return false;
});
$("#zoomin").on("dblclick", function(){
return false;
});
I am trying to update a sample DataTable dynamically using dropdowns that I created within the DataTable. However, it doesn't seem to update regardless of what I try. The sample code below is what I am currently working with in order to update the Species column when the input is selected from the species_selector column.
library(shiny)
library(DT)
ui <- fluidPage(
title = 'Selectinput column in a table',
h3("Source:", tags$a("Yihui Xie", href = "https://yihui.shinyapps.io/DT-radio/")),
DT::dataTableOutput('foo'),
actionButton(inputId = "submit", label = "Submit"),
verbatimTextOutput('sel')
)
server <- function(input, output, session) {
data <- head(iris, 5)
for (i in 1:nrow(data)) {
data$species_selector[i] <- as.character(selectInput(paste0("sel", i), "", choices = unique(iris$Species), width = "100px"))
}
output$foo = DT::renderDataTable(
data, escape = FALSE, selection = 'none', server = FALSE,
options = list(dom = 't', paging = FALSE, ordering = FALSE),
callback = JS("table.rows().every(function(i, tab, row) {
var $this = $(this.node());
$this.attr('id', this.data()[0]);
$this.addClass('shiny-input-container');
});
Shiny.unbindAll(table.table().node());
Shiny.bindAll(table.table().node());")
)
observeEvent(input$submit, {
update_data <- reactive({
df <- data
for(i in 1:nrow(df)) {
df$Species[i] <- as.character(input[[paste0("sel", i)]])
}
return(df)
})
data <- update_data()
})
output$sel = renderPrint({
for(i in 1:nrow(data)) {
data$Species[i] <- as.character(input[[paste0("sel", i)]])
}
data
})
}
shinyApp(ui, server)
Any help would be appreciated. Thank you!
Is it something like this you want?
library(shiny)
library(DT)
selector <- function(id, values, items = values){
options <- HTML(paste0(mapply(
function(i, item){
value <- values[i]
if(i == 1L){
opt <- tags$option(value = value, selected = "selected", item)
}else{
opt <- tags$option(value = value, item)
}
as.character(opt)
}, seq_along(values), items
), collapse = ""))
as.character(tags$select(id = id, options))
}
js <- c(
"function(settings) {",
" var table = this.api().table();",
" var $tbl = $(table.table().node());",
" var id = $tbl.closest('.datatables').attr('id');",
" var nrows = table.rows().count();",
" function selectize(i) {",
" var $slct = $('#slct' + i);",
" $slct.select2({",
" width: '100%',",
" closeOnSelect: true",
" });",
" $slct.on('change', function(e) {",
" var info = [{",
" row: i,",
" col: 4,",
" value: $slct.val()",
" }];",
" Shiny.setInputValue(id + '_cell_selection:DT.cellInfo', info);",
" });",
" }",
" for(var i = 1; i <= nrows; i++) {",
" selectize(i);",
" }",
"}"
)
ui <- fluidPage(
tags$head(
tags$link(rel = "stylesheet", href = "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css"),
tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js")
),
br(),
DTOutput("dtable"),
tags$hr(),
h2("Edited table:"),
tableOutput("table")
)
server <- function(input, output, session) {
dat <- head(iris, 3L)
Dat <- reactiveVal(dat)
for(i in 1L:nrow(dat)){
dat$species_selector[i] <-
selector(id = paste0("slct", i), values = unique(iris$Species))
}
output[["dtable"]] <- renderDT({
datatable(
data = dat,
selection = "none",
escape = FALSE,
rownames = FALSE,
options = list(
initComplete = JS(js),
preDrawCallback = JS(
"function() { Shiny.unbindAll(this.api().table().node()); }"
),
drawCallback = JS(
"function() { Shiny.bindAll(this.api().table().node()); }"
)
)
)
}, server = TRUE)
observeEvent(input[["dtable_cell_selection"]], {
info <- input[["dtable_cell_selection"]]
Dat(editData(Dat(), info, rownames = FALSE))
})
output[["table"]] <- renderTable({
Dat()
})
}
shinyApp(ui, server)
You can take help of reactive values to save the dataframe and perform the changes in the same.
library(shiny)
library(DT)
data <- head(iris, 5)
for (i in 1:nrow(data)) {
data$species_selector[i] <- as.character(selectInput(paste0("sel", i), "", choices = unique(iris$Species), width = "100px"))
}
ui <- fluidPage(
title = 'Selectinput column in a table',
h3("Source:", tags$a("Yihui Xie", href = "https://yihui.shinyapps.io/DT-radio/")),
DT::dataTableOutput('foo'),
actionButton(inputId = "submit", label = "Submit"),
verbatimTextOutput('sel')
)
server <- function(input, output, session) {
rv <- reactiveValues(data = data)
output$foo = DT::renderDataTable(
rv$data, escape = FALSE, selection = 'none', server = FALSE,
options = list(dom = 't', paging = FALSE, ordering = FALSE),
callback = JS("table.rows().every(function(i, tab, row) {
var $this = $(this.node());
$this.attr('id', this.data()[0]);
$this.addClass('shiny-input-container');
});
Shiny.unbindAll(table.table().node());
Shiny.bindAll(table.table().node());")
)
observeEvent(input$submit, {
for(i in 1:nrow(rv$data)) {
rv$data$Species[i] <- as.character(input[[paste0("sel", i)]])
}
})
}
shinyApp(ui, server)
I would like to create a download button within my shiny app to download a reactive plot created with chartJSRadar. I am not able to solve this problem!
As I have been through the documented problem on the internet, I was not able to solve it, receiving all the time an empty png. As suggested (Save plots made in a shiny app), https://groups.google.com/forum/#!msg/shiny-discuss/u7gwXc8_vyY/IZK_o7b7I8gJ
I built a function ...
So my code is an example code:
ui.R:
library(radarchart)
shinyUI(pageWithSidebar(
headerPanel('Radarchart Shiny Example'),
sidebarPanel(
checkboxGroupInput('selectedPeople', 'Who to include',
names(radarchart::skills)[-1], selected="Rich")
),
mainPanel(
chartJSRadarOutput("plot1", width = "450", height = "300"), width = 7,
radioButtons(inputId = "var3", label = "Select the file type", choices = list("png", "pdf")),
downloadButton('downloadPlot', 'Download Plot')
)
))
server.R
library(radarchart)
shinyServer(function(input, output) {
output$plot1 <- renderChartJSRadar({
chartJSRadar(skills[, c("Label", input$selectedPeople)],
maxScale = 10, showToolTipLabel=TRUE)
})
plot2 <- function(){
chartJSRadar(skills[, c("Label", input$selectedPeople)],
maxScale = 10, showToolTipLabel=TRUE)
}
output$downloadPlot <- downloadHandler(
filename = "Shinyplot.png",
content = function(file) {
png(file)
plot2()
print(plot2())
dev.off()
})
})
Here is a JavaScript way which should be faster than webshot, I think.
library(shiny)
library(radarchart)
library(htmlwidgets) # to use the 'onRender' function
js <- c(
"function(el, x){",
" $('#downloadPlot').on('click', function(){",
" // Clone the chart to add a background color.",
" var cloneCanvas = document.createElement('canvas');",
" cloneCanvas.width = el.width;",
" cloneCanvas.height = el.height;",
" var ctx = cloneCanvas.getContext('2d');",
" ctx.fillStyle = '#FFFFFF';",
" ctx.fillRect(0, 0, el.width, el.height);",
" ctx.drawImage(el, 0, 0);",
" // Download.",
" const a = document.createElement('a');",
" document.body.append(a);",
" a.download = 'radarchart.png';",
" a.href = cloneCanvas.toDataURL('image/png');",
" a.click();",
" a.remove();",
" });",
"}"
)
ui <- pageWithSidebar(
headerPanel('Radarchart Shiny Example'),
sidebarPanel(
checkboxGroupInput('selectedPeople', 'Who to include',
names(radarchart::skills)[-1], selected="Rich"),
actionButton('downloadPlot', 'Download Plot')
),
mainPanel(
chartJSRadarOutput("plot1", width = "450", height = "300"), width = 7
)
)
server <- function(input, output) {
output$plot1 <- renderChartJSRadar({
chartJSRadar(skills[, c("Label", input$selectedPeople)],
maxScale = 10, showToolTipLabel=TRUE) %>%
onRender(js)
})
}
shinyApp(ui, server)
This exports to png only. Use webshot to export to pdf.
EDIT
library(shiny)
library(radarchart)
js <- paste0(c(
"$(document).ready(function(){",
" $('#downloadPlot').on('click', function(){",
" var el = document.getElementById('plot1');",
" // Clone the chart to add a background color.",
" var cloneCanvas = document.createElement('canvas');",
" cloneCanvas.width = el.width;",
" cloneCanvas.height = el.height;",
" var ctx = cloneCanvas.getContext('2d');",
" ctx.fillStyle = '#FFFFFF';",
" ctx.fillRect(0, 0, el.width, el.height);",
" ctx.drawImage(el, 0, 0);",
" // Download.",
" const a = document.createElement('a');",
" document.body.append(a);",
" a.download = 'radarchart.png';",
" a.href = cloneCanvas.toDataURL('image/png');",
" a.click();",
" a.remove();",
" cloneCanvas.remove();",
" });",
"});"
), collapse = "\n")
ui <- pageWithSidebar(
headerPanel('Radarchart Shiny Example'),
sidebarPanel(
checkboxGroupInput('selectedPeople', 'Who to include',
names(radarchart::skills)[-1], selected="Rich"),
actionButton('downloadPlot', 'Download Plot')
),
mainPanel(
tags$head(tags$script(HTML(js))),
chartJSRadarOutput("plot1", width = "450", height = "300"), width = 7
)
)
server <- function(input, output) {
output$plot1 <- renderChartJSRadar({
chartJSRadar(skills[, c("Label", input$selectedPeople)],
maxScale = 10, showToolTipLabel=TRUE)
})
}
shinyApp(ui, server)
chartJSRadar returns an htmlWidget. To save, try using saveWidget and then webshot of the temporary html file. Add webshot library:
library(webshot)
and try substituting this for downloadHandler in your server function:
output$downloadPlot <- downloadHandler(
filename = "Shinyplot.png",
content = function(file) {
saveWidget(plot2(), "temp.html", selfcontained = TRUE)
webshot("temp.html", file = file)
}
)
I have the following R Shiny Application:
library(shiny)
shinyApp(
ui = dashboardPage(
dashboardHeader(
title = "Tweetminer",
titleWidth = 350
),
dashboardSidebar(
width = 350,
sidebarMenu(
menuItem("Menu Item")
)
),
dashboardBody(
fluidRow(
tabBox(
tabPanel("Select tweets",
numericInput("tweet_amount", "Amount of tweets:", 10, min = 1, max = 100),
div(style="display:inline-block",numericInput("tweet_long", "Longitude:", 10, min = 1, max = 100)),
div(style="display:inline-block",numericInput("tweet_lat", "Latitude:", 10, min = 1, max = 100)),
#selectInput("tweet_name", "Account name", choices = c("#realDonaldTrump","#GorgeNails"), width = NULL, placeholder = NULL),
selectInput("tweet_name", "Account name", choices = c("#realDonaldTrump","#Yankees"), selected = NULL, multiple = FALSE,
selectize = TRUE, width = NULL, size = NULL),
actionButton("get_tweets", "Fetch the tweets"),
hidden(
div(id='text_div',
verbatimTextOutput("text")
)
)
)
)
)
)
),
server = function(input, output) {
test_list <- c(1,2,3)
run_function <- reactive({
for(i in test_list){
Sys.sleep(2)
}
})
observeEvent(input$get_tweets, {
run_function()
toggle('text_div')
output$text <- renderText({"You're now connecting to the API"})
})
}
)
This application should allow users to input parameters after which tweets will be scraped. However - because it will take some time Im looking for a way to inform users this will take a while.
Using this function:
observeEvent(input$get_tweets, {
run_function()
toggle('text_div')
output$text <- renderText({"You're now connecting to the API"})
})
I inform the user that the function (run_function() in this example, a mockup but just for reproducing purposes) is ready. However Im looking for a notice after you initiate the function and when its done.
So after you press the first time it should say something like - function initiated and after the function is ready -> "You .. api".
Any thoughts on what I should change to get this working?
You can use withProgress function, check this example:
output$plot <- renderPlot({
withProgress(message = 'Calculation in progress', detail = 'This may take a while...', value = 0, {
for (i in 1:15) {
incProgress(1/15)
Sys.sleep(0.25)
}
})
plot(cars)
})
More info
EDIT: New example:
library(shiny)
ui <- fluidPage(
actionButton(inputId = 'DoSomething', label = 'Do something'),
verbatimTextOutput('t1')
)
server <- function(input, output, session) {
output$t1 <- renderPrint('Doing nothing...')
run_function <- reactive({
withProgress(message = "Starting...", max = 60, value = 0, {
for (i in 1:25) {
incProgress(1)
Sys.sleep(0.25)
}
setProgress(message = "Connected..")
for (i in 1:25) {
incProgress(1)
Sys.sleep(0.25)
}
setProgress(message = "Doing Stuffs...")
for (i in 1:10) {
incProgress(1)
Sys.sleep(0.25)
}
setProgress(message = "Disconecting...")
})
return('Finish')
})
observeEvent(input$DoSomething, {
output$t1 <- renderPrint(run_function())
})
}
shinyApp(ui, server)