Say I have a data frame called summarized which includes the columns TY_COMP and LY_COMP (among others). I could write a function in R that performs a calculation on TY_COMP and LY_COMP and creates a new column called cac in the data frame like this:
summarized$cac <- summarized$TY_COMP/summarized$LY_COMP-1
cac is now a new column in the summarized data frame.
Now say that summarized() is a reactive data frame with the same columns.
How could I achieve the effect done in the non-reactive data frame, i.e. create a new column within the current frame? Or how would I get the same effect?
I tried:
summarized$cac <- reactive({summarized()$TY_COMP/summarized()$LY_COMP-1})
I reckon you want to modify a reactive when for example an actionButton is clicked. For this purpose I would use reactiveValues. You can modify reactiveValue inside of observers such as observe or observeEvent.
Check out this simple example:
summarized <- data.frame(id = 1:20, group = letters[1:4], TY_COMP = runif(20), LY_COMP = runif(20))
library(shiny)
ui <- fluidPage(
verbatimTextOutput("text"),
actionButton("btn", "Add the 'cac' column to summarized")
)
server <- function(input, output){
rv <- reactiveValues(summarized = summarized)
output$text <- renderPrint(rv$summarized)
observeEvent(input$btn, {
rv$summarized$cac <- summarized$TY_COMP / summarized$LY_COMP - 1
})
summarized_mod <- reactive({
summarized()$TY_COMP / summarized()$LY_COMP-1
})
}
shinyApp(ui, server)
Another option would be to create another reactive that has an additional column. This is possible to use, but depending on your use case, I recommend the first solution.
Example:
summarized <- data.frame(id = 1:20, group = letters[1:4], TY_COMP = runif(20), LY_COMP = runif(20))
library(shiny)
ui <- fluidPage(
verbatimTextOutput("text1"),
verbatimTextOutput("text2")
)
server <- function(input, output){
output$text1 <- renderPrint(summarized_orig())
output$text2 <- renderPrint(summarized_mod())
summarized_orig <- reactive( {
summarized
})
summarized_mod <- reactive({
df <- summarized_orig()
df$cac <- summarized_orig()$TY_COMP / summarized_orig()$LY_COMP - 1
df
})
}
shinyApp(ui, server)
Related
I'm trying to store user input into a pre-existing dataframe in shiny.
In this simplified example I have a dataframe with a column labelled 'colour' and I want radio choice buttons to be able to assign values to each row in the dataframe, starting with row 1, then row 2 then row 3 etc. But it seems the dataframe always resets to the original value. What am I misunderstanding about shiny here?
library(shiny)
library(tidyverse)
library(DT)
dataframe <- tibble(row_id = c(1,2,3),
colour = c("","",""))
ui <- fluidPage(
radioButtons("colour",
"Pick a colour:",
choices = c("blue","green","red")),
actionButton("next_button", "Pick the next colour"),
DTOutput("dataframe")
)
server <- function(input, output) {
vals <- reactiveValues(active_row = 1)
observeEvent(input$next_button,{
dataframe[vals$active_row, "colour"] = input$colour
# view(dataframe)
# print(vals$active_row)
vals$active_row = vals$active_row + 1
output$dataframe <- renderDataTable(dataframe)
})
}
# Run the application
shinyApp(ui = ui, server = server)
I would store your data also in reactiveValues. In addition, you can move your output outside of your observeEvent. This server function should work based on your description.
server <- function(input, output) {
vals <- reactiveValues(active_row = 1, data = dataframe)
observeEvent(input$next_button,{
vals$data[vals$active_row, "colour"] = input$colour
vals$active_row = vals$active_row + 1
})
output$dataframe <- renderDataTable(vals$data)
}
I am continuing my struggles through R & R Shiny and have a question. I have a list of data frames. I want to use the names of the data frames from this list, to populate selectInput, and based on the selection of the data frame, I want to be able to view selected data frame, and see the statistics of its columns.
So far I have found this code
shinyServer(function(input, output) {
reactive_df <- reactive({
if(input$x=="All")
return df
else
return(select(df, starts_with(input$x)))
}
output$x <- renderDataTable(reactive_df())
}
But it does not do exactly what I want. Does anyone know how to create the table and the summaries?
You could have a look at mastering shiny:
ui <- fluidPage(
selectInput("dataset", label = "Dataset", choices = ls("package:datasets")),
verbatimTextOutput("summary"),
tableOutput("table")
)
server <- function(input, output, session) {
output$summary <- renderPrint({
dataset <- get(input$dataset, "package:datasets")
summary(dataset)
})
output$table <- renderTable({
dataset <- get(input$dataset, "package:datasets")
dataset
})
}
shinyApp(ui=ui,server=server)
If you have your own list of dataset, you can use [[...]] instead of get:
datasetlist <- list(iris = iris, mtcars = mtcars)
data <- datasetlist[[input$datasetname]]
for example if input$datasetname=='iris', you can check that this will assign iris to data for further processing:
data <- datasetlist[["iris"]]
data
Another option is :
data <- eval(parse(text=input$datasetname))
I am trying to create a shiny app that has a rhandsontable in it. I want rhandsontable to be able to update its values in one of its columns if the corresponding values in another column is selected/ checked. So far, I have been able to use reactive / observe events to change the output values between two objects but i am unable to wrap my head around it , i.e, how do i make once column of rhandsontable reactive to another column in the same table ?
Here is a simple example of what i am trying to build:
library(shiny)
library(rhandsontable)
ui <- fluidPage(
rHandsontableOutput('table')
)
server <- function(input,output,session)({
data <- data.frame(c1=c(5,10,15), c2=c(3,6,9) , diff=c(0,0,0), select= as.logical( c(FALSE,FALSE,FALSE)))
output$table <- renderRHandsontable({
rhandsontable(data)
})
})
shinyApp(ui = ui, server = server)
So if i check the column 'Select', column 'diff' should produce the difference between column c1 & c2
From what I understand, your goal is to do some calculation depending on the values of some other column. So if for example a box of the third column is checked, you might want to compute the difference between elements of column 1 and 2.
If you had just a data frame, that would be easy, wouldn't it? Well, this is possible using reactive values. The main idea is that you can store the rhandsontable in a data frame in the backend, modify the data frame and then render the modified data frame once again back in the handsontable.
I hope this helps:
For a more detailed example on reactive values you can see
this: http://stla.github.io/stlapblog/posts/shiny_editTable.html
and this : https://www.youtube.com/watch?v=BzE1JmC0F6Q&list=PL6wLL_RojB5wXR3NR3K38sIvexZ_45alY&index=3
library(rhandsontable)
library(shiny)
ui <- fluidPage(
mainPanel(
rHandsontableOutput("hot")
)
)
server = function(input, output, session){
df<- data.frame(c1=c(5,10,15), c2=c(3,6,9) , diff=c(0,0,0), select= as.logical( c(FALSE,FALSE,FALSE)))
values <- reactiveValues(data = df)
observe({
if(!is.null(input$hot)){
values$data <- as.data.frame(hot_to_r(input$hot))
isolate(values$data[,'diff'] <- ifelse(values$data[,'select'], values$data[,'c1']-values$data[,'c2'] ,0))
print(values$data)
output$hot <- renderRHandsontable({
rhandsontable(values$data)
})
}
})
output$hot <- renderRHandsontable({
rhandsontable(values$data)
})
}
shinyApp(ui, server)
I'm building a shiny app that queries an SQL database so the user can ggplot the data. I would like the user to be able to rename factors manually but am struggling to get going. Here is an example of what I want to do:
ui.R
library(markdown)
shinyUI(fluidPage(
titlePanel("Reactive factor label"),
sidebarLayout(
sidebarPanel(
numericInput("wafer", label = h3("Input wafer ID:"), value = NULL),
actionButton("do", "Search wafer"),
textInput("text", label = h3("Factor name to change"), value = ""),
textInput("text", label = h3("New factor name"), value = ""),
actionButton("do2", "Change name")
),
mainPanel(
verbatimTextOutput("waf"),
verbatimTextOutput("que"),
verbatimTextOutput("pos"),
dataTableOutput(outputId="tstat")
)
)
)
)
server.R
# Create example data
Name <- factor(c("Happy", "New", "Year"))
Id <- 1:3
dd <- data.frame(Id, Name)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con, "dd", dd)
query <- function(...) dbGetQuery(con, ...)
wq = data.frame()
sq = data.frame()
shinyServer(function(input, output){
# create data frame to store reactive data set from query
values <- reactiveValues()
values$df <- data.frame()
# Wait for user to search
d <- eventReactive(input$do, { input$wafer })
# Reactive SQL query
a <- reactive({ paste0("Select * from dd where Id=",d()) })
wq <- reactive({ query( a() ) })
# Check outputs
output$waf <- renderPrint(input$wafer)
output$que <- renderPrint({ a() })
output$pos <- renderPrint( wq()[1,1] )
# observe d() so that data is not added until user presses action button
observe({
if (!is.null(d())) {
sq <- reactive({ query( a() ) })
# add query to reactive data frame
values$df <- rbind(isolate(values$df), sq())
}
})
output$tstat <- renderDataTable({
data <- values$df
})
})
In static R I would normally use data table to rename factors i.e.:
DT <- data.table(df)
DT[Name=="Happy", Name:="Sad"]
But I'm not sure how to go about this with a reactiveValues i.e. values$df.
I have read this (R shiny: How to get an reactive data frame updated each time pressing an actionButton without creating a new reactive data frame?). This lead me to try this but it doesn't do anything (even no error):
observeEvent(input$do2, {
DT <- data.table(values$df)
DT[Name == input$text1, Name := input$text2]
values$df <- data.frame(values$df)
})
Perhaps there is a way around this..maybe there is a way to use an action button to "lock in" the data as a new data frame, which can then be used to rename?
Sorry for such a long winded question. My real app is much longer and more complex. I have tried to strip it down.
Your approach works but there are a few issues in your app.
In ui.R, both textInput have the same id, they need to be different so you can refer to them in the server.R. In the observeEvent you posted, you refer to input$text1 and input$text2 so you should change the id of the textInputs to text1 and text2.
In the observeEvent you posted, the last line should be values$df <- as.data.frame(DT), otherwise it does not change anything.
I am trying to create a shiny app where I want the user to enter a few (but variable number of) rows of a data frame (with 3 columns). The best way would be to have the user enter a row at a time, and perhaps push a button to create a new row.
What is an intuitive way to implement this in a shiny gui?
You can do something like this:
rm(list = ls())
library(shiny)
# Sample data
my_data <- data.frame(matrix(1,nrow=1,ncol=3))
colnames(my_data) <- c("one","two","three")
emptry_row <- as.data.frame(matrix(1,nrow=1,ncol=3))
colnames(emptry_row) <- colnames(my_data)
ui =fluidPage(
sidebarPanel(actionButton("add_row", "Add a row")),
mainPanel(dataTableOutput("my_table"))
)
server = function(input, output, session){
values <- reactiveValues()
values$df <- my_data
newEntry <- observe({
if(input$add_row > 0) {
isolate(values$df <- rbind(values$df, emptry_row))
}
})
output$my_table <- renderDataTable({
if(input$add_row==0){return(values$df)}
values$df
})
}
runApp(list(ui = ui, server = server))