change ggvis plot layer dynamically - r

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)
}
} #
))

Related

Using numeric input in shiny app yields a "Error: object 'input' not found"

I have a very simple shiny app that is makes a gt table using some inputs.
One of my goals is to pass a user input which is numeric into the cols_width() argument so I can add padding to my first column. Although when doing something like the following I get an error that the input is not found.
output$table <- render_gt(
reactive_tab() %>%
gt() %>%
cols_width(
1 ~ px(input$colpad)
)
)
I've also tried doing {input$colpad} and .(input$colpad) with no success either.
Desired Output:
Here is the code:
library(data.table)
library(shiny)
library(gt)
library(shinyscreenshot)
data <- gtcars %>% head(10) %>%
select(mfr, model, msrp)
ui <- navbarPage("Y u no pad??",
tabPanel("Table", icon = icon("table"),
sidebarLayout(
sidebarPanel(
selectInput("input",
label = "Choose mfr",
choices = c("All", data$mfr)),
numericInput("colpad", label = "First Column Padding", min = 1, max = 10000, value = 150),
screenshotButton(selector="#table", label = 'Download Png', filename = 'screenshot'),
),
mainPanel(
gt_output("table")
)
)
)
)
server <- function(input, output, session) {
reactive_tab <- reactive({
d <- data
if(input$input != "All")
d <- subset(d, cyl == input$input)
d
})
output$table <- render_gt(
reactive_tab() %>%
gt() %>%
cols_width(
1 ~ px(input$colpad)
)
)
}
shinyApp(ui, server)
Reason
The reason this is not working is because of the way gt::cols_width() evaluates is arguments. It does not know which environment to look in to find the input object.
One way to circumvent the issue is to first evaluate input$colpad and then pass the value in a way gt::cols_width() will understand.
Code
Here is one such approach where I paste together a formula and cast it as such on line 46:
library(data.table)
library(shiny)
library(gt)
library(shinyscreenshot)
select <- dplyr::select
data <- gtcars %>%
head(10) %>%
select(mfr, model, msrp)
ui <- navbarPage(
"Y u no pad??",
tabPanel("Table",
icon = icon("table"),
sidebarLayout(
sidebarPanel(
selectInput("input",
label = "Choose mfr",
choices = c("All", data$mfr)
),
numericInput("colpad", label = "First Column Padding", min = 1, max = 10000, value = 150),
screenshotButton(selector = "#table", label = "Download Png", filename = "screenshot"),
),
mainPanel(
gt_output("table")
)
)
)
)
server <- function(input, output, session) {
reactive_tab <- reactive({
d <- data
if (input$input != "All") {
d <- subset(d, cyl == input$input)
}
d
})
output$table <- render_gt(
reactive_tab() %>%
gt() %>%
cols_width(
as.formula(paste0("1 ~ ", input$colpad)) # EDIT HERE
)
)
}
shinyApp(ui, server)
Result

How to get reactive values from a click on shiny?

Hello and thanks for reading me. I am working on a small app that shows a table in shiny with the "reactable" library, but I would like to obtain a reactive value when I click on a certain cell, with which I can get a text output type "paste0("you chose" , value0)", but so far I haven't found a correct way to do it. Does anyone have any idea how to do that
The actual code im using is:
shinyApp(
ui = fluidPage(
reactableOutput("tabla")
),
server = function(input, output){
output$tabla <- renderReactable({
iris |>
reactable(
columns = list(
Species = colDef(cell = function(value) {
htmltools::tags$a(href = value, target = "_blank", value)
})
)
)
})
}
)
library(shiny)
library(reactable)
shinyApp(
ui = fluidPage(
reactableOutput("tabla"),
verbatimTextOutput("selected")
),
server = function(input, output){
output$tabla <- renderReactable({
iris |>
reactable(
columns = list(
Species = colDef(cell = function(value) {
htmltools::tags$a(href = value, target = "_blank", value)
})
),
selection = "single", onClick = "select"
)
})
value0 <- reactive({
getReactableState("tabla", "selected")
})
output$selected <- renderPrint({
req(value0())
print(paste("you chose" , value0()))
})
}
)
Read more here

How to update select input inside renderIU?

