I have two problems:
-First I cannot start the table showing only zeros or blank for that reason I've created a button that set's every thing to zero which kind of works but its not ideal.
-Secondly, I'm trying to calculate column sum for each column in a rhandontable but so far I havent been able to make it work.
I have been looking around for similar problems and I have found some code that looked promissing but in the end it only provided the sum for a single column or with some changes it would sum up all columns which is not what I'm after.
ui <- fluidPage(
rHandsontableOutput('table'),
textOutput('result'),
actionButton("recalc", "re-enter data")
)
season<-c("Spring","Summer","Autum","Winter")
server <- function(input,output,session)({
values <- reactiveValues(data = NULL) ## assign it with NULL
## button press resets now the data frame
observeEvent(input$recalc, {
values$data[] <- 0
})
## changes in numericInput sets all (!) new values
observe({
values$data <-data.frame(row.names=season,Lake=1:4,Beach=1:4, Garden=1:4,stringsAsFactors = FALSE)
})
observe({
if(!is.null(input$table))
values$data <- hot_to_r(input$table)
})
output$table <- renderRHandsontable({
req(values$data)
rhandsontable(values$data,rowHeaderWidth = 100)
})
})
shinyApp(ui = ui, server = server)
The expected results would be a 5th column with the sum of each column.
A starting table filled with zeros or blank.
If anyone could point me in the right direction it would be very much appreciated.
You can create empty cells with NA. Please check the following example to calculate colSums:
library(shiny)
library(rhandsontable)
ui <- fluidPage(
br(),
rHandsontableOutput('table'),
textOutput('result'),
br(),
actionButton("recalc", "re-enter data")
)
rowNames <- c("Spring", "Summer", "Autum", "Winter", "Sum")
defaultDF <- data.frame(
row.names = rowNames,
Lake = rep(NA_integer_, 5),
Beach = rep(NA_integer_, 5),
Garden = rep(NA_integer_, 5),
stringsAsFactors = FALSE
)
server <- function(input, output, session)
({
values <- reactiveValues(data = defaultDF) ## assign it with NULL
## button press resets now the data frame
observeEvent(input$recalc, {
values$data[] <- NA_integer_
})
observe({
req(input$table)
DF <- hot_to_r(input$table)
DF[setdiff(rowNames, "Sum"),]
DF["Sum",] <- colSums(DF[setdiff(rowNames, "Sum"),], na.rm = TRUE)
values$data <- DF
})
output$table <- renderRHandsontable({
req(values$data)
rhandsontable(values$data, rowHeaderWidth = 100) %>%
hot_row(nrow(values$data), readOnly = TRUE)
})
})
shinyApp(ui = ui, server = server)
Related
I'm trying to make the value argument for shiny::numericInput() dynamic, based on input from a user.
Both code chunks below will run, but they fail to set a dynamic initial value.
Chunk 1:
idOptions <- c("1","2","3")
ui <- shiny::fluidPage(
shiny::selectInput(inputId = "idSelection", "Identification: ", idOptions),
shiny::numericInput("num", "Number associated with id:", value=shiny::verbatimTextOutput("numberOut")),
)
server <- function(input, output) {
df <- data.frame(id = c("1","2","3"), number = c(100,227,7))
output$numberOut <- shiny::renderText({ input$idSelection })
}
shiny::shinyApp(ui, server)
Chunk 2:
idOptions <- c("1","2","3")
ui <- shiny::fluidPage(
shiny::selectInput(inputId = "idSelection", "Identification: ", idOptions),
shiny::numericInput("num", "Number associated with id:", value=shiny::verbatimTextOutput("numberOut")),
)
server <- function(input, output) {
df <- data.frame(id = c("1","2","3"), number = c(100,227,7))
dfReactive <- shiny::reactive({
dataOut <- df %>%
dplyr::filter(., id %in% input$idSelection)
return(dataOut)
})
shiny::observe({
output$numberOut <- shiny::renderText({
return(dfReactive()$number)
})
})
}
shiny::shinyApp(ui, server)
I want the initial value for shiny::numericInput to change like so:
When the user selects "1" for Identification, the initial value is 100:
When the user selects "2" for Identification, the initial value is 227:
The idea behind this is to have an appropriate initial value suggested to the user based on the identification of the input.
I'm guessing the problem might be with shiny::verbatimTextOutput("numberOut"), but I don't know a way to render a simple numeric value to pass into the value argument of shiny::numericInput.
Any thoughts?
Thanks much.
One way would be to use renderUI and do the computation on the server side:
idOptions <- c("1","2","3")
shiny::shinyApp(
ui = shiny::fluidPage(
shiny::selectInput(inputId = "idSelection", "Identification: ", idOptions),
shiny::uiOutput("num")
),
server = function(input, output) {
df <- data.frame(id = c("1","2","3"), number = c(100,227,7))
output$num <- shiny::renderUI({
shiny::numericInput("num",
"Number associated with id:",
value = df$number[as.numeric(input$idSelection)])
})
})
The alternative is to leave the input on the UI side and use updateNumericInput inside an observeEvent:
idOptions <- c("1","2","3")
shiny::shinyApp(
ui = shiny::fluidPage(
shiny::selectInput(inputId = "idSelection",
"Identification: ",
idOptions),
shiny::numericInput("num",
"Number associated with id:",
value = NULL)
),
server = function(input, output, session) {
df <- data.frame(id = c("1","2","3"),
number = c(100,227,7))
observeEvent(input$idSelection, {
updateNumericInput(session,
inputId = "num",
value = df$number[as.numeric(input$idSelection)])
})
})
I am building app where a user can make edits to a datatable and the hit a button to reflect the changes in a non-editable copy of this datatable (in the final project, I will need to have two datasets that need to be matched manually), but for now this small MWE shows the problem I have with making a copy of the reactive table in which changes can be made, without changing the data of the original reactive table. I would like to make this app work, where you click edit a cell in the table dat_joined$data/output$mytable and that those changes do reflect in a new table mydf$data/output$table2. To do mydf$data initially (before any changes are made) needs to be a copy of dat_joined$data This is a follow up on this question and answer: how to make a copy of a reactive value in shiny server function
library(shiny)
library(DT)
library(shinyWidgets)
library(tidyverse)
# create master dataframe
dat_total <- tibble(ID_1 = 1:10, names = letters[1:10],
ID_2 = 11:20, names_2 = LETTERS[c(3:5, 1, 2, 6:8, 10, 9)])
shinyApp(
ui = fluidPage(
title = 'Radio button and a dropdown manue ',
sliderInput("n_rows_table", "Number of rows:",
min = 0, max = 10,
value = 5),
actionBttn(
inputId = "button_1",
label = "Make tables",
size = "sm",
color = "warning"
),
DT::dataTableOutput("mytable"),
actionBttn(
inputId = "button_2",
label = "Process",
size = "sm",
color = "success"),
DT::dataTableOutput("table2")),
server = function(input, output, session) {
# set up reactive values
dat_left <- reactiveValues(data=NULL)
dat_right <- reactiveValues(data=NULL)
dat_joined <- reactiveValues(data=NULL)
# create reactive daraframe
dat <- eventReactive(input$button_1, {
dat_total[1:input$n_rows_table, ] %>%
rowid_to_column()})
# Split the data into a right and a left set
observe({
dat_left$data <- dat() %>%
select(rowid, ID_1, names)
})
observe({
dat_right$data <- dat() %>%
select(rowid, ID_2, names_2,ID_1)
})
# join these again
# This is needed because my actual app will
# be used to manually match 2 datasets
observe({
if (is.null( dat_right$data )) {
NULL
}else{
dat_joined$data <- left_join(dat_left$data,
dat_right$data,
by = "rowid")
}
})
# Print the the datasets
output$mytable <- renderDT({
datatable(dat_joined$data ,
rownames = F,
editable = "cell")
})
# I want to make a copy of the dat_joined$data dataset into dat$mydf
# none of these function as expected
#mydf <- reactiveValues(data=isolate(dat_joined$data))
#mydf <- reactiveValues(data=local(dat_joined$data))
#mydf <- reactiveValues(data=dat_joined$data)
#mydf <- reactiveValues(data=NULL)
# This works, but only saves the cells to w
mydf <- reactiveValues(data=matrix(NA, nrow=10, ncol = 5))
# Ideally the computation only happens when this both an edit is made
# and the button is pressed (now I need to press it between every edit)
# validate_event <- reactive({
# req(input$mytable_cell_edit) & req(input$button_2)
# })
#observeEvent(input$button_2validate_event(), { DOes not work
observeEvent(input$button_2,{
info = input$mytable_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
mydf$data[i, j] <- DT::coerceValue(v, mydf$data[i, j])
})
# print
output[["table2"]] <- renderDT({
datatable(mydf$data)
})
}
)
Any changes you make in the top table is reflected in the bottom table after you press the button "Process". Try this
library(shiny)
library(DT)
library(shinyWidgets)
library(tidyverse)
# create master dataframe
dat_total <- tibble(ID_1 = 1:10, names = letters[1:10],
ID_2 = 11:20, names_2 = LETTERS[c(3:5, 1, 2, 6:8, 10, 9)])
shinyApp(
ui = fluidPage(
title = 'Radio button and a dropdown manue ',
sliderInput("n_rows_table", "Number of rows:",
min = 0, max = 10,
value = 5),
actionBttn(
inputId = "button_1",
label = "Make tables",
size = "sm",
color = "warning"
),
DT::dataTableOutput("mytable"),
actionBttn(
inputId = "button_2",
label = "Process",
size = "sm",
color = "success"),
DT::dataTableOutput("table2")),
server = function(input, output, session) {
# set up reactive values
dat_left <- reactiveValues(data=NULL)
dat_right <- reactiveValues(data=NULL)
dat_joined <- reactiveValues(data=NULL)
dfon <- reactiveValues(top=NULL,
bottom=NULL)
# create reactive daraframe
dat <- eventReactive(input$button_1, {
dat_total[1:input$n_rows_table, ] %>%
rowid_to_column()})
# Split the data into a right and a left set
observe({
req(dat())
dat_left$data <- dat() %>%
dplyr::select(rowid, ID_1, names)
})
observe({
req(dat())
dat_right$data <- dat() %>%
dplyr::select(rowid, ID_2, names_2,ID_1)
})
# join these again
# This is needed because my actual app will
# be used to manually match 2 datasets
observe({
req(dat())
if (!is.null( dat_right$data )) {
dat_joined$data <- left_join(dat_left$data,
dat_right$data,
by = "rowid")
}
})
observe({ ###assign your orig data to a reactiveValues object
req(dat_joined$data)
if (!is.null(dat_joined$data)) {
dfon$top <- dat_joined$data
}
})
# Print the the datasets
output$mytable <- renderDT({
datatable(dfon$top,
rownames = F,
editable = "cell")
})
# Ideally the computation only happens when this both an edit is made
# and the button is pressed (now I need to press it between every edit)
observeEvent(input$mytable_cell_edit, {
info = input$mytable_cell_edit
str(info)
#i = info$row
#j = info$col + 1 # offset by 1
#v = info$value
#dfon$top[i, j] <<- DT::coerceValue(v, dfon$top[i, j])
dfon$top <<- editData(dfon$top, info)
})
observeEvent(input$button_2,{
dfon$bottom <- dfon$top
output$table2 <- renderDT({
datatable(dfon$bottom)
})
})
## further editing of dfon$bottom is performed below...with...observeEvent(input$table2_cell_edit, {...
}
)
In the output below, I have entered cccc for 3rd element in names column, but I have not clicked on the button Process. Therefore, the edited cell is not reflected in the bottom table.
I am building a Shiny app and using the code from this question as an example: How to download editable data table in shiny. However, in my code the df <- reactiveVal(dat) does not work, because the dat itself is already a reactive value that comes from an eventReactive({}) function. This is the code I am working with, it works if I define the dat outside of the server, but not when it is created inside the server function of shiny. How do I make a copy of it so that I can show it in a new table (and potentially process further and download in later steps in the app)?
library(shiny)
library(DT)
library(shinyWidgets)
# if the data frame is just an object, it works
#dat <- iris[1:3, ]
ui <- fluidPage( actionBttn(
inputId = "btnProcess",
label = "Process",
size = "sm",
color = "success"
),
DTOutput("my_table"),
DTOutput("table2")
)
server <- function(input, output){
# if the dataframe is a reactive variable, this doesnt work.
dat <- eventReactive(input$btnProcess, {
iris[1:3, ]
})
output[["my_table"]] <- renderDT({
datatable(dat(), editable = "cell")
})
#############################
#### none of these work #####
#############################
#df <- reactiveVal(dat)
#df <- reactiveVal(dat())
#df <- dat()
#df <- dat
observeEvent(input[["my_table_cell_edit"]], {
cell <- input[["my_table_cell_edit"]]
newdf <- df()
newdf[cell$row, cell$col] <- cell$value
df(newdf)
})
output[["table2"]] <- renderDT({
datatable(df())
})
}
shinyApp(ui, server)
Try this
ui <- fluidPage( actionBttn(
inputId = "btnProcess",
label = "Process",
size = "sm",
color = "success"
),
actionBttn(inputId = "reset", label = "Reset", size="sm", color="warning"),
DTOutput("mytable"),
DTOutput("table2")
)
server <- function(input, output){
# if the dataframe is a reactive variable, this doesnt work.
dat <- eventReactive(input$btnProcess, {
iris[1:3, ]
})
mydf <- reactiveValues(data=NULL)
observe({
mydf$data <- dat()
})
output$mytable <- renderDT({
datatable(mydf$data, editable = "cell")
})
observeEvent(input$mytable_cell_edit, {
info = input$mytable_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
mydf$data[i, j] <<- DT::coerceValue(v, mydf$data[i, j])
})
output[["table2"]] <- renderDT({
datatable(mydf$data)
})
observeEvent(input$reset, {
mydf$data <- dat() ## reset it to original data
})
}
shinyApp(ui, server)
I have two dataframes (df1 and df2) which are identical. I want a shiny app were the user firstly select one of the dataframes and secondly filter by a specific column value (in the example data the column region) and get a table in return. I manage to achieve the first task but can't seem to figure out how to do the second one. I have made several attempts with the combination of reactive and filter without any success. I have made a comment in the script below were I made the attempts.
library(shiny)
#Dataset
names_df1 <- c("Henry","Charles","Lisa","Jessica","Steven","Ali","Mona","Patricia","George","John")
region_df1 <- sample(c("North","West","East","South"),10,replace=T)
df1 <- data.frame(names_df1,region_df1)
names_df2 <- c("Michael","Simone","Anna","Steven","Billie","Emma","Maria","Gordon","Bruce","Rachel")
region_df2 <- sample(c("North","West","East","South"),10,replace=T)
df2 <- data.frame(names_df2,region_df2)
colnames(df1) <- c("Names","Region")
colnames(df2) <- c("Names","Region")
ui <- fluidPage(
titlePanel("Shiny Text"),
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "df1/df2:",
choices = c("df1", "df2")),
selectInput("region",
"Region:",
c("All","North","West","East","South")),
numericInput(inputId = "obs",
label = "Number of observations to view:",
value = 20)),
mainPanel(
tableOutput("view")
)
)
)
server <- function(input, output) {
#Chose input
datasetInput <- reactive({
switch(input$dataset,
"df1" = df1,
"df2" = df2)
})
#Do I filter here?
#Render table
output$view <- renderTable({
head(datasetInput(), n = input$obs)})
}
shinyApp(ui, server)
Can anybody give me some directions?
Best/John
You need something like that:
#Render table
output$view <- renderTable({
out <- datasetInput()
if (input$region != "All") {
out <- out[out$Region == input$region, ]
}
head(out, n = input$obs)
})
I am new to Shiny. What I want to do in my application is, running & displaying some part of the code only when a condition on another calculation is met.
The conditionalPanel works fine with the conditions on input values but I could not figure out how to do this with the 'output' values, i.e., conditionally on the output values of the functions. Below is my example code:
library(shiny)
msLocation <- "msLoc"
searchMWText <- "searchMW"
bid <- "2333333"
fulltext <- "fullDisplay"
ui <- fluidPage(
titlePanel("Run server codes conditionally"),
sidebarLayout(
sidebarPanel(
helpText("Evaluate input and run different parts of the code depending on the output functions"),
br(),
sliderInput("rand", "select seed", min = 1, max = 50, step = 1, value = 1)
),
mainPanel(
fluidRow(conditionalPanel("output.rand == 1"),
tags$h4("Here comes the default part"),
br(),
textOutput("defaultCalc")),
fluidRow(conditionalPanel("output.randomint != 1",
tags$h4("I can evaluate if the chosen number is even or odd."),
br(),
textOutput("evenodd")
),
fluidRow(conditionalPanel("output.evenodd == 'Number is even'",
tags$h4("Number even calculation "),
textOutput("msLoc"),
br(),
textOutput("searchMW"),
br(),
textOutput("defaultID"),
br()
),
fluidRow(conditionalPanel("output.evenodd == 'Number is odd'",
tags$h4("Here is some id:", textOutput("id")),
textOutput("displayFull")
)
)
)
)
)))
#
server <- function(input, output) {
rand1 <- reactive({
if(is.null(input$rand)){return(NULL)}
rn <- input$rand
return(rn)
})
randomint <- reactive({
seedn <- rand1()
set.seed(seedn)
rint <- sample(1:50, 1)
return(rint)
})
calc1 <- reactive({
intn <- randomint()
modn <- intn %% 2
return(modn)
})
evenOdd <- reactive({
modn <- calc1()
if(modn == 0){valueText = "Number is even"}
if(modn != 0){valueText = "Number is odd"}
return(valueText)
})
idtext <- reactive({
idint <- sample(1:10000, 3)
idint <- as.character(idint)
idint <- paste(idint, collapse = "")
return(idint)
})
output$defaultCalc <- renderText({
as.character(randomint())
})
output$evenodd <- renderText({
evenOdd()
})
output$searchMW <- renderText({
searchMWText
})
output$defaultID <- renderText({
bid
})
output$id <- renderText({
idtext()
})
output$displayFull <- renderText({
fulltext
})
}
shinyApp(ui = ui, server = server)
The problem is, the parts after default always appear, e..g., 'Here is some id' text always appears and this is not what I want. I want to display 'Here is some id' and run the calculation (idtext) only when the number is odd.The number is not coming from the slider input, the slider input is providing the seed only. The number is also calculated and depends on its value, the other parts should be run and displayed. Until the user selects a slider input value, only the 'default part' should be displayed and nothing else.
I searched a lot and could not find a solution that mentions the conditions on output. What is the best way to solve this?
Do:
randomint <- reactive({
seedn <- rand1()
set.seed(seedn)
rint <- sample(1:50, 1)
return(rint)
})
output$randomint <- reactive(randomint())
outputOptions(output, "randomint", suspendWhenHidden = FALSE)
Then you can use "output.randomint !== 1".