use pre assigned variable inside R shiny function as a parameter - r

I am creating a survey using R shiny and have the following function at the beginning of my Shiny App:
install.packages("devtools")
spotifydata<-spotifycharts::chart_top200_weekly()
s<-spotifydata$artist
h<-head(s,20)
I want to know if there is anywhere to display the output of variable "h"??
I had the idea of using "selectInput" in the following manner to display each result in a drop down menu fashion.
selectInput("artists","pick 3 artists out of the top 10",
c("h[1]","h[2]","h[3]","h[4]","h[5]","h[6]",
"h[7]","h[8]","h[9]","h[10]"),multiple = TRUE)
I know this produces an error But I want to know if there is a way to emulate this

In the selectInput the variables should be written without quotes like this:
selectInput("artists","pick 3 artists out of the top 10",
c(h[1],h[2],h[3],h[4],h[5],h[6],
h[7],h[8],h[9],h[10]),multiple = TRUE)
Following is an app showing the working of the same:
library(shiny)
spotifydata<-spotifycharts::chart_top200_weekly()
s<-spotifydata$artist
h<-head(s,20)
ui <- fluidPage(
selectInput("artists","pick 3 artists out of the top 10",
c(h[1],h[2],h[3],h[4],h[5],h[6],
h[7],h[8],h[9],h[10]),multiple = TRUE)
)
server <- function(input, output)
{}
shinyApp(ui, server)
The output is as follows:
Please note that with this approach the variable h is shared between different user sessions.
If you don't want the variable h to be shared between different user sessions you can use the following approach, where we get h value within the server function and update the choices of select input using the function updateSelectInput
ui <- fluidPage(
selectInput("artists","pick 3 artists out of the top 10",
choices = c(), multiple = TRUE)
)
server <- function(input, output, session)
{
observe({
spotifydata<-spotifycharts::chart_top200_weekly()
s<-spotifydata$artist
h<-head(s,20)
updateSelectInput(session, inputId = "artists", choices = c(h[1],h[2],h[3],h[4],h[5],h[6],
h[7],h[8],h[9],h[10]))
})
}
shinyApp(ui, server)

Related

Use functions or loops to create shiny UI elements

I am creating a shiny app and realized I am repeating a particular UI element so I am wondering if there is a way to wrap this in a function and supply parameters to make it work in different cases. In my server file, I have
output$loss <- renderUI({
req(input$got)
if(input$got %in% Years) return(numericInput('got_snow', label = 'John Snow', value = NA))
if(!input$got %in% Years) return(fluidRow(column(3)))
})
and in the ui file, I have:
splitLayout(
cellWidths = c("30%","70%"),
selectInput('got', label = 'Select age', choices = c('',Years) , selected = NULL),
uiOutput("loss")
)
Since I find myself using these several times and only changing a few things in both the UI and server files, I wanted to wrap these in a function and use them as and when I please. I tried this for the server file
ui_renderer <- function(in_put, label, id){
renderUI({
req(input[[in_put]])
if(input[[in_put]] %in% Years) return(numericInput(id, label = label, value = NA))
if(!input[[in_put]] %in% Years) return(fluidRow(column(3)))
})
}
output$p_li <- ui_renderer(input='li', "Enter age", id="c_li")
and in my ui file, I put
uiOutput('c_li')
but it's not working. Any help is greatly appreciated.
I was unable to test your code since there was no minimal working example. I don't know if this is a typo in your example, but your are trying to render c_li, but your output is called p_li. Not sure how wrapping a render object in a standard function works, but I have done something similar using reactive values instead.
This is a minimal example using some of your terminology. It is not a working example, but an outline of the idea to my proposed solution.
# Set up the UI ----
ui <- fluidPage(
uiOutput("loss")
)
# Set up the server side ----
server <- function(input, output, session) {
# Let us define reactive values for the function inputs
func <- reactiveValues(
value <- "got",
label <- "select age",
id <- "xyz"
)
# Set up an observer for when any of the reactive values change
observeEvent({
func$value
func$label
func$id
}, {
# Render a new UI any time a reactive value changes
output[["loss"]] <- renderUI(
if (input[[func$value]] %in% years) {
numericInput(func$id, label = func$label, value = NA)
} else {
fluidRow(
column(3)
)
}
)
})
}
# Combine into an app ----
shinyApp(ui = ui, server = server)
The general idea is to define a set of reactive values and set up an observer that will render the UI every time one or more of the reactive values change. You can assign a new value to any of the reactive values using direct assignment, e.g. current$value <- "object_two". Making that change will update the UI using Shiny's reactive pattern, which means you only need to change one value to update the UI.

R Shiny: Switching datasets based on user input

