Automatic scrolling based on recent output in Shiny - r

This question builds on this previous question R Shiny: keep old output.
I would like to view the output at the top of the page. How to automatically scroll the output to the top of the page?
library(shiny)
library(broom)
library(dplyr)
library(shinyjs)
library(shinydashboard)
header <- dashboardHeader(title = "My Dashboard")
sidebar <- dashboardSidebar(
sidebarMenu(
checkboxGroupInput(inputId = "indep",
label = "Independent Variables",
choices = names(mtcars)[-1],
selected = NULL),
actionButton(inputId = "fit_model",
label = "Fit Model"),
numericInput(inputId = "model_to_show",
label = "Show N most recent models",
value = 20)
)
)
body <- dashboardBody(
includeScript("www/scrolldown.js"),
tags$head(includeCSS('www/style.css')),
htmlOutput("model_record")
)
ui <- dashboardPage(header, sidebar, body)
server <-
shinyServer(function(input, output, session){
Model <- reactiveValues(
Record = list()
)
observeEvent(
input[["fit_model"]],
{
fit <-
lm(mpg ~ .,
data = mtcars[c("mpg", input[["indep"]])])
#Model$Record <- c(Model$Record, list(fit))
#Last result up
Model$Record <- c(list(fit),Model$Record)
}
)
output$model_record <-
renderText({
tail(Model$Record, input[["model_to_show"]]) %>%
lapply(tidy) %>%
lapply(knitr::kable,
format = "html") %>%
lapply(as.character) %>%
unlist() %>%
paste0(collapse = "<br/><br/>")
})
})
shinyApp(ui, server)
style.css file:
.sidebar {
color: #FFF;
position: fixed;
width: 220px;
white-space: nowrap;
overflow: visible;
}
.main-header {
position: fixed;
width:100%;
}
.content {
padding-top: 60px;
}
EDIT:
Javascript added based on Waldi's answer:
scrolldown.js
$(document).on('shiny:value', function(event) {
// Scroll down after model update
if (event.target.id === 'model_record') {
window.scrollTo(0,document.body.scrollHeight);
}
});
View Video Screenshot Gif

As mentionned in the comments, you can set a javascript trigger on model_record tag:
create the js script under www/scrolldown.js :
$(document).on('shiny:value', function(event) {
// Scroll down after model update
if (event.target.id === 'model_record') {
window.scrollTo(0,document.body.scrollHeight);
}
});
include the script in the UI:
library(shiny)
library(broom)
library(dplyr)
library(shinyjs)
library(shinydashboard)
header <- dashboardHeader(title = "My Dashboard")
sidebar <- dashboardSidebar(
sidebarMenu(
checkboxGroupInput(inputId = "indep",
label = "Independent Variables",
choices = names(mtcars)[-1],
selected = NULL),
actionButton(inputId = "fit_model",
label = "Fit Model"),
numericInput(inputId = "model_to_show",
label = "Show N most recent models",
value = 20)
)
)
body <- dashboardBody(
includeScript("www/scrolldown.js"),
tags$head(includeCSS('www/style.css')),
htmlOutput("model_record"),
div(style="height: 90vh;")
)
ui <- dashboardPage(header, sidebar, body)
server <-
shinyServer(function(input, output, session){
Model <- reactiveValues(
Record = list()
)
observeEvent(
input[["fit_model"]],
{
fit <-
lm(mpg ~ .,
data = mtcars[c("mpg", input[["indep"]])])
Model$Record <- c(Model$Record, list(fit))
}
)
output$model_record <-
renderText({
tail(Model$Record, input[["model_to_show"]]) %>%
lapply(tidy) %>%
lapply(knitr::kable,
format = "html") %>%
lapply(as.character) %>%
unlist() %>%
paste0(collapse = "<br/><br/>")
})
})
shinyApp(ui, server)
Now the scrollbar moves down after each model update... but you have to scroll up to find the fit model button : this can be changed by using a fixed sidebar css.
Finally, to show only the last model on top, building on #Tonio Liebrand suggestion, you can add a div with 90% of viewport height so that it automatically adapts to screen size.

