I am new to Shiny and, as an exercise, I am trying to assess global trends over time using the Gapminder data set. My aim is to produce a basic app that allows me to plot life expectancy (lifeExp), population (pop) and GDP per capita (gdpPercap) over time (year) separately. However, when I enter the following code all I get is a ggplot with a straight line. What am I missing?
Thanks in advance!
library(shiny)
library(gapminder)
library(dplyr)
library(ggplot2)
ui <- fluidPage(
selectInput(inputId = "variables",
label = "Select Variable",
choices = names(gapminder[, 4:6])),
plotOutput("plot")
)
server <- function(input, output){
output$plot <- renderPlot({
data <- gapminder %>% group_by(year) %>%
summarise(lifeExp = mean(lifeExp, na.rm = T),
pop = mean(pop, na.rm = T),
gdpPercap = mean(gdpPercap, na.rm = T))
ggplot(data, aes(x = year, y = input$variables)) + geom_line()
})
}
shinyApp(ui = ui, server = server)
With modern versions of ggplot2 rlang, we may modify the aes call to aes(x = year, y = .data[[input$variables]])) and do:
library(shiny)
library(gapminder)
library(dplyr)
library(ggplot2)
ui <- fluidPage(
selectInput(inputId = "variables",
label = "Select Variable",
choices = names(gapminder[, 4:6])),
plotOutput("plot")
)
server <- function(input, output){
output$plot <- renderPlot({
data <- gapminder %>% group_by(year) %>%
summarise(lifeExp = mean(lifeExp, na.rm = TRUE),
pop = mean(pop, na.rm = TRUE),
gdpPercap = mean(gdpPercap, na.rm = TRUE))
ggplot(data, aes(x = year, y = .data[[input$variables]])) +
geom_line()
})
}
shinyApp(ui = ui, server = server)
Reference: https://ggplot2.tidyverse.org/dev/articles/ggplot2-in-packages.html#using-aes-and-vars-in-a-package-function
Related
In the following shiny app, I have embedded the annual and monthly functions on line 7-15 into the selectizeInput placeholder on line 22.
library(shiny)
library(shinydashboard)
library(tidyquant)
library(tidyverse)
library(plotly)
annual <- function(x){
(x/lag(x, 12) - 1)*100
}
monthly <- function(x){
(x/lag(x) - 1)*100
}
ui <- dashboardPage(
dashboardHeader(title = 'Dashboard'),
dashboardSidebar(),
dashboardBody(
fluidRow(
box(selectizeInput('select_calculation', 'Calculation',
choices = c('Monthly' = monthly, 'Annual' = annual)
), height=80,width=4,
)
),
fluidRow(
box(plotlyOutput("chart"))
)
)
)
server <- function(input, output) {
output$chart <- renderPlotly({
chart <- tidyquant::tq_get('PCE',
from = '2019-01-01',
to = '2022-10-01',
get = 'economic.data') %>%
select(-symbol) %>%
mutate_if(is.numeric, ~input$select_calculation(.)) %>%
drop_na() %>% {
ggplot(., aes(x = date, y = price)) +
geom_line()
} %>%
ggplotly()
})
}
shinyApp(ui, server)
When I call one of the formulas in the code for my chart (e.g ~annual(.) on line 44, my app works fine.
However when I try to run this interactively using the selectizeInput option by amending line 44 as follows
mutate_if(is.numeric, ~input$select_calculation(.)) %>%
I get the following error. Is there any way to call a function interactively successfully?
I already wondered where you want to go with this. The issue is that input$select_calculation is a character not a function, i.e. to make your code work you have to parse the input using e.g.
output$chart <- renderPlotly({
calc_method <- eval(parse(text = input$select_calculation))
chart <- tidyquant::tq_get("PCE",
from = "2019-01-01",
to = "2022-10-01",
get = "economic.data"
) %>%
select(-symbol) %>%
mutate_if(is.numeric, ~ calc_method(.)) %>%
drop_na() %>%
{
ggplot(., aes(x = date, y = price)) +
geom_line()
} %>%
ggplotly()
})
But IMHO the easier approach would be to use e.g. switch inside the server to switch the function used for the calculations instead of trying to pass the function via choices:
library(shiny)
library(shinydashboard)
library(tidyquant)
library(tidyverse)
library(plotly)
annual <- function(x) {
(x / lag(x, 12) - 1) * 100
}
monthly <- function(x) {
(x / lag(x) - 1) * 100
}
ui <- dashboardPage(
dashboardHeader(title = "Dashboard"),
dashboardSidebar(),
dashboardBody(
fluidRow(
box(selectizeInput("select_calculation", "Calculation",
choices = c("Monthly" = "monthly", "Annual" = "annual")
), height = 80, width = 4, )
),
fluidRow(
box(plotlyOutput("chart"))
)
)
)
server <- function(input, output) {
output$chart <- renderPlotly({
calc_method <- switch(input$select_calculation,
"monthly" = monthly,
"annual" = annual
)
chart <- tidyquant::tq_get("PCE",
from = "2019-01-01",
to = "2022-10-01",
get = "economic.data"
) %>%
select(-symbol) %>%
mutate_if(is.numeric, ~ calc_method(.)) %>%
drop_na() %>%
{
ggplot(., aes(x = date, y = price)) +
geom_line()
} %>%
ggplotly()
})
}
shinyApp(ui, server)
#>
#> Listening on http://127.0.0.1:6727
I'm new in programming language especially R.
I have data frame and want to show top 3 of my data and sort from the biggest value using bar chart. I have tried some codes but failed to create proper chart. Here is my latest code :
library(shiny)
library(plotly)
my_data <- data.frame(x1 = c("a","b", "c","d","e","f","g","h"),
x2 = c(200, 200, 100,200,200,100,200,100),
x3 = c(100,400,500,50,100,300,100,50))
df1 <- my_data[order(my_data$x3),] #order by x3 value, to create rank
ui <- tabPanel("Test",
sidebarLayout(
sidebarPanel(
selectInput(inputId = "why",
label = "1. Select",
choices = df1$x2),
),
mainPanel(plotlyOutput("test"))
))
server <- function(input, output, session) {
output$test <- renderPlotly({
df2 <- df1 %>%
filter(x2 ==input$why) #filter by x2
p <-ggplot(df2,
aes(x = x1, y=x3)) +
geom_bar(stat = "identity")
fig <- ggplotly(p)
fig
})}
shinyApp(ui = ui, server = server)
the bar chart I created was not ordered correctly (based on x3 values), and I also only want to show top 3 of my data
To filter for the top 3 rows you could use dplyr::slice_max and to reorder your bars use e.g. reorder. Simply reordering the dataset will not work.
library(shiny)
library(dplyr)
library(plotly)
ui <- tabPanel(
"Test",
sidebarLayout(
sidebarPanel(
selectInput(
inputId = "why",
label = "1. Select",
choices = unique(df1$x2),
selected = 200
),
),
mainPanel(plotlyOutput("test"))
)
)
server <- function(input, output, session) {
output$test <- renderPlotly({
df2 <- df1 %>%
filter(x2 == input$why) %>%
slice_max(x3, n = 3, with_ties = FALSE)
p <- ggplot(
df2,
aes(x = reorder(x1, -x3), y = x3)
) +
geom_bar(stat = "identity")
fig <- ggplotly(p)
fig
})
}
shinyApp(ui = ui, server = server)
#>
#> Listening on http://127.0.0.1:8022
I know the question is already answered, but I encourage you to keep your server function as small as possible and try to wrap long series of code into functions.
Here is an example of what I mean
library(tidyverse)
library(shiny)
library(plotly)
my_data <- data.frame(x1 = c("a","b", "c","d","e","f","g","h"),
x2 = c(200, 200, 100,200,200,100,200,100),
x3 = c(100,400,500,50,100,300,100,50))
df1 <- my_data[order(my_data$x3),] #order by x3 value, to create rank
myPlot <- function(data, input) {
df <- data |>
filter(x2 == input) #filter by x2
p <-ggplot(df, aes(x = reorder(x1, -x3), y=x3)) +
geom_bar(stat = "identity")
return(ggplotly(p))
}
ui <- tabPanel("Test",
sidebarLayout(
sidebarPanel(
selectInput(inputId = "why",
label = "1. Select",
choices = df1$x2),
),
mainPanel(plotlyOutput("test"))
))
server <- function(input, output, session) {
output$test <- renderPlotly({
myPlot(df1, input$why)
})
}
shinyApp(ui = ui, server = server)
I am new to the shiny app and trying to write simple code.
I changed the codes so many times but my bar chart doesn't work.
I have this problem in my other trying. That the UI works and also the codes in the server work part by part in R but not in the shiny app. I know some part of my server is not what I want, I just want to know what should I do to run the code which works in R but not in Shiny
#Graph 2
server<-#Graph 2
library("tidyverse")
library("leaflet")
library("leaflet.extras")
library("rnaturalearthdata")
library("sf")
library("DT")
library("ggplot2")
N <- read.csv("https://data.ontario.ca/dataset/f4112442-bdc8-45d2-be3c-12efae72fb27/resource/455fd63b-603d-4608-8216-7d8647f43350/download/conposcovidloc.csv")
function(input, output, session){
if(input$data.Gender){
City ="Ottawa"
N %>% subset(Reporting_PHU_City == City) %>%
select(Case_Reported_Date, Age_Group, Client_Gender, Outcome1)%>%
rename(Date = Case_Reported_Date)%>%
arrange(Age_Group, Client_Gender, Outcome1)
Data.N <- as.data.frame(N)
Data.N %>%
group_by(Age_Group) %>%
summarise(Age = n_distinct(Age_Group)) %>%
arrange(desc(Age))
w = table(N$Age_Group)
t = as.data.frame(w)
}
output$Plot <- renderPlot({
ggplot() +
geom_bar(stat = "identity",data = t,mapping = aes(x = N$Client_Gender , y =Freq))
})
}
Sorry, the site didn't let me share the UI too. This is Ui
UI<- #Graph 2
library("leaflet")
library("DT")
fluidPage(
sidebarLayout(
sidebarPanel(
radioButtons("data.Gender", "",
c("Data female" = "Gender.Female",
"Data male" = "Gender.Male"))
),
enter code here
mainPanel(
plotOutput("Plot")
)
))
Perhaps you should group by Client_Gender. Your present group by of Age_Group will give 1 as the value for all groups.
Try this
server <- function(input, output, session){
t <- reactive({
input$data.Gender
City ="Toronto"
aa <- N %>% subset(Reporting_PHU_City == City) %>%
select(Case_Reported_Date, Age_Group, Client_Gender, Outcome1)%>%
rename(Date = Case_Reported_Date)%>%
arrange(Age_Group, Client_Gender, Outcome1)
bb <- aa %>%
group_by(Client_Gender) %>%
summarise(Age = n_distinct(Age_Group)) %>%
arrange(desc(Age))
bb
})
output$Plot <- renderPlot({
ggplot(data=t()) +
geom_bar(stat = "identity",mapping = aes(x = Client_Gender , y = Age))
})
}
I am trying to get a slider within my barplot page to make the data interactive per year.
#library
library(dplyr)
library(shiny)
library(shinythemes)
library(ggplot2)
#Source
dataset <- read.csv("Wagegap.csv")
SFWage <- dataset %>%
group_by(gender,JobTitle, Year) %>%
summarise(averageBasePay = mean(BasePay, na.rm=TRUE)) %>%
select(gender, JobTitle, averageBasePay, Year)
clean <- SFWage %>% filter(gender != "")
#UI
ui <- fluidPage(
theme = shinytheme("united"),
navbarPage("San Fransisco Wages",
tabPanel("Barplot",
mainPanel(
plotOutput("barplot")
)) ,
tabPanel("Table",
mainPanel(
dataTableOutput("table")
))
)
)
#server
server <- function(input, output){
output$barplot <- renderPlot({
ggplot(clean, aes(x = JobTitle, y = averageBasePay ))+
geom_bar(stat="Identity", width = 0.3, fill="orange")+
labs(x= "Jobs", y = "Wage", title = "Wage per job")
})
output$table <- renderDataTable({
clean
})
}
#Run App
shinyApp(ui = ui, server = server)
I don't fully understand it yet how to put this input in.
I have tried sliding it into the navbarpage but I can't figure out how it works.
I also tried making year reactive but with no success.
It's not the year that has to be reactive; it's the whole data frame. Therefore, in your ui, you can do:
[...]
tabPanel("Barplot",
mainPanel(
sliderInput("year", label = "Which year should be displayed?", min = 1900, max = 2020, step = 5, value = 2000) # new
plotOutput("barplot")
)) ,
[...]
I put it there for convenience; the layout is yours. I tried do change as little as possible.
The server would then have:
server <- function(input, output){
# NEW ########################################
clean <- reactive({
SFWage <- dataset %>%
group_by(gender,JobTitle, Year) %>%
summarise(averageBasePay = mean(as.numeric(BasePay), na.rm=TRUE)) %>% # Notice the as.numeric()
select(gender, JobTitle, averageBasePay, Year)
SFWage %>% filter(gender != "" & Year == input$year)
})
# OLD ########################################
output$barplot <- renderPlot({
ggplot(clean(), aes(x = JobTitle, y = averageBasePay ))+ # Parenthesis
geom_bar(stat="Identity", width = 0.3, fill="orange")+
labs(x= "Jobs", y = "Wage", title = "Wage per job")
})
output$table <- renderDataTable({
clean() # Parenthesis
})
}
Don't forget to add the parenthesis, as I did here.
This should work, but I might have mistyped something or got it completely wrong. Since I don't have your data, I can't test it.
EDIT: Due to your comment, I added the as.numeric() term, as you can see above. However, if your data is not only not numeric but also with ,, you can do:
[...]
summarise(averageBasePay = mean(as.numeric(gsub(",", ".", BasePay)), na.rm=TRUE)) %>% # Notice the as.numeric() and the gsub()
[...]
I am relatively new to R, and I'm trying to build a reactive ggplot in Shiny where the X-axis (dates) is reactive to a dateRangeInput in the UI. I've been googling everywhere, but every thing I try returns an error.
In the ggplot, the aes() calls from a dataset called datecorrected_totals, where x is the dates, and y=load are the two values that I would like to be reactive to the dateRangeInput so the ggplot will adjust the scale based on the period within the daterangeinput.
library(tidyverse)
library(shiny)
library(tidyr)
library(lubridate)
library(zoo)
data <- read_csv("--")
# Define UI ----
ui <- fluidPage(
titlePanel("--"),
sidebarLayout(
sidebarPanel(
h3("Calculator"),
dateRangeInput("dates", label = "Dates",
start = ("10-18-2018"),
end = max("05-29-2019"),
min = min("10-18-2018"),
max = max("05-29-2019"),
format = "mm-dd-yyyy"),
sliderInput("slider_a", label = "--",
min = 0,
max = 7,
value = 0),
sliderInput("slider_c", label = "--",
min = 7,
max = 42,
value = 7)
),
mainPanel(plotOutput('bar_chart'))
)
)
# Define server logic ----
server <- function(input, output, session) {
RE <- reactive({
})
output$bar_chart <- renderPlot(
ggplot(data = datecorrected_totals, aes(x = x, y = load)) +
geom_bar(stat = "identity")
)
}
# Run the app ----
shinyApp(ui = ui, server = server)
You need to filter the original dataset by the input dates. In this example data would be your original dataset.
RE <- reactive({
data %>%
filter(x>=input$dates[1] & x<=input$dates[2])
})
output$bar_chart <- renderPlot(
ggplot(data = RE(), aes(x = x, y = load)) +
geom_bar(stat = "identity")
There is no need to create a separate reactive() expression (unless required otherwise). The filter can be applied directly in renderPlot(). Thus, output$bar_chart becomes
output$bar_chart <- renderPlot(
datecorrected_totals %>%
filter(between(x, input$dates[1], input$dates[2])) %>%
ggplot(aes(x = x, y = load)) +
geom_bar(stat = "identity")
)
Below is a self-contained minimal reproducible example:
library(tidyverse)
library(lubridate)
library(shiny)
datecorrected_totals <- tibble(x = seq(as.Date("2018-10-18"), as.Date("2019-05-29"), length.out = 10L),
load = day(x))
# Define UI ----
ui <- fluidPage(
titlePanel("--"),
sidebarLayout(
sidebarPanel(
h3("Calculator"),
dateRangeInput("dates", label = "Dates",
start = mdy("10-18-2018"),
end = mdy("05-29-2019"),
min = mdy("10-18-2018"),
max = mdy("05-29-2019"),
format = "mm-dd-yyyy"),
),
mainPanel(plotOutput('bar_chart'))
)
)
# Define server logic ----
server <- function(input, output, session) {
output$bar_chart <- renderPlot(
datecorrected_totals %>%
filter(between(x, input$dates[1], input$dates[2])) %>%
ggplot(aes(x = x, y = load)) +
geom_col()
)
}
# Run the app ----
shinyApp(ui = ui, server = server)
Note that the date strings have been coerced to valid Date objects by calling mdy() to avoid error messages.
In addition, geom_bar(stat = "identity") has been replaced by geom_col().