Reformulating my question, I´m trying to synthetize a data frame reactively, with a selectinput = c("col_1","col_2","col_3","col_4","col_5")
My dataframe looks something like this
Date . Store_ID . Sales . Stock . ETC
I need to be able to sum all the data in the same stores, with the different user selected columns.
Using the mtcars dataframe as an example to work with, my objective is to have a table like this
SelectInput = disp
cyl - disp
4 - sum(every 4 cylinders disp)
6 - sum(every 6 cylinders disp)
8 - sum(every 8 cylinders disp)
SelectInput = qsec
cyl . qsec
4 . sum(every 4 cylinders qsec)
6 . sum(every 6 cylinders qsec)
8 . sum(every 8 cylinders qsec)
library(shiny)
library(tidyverse)
ui <- bootstrapPage(
selectInput(
"col",
"Column",
colnames(mtcars),
selected = "mpg"),
plotOutput("histCentile", height = 200)
)
server <- function(input, output) {
data <- reactive({
mtcars() %>%
group_by(cyl = cyl) %>%
pull(input$col) %>%
sum()
})
output$histCentile <- renderPlot({
hist(data()$[[input$col]],
main = "Graph",
xlab = "Units",
xlim = range(data()$[[input$col]]),
col = '#00DD00',
border = 'white')
})
}
# Run the application
shinyApp(ui = ui, server = server)
I'm not sure what you're trying to do but here is a minimal reproducible example using reactive to filter data based on the selectInput variable.
library(shiny)
library(tidyverse)
ui <- bootstrapPage(
selectInput(
"col",
"Column",
colnames(mtcars),
selected = "mpg"),
textOutput("selected_col")
)
server <- function(input, output) {
data <- reactive({
mtcars %>% pull(input$col) %>% sum()
})
output$selected_col <- renderText({
sprintf("The sum of column %s is %f", input$col, data())
})
}
# Run the application
shinyApp(ui = ui, server = server)
Explanation: In data we sum the values from input$col based on the selectInput selection. data is therefore a reactive value, which we show in output$selected_col.
Update
There are a few issues with your updated code example:
In the reactive block, you're summarising data to give a single number. Plotting a histogram based on a single number makes no sense. Secondly, there is a typo: it should be mtcars not mtcars(); and lastly, group_by(cyl = cyl) is unnecessary as you don't do any group-wise calculation afterwards (it should also be group_by(cyl)).
You don't actually need a reactive block here at all, since you can do the filtering in renderPlot directly but I guess that is a matter of personal preference.
The following dynamically updates a histogram based on the selected column from selectInput
library(shiny)
library(tidyverse)
ui <- bootstrapPage(
selectInput(
"col",
"Column",
colnames(mtcars),
selected = "mpg"),
plotOutput("histo")
)
server <- function(input, output) {
data <- reactive({
mtcars %>% pull(input$col)
})
output$histo <- renderPlot({
hist(data())
})
}
# Run the application
shinyApp(ui = ui, server = server)
Update - Solution
Thanks to Maurits Evers help, and some research, I managed to do what I wanted to
library(shiny)
library(tidyverse)
ui <- bootstrapPage(
selectInput(
"col",
"Column",
colnames(mtcars),
selected = "mpg"),
plotOutput("histo")
)
server <- function(input, output) {
data <- reactive({
Graphby <- input$col
with(mtcars,aggregate(qsec,list(cyl=cyl),sum))
aggregate(mtcars[[Graphby]],list(cyl=mtcars$cyl),sum)
})
output$histo <- renderPlot({
hist(data()$x)
})
}
# Run the application
shinyApp(ui = ui, server = server)
What it does is an interactive histogram by merging groups of data like this
in a reactive way, by choosing different columns.
Related
I am creating a shiny App where it will do two things on mtcars dataset
group data based on user selected values and calculate the mean mpg
and then filter based on selected values to display the output
library(shiny)
library(dplyr)
ui <- fluidPage(
titlePanel(" APP"),
sidebarLayout(
sidebarPanel(selectInput("x","Select cylinder",choices = c(mtcars$cyl),multiple = TRUE),
selectInput("y","Select gear",choices = c(mtcars$gear),multiple = TRUE),
submitButton("Submit")),
mainPanel(
tableOutput("m")
)))
server <- function(input,output){
check <- reactive({
if(is.null(input$x) & is.null(input$y)){
mtcars %>% summarise(Average_mpg = mean(mpg))
}else if(!is.null(input$x) & is.null(input$y)){
a <- mtcars %>% group_by(cyl) %>% summarise(Average_mpg = mean(mpg))
a %>% filter(cyl==input$x)
}else if(is.null(input$x) & !is.null(input$y)){
a <- mtcars %>% group_by(gear) %>% summarise(Average_mpg = mean(mpg))
a %>% filter(gear==input$y)
}else{
a <- mtcars %>% group_by(gear,cyl) %>% summarise(Average_mpg = mean(mpg))
a %>% filter(cyl==input$x & gear==input$y)
}
})
output$m <- renderTable(
check()
)
}
shinyApp(ui = ui, server = server)
Currently I have hard coded all possible combination using if else statement and then realized its not efficient way. If the filters/widgets increase then its difficult to manage
for e.g. If I add one more filter here for variable "carb" in mtcars dataset I have to include all possible scenarios what the user will select and hard code it.
My actual app is having 5 -6 more filters.
Is there any way where whatever the user selects the app will group by on the fly and then filter and show results.
This is not a perfect approach as it still involves some copy & paste and duplicated code. But as a first step it gets rid of the if-else to filter your data:
library(shiny)
library(dplyr)
choices_cyl <- unique(mtcars$cyl)
choices_gear <- unique(mtcars$gear)
ui <- fluidPage(
titlePanel(" APP"),
sidebarLayout(
sidebarPanel(
selectInput("x", "Select cylinder", choices = choices_cyl, multiple = TRUE),
selectInput("y", "Select gear", choices = choices_gear, multiple = TRUE),
submitButton("Submit")
),
mainPanel(
tableOutput("m")
)
)
)
server <- function(input, output) {
check <- reactive({
cyls <- input$x
gears <- input$y
grps <- c("cyl", "gear")[c(!is.null(cyls), !is.null(gears))]
if (is.null(cyls)) cyls <- choices_cyl
if (is.null(gears)) gears <- choices_gear
mtcars %>%
filter(cyl %in% cyls, gear %in% gears) %>%
group_by(across(all_of(grps))) %>%
summarise(Average_mpg = mean(mpg))
})
output$m <- renderTable(
check()
)
}
shinyApp(ui = ui, server = server)
I'm working on a project where table is filtered based on the Inputs provided by the user. There are three selectInput conditions.
For better understanding lets assume the mtcars data. User can first select the number of cylinders, then the user should see a selectInput list of number of gears filtered for given value of cylinder. (**for instance, if number of cylinder is 4, then number of gears should be either 4,3,5 **)
Similarly, after selecting the Number of Cylinders and Number of gears the user must see the value of Transmission type as either 0,1.
The table should be updated and filtered based on the selected inputs.
I have tried the given code. Please help me.
#loading libraries
library(tidyverse)
library(shiny)
library(DT)
#using mtcars as dataset
df <- read.csv("https://gist.githubusercontent.com/seankross/a412dfbd88b3db70b74b/raw/5f23f993cd87c283ce766e7ac6b329ee7cc2e1d1/mtcars.csv")
# Define UI for application
ui <- fluidPage(
# Application title
titlePanel("Details of Given Cars"),
# Sidebar for input filter
sidebarLayout(
sidebarPanel(
selectInput("cylinder","Number of Cylinders",unique(df$cyl)),
selectizeInput("gears","Number of gears",choices = NULL),
selectizeInput("gearbox","Transmission Type 'AUTO=0'",choices = NULL)
),
# Show a table
mainPanel(
DT::DTOutput("table")
)
)
)
# Define server logic required
server <- function(input, output,session) {
#----reactive calculations
cyl_sel <- reactive({
df %>% filter(cyl == input$cylinder)
})
observeEvent(cyl_sel(),{
updateSelectizeInput(session,"gears", choices = cyl_sel()$gear)
# })
gearbox_sel <- reactive({
cyl_sel() %>% filter(am == input$gears)
})
observeEvent(gearbox_sel,{
updateSelectizeInput(session,"gearbox",choices = gearbox_sel()$am)
output$table <- DT::renderDT({
df %>% filter(cyl == input$cylinder,
gear == input$gears)
# am== input$gearbox) # commented because output is not shown when uncommented
})
})
})
}
# Run the application
shinyApp(ui = ui, server = server)
You could use selectizeGroupUI from library(shinyWidgets) to achive this:
library(datasets)
library(shiny)
library(shinyWidgets)
library(DT)
df <- mtcars
ui <- fluidPage(
titlePanel("Details of Given Cars"),
sidebarLayout(
sidebarPanel(
selectizeGroupUI(
id = "my-filters",
params = list(
cyl = list(inputId = "cyl", title = "Number of Cylinders:"),
gear = list(inputId = "gear", title = "Number of gears:"),
am = list(inputId = "am", title = "Transmission Type 'AUTO=0':")
),
inline = FALSE
)
),
mainPanel(
DT::DTOutput("table")
)
)
)
server <- function(input, output, session) {
res_mod <- callModule(
module = selectizeGroupServer,
id = "my-filters",
data = df,
vars = c("cyl", "gear", "am"),
inline = FALSE
)
output$table <- DT::renderDT(res_mod())
}
shinyApp(ui = ui, server = server)
There are several questions on this issue, including here, but I am still not sure what I need to change to get this right.
The selectInput choices are working as expected, other than when I change the second selectInput, it temporarily changes to the desired selection but then automatically goes back to the first filtered selection.
For example, if "gear" is chosen for Variable 1, then the Variable 1 choices correctly display "3, 4, 5" for possible gear choices. If I select "5" for gear, it briefly shows up and then goes back to gear "3" as a choice. I am not sure how to prevent that reactive behavior.
Here is a simple reproducible example using the mtcars built-in data set:
library(tidyverse)
library(shiny)
# Variables interested in selecting
my_vars <- c("cyl", "gear", "carb")
# UI
ui <- fluidPage(
# Title
titlePanel("Reprex"),
# Sidebar
sidebarLayout(
sidebarPanel(
selectInput("sel_1",
"Variable 1",
choices = my_vars,
selected = my_vars[[1]],
multiple = FALSE
),
selectInput("sel_2",
"Variable 1 choices",
choices = unique(mtcars[[ my_vars[[1]] ]]),
multiple = FALSE
)
), # sidebarPanel close
# Plot
mainPanel(
plotOutput("plot_out")
) # mainPanel close
) # sidebarLayout close
) # UI close
# Server
server <- function(input, output, session) {
output$plot_out <- renderPlot({
# Assign inputs
sel_1 <- input$sel_1
sel_2 <- input$sel_2
# Make drop-down choice of sel_2 dependent upon user input of sel_1
# *** Must put "shiny::observe" instead of "observe" since "observe" is masked by the Tidy infer package ***
shiny::observe({
updateSelectInput(session,
"sel_2",
choices = sort(unique(mtcars[[sel_1]]))
)
})
# Data to plot
my_data <- mtcars %>%
filter(.data[[sel_1]] == sel_2)
# Plot
p <- ggplot(my_data, aes(x = factor(.data[[sel_1]]), y = hp)) + geom_point()
p
})
}
# Run the application
shinyApp(ui = ui, server = server)
That's because your observer is inside the renderPlot. It has nothing to do here.
server <- function(input, output, session) {
# Make drop-down choice of sel_2 dependent upon user input of sel_1
observeEvent(input$sel_1, {
updateSelectInput(session,
"sel_2",
choices = sort(unique(mtcars[[input$sel_1]]))
)
})
output$plot_out <- renderPlot({
# Assign inputs
sel_1 <- input$sel_1
sel_2 <- input$sel_2
# Data to plot
my_data <- mtcars %>%
filter(.data[[sel_1]] == sel_2)
# Plot
ggplot(my_data, aes(x = factor(.data[[sel_1]]), y = hp)) + geom_point()
})
}
Here the observeEvent instead of observe is not necessary, since input$sel_1 is the only reactive value inside the observer, but I find that observeEvent is more readable.
Also, avoid to load tidyverse. That loads a ton of packages you don't need. Here dplyr and ggplot2 are enough
I am trying to build a shiny app that gives new predictions based on various user inputs.
However, even though the input values are updating with the inputs, the prediction value does not update. Im am having trouble figuring out why.
The model is a random forest regression model, in the example I am using numeric variables but in my situation the inputs are categorical (I dont think this change should effect anything) This is why the sidebar is all select input as opposed to select numeric
I made a reproducible example with the mtcars dataset
model <- ranger(mpg ~ disp + hp + wt, data = mtcars)
ui <- fluidPage(
sidebarPanel(
selectInput('disp', 'disp',
choices = unique(mtcars$disp),
selected = unique(mtcars$disp)[1]),
selectInput('hp', 'hp',
choices = unique(mtcars$hp),
selected = unique(mtcars$hp)[1]),
selectInput('wt', 'wt',
choices = unique(mtcars$wt)),
actionButton("Enter", "Enter Values"),
width = 2
),
mainPanel(
tableOutput('mpg')
)
)
server <- function(input, output, session) {
val <- reactive({
new <- mtcars[1, ]
new$disp <- input$disp
new$hp <- input$hp
new$wt <- input$wt
new
})
out <- eventReactive(
input$Enter,
{
val <- val()
val$pred <- predict(model, data = val)$predictions
val
})
output$mpg <- renderTable({
out()
})
}
shinyApp(ui, server)
There are several issues here.
1) You are using selectInput incorrectly. See below. Basically, using indexes like mtcars$disp[1] will create static values, no matter what is selected.
2) You are using renderTable() when you are only producing a single value as output. Why not just use renderText()? See below.
3) The eventReactive trigger (i.e., input$enter) needs to be used to create the data frame of input values. The model prediction can run on the data frame later, but the initial trigger actually pulls the values from selectInput, so the trigger needs to be in the same block where the data frame is created.
This ran correctly and produced the desired output on my machine:
library(shiny)
library(ranger)
model <- ranger(mpg ~ disp + hp + wt, data = mtcars)
ui <- fluidPage(
sidebarPanel(
selectInput('disp', 'disp',
unique(mtcars$disp)),
selectInput('hp', 'hp',
unique(mtcars$hp)),
selectInput('wt', 'wt',
unique(mtcars$wt)),
actionButton("enter", label = "Enter Values"),
width = 2
),
mainPanel(
textOutput('mpg')
)
)
server <- function(input, output, session) {
val <- eventReactive(
input$enter, {
data.frame(
disp = input$disp,
hp = input$hp,
wt = input$wt,
stringsAsFactors = F
)}
)
output$mpg <- renderText({
predict(model, val())[[1]]
})
}
shinyApp(ui, server)
Issue:
I have a data frame where row A is the names of people in my organization. I have a separate data frame that is a subset of row A in the original table. I would like to highlight all rows in the first data table that match names in the second table. Essentially, I have two sets. Set A and Set B. Both are names, I would like to highlight the data table for all names in Set A that match Set B. However, I keep getting an error: length(levels) must be equal to length(values)
How would I avoid receiving this error?
Reproducible Example:
I have a data frame of mtcars. I am filtering the mtcars dataset based on a slider input for mpg. I would like to highlight the data frame of mtcars that meet the filtering criteria. In effect, this would mean highlighting the output table for all observations where the mpg are <= the slider input mpg.
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Highlight Cell Test (Sets)"),
sidebarLayout(
sidebarPanel = 'side',
sliderInput('slider', 'slider input', 1, 30, 20)),
# Show a plot of the generated distribution
mainPanel(
dataTableOutput("test")
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
subset <- reactive({
mtcars %>%
filter(mpg <= input$slider)
})
output$test <- DT::renderDataTable(
mtcars %>%
DT::datatable(
options = list(
dom = 'ftipr',
searching = TRUE
) %>%
formatStyle(
'test',
background = styleEqual(
(subset()$mpg %in% mtcars$mpg), 'lightgreen'))
)
)
}
# Run the application
shinyApp(ui = ui, server = server)
Any help is much appreciated. Thanks in advance.
You can do this via rowCallback like so:
library(shiny)
library(dplyr)
library(DT)
fnc <- JS('function(row, data, index, rowId) {','console.log(rowId)','if(rowId >= ONE && rowId < TWO) {','row.style.backgroundColor = "lightgreen";','}','}')
ui <- fluidPage(
# Application title
titlePanel("Highlight Cell Test (Sets)"),
sidebarLayout(
sidebarPanel = 'side',
sliderInput('slider', 'slider input', 1, 30, 16)),
# Show a plot of the generated distribution
mainPanel(
dataTableOutput("test")
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
subset <- reactive({
mtcars %>% filter(mpg <= input$slider)
})
Coloring <- eventReactive(subset(),{
a <- which(subset()$mpg %in% mtcars$mpg)
print(a)
if(length(a) <= 0){
return()
}
fnc <- sub("ONE",a[1],fnc)
fnc <- sub("TWO",max(a),fnc)
fnc
})
output$test <- DT::renderDataTable(
mtcars %>%
DT::datatable(options = list(dom = 'ftipr',searching = TRUE,pageLength = 20, scrollY = "400px",rowCallback = Coloring()))
)
}
shinyApp(ui = ui, server = server)