Thanks for clarifying concerning my question in the comments. I think now i understand what you are attempting to achieve.
I think one challenge you might face is that the sidebar wont scroll down as well. I am not sure that it is desired.
Potential solution:
You could add a placeholder that ensures that your latest modell output will be on top if you scroll down. It could be just an empty div:
div(style="height: 850px;")
This is more of a draft as we should ensure first that the spec is fully understood. Enhancements would be to scale this div to the size of the users screen.
Reproducible example:
library(shiny)
library(broom)
library(dplyr)
library(shinyjs)
library(shinydashboard)
header <- dashboardHeader(title = "My Dashboard")
js_code <- "$(document).on('shiny:value', function(event) {
// Scroll down after model update
if (event.target.id === 'model_record') {
window.scrollTo(0,document.body.scrollHeight);
}
});"
sidebar <- dashboardSidebar(
sidebarMenu(
checkboxGroupInput(inputId = "indep",
label = "Independent Variables",
choices = names(mtcars)[-1],
selected = NULL),
actionButton(inputId = "fit_model",
label = "Fit Model"),
numericInput(inputId = "model_to_show",
label = "Show N most recent models",
value = 20)
)
)
body <- dashboardBody(
tags$script(js_code),
htmlOutput("model_record"),
div(style="height: 850px;")
)
ui <- dashboardPage(header, sidebar, body)
server <-
shinyServer(function(input, output, session){
Model <- reactiveValues(
Record = list()
)
observeEvent(
input[["fit_model"]],
{
fit <-
lm(mpg ~ .,
data = mtcars[c("mpg", input[["indep"]])])
Model$Record <- c(Model$Record, list(fit))
}
)
output$model_record <-
renderText({
tail(Model$Record, input[["model_to_show"]]) %>%
lapply(tidy) %>%
lapply(knitr::kable,
format = "html") %>%
lapply(as.character) %>%
unlist() %>%
paste0(collapse = "<br/><br/>")
})
})
shinyApp(ui, server)

Related

How to add a downloadButton in a popup?

