I have a data-frame which is obtained after some processing. In this data-frame the user needs to choose certain criteria which the user wants to go ahead for further processing. For this there is an add button which when clicked by the user will take out the data according to the selected criteria and append to a new data frame. This new frame then goes ahead for further processing. What I seem to be stuck at is I cannot make shiny add a data-frame to another data frame when Add button is pressed. I have provided the code below. Any help will be greatly appreciated.
ui.R
library(shiny)
shinyUI(pageWithSidebar(
headerPanel('Testing'),
sidebarPanel(
conditionalPanel(
condition="input.tabs1=='Observe Data'",
uiOutput("item"),
actionButton("add", "Add"))
),
mainPanel(
tabsetPanel(id ="tabs1",
tabPanel("Observe Data",verbatimTextOutput("Data_table")),
tabPanel("Final Table",verbatimTextOutput(outputId='plot'))
)
)
))
server.R
library(shiny)
library(dplyr)
chosen_category<-data.frame()
shinyServer(function(input, output) {
data<-data.frame(Names=c("A","A","A","B","B","B","C","C","A"),Values=c(1,2,3,4,5,654,3,2,2))
output$item<-renderUI({
selectInput("category","Categories",as.character(unique(data$Names)))
})
filtdata<-reactive({
p<-data
p_filt<-data%>%
filter(Names %in% input$category)
p_filt
})
output$Data_table<-renderPrint({
filtdata()
})
observe({
input$add
chosen_category <<- rbind(chosen_category, filtdata())
})
final_data <- reactive({
chosen_category
})
})
If you want to say print the final data frame in your Final Data tab, you can add a dependency to the action button in a renderPrint rather than in an observe. I remove the observe and final_data expression and added this to your server.R:
output$plot<-renderPrint({
input$add
chosen_category <<- rbind(chosen_category, filtdata())
chosen_category
})
This prints the final data frame in the last tab of your ui.R.
Related
I have a tab of my app where I display a bunch of text inputs based on a three-column data frame that contains: variable_name, text_prompt, and example_data. The code below seems to work fine since it displays how I want it to. Eventually, I will be feeding it different data frames, depending on the circumstances, so I need to be able to do everything programmatically.
library(shiny)
library(tidyverse)
library(DT)
additional.data.fields <- tibble (var.name = c("project.id", "director.name"),
prompt.text = c("Enter Project ID", "Enter Director's name"),
var.value = c("e.g. 09-111", "e.g. Paul Smith"))
ui <- fluidPage(
tabsetPanel(
#Generate Input fields from dataframe
tabPanel("Input", #value = "input.2",
# Generate input fields with pmap
actionButton("submit", "Submit"),
pmap(additional.data.fields, ~textInput(..1, ..2, value = ..3)),
),
#Output data to tell if it updates with button click
tabPanel("Output", value = "output",
DT::dataTableOutput("data")
)
)
)
server <- function(input, output, session) {
# Create a reactive values object to store the input data
values <- reactiveValues()
# Set the reactive values object when the submit button is clicked
observeEvent(input$submit, {
var.names <- pull(additional.data.fields, var.name)
#THIS IS THE PART I DON'T KNOW HOW TO DO
#input.data <- ???
#I'll add dummy data so that the program loads
input.data <- tibble(var.names,
temp = 1:length(var.names))
values$data <- input.data
})
# Render the input data table
output$data <- DT::renderDataTable({
values$data
})
}
shinyApp(ui, server)
But what I want - and really have no idea how to do - is to get it back into a data frame after the user hits "submit" (I only need two columns in the subsequent data frame; I don't need the text_prompt data again.)
I know that the user input creates a list of read-only ReactiveValues called "input". But I can't figure out how to do anything with this list besides access using known names (i.e. I know that there is a variable named "project_id" which I can access using input$project_id). But what I want is not to have to write them all out, so that I can change the data used to create the input fields. So I need a way to collect them in a data frame without knowing all the individual names of the variables or even how many there are.
I figured this out on my own. You can't index reactive values with []. However, for some reason you can using [[]].
I would love to know why this is, if anyone has an answer that can help me understand why it works this way.
Here's the key bit of code that I was missing before:
input.data <- tibble (names = var.names,
values = map_chr(var.names, ~input[[.x]]))
The full code that works as I want it is pasted below. I'd still appreciate any feedback or recommendations for improvement.
library(shiny)
library(tidyverse)
library(DT)
additional.data.fields <- tibble (var.name = c("project.id", "director.name"),
prompt.text = c("Enter Project ID", "Enter Director's name"),
var.value = c("e.g. 09-111", "e.g. Paul Smith"))
ui <- fluidPage(
tabsetPanel(
#Generate Input fields from dataframe
tabPanel("Input", #value = "input.2",
# Generate input fields with pmap
actionButton("submit", "Submit"),
pmap(additional.data.fields, ~textInput(..1, ..2, value = ..3)),
),
#Output data to tell if it updates with button click
tabPanel("Output", value = "output",
DT::dataTableOutput("data")
)
)
)
server <- function(input, output, session) {
# Create a reactive values object to store the input data
values <- reactiveValues()
# Set the reactive values object when the submit button is clicked
observeEvent(input$submit, {
var.names <- pull(additional.data.fields, var.name)
input.data <- tibble (names = var.names,
values = map_chr(var.names, ~input[[.x]]))
values$data <- input.data
})
# Render the input data table
output$data <- DT::renderDataTable({
values$data
})
}
shinyApp(ui, server)
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().
My goal is to retrieve data from a googlesheet and map it on a leaflet map.
Everything is working fine, only if the code to retrieve data from googlesheet is placed in the global.R and it is only valid for that session of the running shiny app. However, if meanwhile the sheet is updated, these updates are not reflected in the running session. So I need to wire up a ui.R button to fetch new data each time the button is fired and pass the data onto the relevant codes in server.R . (I hope this is clear).
In my current setup, the data gets downloaded from googlesheet (via global.R) and passed on to the environment and used for that running app session.
Here is my working shiny app setup:
ui.R
...
leafletOutput("map"),
actionButton("button", "Get New Data")
...
#added the below lines to update the question:
selectInput("Country",
"Country:",
c("All",
unique(as.character(draw$Country))))
server.R
shinyServer(function(input, output, session) {
#...
output$map <- renderLeaflet({
#... some options here
})
draw <- mydata
drawvalue <- reactive({
if (input$year == year1){return(mydata)} else {
filtered <- filter(mydata, Type == input$type1)
return(filtered)
}
})
observe({
#... some other variable definitions
colorBy <- input$color ##added to update the question
sizeBy <- input$size ##added to update the question
draw <- drawvalue()
colorData <- draw[[colorBy]] ##added to update the question
#... code related to the leaflet
})
#...
}
global.R
mydata <- gs_read(gs_key("0123456abcdabcd123123123"))
After some reading and exploring, I am told that I have to use reactive and observeEvent. But my faulty setup results in error, saying that 'object "mydata" not found'.
I tried in the server.R: (I know the code below is all faulty)
observeEvent(input$button,{
mydata <- gs_read(gs_key("0123456abcdabcd123123123"))
})
mydata <- eventReactive(input$button,{
mydata()
})
update:
in my ui.R, I also refer to "draw", this also bugs. How should I change this one? I updated the lines in the ui.R above in the question. this line is part of the ui.R line which call the DT package to show some tables.
by the way, this app is based on the superzip shiny app.
NB: I will give 100 points bounty for the accepted answer.
In general observe and observeEvent do not return any value and they are used for side effects. So this part of the code below doesn't return any value and even if you used <<- to override the variable mydata shiny wouldn't know that its value has changed.
observeEvent(input$button,{
mydata <- gs_read(gs_key("0123456abcdabcd123123123"))
})
So if you want shiny to know when the data is updated you should read it within reactive environment. So, instead of reading the data via global.R I would advice to do following within server.R:
mydata <- eventReactive(input$button, {
gs_read(gs_key("0123456abcdabcd123123123"))
})
After clicking the button shiny would read (new) data which could be then accessed with mydata() and passed to the render* functions and other reactive parts of the code. For example:
drawvalue <- reactive({
if (input$year == year1){return(mydata() )} else { # added ()
filtered <- filter(mydata(), Type == input$type1) # added () to mydata
return(filtered)
}
})
You had to change this part of code
draw <- drawvalue()
to
draw <- reactive({ drawvalue() })
and then access it with draw()
UPDATE:
If you want make choices of the widget selectInput from UI.R dependent on draw you can do following:
1) Add the parameter session to the server function for updateSelectInput
shinyServer(function(input, output, session) {...} # added session
2) Set choices of the widget in UI.R to ""
selectInput("Country", "Country:", choices = "")
3) Update the choices on the server side with:
observe({
req(draw()) # require that draw is available
updateSelectInput(session, "Country", "Country:",
c("All", unique(as.character(draw()$Country)))) # added ()
})
i got my first Shiny App working - at least nearly. The code works find and in simplified form looks like
shinyUI(fluidPage(
titlePanel('Tableau Workbook'),
sidebarPanel(
uiOutput("select")
),
mainPanel(
tableOutput("Columns1"))
))
shinyServer(function(input,output){
output$select <- renderUI({
selectInput("dataset", "Names", as.list(files))
})
output$columns1 <- renderTable({
f<- myfunction(input$dataset)
f[[3]]
})
})
I need to modify "dataset" before it can be used in renderTable(). I tried
output$columns1 <- renderTable({
dataset<- lookuptable[which(dataset== lookuptable$table1),2 ]
f<- myfunction(input$dataset)
f[[3]]
})
The SelectInput shows a selection, from which the user can choose. What the extraline is doing: take the chosen item, look up the matching value in the lookuptable. This value is then fed into the function. The lookuptable is a dataframe with two columns and n rows..
However, when I add the extraline the visualization is broken. Has anyone an idea why?
Thanks a million for any help!
My shiny app allows user to upload a csv by using fileInput and stored as an reactive object df_data. I then created a numericInput for user to enter a row number to delete from the data frame. However, I got an error about evaluation nested too deeply: infinite recursion / options(expressions=)?.
Below is my code for ui.R.
shinyUI(fluidPage(
titlePanel("amend data frame"),
mainPanel(
fileInput("file", "Upload file"),
numericInput("Delete", "Delete row:", 1, step = 1),
actionButton("Go", "Delete!"),
tableOutput("df_data")
)
))
And below is my code for server.R.
shinyServer(function(input, output) {
df_data <- reactive({
read.csv(input$file$datapath)
})
df_data <- eventReactive(
input$Go,
df_data()[-input$Delete,]
)
output$df_data <- renderTable(df_data())
})
I have solved the problem by assigning the subsetted data frame to a new reactive data frame called, say, df_data2. But I want to make the user able to keep deleting different rows by inputting values in Delete row and press the Go button. Then this solution will not work as I will have to assign df_data3, df_data4 ... and I couldn't predict in advance how many times the user will press the Go button.
I am a new user to shiny for about 2 weeks and I have been searching for solutions about this for a week. Is there anyone who can help me? A million thanks !!
Below is a working solution. I created a reactiveValues to store the dataframe. When a file is chosen, the dataframe gets populated. When the delete button is pressed, that same dataframe gets a row deleted. The table always outputs whatever that dataframe object is holding. I hope this code can be a good learning material
runApp(shinyApp(
ui=(fluidPage(
titlePanel("amend data frame"),
mainPanel(
fileInput("file", "Upload file"),
numericInput("Delete", "Delete row:", 1, step = 1),
actionButton("Go", "Delete!"),
tableOutput("df_data_out")
)
)),
server = (function(input, output) {
values <- reactiveValues(df_data = NULL)
observeEvent(input$file, {
values$df_data <- read.csv(input$file$datapath)
})
observeEvent(input$Go, {
temp <- values$df_data[-input$Delete, ]
values$df_data <- temp
})
output$df_data_out <- renderTable(values$df_data)
})))