I am providing here an executable simple R shiny application to plot two lines based on column names.
library(shiny)
library(reshape2)
library(ggplot2)
library(dplyr)
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
uiOutput("moreControls")
),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Cross dating", plotOutput("plot1"))
)
)
)
))
server <- shinyServer(function(input, output) {
datasetInput <- data.frame(chrono_A = rnorm(16,0),chrono_B = rnorm(16,0))
row.names(datasetInput) <- c(seq(2000, 2015))
col_names <- colnames(datasetInput)
output$moreControls <- renderUI({
checkboxGroupInput("variable", "Filter Options", col_names)
})
# Plot data
output$plot1 <- renderPlot({
datasetInput_short <- mutate(datasetInput, year = as.numeric(row.names(datasetInput)))
datasetInput_short <- melt(datasetInput_short, id = c("year"))
datasetInput_short <- dplyr::filter(datasetInput_short, variable %in% input$variable)
ggplot(datasetInput_short, aes(x = year, y = value, group = variable, col = variable)) +
geom_line() + theme_bw() + ylim(-3, 3)
})
})
shinyApp(ui = ui, server = server)
I would like to add two features, which would allow me to move the plotted lines in two ways:
By adding a window where I can directly add the final year for the curve (ideally, the current final year would be entered automatically)
By adding two additional buttons (+ and -), and by clicking them I move each line by one year
Please, see the image below:
Any suggestion is highly appreciated.
I reread your description, maybe this might be helpful, though not entirely sure this is what you have in mind.
You can add two textInput widgets and then add filters to your data so that the data displayed for A and B have years less than these values.
In addition, you can have reactiveValues that include an offsets for A and B that increase/decrease when the buttons are pressed. These offsets will change the year column from the filtered data for A and/or B.
server <- shinyServer(function(input, output) {
datasetInput <- data.frame(chrono_A = rnorm(16,0),chrono_B = rnorm(16,0))
row.names(datasetInput) <- c(seq(2000, 2015))
col_names <- colnames(datasetInput)
rv <- reactiveValues(offset_A = 0, offset_B = 0)
observeEvent(input$but_plus_A, {
rv$offset_A <- rv$offset_A + 1
})
observeEvent(input$but_minus_A, {
rv$offset_A <- rv$offset_A - 1
})
observeEvent(input$but_plus_B, {
rv$offset_B <- rv$offset_B + 1
})
observeEvent(input$but_minus_B, {
rv$offset_B <- rv$offset_B - 1
})
datasetInput_short <- reactive({
datasetInput %>%
mutate(year = as.numeric(row.names(.))) %>%
pivot_longer(cols = starts_with("chrono_"), names_to = "variable", values_to = "value") %>%
dplyr::filter(variable %in% input$variable,
(variable == "chrono_A" & year < input$sel_A) | (variable == "chrono_B" & year < input$sel_B)) %>%
mutate(year = if_else(variable == "chrono_A", year + rv$offset_A, year),
year = if_else(variable == "chrono_B", year + rv$offset_B, year))
})
output$moreControls <- renderUI({
list(
checkboxGroupInput("variable", "Filter Options", col_names),
textInput("sel_A", "Year A", 2015),
actionButton("but_plus_A", "", icon = icon("plus")),
actionButton("but_minus_A", "", icon = icon("minus")),
textInput("sel_B", "Year B", 2015),
actionButton("but_plus_B", "", icon = icon("plus")),
actionButton("but_minus_B", "", icon = icon("minus"))
)
})
# Plot data
output$plot1 <- renderPlot({
ggplot(datasetInput_short(), aes(x = year, y = value, group = variable, col = variable)) +
geom_line() + theme_bw() + ylim(-3, 3)
})
})
Edit:
Based on OP comment below, say you do not know the column names, but there are always 2 columns to work with, you can do the following. You can use the column names vector col_names when filtering.
datasetInput_short <- reactive({
datasetInput %>%
mutate(year = as.numeric(row.names(.))) %>%
pivot_longer(cols = all_of(col_names), names_to = "variable", values_to = "value") %>%
dplyr::filter(variable %in% input$variable,
(variable == col_names[1] & year < input$sel_A) | (variable == col_names[2] & year < input$sel_B)) %>%
mutate(year = if_else(variable == col_names[1], year + rv$offset_A, year),
year = if_else(variable == col_names[2], year + rv$offset_B, year))
})
It is possible to dynamically generate more than 2 sets of inputs (for example, using 3: A, B, and C) but that would be a bit more complex.
Related
I am having trouble with the drop-down menu options and their outputs. Although I can see the list of options the output remains the same and doesn't change even though the user can pick a different person. Any suggestions are welcome! My code is below (I removed some sensitive information):
server.r
senators <- read.csv("senators.csv")
output$senator <- renderUI({
selectInput("variablex",
#inputID = "senator",
label = "Choose a U.S Senator from the list",
selected = senators$name,
choices = senators$name)
})
senTweets <- read.csv("person.year.count.csv")
person <- reactive({
req(variablex)
df <- senTweets %>%
group_by(input$variablex, year) %>%
top_n(input$a, n) %>%
ungroup() %>%
arrange(word, -n)
return(df)
})
observe({
df = input$df
})
output$plot <- renderPlot({
person () %>% mutate(word = reorder(word, n))
ggplot(aes(word, n, fill = factor(year))) +
geom_col(show.legend = FALSE) +
facet_wrap(~ year, scales = "free") + scale_fill_viridis_d() +
coord_flip() + labs(y="Word frequency", x="Term", title = paste("Top words used in 2020"))
})
}
ur.r
ui <- dashboardPage(
dashboardHeader(title = ""),
dashboardSidebar(sidebarMenu(
menuItem("Main", tabName = "Main", icon = icon("r-project")),
menuItem("ReadMe", tabName = "ReadMe", icon = icon("readme"))
)
),
dashboardBody(
tabItems(
tabItem(
tabName = "Main",
sidebarPanel(
helpText("text"),
uiOutput('senator'),
sliderInput(
"a",
label = "Select value to view top common words",
min = 1,
max = 10,
value = 5
),
),
mainPanel(
plotOutput("plot")
)
),
tabItem(tabName = "ReadMe",
includeMarkdown("README.md"))
),
)
)
UPDATE: I made the following changes as gss suggested but I still can't get the output to change, any tips? Also not sure if the observe made a difference but I added that line as well.
Let's try some debugging. I don't have data which you have, so I don't see other possibilities. After reading your code there are two parts which I'm not sure if there are correct. Here is the first part:
person <- reactive({
#req(variablex)
df <- senTweets %>%
group_by(input$variablex, year) %>%
top_n(input$a, n) %>%
ungroup() %>%
arrange(word, -n)
})
First of all, input$variablex is a name (senator's name), right? (Or should be at least). So I assume that senTweets data contains columns with the names which are present in senators$name. Otherwist it won't be possible to group by. input$variablex, as all inputs from shiny, is of type character, so the first thing is that you should probably use some knowledge about programming with dplyr (Programming with dplyr) and use .data[[input$variablex]]:
person <- reactive({
#req(variablex)
df <- senTweets %>%
group_by(.data[[input$variablex]], year) %>%
top_n(input$a, n) %>%
ungroup() %>%
arrange(word, -n)
})
This should not be a problem with input$a because it is just a number and even if top_n() function expects number, probably there are a implicit type conversion.
You can change the code according my adive or first you can check if you really get what you want when user chooses senator's name. To do this, add browser() function here:
person <- reactive({
#req(variablex)
df <- senTweets %>%
group_by(input$variablex, year) %>%
top_n(input$a, n) %>%
ungroup() %>%
arrange(word, -n)
browser()
})
(you may need to add req(input$variablex) at the beginning, otherwise it can be that you do not choose any senator and after opening the app, you will immediately will be moved to the console in RStudio)
When you open the app, choose senator, then go back to RStudio and you should be in debugging mode. Type df in the console and check if this table looks as you think it should.
The second part of your code which seems suspicious is this one:
output$plot <- renderPlot({
person () %>% mutate(word = reorder(word, n))
ggplot(data = person(), aes(word, n, fill = factor(year))) +
geom_col(show.legend = FALSE) +
facet_wrap(~ year, scales = "free") + scale_fill_viridis_d() +
coord_flip() + labs(y="Word frequency", x="Term", title = paste("Top words used in 2020"))
})
Especially this: person () %>% mutate(word = reorder(word, n)) (it changes person() data, but do not save those changes!) doesn't seem to do anything useful. More sense would be to have:
output$plot <- renderPlot({
person () %>% mutate(word = reorder(word, n)) %>%
ggplot(aes(word, n, fill = factor(year))) +
geom_col(show.legend = FALSE) +
facet_wrap(~ year, scales = "free") + scale_fill_viridis_d() +
coord_flip() + labs(y="Word frequency", x="Term", title = paste("Top words used in 2020"))
})
Problem:
I was trying to build a shiny app that plot frequency of n-grams based on a user specified column from a user uploaded csv. In addition, a function was added to plot the senetiment over time, based on a date column specified by the user as well.
The app was working okay locally, with Warning, but failed work after published. Please see the following for a reproducible example.
Preparation: libraries and example data
# Load R packages
library(shiny)
library(tidyverse)
library(shinythemes)
library(lubridate)
library(tidytext)
library(textdata)
# Creating a example csv file for upload
Sample_csv <-
data.frame(text = janeaustenr::emma,
id = 1:length(janeaustenr::emma),
date = sample(seq(as.Date('1900/01/01'), as.Date('1920/01/01'), by="day"),
replace = T,
length(janeaustenr::emma)))
write.csv(Sample_csv, "Sample_csv.csv", row.names = F)
UI
ui <- fluidPage(theme = shinytheme("united"),
titlePanel("Text glancer"),
sidebarLayout(
sidebarPanel(
# Input: Select a file ----
fileInput("csv_file", "Feed csv here",
multiple = FALSE,
accept = c(".csv")),
#Conditional panel
conditionalPanel(
# use a server side condition
condition = "output$fileUploaded",
# Input: Select ----
uiOutput("text_select"),
# Input: Select ----
uiOutput("date_select"),
# Input: Simple integer interval ----
sliderInput("top_frequency", "Top n ngrams to be plotted:",
min = 5, max = 20, value = 10),
# Input: Select ----
selectInput("ngrams", "Ngrams of your choice:",
c("Single word" = 1,
"Bigram" = 2,
"Trigram" = 3)
)
),
# Submit bottom
submitButton("Update View", icon("refresh"))
),
# sidebarPanel
mainPanel(
tabsetPanel(
tabPanel(h2("Most frequenlty used n-grams"),
plotOutput("frequency_plot", height = 900, width = 1200)),
tabPanel(h2("Sentiment of the months"),
plotOutput("sentiment_plot", height = 900, width = 1200))
)
)
)
)
server
server <- function(input, output, session) {
# create reactive version of the dataset (a data.frame object)
LOAD_DATA <- reactive({
infile <- input$csv_file
if (is.null(infile))
{return(NULL)}
{read_csv(infile$datapath)}
})
# inform conditionalPanel wheter dropdowns sohould be hidden
output$fileUploaded <- reactive({
return(!is.null(LOAD_DATA()))
})
outputOptions(output, 'fileUploaded', suspendWhenHidden=FALSE)
## update 'column' selectors
output$text_select <- renderUI({
if(is.null(LOAD_DATA()))
{return(NULL)}
else
selectInput("text_col", "Select the text column:", colnames(LOAD_DATA()))
})
output$date_select <- renderUI({
if(is.null(LOAD_DATA()))
{return(NULL)}
else
selectInput("date_col", "Select the date column (ymd):", colnames(LOAD_DATA()))
})
# Create reactive parameters
TOP_FREQUENCY <- reactive({
input$top_frequency
})
N_GRAMS <- reactive({
as.numeric(as.character(input$ngrams))
})
# Output frequency of ngrams
output$frequency_plot <- renderPlot( {
if(is.null(LOAD_DATA()))
{return(NULL)}
else{
WORK_DATA <- LOAD_DATA()[,c(input$text_col,
input$date_col)]
names(WORK_DATA) <- c("TEXTS", "DATES")
CSV_DOC_N_Grams <-
WORK_DATA %>%
# LOAD_DATA() %>%
# select(TEXTS = TEXT_COL(), DATES = DATE_COL()) %>%
mutate(TEXTS = gsub("http.*", " ", TEXTS)) %>%
# mutate(text = gsub("\\#.* |\\#.* .|\\#.* ,", " ", text)) %>%
unnest_tokens(words, TEXTS, token = "ngrams", n = N_GRAMS()) %>%
select(words) %>%
filter(str_detect(words, "[a-zA-Z]")) %>%
separate(words, c("word1","word2","word3"),sep = " ", remove = F) %>%
filter(! word1 %in% stop_words$word &
! word2 %in% stop_words$word&
! word3 %in% stop_words$word)
#Counting ngrams
CSV_DOC_N_Gramss_Count <-
CSV_DOC_N_Grams %>%
count(words, sort=T) %>%
select(N_Gram_Text = words,
N_Gram_Count = n)
#Plotting ngram frequency
CSV_DOC_N_Gramss_Count_freq <-
CSV_DOC_N_Gramss_Count %>%
mutate(N_Gram_Text = fct_reorder(N_Gram_Text, N_Gram_Count)) %>%
top_n(TOP_FREQUENCY(), N_Gram_Count) %>%
ggplot(aes(x = N_Gram_Text,
y = N_Gram_Count,
fill = N_Gram_Count)) +
geom_col()+
coord_flip() +
scale_fill_gradient2()+
labs(title = paste0("Top ", TOP_FREQUENCY(), " ngrams used in csv doc"),
x = "ngrams",
y = "frequency") +
theme_bw()+
theme(legend.position = "none",
axis.text.x = element_text(face='bold',size=12),
axis.text.y = element_text(face='bold',size=12),
axis.title.x = element_text(face='bold',size=18),
axis.title.y = element_blank())
print(CSV_DOC_N_Gramss_Count_freq)
}
})
output$sentiment_plot <- renderPlot( {
if(is.null(LOAD_DATA())){return(NULL)}
else{
WORK_DATA <- LOAD_DATA()[,c(input$text_col,
input$date_col)]
names(WORK_DATA) <- c("TEXTS", "DATES")
tk_afinn <-
WORK_DATA %>%
mutate(TEXTS = gsub("http.*", " ", TEXTS)) %>%
unnest_tokens(word, TEXTS) %>%
filter(! word %in% stop_words$word) %>%
filter(str_detect(word, "[a-zA-Z]")) %>%
filter(! DATES %in% NA) %>%
inner_join(get_sentiments("afinn")) %>%
mutate(YEAR_Month = ymd(paste(year(DATES),
month(DATES),
"1", sep="-"))) %>%
group_by(index = YEAR_Month) %>%
summarise(sentiment = sum(value))
tk_afinn_plot <-
tk_afinn %>%
ggplot(aes(x = index, y = sentiment)) +
geom_line()+
labs(x = "date (year-month)",
y = "sentiment of the month") +
theme_bw()+
theme(legend.position = "none",
axis.text.x = element_text(face='bold',size=12),
axis.text.y = element_text(face='bold',size=12),
axis.title.x = element_text(face='bold',size=18),
axis.title.y = element_blank())
print(tk_afinn_plot)
}
})
}
Fuse
shinyApp(ui = ui, server = server)
Warnings:
After loading the csv file, the local app reports :
"Problem with mutate() input TEXTS.
object 'TEXTS' not found
Input TEXTS is gsub("http.*", " ", TEXTS)."
After specify the text column and date column, both tab showed plots. However, after publishing it to shinyapp.io, it reports error and would not run.
Can anybody help with this issue? I have consulted the other thread includin this>https://stackoverflow.com/questions/47248534/dynamically-list-choices-for-selectinput-from-a-user-selected-column, but still no luck.
Any insight would be greatly appreciated!
I'm hoping to implement this ggplotly bug fix offered here:
https://community.plot.ly/t/bug-with-ggplot2-stat-ecdf-function/1187/4
into a Shiny reactive expression. The top plot below shows the ggplot() call results within Shiny (as expected), the bottom is from ggplotly().
When I try to insert data <- data[order(data$val), ] inside the reactive expression, I'm unable to subset as suggested by the fix: Error in data$val : object of type 'closure' is not subsettable and I can't seem to find any other place for it to work.
reproducible app.r:
library(tidyverse)
library(shiny)
library(shinydashboard)
library(plotly)
# generate sample p & t observation data
zone <- c(rep("a", 6), rep("b", 6), rep("c", 6), rep("d", 6))
set.seed(1)
val <- rnorm(24, 12, 18)
param <- rep(c("p", "t"), 12)
p_t <- data.frame(zone, val, param, stringsAsFactors = FALSE)
# sample elevation frequency data - too many obs to uncount all at once
set.seed(2)
val <- sample(50, 24)
count <- sample(200000, 24)
e_countcsv <- data.frame(zone, val, count, stringsAsFactors = FALSE) %>%
mutate(param = "elev")
shinyApp(
ui = fluidPage(
sidebarLayout(sidebarPanel(
selectizeInput(
"zone", "zone", choices = unique(p_t$zone),
selected = c("a"),
multiple = TRUE),
checkboxGroupInput("param", "parameter",
choices = c("elev", "p", "t"), selected =c("elev", "p"))
),
mainPanel(
tabsetPanel(position=c("right"),
tabPanel(strong("static cdf"),
br(),
plotOutput("reg_plot", height = "750px")) ,
tabPanel(strong("interactive cdf"),
br(),
plotlyOutput("plotlyPlot", height = "750px")) )))
),
server = function(input, output) {
data <- reactive({
p_t %>%
filter(param %in% input$param,
zone %in% input$zone) %>%
bind_rows({e_countcsv %>%
filter(param %in% input$param,
zone %in% input$zone) %>%
uncount(count)})
})
output$reg_plot <- renderPlot({
ggplot(data(), aes(val, color = param, linetype = zone)) +
labs(y = "proportion of total", x = NULL) +
stat_ecdf(pad = FALSE) + coord_flip()
})
output$plotlyPlot <- renderPlotly({
p <- ggplot(data(), aes(val, color = param, linetype = zone)) +
labs(y = "proportion of total", x = NULL) +
stat_ecdf(pad = FALSE) + coord_flip()
p <- ggplotly(p)
p
})
}
)
Any ideas? Thank you!
Like #MrGumble suggested you should not use data as a name because it points to a function (try to print data in your console and you will see the function).
Just give your dataset in the reactive expression another name and it will work:
data <- reactive({
dataset <- p_t %>%
filter(param %in% input$param,
zone %in% input$zone) %>%
bind_rows({e_countcsv %>%
filter(param %in% input$param,
zone %in% input$zone) %>%
uncount(count)})
dataset[order(dataset$val), ]
})
I have a complicated shiny app (here is a simpler example) which looks like that:
The app gives user the possibility to change four parameters (selectInput). The lower parameter depends on the highter one (ex. month on year, type on year and month and so on). Everything works but the fact that when I change one parameter, the other one changes too. It is needed in some situations, but not always. It is needed when the level chosen earlier does not exist in new configuration but for example when I have the following situation it should not be changed. Ex. I chose type 'AGD' and size 'medium' for some year and month and I show the prise or something for this combination. Then I would like to compare it to the same size in type 'RTV' so I change type parameter. Everything works but the size changes to the 'big' while I wanted it still to be 'medium'. I can make another click but what for? It is very inconvenient then...
Do you know how to deal with a problem like that?
I managed to do it for two dependencies using observe and reactive values, but for four dependencies it does not work.
Here is my code:
library("shiny")
library("plotly")
library("dplyr")
data <- data.frame(year = rep(c(rep(2018, 6), rep(2019, 11)), each = 5),
month = rep(c(7:12, 1:11), each = 5),
type = rep(c("AGD", "AGD", "AGD", "RTV", "RTV"), 6 + 11),
value = sample(1:100, 85),
size = rep(c("big", "small", "medium", "big", "miedium"), 6 + 11))
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
uiOutput("year"),
uiOutput("month"),
uiOutput("type"),
uiOutput("size")
),
mainPanel(
)
)
)
server <- function(input, output, session) {
output$year <- renderUI({
year <- data %>%
select(year) %>%
unique()
selectInput("year",
"YEAR",
year$year,
selected = max(year$year))
})
output$month <- renderUI({
month <- data %>%
filter(year == input$year) %>%
select(month) %>%
unique() %>%
arrange()
selectInput("month",
"MONTH",
month$month,
selected = max(month$month))
})
output$type <- renderUI({
type <- data %>%
filter(year == input$year,
month == input$month) %>%
select(type) %>%
unique() %>%
arrange()
selectInput("type",
"TYPE",
type$type,
selected = type$type[1])
})
output$size <- renderUI({
size <- data %>%
filter(year == input$year,
month == input$month,
type == input$type) %>%
select(size) %>%
unique() %>%
arrange()
selectInput("size",
"SIZE",
size$size,
selected = size$size[1])
})
}
shinyApp(ui = ui, server = server)
Issues With the Existing Code
There are a couple of issues with the code here and the solution allows us to introduce the concept of memory into the app. First and foremost there are two issues I would like to address right off the bat.
c("big", "small", "medium", "big", "medium") and not c("big", "small", "medium", "big", "miedium")
The uiOutput() and renderUI() combination results the server serving a new selectInput button, everytime the input is changed. Instead we can simply instantiate a static UI element and update it using updateSelectInput()
Solution
To solve this problem lets first fix 1) and 2) described above. Then we need to introduce the concept of memory. The server needs to know what was previously selected, so that we can set it as the default option when the selectInput is updated. We can store this as a regular list (a variable for year, month, type and size) or a reactive list using reactiveValues.
Its great that you have settled on a clear cut logic for the filtering options, there is a clear hierarchy from years-> months -> type -> size. However, everytime months was changed for example a new input was generated for type and size.
We would now like to introduce a simple logic where the input selection only modifies the memory selected_vals. Then a change in memory triggers the other inputs to be updated. This is best seen in the solution below.
Code Solution
library("shiny")
library("plotly")
library("dplyr")
data <- data.frame(year = rep(c(rep(2018, 6), rep(2019, 11)), each = 5),
month = rep(c(7:12, 1:11), each = 5),
type = rep(c("AGD", "AGD", "AGD", "RTV", "RTV"), 6 + 11),
value = sample(1:100, 85),
size = rep(c("big", "small", "medium", "big", "medium"), 6 + 11))
years = data %>% arrange(year) %>% .$year %>% unique(.)
month = data %>% arrange(month) %>% .$month %>% unique(.)
type = data %>% arrange(type)%>% .$type %>% unique(.)
size = data %>% arrange(size) %>%.$size %>% unique(.)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("year","Year",choices = years,selected = 2018),
selectInput("month","Month",choices = month,selected = 7),
selectInput("type","Type",choices = type,selected = "AGD"),
selectInput("size","Size",choices = size,selected = "big")
),
mainPanel(
)
)
)
server <- function(input, output, session) {
#------- Initialize the Memory ----------
selected_vals = reactiveValues(year = 2019,month = 7, type = "AGD", size = "big")
#------ Whenever any of the inputs are changed, it only modifies the memory----
observe({
req(input$year,input$month,input$type,input$size)
selected_vals$year <- input$year
selected_vals$month <- input$month
selected_vals$type <- input$type
selected_vals$size <- input$size
})
#------ Update all UI elements using the values stored in memory ------
observe({
year <- data %>%
select(year) %>%
unique()
updateSelectInput(session,"year",choices = year$year,selected = selected_vals$year)
})
observe({
month <- data %>%
filter(year == selected_vals$year) %>%
select(month) %>%
unique() %>%
arrange()
#Check if the value is in memory, if not return NULL (it defaults to the first element)
if (selected_vals$month %in% month$month) displayVal = selected_vals$month else displayVal = NULL
updateSelectInput(session,"month",choices = month$month,selected = displayVal)
})
observe({
type <- data %>%
filter(year == selected_vals$year,
month == selected_vals$month) %>%
select(type) %>%
unique() %>%
arrange()
#Check if the value is in memory, if not return NULL (it defaults to the first element)
if (selected_vals$type %in% type$type) displayVal = selected_vals$type else displayVal = NULL
updateSelectInput(session,"type",choices = type$type,selected = displayVal)
})
observe({
size <- data %>%
filter(year == selected_vals$year,
month == selected_vals$month,
type == selected_vals$type) %>%
select(size) %>%
unique() %>%
arrange()
#Check if the value is in memory, if not return NULL (it defaults to the first element)
if(selected_vals$size %in% size$size) displayVal = selected_vals$size else displayVal = NULL
updateSelectInput(session,"size",choices = size$size,selected = displayVal)
})
}
shinyApp(ui = ui, server = server)
Edit
As mentioned in the comment below there is a bug in the code. This is caused by the fact that then displayVal = NULL shiny sets the default value to display as the first element in he array. However we forget to store this in memory, selected_vals. The code below fixes this.
library("shiny")
library("plotly")
library("dplyr")
data <- data.frame(year = rep(c(rep(2018, 6), rep(2019, 11)), each = 5),
month = rep(c(7:12, 1:11), each = 5),
type = rep(c("AGD", "AGD", "AGD", "RTV", "RTV"), 6 + 11),
value = sample(1:100, 85),
size = rep(c("big", "small", "medium", "big", "medium"), 6 + 11))
years = data %>% arrange(year) %>% .$year %>% unique(.)
month = data %>% arrange(month) %>% .$month %>% unique(.)
type = data %>% arrange(type)%>% .$type %>% unique(.)
size = data %>% arrange(size) %>%.$size %>% unique(.)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("year","Year",choices = years,selected = 2018),
selectInput("month","Month",choices = month,selected = 7),
selectInput("type","Type",choices = type,selected = "AGD"),
selectInput("size","Size",choices = size,selected = "big")
),
mainPanel(
)
)
)
server <- function(input, output, session) {
#------- Initialize the Memory ----------
selected_vals = reactiveValues(year = 2019,month = 7, type = "AGD", size = "big")
#------ Whenever any of the inputs are changed, it only modifies the memory----
observe({
req(input$year,input$month,input$type,input$size)
selected_vals$year <- input$year
selected_vals$month <- input$month
selected_vals$type <- input$type
selected_vals$size <- input$size
})
#------ Update all UI elements using the values stored in memory ------
observe({
year <- data %>%
select(year) %>%
unique()
updateSelectInput(session,"year",choices = year$year,selected = selected_vals$year)
})
observe({
month <- data %>%
filter(year == selected_vals$year) %>%
select(month) %>%
unique() %>%
arrange()
#Check if the value is in memory, if not return NULL (it defaults to the first element)
if (selected_vals$month %in% month$month){
displayVal = selected_vals$month
}else{
displayVal = NULL
selected_vals$month = month$month[1]
}
updateSelectInput(session,"month",choices = month$month,selected = displayVal)
})
observe({
type <- data %>%
filter(year == selected_vals$year,
month == selected_vals$month) %>%
select(type) %>%
unique() %>%
arrange()
#Check if the value is in memory, if not return NULL (it defaults to the first element)
if (selected_vals$type %in% type$type){
displayVal = selected_vals$type
}else{
displayVal = NULL
selected_vals$type = tpye$type[1]
}
updateSelectInput(session,"type",choices = type$type,selected = displayVal)
})
observe({
size <- data %>%
filter(year == selected_vals$year,
month == selected_vals$month,
type == selected_vals$type) %>%
select(size) %>%
unique() %>%
arrange()
#Check if the value is in memory, if not return NULL (it defaults to the first element)
if(selected_vals$size %in% size$size){
displayVal = selected_vals$size
} else{
displayVal = NULL
selected_vals$size = size$size[1]
}
updateSelectInput(session,"size",choices = size$size,selected = displayVal)
})
}
shinyApp(ui = ui, server = server)
thanks to your answers, I managed to make a barplot that reacts according to the time unit (Week, Month, Year) and agregates data by time unit (the link is here) :
R Shiny - How to create a barplot that reacts according to the time unit (Week, Month, Year) and agregates data by time unit
Then, I wish to make a stacked barplot with two variables. For it, I generate the follow data frame with two variables (i.e. in my example: Imported_cases and Autochthonous_cases) and I apply the “melt” function. The UI is here :
library(shiny)
library(dplyr)
library(lubridate)
library(ggplot2)
library(scales)
library(reshape2)
Disease <- data.frame(
Date = seq(as.Date("2015/1/1"), as.Date("2017/1/1"), "days"),
Imported_cases = rep(1),Autochtonous_cases=rep(2))
Disease <- Disease %>% mutate(
Week = format(Date, "%Y-%m-%U"),
Month = format(Date, "%Y-%m"), Year = format(Date, "%Y"))
Disease<- melt(Disease, id = c("Date","Week","Month","Year"),
measured = c("Imported_cases", "Autochtonous_cases"))
print(head(Disease))
ui <- fluidPage(
dateRangeInput("daterange", "Choice the date",
start = min(Disease$Date),
end = max(Disease$Date),
min = min(Disease$Date),
max = max(Disease$Date),
separator = " - ", format = "dd/mm/yy",
startview = 'Month', language = 'fr', weekstart = 1),
selectInput(inputId = 'Time_unit',
label = 'Time_unit',
choices = c('Week', 'Month', 'Year'),
selected = 'Month'),
plotOutput("Disease"))
When I run my server, R Shiny displays : Error object 'variable' not found. You find bellow the server code :
server <- function(input, output) {
dateRangeInput <- reactive({
dataset <- subset(
Disease, Date >= input$daterange[1] & Date <= input$daterange[2])
dataset
})
selectInput = reactive({
dataset <- dateRangeInput() %>% group_by_(input$Time_unit) %>%
summarise(Sum = sum(value))
dataset
})
output$Disease <-renderPlot({
ggplot(data=selectInput(),
aes_string(x = input$Time_unit, y = "Sum",
fill = "variable")) +
geom_bar(stat = "identity")
})
}
shinyApp (ui = ui, server = server)
I don't know if the problem is the code of selectInput or the code of output$Disease. I don't understand why Shiny doesn't find "variable" (cf. print(head(Disease)). Thank you for your help (I hope to be clear).
Hier is code which is going to work and create the stacked bar plot:
library(shiny)
library(dplyr)
library(lubridate)
library(ggplot2)
library(scales)
library(reshape2)
Disease<-data.frame(Date=seq(as.Date("2015/1/1"), as.Date("2017/1/1"), "days"),Cases=rep(1),Autochtonous_cases=rep(2))
Disease <- Disease %>% mutate(Week = format(Date, "%Y-%m-%U"),Month = format(Date, "%Y-%m"), Year = format(Date, "%Y"))
Disease<-melt(Disease,id=c("Date","Week","Month","Year")) # just id
ui <- fluidPage(
dateRangeInput("daterange", "Choice the date",
start = min(Disease$Date),
end = max(Disease$Date),
min = min(Disease$Date),
max = max(Disease$Date),
separator = " - ", format = "dd/mm/yy",
startview = 'Month', language = 'fr', weekstart = 1),
selectInput(inputId = 'Time_unit',
label='Time_unit',
choices=c('Week','Month','Year'),
selected='Month'),
plotOutput("Disease"))
server <- function(input, output) {
dateRangeInput<-reactive({
dataset <- subset(Disease, Date >= input$daterange[1] & Date <= input$daterange[2])
dataset
})
selectInput= reactive({
dataset <- dateRangeInput() %>% group_by_(input$Time_unit,"variable") %>% summarise(Sum = sum(value)) #I have added here grouping as variable
print(head(dataset))
dataset
})
output$Disease <-renderPlot({
ggplot(data=selectInput(), aes_string(x=input$Time_unit,y="Sum", fill = "variable")) + geom_bar(stat="identity") +
labs(title="Disease", y ="Number of cases") +
theme_classic() +
theme(plot.title = element_text(hjust = 0.5))
})
}
shinyApp (ui = ui, server = server)
I guess this is what You are looking for. You had small mistakes in melt function, setting up only id variables is fair enough, second thing is to consider the created variable column in group_by_ (as You wanna get the count of cases and autochtonous cases), and last is using variable as an fill argument in ggplot.