Problem with Shiny and Plotly. Error in UseMethod - r

I am trying to render plotly based on the input selection. I am receiving an error: Warning: Error in UseMethod: no applicable method for 'layout' applied to an object of class "shiny.tag".
library(dplyr)
library(ggplot2)
library(shiny)
library(shinydashboard)
library(ggplot2)
library(plotly)
library(plotDK)
df <- tibble(postnr = c(4000, 2000,9000),
kommunekoder = c(101, 147,153),
reg_code = c(1,2,3),
count = c(3,5,6))
ui <- shinyUI(fluidPage(
box(plotlyOutput("map")),
box(selectInput(
"level",
label= "Select map level:",
choices = c("Zip code", "Municipality", "Region"),
multiple = FALSE,
selected = "Zip code"),
solidHeader = TRUE,
width = "5",
height = "75px",
status = "primary"
)))
server <- shinyServer(function(input, output) {
plot <- reactive({ifelse(input$level == "Zip code", plotDK(plotlevel = "zipcode", value = "count", id ="postnr" , data = df, show_missing = TRUE),
ifelse(input$level == "Municipality", plotDK(plotlevel = "municipality", value = "count", id ="kommunekoder" , data = df, show_missing = TRUE),
plotDK(plotlevel = "region", value = "count", id ="reg_code" , data = df, show_missing = TRUE)))})
output$map <- renderPlotly({ggplotly(plot() + scale_fill_continuous(name ="Number of firms")) %>% layout(height = 500, width = 650)
})
})
shinyApp(ui = ui, server)
If I run the code in outside Shiny, it works:
plot <- plotDK(plotlevel = "region", value = "count", id ="reg_code" , data = df, show_missing = TRUE)
ggplotly(plot + scale_fill_continuous(name ="Number of firms")) %>% layout(height = 500, width = 650)
What am I missing?

Would it be possible to change your Server function to:
server <- shinyServer(function(input, output) {
output$map <- renderPlotly({
if(input$level == "Zip code"){
p <- plotDK(plotlevel = "zipcode", value = "count", id ="postnr" ,
data = df, show_missing = TRUE)
}
if(input$level == "Municipality"){
p <- plotDK(plotlevel = "municipality", value = "count", id ="kommunekoder" ,
data = df, show_missing = TRUE)
}
if(input$level == "Region"){
p <- plotDK(plotlevel = "region", value = "count", id ="reg_code" ,
data = df, show_missing = TRUE)
}
ggplotly(p + scale_fill_continuous(name ="Number of firms")) %>% layout(height = 500, width = 650)
})
})
This embeds the plotting function inside the map output. If you really need the plot to be stored in a reactive, then this won't work, but if you just need to make the plot so it can be rendered in the output, this should do the trick.

Related

Incorporating Shiny app sliders into ggplot graphs

