R Shiny: Computing new Variables selected by "selectInput" - r

I'm working on a dashbord with Shiny and want to compute new variables based on the selected Variabels by selectInput.
Comparable to this in normal R-Code:
library(dplyr)
new_df <- old_df %>% mutate(new_1 = old_var1 + old_var2)
I'm able to compute new values with the sliderInput, but this are only single values. I want to compute a hole new variable with all the oppertunities of displaying the new variable in Tables and graphics.
Please try the followring syntax (the data is online avalible).
As you mentioned, all Inputs are working as they should.
library(shiny)
library(readr)
library(ggplot2)
library(stringr)
library(dplyr)
library(DT)
library(tools)
load(url("http://s3.amazonaws.com/assets.datacamp.com/production/course_4850/datasets/movies.Rdata"))
ui <- fluidPage(
sidebarLayout(
# Inputs
sidebarPanel(
h3("Plotting"), # Third level header: Plotting
# Select variable for y-axis
selectInput(inputId = "y",
label = "Y-axis:",
choices = c("IMDB rating" = "imdb_rating",
"IMDB number of votes" = "imdb_num_votes",
"Critics Score" = "critics_score",
"Audience Score" = "audience_score",
"Runtime" = "runtime"),
selected = "audience_score"),
# Select variable for x-axis
selectInput(inputId = "x",
label = "X-axis:",
choices = c("IMDB rating" = "imdb_rating",
"IMDB number of votes" = "imdb_num_votes",
"Critics Score" = "critics_score",
"Audience Score" = "audience_score",
"Runtime" = "runtime"),
selected = "critics_score"),
# Select variable for color
selectInput(inputId = "z",
label = "Color by:",
choices = c("Title Type" = "title_type",
"Genre" = "genre",
"MPAA Rating" = "mpaa_rating",
"Critics Rating" = "critics_rating",
"Audience Rating" = "audience_rating"),
selected = "mpaa_rating"),
hr(),
# Set alpha level
sliderInput(inputId = "alpha",
label = "Alpha:",
min = 0, max = 1,
value = 0.5),
# Set point size
sliderInput(inputId = "beta",
label = "Beta:",
min = 0, max = 5,
value = 2)
),
# Output:
mainPanel(plotOutput(outputId = "scatterplot"),
textOutput(outputId = "description"),
DT::dataTableOutput("moviestable"))
)
)
server <- function(input, output, session) {
output$scatterplot <- renderPlot({
ggplot(data = movies, aes_string(x = input$x, y = input$y,
color = input$z)) +
geom_point(alpha = input$alpha, size = input$beta) +
labs(x = toTitleCase(str_replace_all(input$x, "_", " ")),
y = toTitleCase(str_replace_all(input$y, "_", " ")),
color = toTitleCase(str_replace_all(input$z, "_", " ")))
})
vals <- reactiveValues()
observe({
vals$x <- input$alpha
vals$y <- input$beta
vals$sum <- vals$x + vals$y
})
output$description <- renderText({
paste0("Alpha: ",input$alpha, " Beta:", input$beta," and the sum of alpha and beta:",vals$sum, ".")
})
output$moviestable <- DT::renderDataTable({
DT::datatable(data = movies,
options = list(pageLength = 10),
rownames = FALSE)
})
}
shinyApp(ui = ui, server = server)
I tried different ways to solve this problem:
1st try:
vals2 <- reactiveValues()
observe({
vals2$x <- input$y
vals2$y <- input$x
vals2$sum <- vals2$x + vals2$y
})
output$description2 <- renderText({
paste0("Input y: ",input$y, " Input x:", input$x," and the sum of both variables is:",vals2$sum, ".")
})
Warning: Error in +: non-numeric argument to binary operator
Stack trace (innermost first):
56: observerFunc [C:/Users/XXXXXX/Desktop/app.R#110]
1: runApp
ERROR: [on_request_read] connection reset by peer
2nd try:
output$try2 <- renderUI({
movies_2 <- movies %>% mutate(new_1 = input$y + input$x)
})
output$moviestable2 <- DT::renderDataTable({
DT::datatable(data = movies_2,
options = list(pageLength = 10),
rownames = FALSE)
})
Warning: Error in inherits: object 'movies_2' not found
I've no idea where I what I can try next...
I'm very happy for every kind of help!

You should make movies_2 in a reactive. Your output$try2 won't work because its expecting UI objects.
To match the call you make on the UI side I've renamed back to moviestable and have changed input$x + input$y to paste0(input$y, input$x) since they are both character.
movies_2 <- reactive({
movies %>% mutate(new_1 := movies[[input$x]] + movies[[input$y]])
})
output$moviestable <- DT::renderDataTable({
DT::datatable(data = movies_2(),
options = list(pageLength = 10),
rownames = FALSE)
})

Related

Create graph based on selection of input and output

New to shiny. I am trying to create a plot based on chosen x and y values. Basically, whatever the user selects for the select1 and select2 selectInput function will graph it accordingly. My original data has many columns, not just two. When I try to graph very specific things, my code works great, but when I try to graph what the user "selects" it does not work.
library(shiny)
library(readr)
library(ggplot2)
library(dplyr)
data0 <- rnorm(n = 10, mean = 100, sd = 5)
data1 <- rnorm(n = 10, mean = 50, sd = 10)
data2 <- data.frame(data0, data1)
attach(data2)
ui <- fluidPage(
selectInput(inputId = "select1",
label = "select the x-axis",
choices = c(" ", "data0", "data1")
),
selectInput(inputId = "select2",
label = "select the y-axis",
choices = c(" ", "data0", "data1")
),
submitButton(text = "Apply Changes", icon = NULL, width = NULL),
plotOutput(outputId = "myplot")
)
server <- function(input, output) {
output$myplot <- renderPlot({
data2 %>%
ggplot(aes(input$select1 ~ input$select2))+
geom_point(alpha = 0.8)
})
}
shinyApp(ui = ui, server = server)
I had to add ggplot(aes(x = get(paste(input$select1)), y = get(paste(input$select2)) to make the input selects work.
library(shiny)
library(readr)
library(ggplot2)
library(dplyr)
data0 <- read_csv("DeltaX_Soil_Properties_Fall2020_Spring2021_Fall2021.csv")
data1 <- data0[!(data0$time_marker_sampled == "-9999"),]
attach(data1)
ui <- fluidPage(
selectInput(inputId = "select1",
label = "select the x-axis",
choices = c(" ", "elevation_navd88", "sediment_accretion", "days_between_sampling_and_deployment", "normalized_accretion", "soil_bulk_density", "soil_organic_matter_content", "soil_organic_carbon", "soil_organic_carbon_density")
),
selectInput(inputId = "select2",
label = "select the y-axis",
choices = c(" ", "elevation_navd88", "sediment_accretion", "days_between_sampling_and_deployment", "normalized_accretion", "soil_bulk_density", "soil_organic_matter_content", "soil_organic_carbon", "soil_organic_carbon_density")
),
submitButton(text = "Apply Changes", icon = NULL, width = NULL),
plotOutput(outputId = "myplot")
)
server <- function(input, output) {
output$myplot <- renderPlot({
data1 %>%
ggplot(aes(x = get(paste(input$select1)), y = get(paste(input$select2)), col = hydrogeomorphic_zone))+
geom_point(alpha = 0.8)
})
}
shinyApp(ui = ui, server = server)
If you want to use a variable as x or y, you can alternatively use aes_() instead of aes().
This would then result in:
ggplot(aes_(x = input$select1, y = input$select2))
Beware, that you need to add a tilde if you want to use a normal column name with aes_(), e.g.:
ggplot(aes_(x = ~elevation_navd88, y = input$select2))

Display line plot when condition is met in data entry

I am building a shiny budgeting shiny application that prompts the user to enter data such as what type of expense was spent, the amount, and a description. I would like to display a line plot in the second pannel of the application labeled "Monthly Budget" ONLY when the user has entered at least one data entry where the category is "Savings". I have tried experimenting with things such as hiding/displaying the plot whenever the condition is met, but it seems that I always get a NaN error message with this approach. Thus, I am experimenting with conditionalPanel() in hopes of accomplishing this task. I've noticed similar posts to this one, however this is the first case that I have found where conditionalPanel() deals with data that the user inputs as opposed to a given dataset. In the code below I get the following error message: "Error in: Invalid input: date_trans works with objects of class Date only".
Here is the code:
# Libraries
library(shiny)
library(ggplot2)
library(shinycssloaders)
library(colortools)
library(shinythemes)
library(DT)
library(tidyverse)
library(kableExtra)
library(formattable)
library(xts)
# Creating Contrasting Colors For Buckets
bucket_colors <- wheel("skyblue", num = 6)
# Define UI for application that draws a histogram
ui <- fluidPage(
# theme = shinytheme("spacelab"),
shinythemes::themeSelector(),
## Application Title
titlePanel("2021 Budgeting & Finances"),
tags$em("By:"),
tags$hr(),
navbarPage("", id = "Budget",
tabPanel("Data Entry",
div(class = "outer",
# Sidebar Layout
sidebarLayout(
sidebarPanel(
selectInput("Name",
label = "Name:",
choices = c("","Jack", "Jill")),
selectInput("Bucket",
label = "Item Bucket:",
choices = c("","Essential", "Non-Essential", "Savings", "Rent/Bills", "Trip", "Other")),
textInput("Item",
label = "Item Name:",
placeholder = "Ex: McDonald's"),
shinyWidgets::numericInputIcon("Amount",
"Amount:",
value = 0,
step = 0.01,
min = 0,
max = 1000000,
icon = list(icon("dollar"), NULL)),
dateInput("Date",
label = "Date",
value = Sys.Date(),
min = "2021-05-01",
max = "2022-12-31",
format = "M-d-yyyy"),
actionButton("Submit", "Submit", class = "btn btn-primary"),
downloadButton("Download", "Download")),
# Show a plot of the generated distribution
mainPanel(
tableOutput("PreviewTable")
)
)
)
),
############ THIS IS WHERE THE ERROR HAPPENS #############
tabPanel("Monthly Budget",
conditionalPanel("output.any(ReactiveDf() == 'Savings') == TRUE ",
plotOutput("SavingsPlot")
)
########### THIS IS WHERE THE ERROR HAPPENS ##############
),
tabPanel("Budget to Date",
tableOutput("YearTable")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
## SAVE DATA
# Set Up Empty DF
df <- tibble("Name" = character(),
"Date" = character(),
"Category" = character(),
"Amount" = numeric(),
"Description" = character())
# DF is made reactive so we can add new lines
ReactiveDf <- reactiveVal(value = df)
# Add inputs as new data (lines)
observeEvent(input$Submit, {
if (input$Bucket == "" | input$Amount == 0 |
is.na(input$Amount)) {
return(NULL)
}
else {
# New lines are packaged together in a DF
new_lines <- data.frame(Name = as.character(input$Name),
Date = as.character(input$Date),
Category = input$Bucket,
Amount = as.character(input$Amount),
Description = as.character(input$Item))
# change df globally
df <<- rbind(df, new_lines)
# ensure amount is numeric
df <<- df %>%
mutate("Amount" = as.numeric(Amount))
# Update reactive values
ReactiveDf(df)
#clear out original inputs now that they are written to df
updateSelectInput(session, inputId = "Name", selected = "")
updateSelectInput(session, inputId = "Bucket", selected = "")
updateNumericInput(session, inputId = "Amount", value = 0)
updateTextInput(session, inputId = "Item", value = "")
}
})
## Preview Table
observeEvent(input$Submit, {
output$PreviewTable <-
function(){
ReactiveDf()[order(ReactiveDf()$Date, decreasing = TRUE),] %>%
kable("html") %>%
kable_material(c("striped", "hover")) %>%
kable_styling("striped", full_width = TRUE) %>%
column_spec(3, color = "black", background = ifelse(ReactiveDf()[3]=="Essential", "#87CEEB", ifelse(ReactiveDf()[3] == "Non-Essential", "#EBA487", ifelse(ReactiveDf()[3] == "Savings", "#87EBA4", ifelse(ReactiveDf()[3] == "Rent/Bills", "#A487EB", ifelse(ReactiveDf()[3] == "Trip", "#CEEB87", "#EB87CE")))))) %>%
column_spec(1, color = ifelse(ReactiveDf()[1] == "Ashley", "lightpink", "lightcyan"))
}
########## THIS IS THE LINE PLOT I AM TRYING TO RENDER ##########
output$SavingsPlot <- renderPlot({
savings <- ReactiveDf()[ReactiveDf()$Category == "Savings",]
savings <- savings[, -c(1,3,5)]
savings$Date <- as.Date(savings$Date)
savings$Amount <- as.numeric(savings$Amount)
savings <- as.xts(savings$Amount, order.by = as.Date(savings$Date))
weekly <- apply.weekly(savings,sum)
weekly_savings <- as.data.frame(weekly)
weekly_savings$names <- rownames(weekly_savings)
rownames(weekly_savings) <- NULL
colnames(weekly_savings) <- c("Amount", "Date")
Expected <- NULL
for(i in 1:dim(weekly_savings)[1]){
Expected[i] <- i * 625
}
weekly_savings$Expected <- Expected
ggplot(weekly_savings, aes(x = Date)) +
geom_line(aes(y = Expected), color = "red") +
geom_line(aes(y = Amount), color = "blue") +
ggtitle("House Downpayment Savings Over Time") +
ylab("Dollars") +
scale_x_date(date_minor_breaks = "2 day") +
scale_y_continuous(labels=scales::dollar_format())
})
})
########## THIS IS THE LINE PLOT I AM TRYING TO RENDER ##########
# Downloadable csv of selected dataset ----
output$Download <- downloadHandler(
filename = function() {
paste("A&J Budgeting ", Sys.Date(),".csv", sep = "")
},
content = function(file) {
write.csv(ReactiveDf(), file, row.names = FALSE)
}
)
# use if df new lines have errors
observeEvent(input$start_over, {
# change df globally
df <- tibble("Name" = character(),
"Date" = character(),
"Expense Category" = character(),
"Amount" = numeric(),
"Description" = character())
# Update reactive values to empty out df
ReactiveDf(df)
})
## MONTHLY TABLE
output$MonthlyTable <- renderTable({
ReactiveDf()
})
## YEAR TO DATE TABLE
output$YearTable <- renderTable({
ReactiveDf()
})
}
# Run the application
shinyApp(ui = ui, server = server)
We can use a condition like nrow(filter(ReactiveDf(), Category == 'Savings')) > 0 as if ReactiveDf is a normal df. Also, when converting the xts object to a df the Date column was coerced to character.
app:
# Libraries
library(shiny)
library(tidyverse)
library(shinycssloaders)
library(colortools)
library(shinythemes)
library(DT)
library(tidyverse)
library(kableExtra)
library(formattable)
library(xts)
library(lubridate)
# Creating Contrasting Colors For Buckets
bucket_colors <- wheel("skyblue", num = 6)
# Define UI for application that draws a histogram
ui <- fluidPage(
# theme = shinytheme("spacelab"),
shinythemes::themeSelector(),
## Application Title
titlePanel("2021 Budgeting & Finances"),
tags$em("By:"),
tags$hr(),
navbarPage("", id = "Budget",
tabPanel("Data Entry",
div(class = "outer",
# Sidebar Layout
sidebarLayout(
sidebarPanel(
selectInput("Name",
label = "Name:",
choices = c("","Jack", "Jill")),
selectInput("Bucket",
label = "Item Bucket:",
choices = c("","Essential", "Non-Essential", "Savings", "Rent/Bills", "Trip", "Other")),
textInput("Item",
label = "Item Name:",
placeholder = "Ex: McDonald's"),
shinyWidgets::numericInputIcon("Amount",
"Amount:",
value = 0,
step = 0.01,
min = 0,
max = 1000000,
icon = list(icon("dollar"), NULL)),
dateInput("Date",
label = "Date",
value = Sys.Date(),
min = "2021-05-01",
max = "2022-12-31",
format = "M-d-yyyy"),
actionButton("Submit", "Submit", class = "btn btn-primary"),
downloadButton("Download", "Download")),
# Show a plot of the generated distribution
mainPanel(
tableOutput("PreviewTable")
)
)
)
),
tabPanel("Monthly Budget",
plotOutput("SavingsPlot")
),
tabPanel("Budget to Date",
tableOutput("YearTable")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
## SAVE DATA
# Set Up Empty DF
df <- tibble("Name" = character(),
"Date" = character(),
"Category" = character(),
"Amount" = numeric(),
"Description" = character())
# DF is made reactive so we can add new lines
ReactiveDf <- reactiveVal(value = df)
# Add inputs as new data (lines)
observeEvent(input$Submit, {
if (input$Bucket == "" | input$Amount == 0 |
is.na(input$Amount)) {
return(NULL)
}
else {
# New lines are packaged together in a DF
new_lines <- data.frame(Name = as.character(input$Name),
Date = as.character(input$Date),
Category = input$Bucket,
Amount = as.character(input$Amount),
Description = as.character(input$Item))
# change df globally
df <<- rbind(df, new_lines)
# ensure amount is numeric
df <<- df %>%
mutate("Amount" = as.numeric(Amount))
# Update reactive values
ReactiveDf(df)
#clear out original inputs now that they are written to df
updateSelectInput(session, inputId = "Name", selected = "")
updateSelectInput(session, inputId = "Bucket", selected = "")
updateNumericInput(session, inputId = "Amount", value = 0)
updateTextInput(session, inputId = "Item", value = "")
}
})
## Preview Table
observeEvent(input$Submit, {
output$PreviewTable <-
function(){
ReactiveDf()[order(ReactiveDf()$Date, decreasing = TRUE),] %>%
kable("html") %>%
kable_material(c("striped", "hover")) %>%
kable_styling("striped", full_width = TRUE) %>%
column_spec(3, color = "black", background = ifelse(ReactiveDf()[3]=="Essential", "#87CEEB", ifelse(ReactiveDf()[3] == "Non-Essential", "#EBA487", ifelse(ReactiveDf()[3] == "Savings", "#87EBA4", ifelse(ReactiveDf()[3] == "Rent/Bills", "#A487EB", ifelse(ReactiveDf()[3] == "Trip", "#CEEB87", "#EB87CE")))))) %>%
column_spec(1, color = ifelse(ReactiveDf()[1] == "Ashley", "lightpink", "lightcyan"))
}
########## THIS IS THE LINE PLOT I AM TRYING TO RENDER ##########
if (nrow(filter(ReactiveDf(), Category == 'Savings')) > 0) {
output$SavingsPlot <- renderPlot({
savings <- filter(ReactiveDf(), Category == 'Savings')
savings$Date <- as.Date(savings$Date, format = "%Y-%m-%d")
savings$Amount <- as.numeric(savings$Amount)
savings <- as.xts(savings$Amount, order.by = savings$Date)
weekly <- apply.weekly(savings, sum)
weekly_savings <- as.data.frame(weekly)
weekly_savings$names <- rownames(weekly_savings)
rownames(weekly_savings) <- NULL
colnames(weekly_savings) <- c("Amount", "Date")
Expected <- NULL
for(i in 1:dim(weekly_savings)[1]){
Expected[i] <- i * 625
}
weekly_savings$Expected <- Expected
ggplot(weekly_savings, aes(x = ymd(Date))) +
geom_line(aes(y = Expected), color = "red") +
geom_line(aes(y = Amount), color = "blue") +
ggtitle("House Downpayment Savings Over Time") +
ylab("Dollars") +
scale_x_date(date_minor_breaks = "2 day") +
scale_y_continuous(labels=scales::dollar_format())
}) }
})
########## THIS IS THE LINE PLOT I AM TRYING TO RENDER ##########
# Downloadable csv of selected dataset ----
output$Download <- downloadHandler(
filename = function() {
paste("A&J Budgeting ", Sys.Date(),".csv", sep = "")
},
content = function(file) {
write.csv(ReactiveDf(), file, row.names = FALSE)
}
)
# use if df new lines have errors
observeEvent(input$start_over, {
# change df globally
df <- tibble("Name" = character(),
"Date" = character(),
"Expense Category" = character(),
"Amount" = numeric(),
"Description" = character())
# Update reactive values to empty out df
ReactiveDf(df)
})
## MONTHLY TABLE
output$MonthlyTable <- renderTable({
ReactiveDf()
})
## YEAR TO DATE TABLE
output$YearTable <- renderTable({
ReactiveDf()
})
}
# Run the application
shinyApp(ui = ui, server = server)

Saving Dynamically Generated Plots in Shiny

so I have recently adapted some code that I found on StackOverflow to create a dynamic number of plots based on user input. However, I now cannot figure out how to save all of those dynamic plots in one file; when I use ggsave() in downloadHandler, it only saves the last plot generated, as the plots are created inside of a for loop, inside of an observe function. I have tried saving the for loop as a separate function and saving that instead of last plot, I have tried saving the observe() as a function and calling that inside ggsave(), but nothing works. Any idea how I can save all of the generated plots to one file?
ui <- fluidPanel(
sidebarLayout(
sidebarPanel(
#this is the input widget for dataset selection
selectInput(inputId = "dataset_selec",
label = "Choose which Dataset to explore:",
choices = list("NK AD Dataset (Zhang, 2020)",
"APPPS1 Dataset (Van Hove, 2019)",
"Aging T Cell Dataset (Dulken, 2019)"),
selected = "APPPS1 Dataset (Van Hove, 2019)"))
mainPanel(
fluidRow(
column(4,
textInput(inputId = "gene_fp",
label = "Enter gene(s) of interest here, separated by commas: ")
),
column(4,
br(),
checkboxInput("split_fp", "Split the graph?")
),
column(4,
conditionalPanel(condition = "input.split_fp == true",
#display choices to split by
selectInput(inputId = "metadata_split_fp",
label = "Choose how to split the Seurat data: ",
choices = list("Genotype", "Timepoint")))
)
),
#ask users if they want to split the graphs
br(),
fluidRow(
column(4,
textInput("save_name_fp",
label = "Enter a file name: ")
),
column(4,
conditionalPanel(condition = "input.save_name_fp.length > 0",
selectInput("fp_device",
label = "Select file type: ",
choices = list("PNG", "JPEG", "PDF", "TIFF",
"BMP", "SVG")))
),
column(4,
br(),
conditionalPanel(condition = "input.save_name_fp.length > 0",
downloadButton("fp_save", label = "Save Feature Plot"))
)
),
#plot the actual plot
uiOutput("fp_plots")
)
)
)
server <- function(input, output, session) {
datasetInput <- reactive({
switch(input$dataset_selec,
"NK AD Dataset (Zhang, 2020)" = nk_data,
"APPPS1 Dataset (Van Hove, 2019)" = appps1_data,
"Aging T Cell Dataset (Dulken, 2019)" = tcellinfil_data)
})
output$fp_plots <- renderUI({
#validate is to prevent an error message from being displayed when a gene hasn't been entered yet
validate(
need(input$gene_fp !="", "Please enter a gene.")
)
fp_genes <- input$gene_fp
fp_genes <- gsub(" ", "", fp_genes)
fp_genes <- unlist(strsplit(fp_genes, split = ","))
n <- length(fp_genes)
plot_output_list <- lapply(1:n, function(i) {
plotname <- paste("plot", i, sep = "")
if (input$split_fp == TRUE) {plotOutput(plotname, height = 580, width = 1100)}
else {plotOutput(plotname, height = 580, width = 550)}
})
do.call(tagList, plot_output_list)
})
#Here, we take the input of genes, and turn it into a character vector, so that we can iterate
#over it. This needs to be under observe({}) because it involves an input.
#Next, we iterate through the list of genes using a for loop, and within that for loop we assign
#the plots that we want to be displayed to each plotname, which is also sequentially created within
#this for loop, and assign it to the tagList we generated earlier. Basically, we're adding objects to
#list of names we made earlier.
#This needs to be under local({}) control, otherwise each graph doesn't get its own number,
#because of when renderPlot is evaluated
observe({
fp_genes <- input$gene_fp
fp_genes <- gsub(" ", "", fp_genes)
fp_genes <- unlist(strsplit(fp_genes, split = ","))
for (i in 1:length(fp_genes)) {
local({
plotname <- paste("plot", i, sep = "")
gene <- fp_genes[i]
output[[plotname]] <- renderPlot({
if (input$split_fp == TRUE) {FeaturePlot(datasetInput(), features = gene, split.by = input$metadata_split_fp)}
else {FeaturePlot(datasetInput(), features = gene)}
})
})
}
})
output$fp_save <- downloadHandler(
filename = function() {
paste(input$save_name_fp, tolower(input$fp_device), sep = ".")
},
content = function(file) {
ggsave(file, device = tolower(input$fp_device))
}
)
}
Create a list of plots, use grid.arrange to save it in a format you wish, and then save it. Perhaps you can adapt this code.
library(shiny)
library(dplyr)
library(tidyr)
library(ggplot2)
library(gridExtra)
mean_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(sample(1:1000, 1000, replace = T), nrow = 20)
)
names(mean_data)[-1] <- c(paste0("Gene_", 1:50))
sd_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(runif(1000, 5, 10), nrow = 20)
)
names(sd_data)[-1] <- c(paste0("Gene_", 1:50))
# Prepare dataset.
# 1. Bind mean and sd data
# 2. Reshape
data <- bind_rows(list(
mean = mean_data,
sd = sd_data
), .id = "stat")
data_mean_sd1 <- data %>%
pivot_longer(-c(Name, stat), names_to = "Gene", values_to = "value") %>%
pivot_wider(names_from = "stat", values_from = "value")
###
ui <- fluidPage(
pageWithSidebar(
headerPanel("Gene_FPKM Value Barplot"),
sidebarPanel(
selectInput(
"selectGeneSymbol",
"Select Gene Symbol:",
choices = unique(data_mean_sd1$Gene),
multiple =F,
width = 400,
selected = 1 #"Igfbp7"
),
selectInput(
"selectGeneSymbol2",
"Select Gene Symbol2:",
choices = unique(data_mean_sd1$Gene),
multiple =F,
width = 400,
selected = 1 #"Igfbp7"
),
selectInput("fp_device",
label = "Select file type: ",
choices = list("PNG", "JPEG", "PDF", "TIFF","BMP", "SVG")
),
actionButton(inputId = "plot1", label = "FPKM"),
actionButton(inputId = "plot2", label = "logFC"),
actionButton(inputId = "all",label = "logFC&FPKM"),br(),
downloadButton("fp_save", label = "Save Feature Plot")
),
mainPanel(
uiOutput("all")
)
)
)
server <- function(input, output, session) {
plot_data1 <- reactive({
subset(data_mean_sd1, Gene %in% input$selectGeneSymbol)
})
plot_data2 <- reactive({
subset(data_mean_sd1, Gene %in% input$selectGeneSymbol2)
})
global <- reactiveValues(out = NULL)
observeEvent(input$plot1, {
global$out <- plotOutput("plot1", height=750)
})
observeEvent(input$plot2, {
global$out <- plotOutput("plot2", height=750)
})
observeEvent(input$all, {
global$out <- plotOutput("plot3", height=1150)
})
output$all <- renderUI({
global$out
})
p1 <- eventReactive(list(input$plot1,
input$all), {
ggplot(data = plot_data1(), aes(x = Name, y = mean,fill=Name)) +
geom_bar(stat = "identity", position = position_dodge(0.9), width = 0.9) +
geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd), width = .2, position = position_dodge(0.9)) +
theme_classic2() +
rotate_x_text(angle = 45) +
theme(legend.position = "none") +
labs(title = input$selectGeneSymbol, x = NULL, y = "FPKM_value") +
theme(plot.title = element_text(hjust = 0.5)) +
theme(plot.margin = unit(c(20, 5, 1, 5), "mm"))+
theme(axis.text.x=element_text(vjust=1,size=12))
})
p2 <- eventReactive(list(input$plot2,
input$all), {
ggplot(data = plot_data2(), aes(x = Name, y = mean,fill=Name)) +
geom_bar(stat = "identity", position = position_dodge(0.9), width = 0.9) +
geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd), width = .2, position = position_dodge(0.9)) +
theme_classic2() +
rotate_x_text(angle = 45) +
theme(legend.position = "none") +
labs(title = input$selectGeneSymbol2, x = NULL, y = "FPKM_value") +
theme(plot.title = element_text(hjust = 0.5)) +
theme(plot.margin = unit(c(20, 5, 1, 5), "mm"))+
theme(axis.text.x=element_text(vjust=1,size=12))
})
#plotlist <- do.call(tagList, list(p1(),p2()))
output$plot1 <- renderPlot({ p1() })
output$plot2 <- renderPlot({ p2() })
output$plot3 <- renderPlot({ grid.arrange(p1(),p2(), ncol=1) })
observe({
plots <- list(p1(),p2())
myplots <- do.call(grid.arrange, c(plots, ncol = 1))
output$fp_save <- downloadHandler(
filename = function() {
paste("myplots", tolower(input$fp_device), sep = ".")
},
content = function(file) {
ggsave(file, plot=myplots, device = tolower(input$fp_device))
}
)
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)

Creating variables when importing data into the shiny-application, managing the received data

Comrades! Greetings.
Please help me out ... there is some significant misunderstanding.
Suppose I created like this data.frame:
df<-data.frame(num = c(1:250),
app_num = sample(1:100, 250, replace=T),
entrance=sample(1:4, 250, replace=T),
gender=sample(c('m','f'), 250,replace=T),
age= sample(1:100, 250, replace=T))
I save it in the "*csv" format, using the command:
write.csv2(data_file,file = file.choose(new = T), row.names = FALSE, quote = FALSE)
O.K.
Now I want to create a shiny-application for displaying and working with this data like his:
library("shiny")
#to work with extra string functions
library("stringr")
library("data.table")
library("readr")
# Define UI for application that draws a histogram
ui <- fluidPage(
titlePanel(h2(strong("Analysis of the composition and structure of residents"),
align = "center")),
fileInput(
inputId="fileInput",
label="Choose file",
multiple = FALSE,
accept = ".csv",
width = '100%',
buttonLabel = "Choosing ...",
placeholder = "No files selected yet"
),
sidebarPanel(
checkboxGroupInput(inputId="gender", label = "Choosing a gender feature:",
choices = c("Men" = "m",
"Women" = "f"),
selected= c("Men" = "m",
"Women" = "f")),
sliderInput(inputId = "age", label = "Indicate the age group:",
min = 1, max = 100, value = c(1, 100)),
selectInput(
inputId = "group",
label="Indicate the entrance",
choices=c(1:4),
selected = c(1:4),
multiple = TRUE,
selectize = TRUE,
width = NULL,
size = NULL
)
),
mainPanel(
navbarPage("",
tabPanel("Сommon data",
textOutput(outputId = "text1"),
),
tabPanel("Results table",
dataTableOutput(outputId = "content")
),
tabPanel("Graphic data")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
fileinfor <- reactiveValues(file=NULL,
ext=NULL,
datapath=NULL)
output$content <- renderDataTable({
fileinfor$file <- input$fileInput
fileinfor$datapath<-fileinfor$file$datapath
fileinfor.datapath <- fileinfor$file$datapath
fileinfor$ext <- tools::file_ext(fileinfor$datapath)
req(fileinfor$file)
validate(need(fileinfor$ext== "csv", "Please upload a csv file"))
fread(fileinfor$datapath,
showProgress = FALSE,
sep=";", quote="",header=TRUE)
})
output$text1 <- renderUI(renderText({
paste("Check ", fileinfor$datapath)
}))
}
# Run the application
shinyApp(ui = ui, server = server)
On the server side, I have several questions:
How to get the data correctly so that you can create a variable based on it and use it several times. On the example of my code, you can see that the server-side code block below no longer sees the created variable:
output $ text1 <- renderUI (renderText ({
paste ("Check", fileinfor $ datapath)
}))
Could you show by my example the creation of manipulated variables and their application? Can't figure out where and how to move?
Perhaps you are looking for this.
server <- function(input, output) {
mydf <- reactive({
req(input$fileInput)
inData <- input$fileInput
if (is.null(inData)){ return(NULL) }
mydata <- read.csv(inData$datapath, header = TRUE, sep=",")
})
output$content <- renderDT(mydf())
output$text1 <- renderText({
req(input$fileInput)
paste("Check ", input$fileInput$datapath)
})
}
First of all, I would like to thank #YBS for this teaching.
Thanks to these tips, I managed to solve half of the problem.
The essence of the solution lies in how Shainiy works with variables. In fact, there is no way to store variables like when writing regular code. However, you can write a reactive function that will receive data and issue it to a variable that is within the framework of another function when called.
It should be noted that an explicit mention of this approach was found in the tutorial "Mastering Shiny"
As a result, a version of the working code was obtained.
If you want to try the end result, then sequentially sell the following steps:
Create a CSV file for our experiment:
df<-data.frame(num = c(1:250),
app_num = sample(1:100, 250, replace=T),
entrance=sample(1:4, 250, replace=T),
gender=sample(c('m','f'), 250,replace=T),
age= sample(1:100, 250, replace=T))
Save it in the "*csv" format, using the command:
write.csv2(data_file,file = file.choose(new = T), row.names = FALSE, quote = FALSE)
Use the below mentioned code to create Shiny app:
library("shiny")
library("stringr")
library("data.table")
library("readr")
library("DT")
library("readr")
library("here")
library("ggplot2")
library("dplyr")
library("tidyr")
# Define UI for application that draws a histogram
ui <- fluidPage(
titlePanel(h2(strong("Analysis of the composition and structure of residents"),
align = "center")),
fileInput(
inputId="fileInput",
label="Choose file",
multiple = FALSE,
accept = ".csv",
width = '100%',
buttonLabel = "Choosing ...",
placeholder = "No files selected yet"
),
sidebarPanel(
checkboxGroupInput(inputId="gender", label = "Choosing a gender feature:",
choices = c("Men" = "M",
"Women" = "F"),
selected= c("Men" = "M",
"Women" = "F")),
sliderInput(inputId = "age", label = "Indicate the age group:",
min = 1, max = 100, value = c(1, 100)),
selectInput(
inputId = "group",
label="Indicate the entrance",
choices=c(1:4),
selected = c(1:4),
multiple = TRUE,
selectize = TRUE,
width = NULL,
size = NULL
)
),
mainPanel(
navbarPage("",
tabPanel("РЎommon data",
textOutput(outputId = "text1")
),
tabPanel("Results table",
dataTableOutput(outputId = "content")
),
tabPanel("Graphic data",
plotOutput(outputId = "my_plot")
)
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
fileinfor <- reactiveValues(file=NULL,
ext=NULL,
datapath=NULL)
gender = reactive({
gender <- input$gender
gender
})
age = reactive({
cbind(input$age[1],input$age[2])
})
group = reactive({
input$group
})
import_data <- reactive({
req(input$fileInput)
fileinfor$file <- input$fileInput
if (is.null(input$fileInput)){ return(NULL) }
fileinfor$datapath<-fileinfor$file$datapath
fileinfor$ext <- tools::file_ext(fileinfor$datapath)
validate(need(fileinfor$ext== "csv", "Please upload a csv file"))
import_data <- fread(fileinfor$datapath,
showProgress = FALSE,
sep=";", quote="",header=TRUE)
})
output$content <- renderDT({
GENDER = gender()
GROUP = group()
AGE = age()
req(import_data())
data_file <- import_data()
names(data_file) <- c("ID", "App", "Entrance", "Gender", "Age")
data_file <- mutate_at(data_file, vars(Gender), as.factor)
data_file<- mutate(data_file, Gender = factor(Gender, labels = c("F", "M")))
data_file <- subset(data_file,data_file$Age>=AGE[1]
& data_file$Age<=AGE[2]
& data_file$Entrance %in% GROUP
& data_file$Gender %in% GENDER)
})
output$text1 <- renderText({
req(input$fileInput)
gender <- gender()
paste(length(gender))
})
output$my_plot= reactivePlot(function(){
GENDER = gender()
GROUP = group()
AGE = age()
req(import_data())
data_file <- import_data()
names(data_file) <- c("ID", "App", "Entrance", "Gender", "Age")
data_file <- mutate_at(data_file, vars(Gender), as.factor)
data_file<- mutate(data_file, Gender = factor(Gender, labels = c("F", "M")))
data_file <- subset(data_file,data_file$Age>=AGE[1]
& data_file$Age<=AGE[2]
& data_file$Entrance %in% GROUP
& data_file$Gender %in% GENDER)
df <- group_by(data_file, data_file$Entrance, data_file$Gender)
df <- summarise(df, N = n())
names(df) <- c("Entrance", "Gender", "Quantity")
df <- mutate_at(df, vars(Gender), as.factor)
print(data_file$Gender)
#df <- mutate(df, Gender = factor(Gender, levels = c("f", "m")))
df <- complete(df, Gender, fill = list(M = 0, F = 0))
baseR.sbst.rssgn <- function(x) {
x[is.na(x)] <- 0
x
}
df$Quantity <- baseR.sbst.rssgn(df$Quantity)
ggplot(data = df, aes(x = factor(df$Gender), y = df$Quantity, fill = df$Gender)) +
geom_bar(stat = "identity", position = position_dodge2(0.9)) +
geom_text(data = df, aes(label = df$Quantity, y = 0), vjust = -0.5, position = position_dodge2(0.9)) +
scale_fill_discrete(name = "Title", labels = c("F", "M")) +
facet_wrap(~ df$Entrance, nrow = 1, strip.position = "bottom") +
xlab("Distribution of residents by entrances, taking into account gender") +
ylab("Number of residents") +
theme(
strip.placement = "outside",
strip.background = element_blank(),
axis.text.x = element_blank(),
axis.ticks.x = element_blank()
)
#?(ZMlength ~ Month, data = dat[dat$Lake == LAKE, ],
# main = "", xlab = "Month", ylab = "Shell length (mm)")
})
}
# Run the application
shinyApp(ui = ui, server = server)
What problems did I not solve:
I would like to immediately calculate the maximum and minimum values in the "Age" column when opening a file and change the settings for sliderInput. I would like to do the same with selectInput.
I would like to use the Saini application not only to analyze the downloaded data, but also to replenish the CSV file. In this part, I do not know anything at all.

wilcox.test does not work in shiny

I am trying to build a 'data explorer' shiny app which contains DataTables, ggplot2 graphs and wilcox.test results. I can't seem to make the wilcox.test to work though.
Outside the shiny app, things work as it should:
dat <- data.frame(outcome=sample(c("died","survived",NA), 20, TRUE),
cntr=sample(c("hospa","hospb"), 20, TRUE),
s=rnorm(20),
t=rnorm(20), stringsAsFactors=FALSE)
wilcox.test(dat$s ~ dat$outcome)
Results:
Wilcoxon rank sum test
data: dat$s by dat$outcome
W = 25, p-value = 0.3301
alternative hypothesis: true location shift is not equal to 0
Within the shiny app, the code below gives an 'Error: grouping factor > must have exactly 2 levels'. (graphs & tables work fine; I have omitted these for clarity).
library(shiny)
library(dplyr)
dat <- data.frame(outcome=sample(c("died","survived",NA), 20, TRUE),
cntr=sample(c("hospa","hospb"), 20, TRUE),
s=rnorm(20),
t=rnorm(20), stringsAsFactors=FALSE)
ui <- navbarPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "y",
label = "Y-axis:",
choices = c("s"="s", "t"="t"),
selected = "s"),
selectInput(inputId = "z",
label = "Color by:",
choices = c("outcome", "cntr"),
selected = "outcome")
),
mainPanel(
tabsetPanel(id="tabspanel", type = "tabs",
tabPanel(title = "Wilcox"),
h4(textOutput(outputId = "p")))
)
)
)
server <- function(input, output, session) {
df <- reactive({
data.frame(input$y, input$z)
})
output$p <- renderText({
wilcox.test(df()[,1] ~ df()[,2])
})
}
shinyApp(ui=ui, server=server)
If the code is rewritten:
wilcox.test(dat$s, dat$outcome)
then the error is 'Error: 'x' must be numeric'.
Can someone help?
The issue you are having is that the line
data.frame(input$y, input$z)
gets translated to something like
data.frame("s", "outcome")
which can't be reasonably handeled by wicox.text. You should use the following instead
data.frame(dat[[input$y]], dat[[input$z]])
There were also some other minor issues. See the code code below for a full fix.
library(shiny)
library(dplyr)
dat <- data.frame(outcome=sample(c("died","survived",NA), 20, TRUE),
cntr=sample(c("hospa","hospb"), 20, TRUE),
s=rnorm(20),
t=rnorm(20), stringsAsFactors=FALSE)
ui <- navbarPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "y",
label = "Y-axis:",
choices = c("s"="s", "t"="t"),
selected = "s"),
selectInput(inputId = "z",
label = "Color by:",
choices = c("outcome", "cntr"),
selected = "outcome")
),
mainPanel(
tabsetPanel(id="tabspanel", type = "tabs",
tabPanel(title = "Wilcox",
verbatimTextOutput(outputId = "p")))
)
)
)
server <- function(input, output, session) {
df <- reactive({
data.frame(dat[[input$y]], dat[[input$z]])
})
output$p <- renderPrint({
wilcox.test(df()[,1] ~ df()[,2])
})
}
shinyApp(ui=ui, server=server)
Gregor's guess is quite spot on; below snippet from the server codes:
dat_subset <- reactive({
req(input$selected_type)
filter(dat, outcome %in% input$selected_type)
})
output$scatterplot <- renderPlot({
ggplot(data = dat_subset(), aes_string(x = input$x, y = input$y, color = input$z)) + geom_boxplot() + labs()
})
output$nsdtable <- DT::renderDataTable({
DT::datatable(data = dat_subset()[, 1:4],
options = list(pageLength = 10),
rownames = FALSE)
})

Resources