I'm currently developing an R Shiny application where I'm mapping services providers on a map and when I click on a specific marker I have a popup with additional information and I would like to include a downloadButton in that popup. Unfortunately when I'm calling the downloadHandler it doesn't work and I'm downloading a html file called qwe_download.html. But if I put the downloadButton outside the popup (i.e. in the ui) then it works. Is it possible to use a downloadButton inside a leaflet popup?
I can't share the original code as it is quite sensitive but you can find below what I'm trying to achieve.
library('leaflet')
library('shinydashboard')
id <- c(1, 2, 3)
lat <- c(10.01, 10.6, 10.3)
long <- c(0.2, 0.3, 0.4)
name <- c('test1', ' test2', 'test3')
test <- data_frame(id, lat, long, name)
#User interface
header <- dashboardHeader(title = 'Title', titleWidth = 900)
sidebar <- dashboardSidebar(
width = 300)
body <- dashboardBody(
tags$style(type = "text/css", "#map {height: calc(100vh - 80px) !important;}"),
leafletOutput("map")
)
ui <- dashboardPage(header, sidebar, body)
server <- function(input, output, session) {
data <- reactiveValues(clickedMarker=NULL)
output$map <- renderLeaflet({
mymap <- leaflet() %>%
addTiles() %>%
addMarkers(data = test, lng = long, lat = lat, layerId = id,
popup = paste0(
"<div>",
"<h3>",
"Name: ",
test$name,
downloadButton(outputId = "dlData",label = "Download Details"),
"</div>"))
observeEvent(input$map_marker_click,{
print("observed map_marker_click")
data$clickedMarker <- input$map_marker_click
print(data$clickedMarker)
x <- filter(test, id == data$clickedMarker$id)
view(x)})
data_react <- reactive({
data_table <- filter(test, test$id == data$clickedMarker$id)
})
output$dlData <- downloadHandler(
filename = "dataset.csv",
content = function(file) {
write.csv(data_react(), file)
}
)
mymap
})
}
# Run app ----
shinyApp(ui, server)
Note that the observeEvent block was just there for me to check if my code was filtering the right selection.
Hope this makes sense.
Thanks!
You need to bind the downloadButtons yourself after placing them in the popup.
Please see this related answer from Joe Cheng.
Here you can find some great answers on how to bindAll custom inputs in a leaflet popup.
And this is how to apply those answers regarding your particular requirements:
library('leaflet')
library('shinydashboard')
id <- c(1, 2, 3)
lat <- c(10.01, 10.6, 10.3)
long <- c(0.2, 0.3, 0.4)
name <- c('test1', ' test2', 'test3')
test <- data.frame(id, lat, long, name)
header <- dashboardHeader(title = 'Title', titleWidth = 900)
sidebar <- dashboardSidebar(width = 300)
body <- dashboardBody(
tags$div(id = "garbage"),
tags$style(type = "text/css", "#map {height: calc(100vh - 80px) !important;}"),
leafletOutput("map")
)
ui <- dashboardPage(header, sidebar, body)
server <- function(input, output, session) {
data <- reactiveValues(clickedMarker = NULL)
output$map <- renderLeaflet({
mymap <- leaflet() %>%
addTiles() %>%
addMarkers(
data = test,
lng = long,
lat = lat,
layerId = id,
popup = sprintf(
paste0(
"<div>",
"<h3>",
"Name: ",
test$name,
br(),
downloadButton(outputId = "dlData%s", label = "Download Details"),
"</div>"
),
id
)
) %>% htmlwidgets::onRender(
'function(el, x) {
var target = document.querySelector(".leaflet-popup-pane");
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if(mutation.addedNodes.length > 0){
Shiny.bindAll(".leaflet-popup-content");
}
if(mutation.removedNodes.length > 0){
var popupNode = mutation.removedNodes[0];
var garbageCan = document.getElementById("garbage");
garbageCan.appendChild(popupNode);
Shiny.unbindAll("#garbage");
garbageCan.innerHTML = "";
}
});
});
var config = {childList: true};
observer.observe(target, config);
}'
)
})
observeEvent(input$map_marker_click,{
print("observed map_marker_click")
data$clickedMarker <- input$map_marker_click
print(data$clickedMarker)
x <- filter(test, id == data$clickedMarker$id)
})
data_react <- reactive({
data_table <- filter(test, test$id == data$clickedMarker$id)
})
lapply(id, function(i) {
output[[paste0("dlData", i)]] <- downloadHandler(
filename = "dataset.csv",
content = function(file) {
write.csv(data_react(), file)
}
)
})
}
shinyApp(ui, server)
The download button is not binded to Shiny. You can use the pointerenter event to run Shiny.bindAll() and the pointerleave event to run Shiny.unbindAll():
library('leaflet')
library('shinydashboard')
library(shiny)
library(dplyr)
id <- c(1, 2, 3)
lat <- c(10.01, 10.6, 10.3)
long <- c(0.2, 0.3, 0.4)
name <- c('test1', ' test2', 'test3')
test <- tibble(id, lat, long, name)
js <- "$('body').on('pointerenter', '#dlData', function(){Shiny.bindAll('#dwnld');}).on('pointerleave', '#dlData', function(){Shiny.unbindAll('#dwnld');})"
header <- dashboardHeader(title = 'Title', titleWidth = 900)
sidebar <- dashboardSidebar(
width = 300)
body <- dashboardBody(
useShinyjs(),
tags$script(HTML(js)),
tags$style(type = "text/css", "#map {height: calc(100vh - 80px) !important;}"),
leafletOutput("map")
)
ui <- dashboardPage(header, sidebar, body)
server <- function(input, output, session) {
data <- reactiveValues(clickedMarker=NULL)
output$map <- renderLeaflet({
mymap <- leaflet() %>%
addTiles() %>%
addMarkers(
data = test, lng = long, lat = lat, layerId = id,
popup = paste0(
"<div id='dwnld'>",
"<h3>",
"Name: ",
test$name,
"</h3>",
downloadButton(
outputId = "dlData", label = "Download Details"
),
"</div>"))
mymap
})
observeEvent(input$map_marker_click,{
data$clickedMarker <- input$map_marker_click
})
data_react <- reactive({
filter(test, id == data$clickedMarker$id)
})
output$dlData <- downloadHandler(
"dataset.csv",
content = function(file) {
write.csv(data_react(), file)
})
}
# Run app ----
shinyApp(ui, server)
To add a summarizing answer, what we need to do:
Call Shiny.[un]bindAll in the "right" moment.
The "right" moment is apparently once the popup is added / removed from the DOM.
Non working downloads can happen as a result of re-using the same id (unfortunately I could not identify a pattern and I thought that unbinding helps, but it does not). Thus, to play it safe creating unique download handlers should avoid this behaviour.
Having said that, the IMHO cleanest option to call Shiny.bindAll() is in response to the popupopen event:
output$map <- renderLeaflet({
mymap <- leaflet() %>%
addTiles() %>%
addMarkers(
data = test, lng = long, lat = lat, layerId = id,
popup = paste0(
"<div id='dwnld'>",
"<h3>",
"Name: ",
test$name,
downloadButton(outputId = "dlData",label = "Download Details"),
"</div>"))
mymap %>% htmlwidgets::onRender(HTML("
function(el, x) {
this.on('popupopen', function() {
Shiny.bindAll('#dwnld');
});
this.on('popupclose', function() {
Shiny.unbindAll('#dwnld');
});
}"))
})

R Shiny: Set default value for reactive filter

I set up a filter by year using year_filter and would like the default view to be 2021. How to do I this given the code below? Currently, the default display is to show all data entries for all years.
The complete code and file can be found here for reference: https://drive.google.com/drive/folders/1C7SWkl8zyGXLGEQIiBEg4UsNQ5GDaKoa?usp=sharing
Thank you for your assistance!
# Define UI for application
ui <- fluidPage(
tags$div(
style = "padding: 10px;",
# Application title
titlePanel("Testing and Quarantine Measures"),
fluidRow(
uiOutput("CountryFilter_ui"),
uiOutput("YearFilter_ui")
),
fluidRow(
tags$div(style = "width: 100%; overflow: scroll; font-size:80%;",
DT::dataTableOutput('travel_table')
)
)
)
)
server <- function(input, output) {
# Render UI
output$CountryFilter_ui <- renderUI({
countries <- travel_clean %>%
pull(country_area)
selectInput('country_filter', 'Member State Filter', choices = countries, multiple = TRUE)
})
output$YearFilter_ui <- renderUI({
year <- travel_clean %>%
pull(year)
selectInput('year_filter', 'Year Filter', choices = year, multiple = TRUE)
})
# Filter data
travel_filtered <- reactive({
tmp_travel <- travel_measures %>%
select(-Sources)
if(is.null(input$country_filter) == FALSE) {
tmp_travel <- tmp_travel %>%
filter(`Country/area` %in% input$country_filter)
}
return(tmp_travel)
})
travel_filtered <- reactive({
tmp_travel <- travel_measures %>%
select(-Sources)
if(is.null(input$year_filter) == FALSE) {
tmp_travel <- tmp_travel %>%
filter(`Year` %in% input$year_filter)
}
return(tmp_travel)
})

Persistent data in reactive editable table in Shiny app using DT

I have an app, which fetches data from an SQL-db, then allows the user to edit it, and this should be saved to the DB. In the repex I have used a CSV-file, but the logic should still be comparable.
However, the data is saved in the session once I edit the column value, but if I switch input or close the app and re-open, it's back to the original. Edits are not reflected in the summary table. What am I doing wrong?
# Load libraries
library(DT)
library(gt)
library(shiny)
library(shinydashboard)
library(dplyr)
# Load data (run once for replication; in real use case will be a DB-connection)
#gtcars_tbl <- gtcars
#write.csv(gtcars_tbl, "gtcars_tbl.csv", row.names = FALSE)
# Simple UI
sidebar <- dashboardSidebar(
sidebarMenu(
menuItem("Summary table", tabName = "summary", icon = icon("project-diagram")),
menuItem("Edit table", tabName = "edit", icon = icon("project-diagram")),
uiOutput("country")
)
)
body <- dashboardBody(
tabItems(
tabItem(tabName = "summary",
h2("Summary of GT Cars"),
gt_output(outputId = "gt_filt_tbl")
),
tabItem(tabName = "edit",
h2("Editer GT Cars"),
DTOutput("edit")
)
)
)
ui <- dashboardPage(
dashboardHeader(title = "GT Cars"),
sidebar,
body)
# Define server functions
server <- function(input, output, session) {
# Load data
gtcars_tbl <- read.csv("gtcars_tbl.csv")
countries <- sort(as.vector(unique(gtcars_tbl$ctry_origin)))
# Create dropdown output
output$country <- renderUI({
selectInput("country", "Country", countries)
})
# Create reactive table
gt_tbl_react <- reactiveVal(NULL)
gt_tbl_react(gtcars_tbl)
# Create filtered table
gt_filt_tbl <- reactive({
req(input$country)
gt_tbl_react() %>%
filter(ctry_origin == input$country)
})
# Render summary table
output$gt_filt_tbl <- render_gt({
gt_filt_tbl() %>%
group_by(ctry_origin, mfr) %>%
summarise(
N = n(),
Avg_HP = mean(hp),
MSRP = mean(msrp)
) %>%
gt(
rowname_col = "ctry_origin",
groupname_col = "mfr")
})
# Render editable table
output$edit <- renderDT(
gt_tbl_react() %>%
filter(ctry_origin == input$country),
selection = 'none', editable = TRUE,
rownames = TRUE,
extensions = 'Buttons'
)
observeEvent(input$edit_cell_edit, {
gtcars_tbl[input$edit_cell_edit$row,input$edit_cell_edit$col] <<- input$edit_cell_edit$value
write.csv(gtcars_tbl, "gtcars_tbl.csv", row.names = FALSE)
})
}
# Run app
shinyApp(ui, server)
The issue is that input$edit_cell_edit$row and input$edit_cell_edit$col are provided according to the subsetted dataframe that is displayed whereas you are changing the values on complete dataframe.
Use this in observeEvent -
observeEvent(input$edit_cell_edit, {
inds <- which(gtcars_tbl$ctry_origin == input$country)
gtcars_tbl[inds[input$edit_cell_edit$row],input$edit_cell_edit$col] <- input$edit_cell_edit$value
write.csv(gtcars_tbl, "gtcars_tbl.csv", row.names = FALSE)
})

Shiny - different plots in different tabs

I have what could appear as a very simple problem. I'd like to display different plots in different tabs. For this I have some code already where I use output$Sidebar and output$TABUI for the content of the tabs.
I do wish to use some controls for the plots, but all the controls being identical, I need them just below the different tabs, as I don't want to replicate them across and having them appearing within each tab.
I must miss something in my code because nothing show up in the dashboardbody. The tabs are created just fine (as it seems) so are my controls, just below them. My data is read through (can see this in the console) and I can work with the controls, but nothing appears in the body.
I've tried to modify my code (much longer) to make a minimal example, as follow.
Edit : If both the sidebarmenu and tabitems are in the UI.R, then everything on the ui gets compiled correctly, except that my data, which are being loaded at the beginning of the SERVER.R are not loaded. It seems as if server.R is not even ran.
If I define the sidebarmenu and thetabitems from the server.R, then the data are loaded, but only my controls are displayed, sidebarmenu and body are not displayed. I can't understand this behavior either.
If I leave tabitems in the UI.R and sidebarmenu from server.R, it does not load the data either. The app just seats there and nothing happens.
If someone think they might know why, I'd be glad to have an explanation.
Thank you.
ui.R :
library(shiny)
library(shinydashboard)
body <- dashboardBody(
tags$head(
tags$link(
rel = "stylesheet",
type = "text/css",
href = "css/custom.css"
)
),
uiOutput("TABUI")
)
sidebar <- dashboardSidebar(
width = 350,
uiOutput("Sidebar")
)
header <- dashboardHeader(
title = "Dashboard",
titleWidth = 350,
tags$li(
class = "dropdown",
img(
src = 'img/General_Logo.png',
style = 'margin-right:150px; margin-top:21px')
)
)
dashboardPage(
header,
sidebar,
body
)
Server.R
library(ggplot2)
library(dplyr)
library(RColorBrewer)
library(XLConnect)
library(htmlTable)
library(plotly)
# Loading data -----------------------------------------------------
raw_data <- read.csv("file.csv")
# Server function ---------------------------------------------------
shinyServer(function(input, output) {
# Tabs and content
ntabs <- 4
tabnames <- paste0("tab ", 1:ntabs)
output$Sidebar <- renderUI({
Menus <- vector("list", ntabs + 2)
for (i in 1:ntabs){
Menus[[i]] <- menuItem(tabnames[i], tabName = tabnames[i], icon = icon("dashboard"))
}
# Controls to appear below tabs
Menus[[ntabs + 1]] <- selectInput("dpt", "Departments :",
c("dpt 1" = "DPT1",
"dpt 2" = "DPT2",
"dpt 3" = "DPT3"),
multiple = TRUE,
selectize = TRUE)
Menus[[ntabs + 2]] <- uiOutput("bottleneck")
Menus[[ntabs + 3]] <- uiOutput("daterange")
Menus[[ntabs + 4]] <- submitButton()
do.call(function(...) sidebarMenu(id = 'sidebarMenu', ...), Menus)
})
# content of each tab
output$TABUI <- renderUI({
Tabs <- vector("list", ntabs)
Tabs[[1]] <- tabItem(tabName = tabnames[1],
# fluidRow(box(h3("foo.")))
fluidRow(
box(
plotOutput("plot_1")
)
)
)
Tabs[[2]] <- tabItem(tabName = tabnames[2],
"Tab 2 Stuff")
Tabs[[3]] <- tabItem(tabName = tabnames[3],
"Tab 3 Stuff")
Tabs[[4]] <- tabItem(tabName = tabnames[4],
"Tab 4 Stuff")
do.call(tabItems, Tabs)
})
formulaText <- reactive({
if (is.null(data.r())) {
return("some text")
}
paste0(as.character(input$daterange[1]), " to ", as.character(input$daterange[2]), " - blah blah")
})
output$bottleneck <- renderUI({
selectInput('bottleneck', HTML('<font color=\"black\"> Bottlenecks : </font>'), c(Choose = '', raw_data[raw_data$is_bottleneck == 1 & !is.na(raw_data$Sort.field) & raw_data$Cost.Center %in% input$dpt,]$Sort.field %>% unique() %>% sort()), selectize = TRUE)
})
output$daterange <- renderUI({
dateRangeInput(inputId = 'daterange',
label = HTML('<font color=\"black\"> Select period : </font>'),
min = min(raw_data$Completn.date) ,
start = min(raw_data$Completn.date) ,
max = max(raw_data$Completn.date),
end = max(raw_data$Completn.date))
})
data.r = reactive({
if (is.null(input$dpt)) {
return(NULL)
}
ifelse(input$bottleneck == "", a <- raw_data %>% filter(Completn.date >= input$daterange[1],
Completn.date <= input$daterange[2]),
a <- raw_data %>% filter(Completn.date >= input$daterange[1],
Completn.date <= input$daterange[2],
Sort.field %in% input$bottleneck))
return(a)
})
output$table_ranking <- renderHtmlTableWidget({
if (is.null(data.r())) {
return()
}
ranking <- read.csv("ranking.csv", header = TRUE)
htmlTableWidget(ranking)
})
output$caption <- renderText({
formulaText()
})
output$plot_1 <- renderPlot({
if (is.null(data.r())) {
return()
}
current_data <- data.r()
p0 <- current_data %>%
ggplot(aes(x = x1, y = y1)) +
geom_point()
p0
})
output$plot_2 <- renderPlot({
if (is.null(data.r())) {
return()
}
current_data <- data.r()
p0 <- current_data %>%
ggplot(aes(x = x2, y = y2)) +
geom_point()
p0
})
})
This is a failed attempt to replicate what was suggested here.
Thanks ahead of time for looking into this.
I finally got to find the answer.
I've had several reactive element duplicated across different tabs. For some reason Shiny does not like this. Once I've created different reactive strings (in my case) then everything was fine (tabitems with renderUI in server.r, as well as sidebarmenu).
Weird but anyway.

change ggvis plot layer dynamically

I would like to change the layer of a ggvis plot using a selectInput widget using a dynamic interface. The problem is that when I choose a different layer after creating the plot, it changes but it just disappear really quick. Below is a simplified version of the code to show the problem that omit all the extra dynamic content. I just plot some number of values from a dataset. I added a couple of selectInput widgets to let the user choose what type of plot and when to show the plot. Please note that I need to have all the elements inside of a renderUI.
library(shiny)
library(ggvis)
runApp(list(
ui = shinyUI(
fluidPage(
sidebarLayout(
sidebarPanel( uiOutput("controls") ),
mainPanel( uiOutput("Plot_UI" )
)
)
)
),
server = function(input, output, session) {
dat <- reactive(iris[sample(nrow(iris),input$numbers),])
buildPlot <- function(layer = 'points'){
if (layer=='points'){
dat %>%
ggvis(~Sepal.Width, ~Sepal.Length) %>%
layer_points() %>%
bind_shiny("ggvis1")
} else {
dat %>%
ggvis(~Sepal.Width, ~Sepal.Length) %>%
layer_bars() %>%
bind_shiny("ggvis1")
}
}
output$controls <- renderUI({
div(
sliderInput("numbers", label = "Number of values to plot?", min = 1, max = 150, value = 75),
selectInput('plot_type', 'Plot Type', c("points","bars")),
selectInput("show", 'Show plot?', c('No','Yes'))
)
})
output$Plot_UI <- renderUI({
if (!is.null(input$show) && input$show == 'Yes'){
cat("Plot_UI -> Build plot\n")
buildPlot(input$plot_type)
div(
uiOutput("ggvis_ui"),
ggvisOutput("ggvis1")
)
}
})
}
))
The only way to see the plot again is by selecting to not show the plot and later select show the plot again using the "Show plot" selectInput.
I don't know if this is a bug or I'm doing it incorrectly.
I think the problem is that your trying to render and update the div at the same time.
library(shiny)
library(ggvis)
runApp(list(
ui = shinyUI(
fluidPage(
sidebarLayout(
sidebarPanel( uiOutput("controls") ),
mainPanel( uiOutput("Plot_UI" )
)
)
)
),
server = function(input, output, session) {
dat <- reactive(iris[sample(nrow(iris),input$numbers),])
buildPlot <- function(layer = 'points'){
if (layer=='points'){
dat %>%
ggvis(~Sepal.Width, ~Sepal.Length) %>%
layer_points() %>%
bind_shiny("ggvis1")
} else {
dat %>%
ggvis(~Sepal.Width, ~Sepal.Length) %>%
layer_bars() %>%
bind_shiny("ggvis1")
}
}
output$controls <- renderUI({
div(
sliderInput("numbers", label = "Number of values to plot?", min = 1, max = 150, value = 75),
selectInput('plot_type', 'Plot Type', c("points","bars")),
selectInput("show", 'Show plot?', c('No','Yes'))
)
})
observeEvent(input$show,{
if (!is.null(input$show) && input$show == 'Yes'){
output$Plot_UI <- renderUI({
cat("Plot_UI -> Build plot\n")
div(
uiOutput("ggvis_ui"),
ggvisOutput("ggvis1")
)
})
}
if (!is.null(input$show) && input$show == 'No'){
output$Plot_UI <- renderUI({ div() })
}
})
observe({
if (!is.null(input$show) && input$show == 'Yes'){
invalidateLater(100,session)
renderPlot()
}
})
renderPlot <- function(){
if(is.null(input$plot_type)) return(NULL)
buildPlot(input$plot_type)
}
} #
))

Resources