I am trying to filter the dataframe that I use for my graph based on the input values from two sliders. I have sliders that select a range for temperature and wind speed in a given NFL game. (Each row of the dataframe is a quarterback's performance in a game along with game weather and QB measurables, so at least two rows per game.) How do I take the output from the sliders and filter the dataframe based on that? For example, how do I filter df$temperature based on the slider with id "z"?
library(shiny)
library(dplyr)
library(ggplot2)
library(tidyr)
df = read.csv("Combined_QB_Game_Data.csv")
df[df == "--"] = NA
df$Passes.Completed = as.double(df$Passes.Completed)
df$Passes.Attempted = as.double(df$Passes.Attempted)
df$Completion.Percentage = as.double(df$Completion.Percentage)
df$Passing.Yards = as.double(df$Passing.Yards)
df$Passing.Yards.Per.Attempt = as.double(df$Passing.Yards.Per.Attempt)
df$TD.Passes = as.double(df$TD.Passes)
df$Sacks = as.double(df$Sacks)
ui = fluidPage(
titlePanel("QB Performance"),
sidebarLayout(
sidebarPanel(
selectInput(inputId = "x",
label = "Options:",
choices = c("Ht", "Wt",
"Forty", "Vertical", "BenchReps",
"BroadJump", "Cone", "Shuttle", "Round", "Pick"),
selected = "Ht"),
selectInput(inputId = "y",
label = "Options2:",
choices = c("Passer.Rating","Passes.Completed","Passes.Attempted","Completion.Percentage","Passing.Yards","Passing.Yards.Per.Attempt","TD.Passes","Ints","Sacks"),
selected = "Passer.Rating"),
sliderInput("z", "Tempurature",
min = 0, max = 100, value = c(25, 75)),
sliderInput("a", "Wind",
min = 0, max = 30, value = c(5, 25))
),
mainPanel(
plotOutput(outputId = "scatterplot")
)
)
)
server = function(input, output) {
output$scatterplot = renderPlot({
p = ggplot(data = df) +
aes_string(x = input$x, y = input$y) +
geom_point()+
geom_smooth(method = "lm")
plot(p)
})
}
shinyApp(ui, server)
One possibility is to treat the data in a reactive conductor:
ggdata <- reactive({
bounds <- input$z
df %>% filter(temperature > bounds[1], temperature < bounds[2])
})
and then use it in the renderPlot:
output$scatterplot = renderPlot({
ggplot(data = ggdata()) +
aes_string(x = input$x, y = input$y) +
geom_point() +
geom_smooth(method = "lm")
})

R shiny: How to copy data derived from plotly_selection events into a data frame/table and update each time by pressing an actionButton?

I'm putting together a shiny app to play around with some athlete GPS data. Essentially, I'm looking to structure my script so that each time the user selects an area of interest on the plotly plot and the "Add" actionButton is clicked, the table below will add the calculated Start_time, Time_at_peak, Max_velocity, Time_to_peak, and Distance_to_peak values.
The issue can be seen in the GIF below: - Once the area of interest is selected and the "Add" button clicked, the first values seem correct. However, when the user selects a second area of interest to add to the table, it overwrites the initial entry and will keep overwriting each time a new selection is made. This is seemingly because because the code is inside the observeEvent(event_data("plotly_selected"), which, confusingly, it needs to be in order to calculate the variables of interest.
I'm currently a little stumped and can't seem to find any relevant information. As such, any guidance would be greatly appreciated!
Here is a we transfer link to some test data that can be uploaded to the app: https://wetransfer.com/downloads/5a7c5da5a7647bdbe133eb3fdac79c6b20211119052848/afe3e5
library(shiny)
library(readr)
library(DT)
library(dplyr)
library(plotly)
library(lubridate)
library(tidyr)
library(purrr)
library(htmlwidgets)
library(shinydashboard)
library(dashboardthemes)
library(shinyjs)
x_df <- data.frame(Start_time = character(1), Time_at_peak = character(1), Max_velocity = integer(1),
Time_to_peak = integer(1), Distance_to_peak = integer(1))
x_df$Start_time <- as.character("0:00:00.0")
x_df$Time_at_peak <- as.character("0:00:00.0")
x_df$Max_velocity <- as.integer(0)
x_df$Time_to_peak <- as.integer(0)
x_df$Distance_to_peak <- as.integer(0)
runApp(shinyApp(
ui=(fluidPage(
titlePanel("Event to Table"),
mainPanel(
fileInput(
inputId = "filedata",
label = "Upload data file (.csv)",
accept = c(".csv")),
plotlyOutput('myPlot'),br(),br(),br(),br(),
DTOutput("testing"), br(), br(),
fluidRow(
valueBoxOutput("starttime", width = 2),
valueBoxOutput("endtime", width = 2),
valueBoxOutput("maxvelocity", width = 2),
valueBoxOutput("timediff", width = 3),
valueBoxOutput("distance", width = 3)
),
useShinyjs(),
fluidRow(
div(style = "text-align:center", actionButton("Add", "Add Data to Table"),
downloadButton("export", "Export Table as .CSV"))), br(),
DTOutput(outputId = "table")))
),
server = (function(input, output, session) {
data<-reactive({
req(input$filedata)
read.csv(input$filedata$datapath, header = TRUE)%>%
rename(Velocity = 'Speed..m.s.',
Player = 'Player.Display.Name',
Latitude = 'Lat',
Longtitude = 'Lon',
AccelImpulse = 'Instantaneous.Acceleration.Impulse',
HeartRate = 'Heart.Rate..bpm.')
})
observe({
thedata<-data()
updateSelectInput(session, 'y', choices = names(data))
})
output$myPlot = renderPlotly({
plot_ly(data = data(), x = ~Time, y = ~Velocity, height = 450,
marker =list(color = 'rgb(132,179,202)', size = 0.1),
line = list(color = 'rgb(132,179,202)', size = 0.1, width = 0.9),
type = 'scatter', mode = 'markers+lines') %>%
layout(dragmode = "select",
showlegend = F,
title = list(text = 'Velocity Trace', font = list(size = 20)),
xaxis = list(title = list(text = "", standoff = 0), nticks = 10),
yaxis = list(title = list(text = "Velocity (m/s)"), nticks = 5, gridcolor = "#46505a"),
font = list(color = 'black'),
margin = list(t = 70))
})
observeEvent(event_data("plotly_selected"), {
event.data <- event_data("plotly_selected")
if (max(event.data$y) < 1.5) {
maxvel <- (max(event.data$y))
maxpos <- match(maxvel, event.data$y)
}
else {
filter1 <- filter (event.data, event.data$y > 1.5)
maxvel <- (max(filter1$y))
maxpos <- match(maxvel, event.data$y)
}
zero_val <- function(x) x == 0
zero_index <- event.data$y[1:maxpos] %>% detect_index(zero_val, .dir = "backward")
if (zero_index==0) {starttime <- event.data$x[1]}
else {starttime <- event.data$x[zero_index]}
endvel <- which.max(event.data$y)
endtime <- event.data$x[endvel]
timediff <- paste(today(), endtime) %>% as_datetime() - paste(today(), starttime) %>% as_datetime()
sprint <- as_tibble(event.data$y[zero_index:endvel])
ms <- as_tibble(rep(0.1, count(sprint)))
time_vel <- cbind(ms, sprint)
distance <- sum(time_vel[1]*time_vel[2])
sprintselect <- as_tibble(cbind(Start_time = starttime,
Time_at_peak = endtime,
Max_velocity = round(maxvel, 2),
Time_to_peak = round(timediff, 1),
Distance_to_peak = round(distance, 1)))
values <- reactiveValues()
values$df <- x_df
addData <- observe({
if(input$Add > 0) {
newLine <- isolate(data.frame(Start_time = sprintselect$Start_time, Time_at_peak = sprintselect$Time_at_peak,
Max_velocity = sprintselect$Max_velocity,
Time_to_peak = sprintselect$Time_to_peak,
Distance_to_peak = sprintselect$Distance_to_peak,
stringsAsFactors= FALSE))
values$df <- isolate(rbind(values$df, newLine))}
})
output$testing <- renderDataTable({values$df})
})
})
))
I've managed to figure it out and thought I'd post an answer rather than delete the question - just in case someone out there is looking to do a similar thing and they are unsure how to do it.
Firstly, I removed the pre-populated table x_df from the beginning - it was no longer required.
Although I thought the code needed to sit inside the observeEvent(event_data("plotly_selected") to function correctly, it did not - thankfully, because that was at the root of the issue. Instead, I used observeEvent(input$Add, { (which is the correct code to use as opposed to if(input$Add > 0)) to anchor the event to the click of the Add button.
The values <- reactiveValues() was placed outside the observeEvent() and an IF statement was used to either add the data to the values$df data frame on it's own if it was the first selection, or bind it to the existing saved data.
Here's the new code and a GIF demonstrating.
library(shiny)
library(readr)
library(DT)
library(dplyr)
library(plotly)
library(lubridate)
library(tidyr)
library(purrr)
library(htmlwidgets)
library(shinydashboard)
library(dashboardthemes)
library(shinyjs)
runApp(shinyApp(
ui=(fluidPage(
titlePanel("Event to Table"),
mainPanel(
fileInput(
inputId = "filedata",
label = "Upload data file (.csv)",
accept = c(".csv")),
plotlyOutput('myPlot'),br(),br(),br(),br(),
DTOutput("testing"), br(), br(),
fluidRow(
valueBoxOutput("starttime", width = 2),
valueBoxOutput("endtime", width = 2),
valueBoxOutput("maxvelocity", width = 2),
valueBoxOutput("timediff", width = 3),
valueBoxOutput("distance", width = 3)
),
useShinyjs(),
fluidRow(
div(style = "text-align:center", actionButton("Add", "Add Data to Table"),
downloadButton("export", "Export Table as .CSV"))), br(),
DTOutput(outputId = "table")))
),
server = (function(input, output, session) {
values <- reactiveValues(df_data = NULL)
data<-reactive({
req(input$filedata)
read.csv(input$filedata$datapath, header = TRUE)%>%
rename(Velocity = 'Speed..m.s.',
Player = 'Player.Display.Name',
Latitude = 'Lat',
Longtitude = 'Lon',
AccelImpulse = 'Instantaneous.Acceleration.Impulse',
HeartRate = 'Heart.Rate..bpm.')
})
observe({
thedata<-data()
updateSelectInput(session, 'y', choices = names(data))
})
output$myPlot = renderPlotly({
plot_ly(data = data(), x = ~Time, y = ~Velocity, height = 450,
marker =list(color = 'rgb(132,179,202)', size = 0.1),
line = list(color = 'rgb(132,179,202)', size = 0.1, width = 0.9),
type = 'scatter', mode = 'markers+lines') %>%
layout(dragmode = "select",
showlegend = F,
title = list(text = 'Velocity Trace', font = list(size = 20)),
xaxis = list(title = list(text = "", standoff = 0), nticks = 10),
yaxis = list(title = list(text = "Velocity (m/s)"), nticks = 5, gridcolor = "#46505a"),
font = list(color = 'black'),
margin = list(t = 70))
})
observeEvent(input$Add, {
event.data <- event_data("plotly_selected")
if (max(event.data$y) < 1.5) {
maxvel <- (max(event.data$y))
maxpos <- match(maxvel, event.data$y)
}
else {
filter1 <- filter (event.data, event.data$y > 1.5)
maxvel <- (max(filter1$y))
maxpos <- match(maxvel, event.data$y)
}
zero_val <- function(x) x == 0
zero_index <- event.data$y[1:maxpos] %>% detect_index(zero_val, .dir = "backward")
if (zero_index==0) {starttime <- event.data$x[1]}
else {starttime <- event.data$x[zero_index]}
endvel <- which.max(event.data$y)
endtime <- event.data$x[endvel]
timediff <- paste(today(), endtime) %>% as_datetime() - paste(today(), starttime) %>% as_datetime()
sprint <- as_tibble(event.data$y[zero_index:endvel])
ms <- as_tibble(rep(0.1, count(sprint)))
time_vel <- cbind(ms, sprint)
distance <- sum(time_vel[1]*time_vel[2])
sprintselect <- as_tibble(cbind(Start_time = starttime,
Time_at_peak = endtime,
Max_velocity = round(maxvel, 2),
Time_to_peak = round(timediff, 1),
Distance_to_peak = round(distance, 1)))
newLine <- isolate(data.frame(Start_time = sprintselect$Start_time, Time_at_peak = sprintselect$Time_at_peak,
Max_velocity = sprintselect$Max_velocity,
Time_to_peak = sprintselect$Time_to_peak,
Distance_to_peak = sprintselect$Distance_to_peak,
stringsAsFactors= FALSE))
if (is.null(values$df)){
values$df <- newLine}
else {
values$df <- isolate(rbind(values$df, newLine))}
output$testing <- renderDataTable({values$df})
})
})
))

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.

ggplot2 isn't recognizing shiny's reactive data

everyone!
I'm trying hard here to get the data I grouped by the 'fc' function and it was supposed to be in this new dataset 'reac', where I wanted it to be updated when a user input which variable he/she wants to use at shiny's UI (input$x, input$y, input$color). Then I want to use this new reac dataset in ggplot, but the 'aes_string() isn't working, the compiler doesn't recognize the data type as a dataframe and I'm getting a "Can't convert NULL to a quosure" error and "Unknown input:tbl_df" error.
Sorry for the bad english, it isn't my mothertongue! :(
Thanks in advance!
PS: Link for the code
library(shiny)
library(plotly)
library(rsconnect)
library(sidrar)
library(dplyr)
library(ggplot2)
#dados261<-get_sidra(api="/t/261/n2/all/n3/all/v/allxp/p/last%2011/c1/allxt/c2/allxt/c58/1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,2792,2793,3244,3245/d/v93%203")
load("C:/Users/Fausto/Desktop/dados_1.RData")
colnames(dados261)<-c("nt_cod","nt","regiao_cod","regiao","va_cod","va","ano_cod","ano","dom_cod","dom","sexo_cod","sexo","id_cod","id","um_cod","um","valor")
names1 <- c("nt_cod","regiao_cod","va_cod","ano_cod","dom_cod","sexo_cod","id_cod","um_cod")
dados261[names1] <- sapply(dados261[names1],as.numeric)
years<-as.numeric(sort(unique(dados261$ano)))
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
h1("Tabela 261 - SIDRA - Dados Gerais"),
selectInput("x", label = "Eixo x", choices = list("Região" = "regiao", "Idade" = "id", "Sexo" = "sexo", "Domicílio" = "dom", "Valores" = "valor"), selected = "regiao"),
selectInput("y", label = "Eixo Y", choices = list("Região" = "regiao", "Idade" = "id", "Sexo" = "sexo", "Domicílio" = "dom", "Valores" = "valor"), selected = "valor")
),
mainPanel(
tabsetPanel(
tabPanel("Gráfico de barras",
plotOutput("plot", width = "80%", height = "80%"),
radioButtons("color", label = "Preenchimento", choices = list("Região" = "regiao", "Idade" = "id", "Sexo" = "sexo", "Domicílio" = "dom", "Nenhuma" = "id"), selected = "nn", inline = TRUE)),
tabPanel("Série Temporal",
plotOutput("plot2", width = "100%", height = "100%"),
sliderInput("ano", label = "Anos", min = min(years), max= max(years), value=c(min(years),max(years)))
)
)
)
)
)
server <- function(input, output){
fc<- function(data, ...) {
data %>% group_by_(...) %>%
summarise(valor2 = sum(valor, na.rm = TRUE)) -> data
return(data)
}
reac<-reactive({
fc(dados261, input$x, input$y, input$color)
})
output$plot <- renderPlot({
eixox<-as.character(reac()[,1])
eixoy<-as.numeric(reac()$valor2)
eixoz<-as.character(reac()[,2])
p<- reac() %>%
ggplot() +
aes_q(eixox, eixoy, fill= eixoz) +
geom_bar(stat = "identity")
ggplotly(p)
}, height = 600, width = 900)
}
shinyApp(ui = ui, server = server)
When I loaded your .Rdata, and ran the code with changes suggested by Alejandro, my graphs changed.
loaded the libraries excluding sidrar and rsconnect, and ran the code:
library(shiny)
library(plotly)
library(dplyr)
library(ggplot2)
load("/Users/username/Downloads/RData.RData")
#Renomeando as colunas
colnames(dados261)<-c("nt_cod","nt","regiao_cod","regiao","va_cod","va","ano_cod","ano","dom_cod","dom","sexo_cod","sexo","id_cod","id","um_cod","um","valor")
#transformando as variáveis que estao como "char" em "integer"
names1 <- c("nt_cod","regiao_cod","va_cod","ano_cod","dom_cod","sexo_cod","id_cod","um_cod")
dados261[names1] <- sapply(dados261[names1],as.numeric)
years<-as.numeric(sort(unique(dados261$ano)))
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
h1("Tabela 261 - SIDRA - Dados Gerais"),
selectInput("x", label = "Eixo x", choices = list("Regiao" = "regiao", "Idade" = "id", "Sexo" = "sexo", "Domicilio" = "dom", "Valores" = "valor"), selected = "regiao"),
selectInput("y", label = "Eixo Y", choices = list("Regiao" = "regiao", "Idade" = "id", "Sexo" = "sexo", "Domicilio" = "dom", "Valores" = "valor"), selected = "valor")
),
mainPanel(
tabsetPanel(
tabPanel("Grafico de barras",
plotOutput("plot", width = "80%", height = "80%"),
radioButtons("color", label = "Preenchimento", choices = list("Regiao" = "regiao", "Idade" = "id", "Sexo" = "sexo", "Domicilio" = "dom"), selected = "id", inline = TRUE)),
tabPanel("Serie Temporal",
plotOutput("plot2", width = "100%", height = "100%"),
sliderInput("ano", label = "Anos", min = min(years), max= max(years), value=c(min(years),max(years)))
)
)
)
)
)
server <- function(input, output){
fc<- function(data, ...) {
data %>% group_by_(...) %>%
summarise(valor2 = sum(valor, na.rm = TRUE)) -> data
return(data)
}
reac<-reactive({
fc(dados261, input$x, input$y, input$color)
})
output$plot <- renderPlot({
eixox<-as.character(reac()[,1])
eixoy<-as.numeric(reac()$valor2)
eixoz<-as.character(reac()[,3])
reac() %>%
ggplot() +
aes_string(eixox, eixoy, fill= eixoz) +
geom_bar(stat = "identity")
}, height = 600, width = 900)
}
shinyApp(ui,server)

Resources