I show you my shiny application, but I have a problem, I cannot update the selectimput, I have used updateSelectInput but it does not work.
I have two selectInputs inside a tabsetPanel, since I need to update the table with two filters, one is the category and the other the subcategory.
here my code.
library(shiny)
library(tidyverse)
library(DT)
cat1<-rep("LINEA BLANCA", 75)
cat2<- rep("VIDEO", 75)
subcat1<-rep("LAVADORAS", 40)
subcat2<- rep("REFRIS", 35)
subcat3<- rep("TV", 40)
subcat4<- rep("SONIDO", 35)
vent<-sample(100:900, 150, replace=T)
segm1<-rep("AAA", 25)
segm2<-rep("BBB", 25)
segm3<-rep("CCC", 25)
segm4<-rep("ABB", 25)
segm5<-rep("ACC", 25)
segm6<-rep("BAC", 25)
db<- tibble(segment=c(segm1,segm2,segm3,segm4,segm5,
segm1),CATEGORIA=c(cat1,cat2), SUBCAT=c(subcat1,subcat2, subcat3, subcat4), vent=vent)
ui <- fluidPage(
# App title
titlePanel("EXAMPLE"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Tabset w/ plot, summary, and table ----
tabsetPanel(type = "tabs",
tabPanel("Ana_inv", uiOutput("selectcat"), uiOutput("selectsubcat"),DT::dataTableOutput("ana_inv")),
#tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
)
server <- function(input, output, session) {
output$selectcat <- renderUI({
selectInput("Cat", "Seleccione Categoria", choices = c("ALL",as.vector(db$CATEGORIA)))
})
output$selectsubcat <- renderUI({
#opciones<- db_prueba %>% filter(CATEGORIA==input$CAT)
selectInput("Subcat", "Seleccione Subcategoria", choices = c("ALL",as.vector(db$SUBCAT)))
})
activar<- reactive({
req(input$Cat)
req(input$Subcat)
opciones<- db %>% filter(CATEGORIA==input$Cat)
if(input$Cat == "TODOS") {
filt1 <- quote(CATEGORIA != "#?><")
} else {
filt1 <- quote(CATEGORIA == input$Cat)
}
if (input$Subcat == "TODOS") {
filt2 <- quote(SUBCAT != "#?><")
} else {
filt2 <- quote(SUBCAT == input$Subcat)
}
db %>%
filter_(filt1) %>%
filter_(filt2) %>% group_by(segment)%>%
summarise(SKUs=n(),
vta=sum(vent))
})
# Return the formula text for printing as a caption ----
output$ana_inv <- DT::renderDataTable({
activar()
})
}
shinyApp(ui = ui, server = server)
So I need that if the category "LINEA BLANCA" is selected in the subcategory it only shows "REFRIS" and "LAVADORAS", but also if someone selects "ALL" in the category he can also select each subcategory, that is, it can be filtered by subcategory assuming I only want to see subcategories.
I have tried many ways but none works, any ideas? you can run the application in R to get an idea of what I want.
Try this
server <- function(input, output, session) {
output$selectcat <- renderUI({
selectInput("Cat", "Seleccione Categoria", choices = c("ALL",as.vector(db$CATEGORIA)))
})
output$selectsubcat <- renderUI({
req(input$Cat)
if (input$Cat=="ALL"){ df <- db
}else df <- db %>% filter(CATEGORIA %in% input$Cat)
selectInput("Subcat", "Seleccione Subcategoria", choices = c("ALL",as.vector(df$SUBCAT)))
})
activar<- reactive({
req(input$Cat,input$Subcat)
if (input$Cat=="ALL"){ df <- db
}else df <- db %>% filter(CATEGORIA %in% input$Cat)
if (input$Subcat=="ALL"){ df <- df
}else df <- df %>% filter(SUBCAT == input$Subcat)
df %>%
group_by(segment) %>%
summarise(SKUs=n(),
vta=sum(vent))
})
# Return the formula text for printing as a caption ----
output$ana_inv <- DT::renderDataTable({
activar()
})
}

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)
})

Not getting graph in Shiny App in R

I am trying to create small application using Shiny. Below is the data frame for which I am trying to create.
data<-data.frame(state=c('AZ','VA','CA','AZ','VA','CA'), city=c('Phoenix','Arlington','SantaClara','Mesa','Richmond','SF'),
avg=c(10,15,16,13,14,14), date=c('01/09/2017','01/10/2017','01/11/2017','02/09/2017','02/10/2017','02/10/2017'),stringsAsFactors = FALSE)
So, I am trying to create a graph between date(x-axis) and avg(y-axis). So this graph should change based on the selection from dropdown list of State.For example, for a particular selected state, it should show cities available(in other dropdown) in that state.
Below is my code:
library(shiny)
library(ggplot2)
library(plotly)
statelist<-as.list(data$state)
citylist<-as.list(data$city)
ui <- basicPage(
# plotOutput("plot1", click = "plot_click"),
# verbatimTextOutput("info")
sidebarPanel(
selectInput("plot1", label=h3("Select State"), choices = statelist),
selectInput("plot2", label=h3("Select City"), choices = citylist)
),
plotOutput(outputId="plot")
),
server <- function(input, output, session) {
observe(
{
state <- input$plot1
updateSelectInput(session, "plot2", choices = data$city[data$state == state])
}
),
output$plot<-renderPlot({
ggplot(data[data$city == input$plot2 &
data$state == input$plot1],aes(date,avg))
+geom_line()
})
}
shinyApp(ui, server)
Dropdown is working perfectly but not getting the graph.
Thanks in advance!!
I made some minor modifications to your code:
There were some commas in places where they should not be: after the ui constructor, and after the observe constructor.
There was a comma missing in data[data$city == input$plot2 &
data$state == input$plot1,]
I edited your observe to be an observeEvent
I modified the plot to show that it actually changes, since the sample data is quite limited.
Hope this helps!
library(shiny)
library(ggplot2)
library(plotly)
data<-data.frame(state=c('AZ','VA','CA','AZ','VA','CA'), city=c('Phoenix','Arlington','SantaClara','Mesa','Richmond','SF'),
avg=c(10,15,16,13,14,14), Date=c('01/09/2017','01/10/2017','01/11/2017','02/09/2017','02/10/2017','02/10/2017'),stringsAsFactors = FALSE)
statelist<-unique(data$state)
citylist<-unique(data$city)
ui <- basicPage(
# plotOutput("plot1", click = "plot_click"),
# verbatimTextOutput("info")
sidebarPanel(
selectInput("plot1", label=h3("Select State"), choices = statelist),
selectInput("plot2", label=h3("Select City"), choices = citylist)
),
plotOutput(outputId="plot")
)
server <- function(input, output, session) {
observeEvent(input$plot1,
{
state <- input$plot1
updateSelectInput(session, "plot2", choices = data$city[data$state == state])
}
)
output$plot<-renderPlot({
data = data[data$city == input$plot2 &
data$state == input$plot1,]
ggplot(data,aes(Date,avg)) + geom_point(size=5) + ggtitle(paste0(input$plot1," - ",input$plot2 ))
})
}
shinyApp(ui, server)

Resources