I am working on a shiny app where users can upload their own data and get some plots and statistics back. However, I also want to include an example dataset that gets used instead if the user presses a specific button. Importantly, the plots should be reactive so that users get updated plots whenever they click on the "use example data instead" button or upload a new file. I tried to recreate my current approach of overwriting the data object as best as I could here, but simply defining the data object twice doesn't overwrite the data in the way I hoped it would. Any suggestions are appreciated.
library(shiny)
# UI
ui <- fluidPage(
# Application title
titlePanel("Reproducible Example"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
fileInput("Upload", "Upload your own Data"),
actionButton("Example", "Use Example Data instead")
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("hist")
)
)
)
# Server Logic
server <- function(input, output) {
data <- eventReactive(input$Upload,{input$Upload})
data <- eventReactive(input$Example, {faithful$eruptions})
output$hist <- renderPlot({hist(data())})
}
# Run the application
shinyApp(ui = ui, server = server)
You can use a reactiveVal like this:
server <- function(input, output) {
my_data <- reactiveVal()
observeEvent(input$Upload, {
tmp <- read.csv(input$Upload$datapath)
## do whatever is needed to parse the data
my_data(tmp)
})
observeEvent(input$Example, {
my_data(faithful)
})
output$hist <- renderPlot({
dat <- as.data.frame(req(my_data()))
dat <- dat[, sapply(dat, is.numeric), drop = FALSE]
validate(need(NCOL(dat) > 1, "No numeric columns found in provided data"))
hist(dat[,1])
})
}
Depending on upload or button click, you store your data in my_data which is a reactive value. Whenever this value changes, the renderPlot function fires and uses the correct data.
You can use a reactive value to access whether the user has chosen to use an example dataset or use their own dataset. The user can choose to switch between the active dataset using an input from your UI.
Here's the official explanation on reactive values from RStudio: link
This would go in your ui.R:
radioButtons("sample_or_real",
label = h4("User data or sample data?"),
choices = list(
"Sample Data" = "sample",
"Upload from user data" = "user",
),
selected = "user"
)
This would go in your server.R:
data_active <- reactive({
# if user switches to internal data, switch in-app data
observeEvent(input$sample_or_real_button, {
if(input$sample_or_real == "sample"){
data_internal <- sample_data_object
} else {
data_internal <- uploaded_data_object
}
})
Note, that when using a reactive value in your server.R file, it must have parentheses () at the end of the object name. So, you call the data_internal object as data_internal().

R shiny matrix or table input

I want to create a matrix or table as input for user to interact with in Shiny.
For example:
sample name number of tests
350292 3
... ...
I want to automatically generate tabs in the mainPanel for user to input data for the different samples.
This is possible with matrixInput in the shinyIncubator package, but the matrixInput function does not support column names.
Is there a better way to do this?
Update
I tried the rhandsontable package.
Code:
library(shiny)
library(rhandsontable)
DF <- data.frame(name=c(350292, 360765), run=c(3,2))
colnames(DF) <- c("sample name", "number of tests")
ui <- fluidPage(
headerPanel("test"),
mainPanel(rHandsontableOutput("sample"))
)
server <- function(input, output) {
output$sample <- renderRHandsontable({
rhandsontable(DF, rowHeaders = NULL) %>%
hot_col(c("sample name", "number of tests"), format = "0")
})
}
shinyApp(ui = ui, server = server)
How can I call values using the reactive() and rhandsontable?
I want to create tabs based on sample name and test number.

My gvisBubbleChart Plot in Shiny R stops displaying when I attempt to introduce a dynamic selectInput field

I have encountered this problem while developing an app, and reproduced it here in a simplified script using Fruits df.
Basically, i have selectInput box to select a Year, which is a column in Fruits. I create unique list of Years, and feed it into selectInput box.
Then, ideally, i wanted my plot to display only the records for the year I selected. However, as you'll see in my code - the second you uncomment a block of 3 lines to accomplish that, - the plot stops displaying even though there doesn't seem to be any errors. Anybody knows why is this? Thanks in advance!!!
Related question - while debugging this i saw that the input$explore_year is at first "Null". I'm trying to handle this in the code but not sure why the selected="2010" doesn't take care of it automatically.
library(shiny)
library(googleVis)
library(DT)
listOfFruits <- sort(unique(Fruits$Year), decreasing = FALSE)
ui <- fluidPage(title = "Fruits Bug Recreated",
fluidRow(
column(3,
wellPanel(
uiOutput("choose_year"),
br()
)),
column(9,
tags$hr(),
htmlOutput("view")
)),
fluidRow(DT::dataTableOutput("tableExplore"))
)
server <- function(input, output) {
output$view <- renderGvis({
#Uncomment these 3 lines to see how the plot stops displaying.
# local_exloreYear <- input$explore_year
# if (is.null(local_exloreYear)) {local_exloreYear <- "2010"}
# FruitsSubset <- subset(Fruits, Year == local_exloreYear)
#------------I wanted to use the commented line below instead of the
#that follows
#gvisBubbleChart(FruitsSubset, idvar="Fruit",
#-------------
gvisBubbleChart(Fruits, idvar="Fruit",
xvar="Sales", yvar="Expenses",
colorvar="Year", sizevar="Profit",
options=list(
hAxis='{minValue:70, maxValue:125, title:"Sales"}',sortBubblesBySize=TRUE,
vAxis='{title: "Expenses",minValue:60, maxValue:95}'
))
})
# Drop-down selection box for dynamic choice of minutes in the plans to compare
output$choose_year <- renderUI({
selectInput("explore_year", "Select Year", as.list(listOfFruits),selected ="2010")
})
output$tableExplore <- DT::renderDataTable(DT::datatable({
FruitsSubset <- subset(Fruits, Fruits$Year == input$explore_year)
myTable <-FruitsSubset[,c(1,2,3,4,5,6)]
data <- myTable
data
},options = list(searching = FALSE,paging = FALSE)
))
}
shinyApp(ui = ui, server = server)
Like i wrote in the comments you can solve it by make the rendering conditional on the input being non-NULL.
output$view <- renderGvis({
if(!is.null(input$explore_year)){
...
}
})
Nevertheless, I donĀ“t think it is really intended that you have to do that, as in other render functions it is not required e.g. in the DT::renderDataTable(), where you also use the same input (being NULL initially).
Therefore, I would suggest reporting it as a bug.

Interactively change the selectInput choices

Originally I create this shiny interface that takes in a parameter "company id" and "date", but here we have a problem: most people dont know the companies we work with by their id, only their name, i.e. (McDonalds, Radioshack).
So I want to ideally create a search function like this
My current idea is to pass in a table including a list of all our partner companies and their ids to global.R. Then pass in the textInput as the search variables and perform the search on server side. However, I get lost on how to pass searchResults back into the UI on a selectInput panel?
My current code:
ui.R
library(shiny)
shinyUI(pageWithSidebar(
sidebarPanel(
textInput("nameSearch", "Or, Search for company name", 'McDonald'),
selectInput("partnerName", "Select your choice", list( "searchResults" ),
br(),
submitButton("Update View"),
br(),
),
server.R
shinyServer(function(input, output) {
#subTable
searchResult<- reactive({
subset(partners, grepl(input$nameSearch, partners$name))
})
output$searchResults <- renderTable({
searchResult[,1]
})
global.R
partners<- read.csv("partnersList.csv", fill=TRUE)
partnersList is just in this format
name id
------------------
McDonalds 1
Wendy's 2
Bestbuy 3
You need to make the UI reactive. I haven't tested this (miss data for it too) but should work I think. In server.R add:
output$selectUI <- renderUI({
selectInput("partnerName", "Select your choice", searchResult()[,1] ),
})
And in ui.R replace the selectInput with:
htmlOutput("selectUI")
In Shiny version 0.8 (where I have tested it), in server.R add the following:
shinyServer(function(input, output, session) {
observe({
# This will change the value of input$partnerName to searchResult()[,1]
updateTextInput(session, "partnerName",
label = "Select your choice",
value = searchResult()[,1])
})
})
Now the function within shinyServer has additional argument session.
You can skip the label if you don't need to change it.
You don't need to change anything in ui.R.
Reply from Rstudio's JC:
Sure, just use a textInput for the search string, and use
renderUI/uiOutput to make a dynamic selectInput. Then the rest of
your code can depend on the selectInput's value. (Make sure to check
for NULL or whatever when reading the selectInput value, because it
will start out with no value.)
If I understand the question correcly, all you need to do is display to the user company names and have company ids passed to the server.
I suppose this feature was not available back in the days (and you had to work around as suggested above) but nowadays the argument choices in selectInput function accepts named lists exactly for this need. Hopefully example below clarifies the situation.
library(shiny)
library(tidyverse)
companies <- tribble(
~name, ~id,
"McDonalds", 1,
"Wendy's", 2,
"Bestbuy", 3
)
ui <- fluidPage(
uiOutput("select_company_ui"),
textOutput("value")
)
server <- function(input, output) {
output$select_company_ui <- renderUI({
selectInput("select_company", "Select company", choices = deframe(companies))
})
output$value <- renderText(paste0("Value of the company filter is ", input$select_company))
}
# Run the application
shinyApp(ui = ui, server = server)
Here you can see the resulting app:
Side note: I use function deframe from package tibble to turn a tibble into a named list just for convenience, you could do without it by writing
choices = c("McDonalds" = 1, "Wendy's" = 2, "Bestbuy" = 3)

Resources