Referencing a dynamic input ID in Shiny - r

In the example below, I am trying to produce a box and plot for each group within a dataset, using lapply within a renderUI function. However, some of these groups require an additional filter as they have sub-groupings.
This means creating a selectInput inside the box for those groups only and having the corresponding chart reference that selectInput only.
Here's the reproducible example... my problem is in the lapply loop creating a selectInput with the inputID of paste("selector_",i) and then immediately referencing this in the data to be output inside the corresponding box with input$(what goes here?)
library(shiny)
library(shinydashboard)
library(tidyverse)
library(nycflights13)
library(DT)
data <- planes %>%
select(manufacturer, type, model, year, seats) %>%
unique() %>%
filter(!is.na(year)) %>%
mutate(year = as.character(year))
ui <- dashboardPage(
dashboardHeader(title = "Testing"),
dashboardSidebar(),
dashboardBody(
fluidRow(
column(12, selectInput("type","Type", choices = unique(data$type)),
uiOutput("mytabs"))
)
)
)
server <- function(input, output) {
data_filtered <- reactive({
req(input$type)
data %>%
filter(type == input$type)
})
mfrs <- reactive({
data_filtered() %>%
select(manufacturer) %>%
unique() %>%
pull()
})
output$mytabs = renderUI({
fluidRow(
lapply(mfrs(), function(i) {
dt <- data_filtered() %>%
filter(manufacturer == i) %>%
arrange(year) %>%
select(model, year, seats)
models <- dt %>%
filter(!is.na(model)) %>%
select(model) %>%
unique() %>%
pull()
if(length(models) > 1) {
box(id = paste0('card', i), title = paste(i),
selectInput(inputId = paste0("selector_",i), "Question",
choices = models, selected = models[1]),
DT::datatable(dt[dt$qntext == input$the_one_above],
width = "100%", rownames = F,
options = list(
columnDefs = list(list(width = '40px', targets = "_all"))
))
)
} else {
box(id = paste0('card', i), title = paste(i),
DT::datatable(dt,
width = "100%", rownames = F,
options = list(
columnDefs = list(list(width = '40px', targets = "_all"))
))
)
}
})
)
})
}
shinyApp(ui, server)

As I am not sure what qns means, I have assigned qns to be models. Try this code:
data <- planes %>%
select(manufacturer, type, model, year, seats) %>%
unique() %>%
filter(!is.na(year)) %>%
mutate(year = as.character(year))
ui <- dashboardPage(
dashboardHeader(title = "Testing"),
dashboardSidebar(uiOutput("myqns")),
dashboardBody(
fluidRow(
column(12, selectInput("type","Type", choices = unique(data$type)), uiOutput("mytabs"))
)
)
)
server <- function(input, output) {
data_filtered <- reactive({
req(input$type)
data %>%
filter(type == input$type)
})
mfrs <- reactive({
req(data_filtered())
data_filtered() %>%
select(manufacturer) %>%
unique() %>%
pull()
})
output$myqns <- renderUI({
req(mfrs())
lapply(1:length(mfrs()), function(i) {
dt <- data_filtered() %>%
filter(manufacturer == mfrs()[i]) %>%
arrange(year) %>%
select(model, year, seats)
models <- dt %>%
filter(!is.na(model)) %>%
select(model) %>%
unique() %>%
pull()
qns <- models
selectInput(inputId = paste0("selector_",i), paste("Question",i), choices = as.list(qns), selected = 1)
})
})
output$mytabs = renderUI({
req(mfrs())
fluidRow(
lapply(1:length(mfrs()), function(i) {
req(input[[paste0("selector_",i)]])
dt <- data_filtered() %>%
filter(manufacturer == mfrs()[i]) %>%
arrange(year) %>%
select(model, year, seats)
models <- dt %>%
filter(!is.na(model)) %>%
select(model) %>%
unique() %>%
pull()
qns <- models
if(length(models) > 1) {
box(id = paste0('card', i), title = paste(mfrs()[i]),
# selectInput(inputId = paste0("selector_",i), "Question",
# choices = qns, selected = qns[1]),
DT::datatable(dt[dt$model == input[[paste0("selector_",i)]], ],
width = "100%", rownames = F,
options = list(
columnDefs = list(list(width = '40px', targets = "_all"))
))
)
} else {
box(id = paste0('card', i), title = paste(mfrs()[i]),
DT::datatable(dt,
width = "100%", rownames = F,
options = list(
columnDefs = list(list(width = '40px', targets = "_all"))
))
)
}
})
)
})
}
shinyApp(ui, server)

Answered by the awesome Paul Campbell... using modules.
library(shinydashboard)
library(tidyverse)
library(highcharter)
library(nycflights13)
# Modules ===============================================
# UI and server module for box with chart
box_chart_UI <- function(id, title) {
ns <- NS(id)
box(
title = title, height = 550,
highcharter::highchartOutput(ns("chart"))
)
}
box_chart <- function(input, output, session, df) {
output$chart <- renderHighchart({
validate(need(nrow(df) > 0, "No data"))
hchart(df, "column", hcaes(year, seats))
})
}
# UI and server module for box with chart and filter
box_chart_filter_UI <- function(id, title, filters, filter_lab = "Model") {
ns <- NS(id)
box(
title = title, height = 550,
selectInput(inputId = ns("selector"), label = filter_lab, choices = filters),
highchartOutput(ns("chart"))
)
}
box_chart_filter <- function(input, output, session, df) {
output$chart <- renderHighchart({
req(input$selector)
df_chart <- df %>% filter(model == input$selector)
validate(need(nrow(df_chart) > 0, "No data"))
hchart(df_chart, "column", hcaes(year, seats))
})
}
# Main App ===============================================
# load app data
data <- planes %>%
select(manufacturer, type, model, year, seats) %>%
unique() %>%
filter(!is.na(year)) %>%
mutate(year = as.character(year))
ui <- dashboardPage(
dashboardHeader(title = "Testing"),
dashboardSidebar(),
dashboardBody(
fluidRow(
column(
width = 12,
selectInput("type", "Type", choices = unique(data$type))
)
),
uiOutput("mytabs")
)
)
server <- function(input, output, session) {
data_filtered <- reactive({
req(input$type)
data %>% filter(type == input$type)
})
mfrs <- reactive({
data_filtered() %>%
distinct(manufacturer) %>%
pull()
})
# first load all the UI module functions
output$mytabs <- renderUI({
fluidRow(
lapply(1:length(mfrs()), function(i) {
models <- data_filtered() %>%
filter(manufacturer == mfrs()[i], !is.na(model)) %>%
distinct(model) %>%
pull() %>%
sort()
# depending on how many models, load the correct UI module
if (length(models) > 1) {
box_chart_filter_UI(id = i, title = mfrs()[i], filters = models)
} else {
box_chart_UI(id = i, title = mfrs()[i])
}
})
)
})
# now separately load the module server functions
# need to do this inside an observe due to reactive objects
observe({
lapply(1:length(mfrs()), function(i) {
dt <- data_filtered() %>%
filter(manufacturer == mfrs()[i]) %>%
arrange(year) %>%
select(model, year, seats)
models <- dt %>%
filter(!is.na(model)) %>%
distinct(model) %>%
pull() %>%
sort()
# depending on how many models, load the correct server module
if (length(models) > 1) {
callModule(box_chart_filter, id = i, df = dt)
} else {
callModule(box_chart, id = i, df = dt)
}
})
})
}
shinyApp(ui, server)

Related

Creating two corresponding selecInput lists (input$* after removing selections never goes null)

I am trying to create two corresponding selectInput lists. To do so I made two uiOutput in ui attached to renderUI in server. The renderUIs are linked to reactiveValues which should change according to input$* values.
And it does work until one point. The selection list is shrinking and can't go back to default (while in my opinion it should, based on second line of observeEvent).
I have a feeling that no matter what the input$* values are never null so the is.null() won't work.
I will apprecieate any help in this topic.
if (interactive()) {
library(dplyr)
library(shiny)
library(shinydashboard)
library(plotly)
library(DT)
library(tidyr)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
uiOutput('hair_filter'),
uiOutput('species_filter')
),
mainPanel( tableOutput('hairs'),
tableOutput('species'),
textOutput('text'),
textOutput('text2'),
tableOutput('hairfiltertable'),
tableOutput('speciesfiltertable')
)
))
server <- function(input, output, session){
starwars_full <- starwars %>%
as.data.frame() %>%
tibble::rownames_to_column(var = 'ID') %>%
transform(ID=as.numeric(ID), height=as.numeric(height), mass=as.numeric(mass), birth_year=as.numeric(birth_year)) %>%
group_by(ID, name, height,mass,hair_color, skin_color, eye_color, birth_year,sex,homeworld,species, films, vehicles, starships) %>%
summarise('cnt_films'=lengths(films),'cnt_vehicles'=lengths(vehicles),'cnt_ships'=lengths(starships))
#creating list of hair colors based on selected species
rv3 <- reactiveValues(hair_list = starwars_full %>%
separate_rows(hair_color,sep=", ") %>%
arrange(hair_color) %>%
as.data.frame() %>%
select(hair_color,species, name) %>%
distinct()
)
observeEvent(input$selected_from_dropdown_species,{
if(isTruthy(input$selected_from_dropdown_species))
{
rv3$hair_list <- starwars_full %>%
separate_rows(hair_color,sep=", ") %>%
arrange(hair_color) %>%
as.data.frame() %>%
select(hair_color,species, name) %>%
distinct() %>%
filter(species %in% input$selected_from_dropdown_species)
rv6$selected_species <- input$selected_from_dropdown_species
}
else
{
rv3$hair_list <- starwars_full %>%
separate_rows(hair_color,sep=", ") %>%
arrange(hair_color) %>%
as.data.frame() %>%
select(hair_color,species, name) %>%
distinct()
rv6$selected_species <- NULL
}
})
#creating species list, based on selected hair colors
rv4 <- reactiveValues(specie_list = starwars_full %>%
separate_rows(species,sep=", ") %>%
arrange(species) %>% as.data.frame() %>%
select(hair_color,species, name) %>%
distinct()
)
observeEvent(input$selected_from_dropdown_color,{
if(isTruthy(input$selected_from_dropdown_color))
{
rv4$specie_list <- starwars_full %>%
separate_rows(species,sep=", ") %>%
arrange(species) %>% as.data.frame() %>%
select(hair_color,species, name) %>%
distinct() %>%
filter(hair_color %in% input$selected_from_dropdown_color)
rv5$selected_colors <- input$selected_from_dropdown_color
}
else
{
rv4$specie_list <- starwars_full %>%
separate_rows(species,sep=", ") %>%
arrange(species) %>% as.data.frame() %>%
select(hair_color,species, name) %>%
distinct()
rv5$selected_colors <- NULL
}
})
rv5 <- reactiveValues(selected_colors = NULL)
rv6 <- reactiveValues(selected_species = NULL)
#selecinput of hair color
output$hair_filter = renderUI({
selectInput("selected_from_dropdown_color",
label ="Hair colors:",
choices=rv3$hair_list$hair_color,
multiple=TRUE,
selected=isolate(rv5$selected_colors))
})
#selectinput for species
output$species_filter = renderUI({
selectInput("selected_from_dropdown_species",
label ="Species",
choices=rv4$specie_list$species,
multiple=TRUE,
selected=isolate(rv6$selected_species))
})
output$hairs = renderTable({input$selected_from_dropdown_color})
output$species = renderTable({input$selected_from_dropdown_species})
output$text = renderPrint({print(input$selected_from_dropdown_color)})
output$text2 = renderPrint({print(input$selected_from_dropdown_species)})
output$hairfiltertable = renderTable({rv3$hair_list})
output$speciesfiltertable = renderTable({rv4$specie_list})
}
shinyApp(ui,server)
}
Edit:
We can use selectizeGroup from shinyWidgets to achieve the desired behaviour.
library(tidyverse)
library(shiny)
library(shinydashboard)
library(plotly)
library(DT)
library(tidyr)
library(shinyWidgets)
starwars_full <- starwars %>%
as.data.frame() %>%
rownames_to_column(var = "ID") %>%
transform(ID = as.numeric(ID), height = as.numeric(height), mass = as.numeric(mass), birth_year = as.numeric(birth_year)) %>%
group_by(ID, name, height, mass, hair_color, skin_color, eye_color, birth_year, sex, homeworld, species, films, vehicles, starships) %>%
summarise("cnt_films" = lengths(films), "cnt_vehicles" = lengths(vehicles), "cnt_ships" = lengths(starships))
starwars_species_hair <- starwars_full %>%
separate_rows(hair_color, sep = ", ") %>%
separate_rows(species, sep = ", ") %>%
select(hair_color, species, name)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectizeGroupUI(
id = "my-filters",
params = list(
hair_color = list(inputId = "hair_color", title = "Hair color:"),
species = list(inputId = "species", title = "Species:")
)
)
),
mainPanel(DTOutput("resulting_table"))
)
)
server <- function(input, output, session) {
res_mod <- callModule(
module = selectizeGroupServer,
id = "my-filters",
data = starwars_species_hair,
vars = c("hair_color", "species")
)
output$resulting_table <- renderDT({
req(res_mod)
datatable(res_mod())
})
}
shinyApp(ui, server)
We can access selected values inside a reactive/observer by:
observe({
input[["my-filters-hair_color"]]
input[["my-filters-species"]]
)}

How avoid "invalid (NULL) left side of assignment" error in R Shiny app?

I have a dataset and want to create an R Shiny app with if condition (based on RadioButton).
Additionally, after filtering my initial dataset, I want to replace all 2 values in Quantity column to 200 (Yes, it it possible to do it outside the server(), but in my case, it is necessary to do it inside).
I always get error here sales_by_mfr()$Quantity <- reactive(ifelse(sales_by_mfr()$Quantity == 2,200,sales_by_mfr()$Quantity))
Additionally, I tried to replace all 2 values in my dataset with sales_by_mfr()[sales_by_mfr() == 2] <- reactive({200}) , however got the same error.
Could you help to find a way to avoid "invalid (NULL) left side of assignment" error inside this code?
library(dplyr)
library(shiny)
data <- MASS::Cars93[18:47, ] %>%
mutate(ID = as.character(18:47), Date = seq(as.Date("2019-01-01"), by = "day", length.out = 30)) %>%
select(ID, Date, Manufacturer, Model, Type, Price)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
#sliderInput
radioButtons("dist", "Data:",
c("The most recent" = "most_recent",
"Historical" = "historical"))
),
# plot graphs
mainPanel(tabsetPanel(
tabPanel("Plot",
h3(helpText("Nordpool prices")),
#plotOutput("plot"),
reactableOutput("table")
#h3(helpText("Descr.statistics")),
#verbatimTextOutput("Descr.stat.price")
)
)
))
)
server <- function(input, output, session) {
sales_by_mfr<-reactive({
if (input$dist == "most_recent"){
data %>%
filter(Manufacturer %in% c("Chevrolet","Hyundai","Honda")) %>% group_by( Manufacturer) %>%
summarize(Quantity = n(), Sales = sum(Price))
}else{
data %>%
group_by( Manufacturer) %>%
summarize(Quantity = n(), Sales = sum(Price))
}
})
sales_by_mfr()$Quantity <- reactive(ifelse(sales_by_mfr()$Quantity == 2,200,sales_by_mfr()$Quantity))
#sales_by_mfr()[sales_by_mfr() == 2] <- reactive({200})
#Create columns in two rows (1-dat,2-diffs)
output$table <- renderReactable({
reactable(
sales_by_mfr(),#
# columns = columns(),columnGroups = columnGroups()
#defaultColDef = colDef(minWidth = 222,vAlign = "center"),
#defaultColDef = colDef(vAlign = "center", headerVAlign = "bottom"),
# Set a maximum width on the table:
#style = list(maxWidth = 650),
# Or a fixed width:
#width = 650,
)
})
}
shinyApp(ui = ui, server = server)
Try this
library(MASS)
library(reactable)
data <- MASS::Cars93[18:47, ] %>%
mutate(ID = as.character(18:47), Date = seq(as.Date("2019-01-01"), by = "day", length.out = 30)) %>%
dplyr::select(ID, Date, Manufacturer, Model, Type, Price)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
#sliderInput
radioButtons("dist", "Data:",
c("The most recent" = "most_recent",
"Historical" = "historical"))
),
# plot graphs
mainPanel(tabsetPanel(
tabPanel("Plot",
h3(helpText("Nordpool prices")),
#plotOutput("plot"),
reactableOutput("table")
#h3(helpText("Descr.statistics")),
#verbatimTextOutput("Descr.stat.price")
)
)
))
)
server <- function(input, output, session) {
sales_by_mfr<-reactive({
if (input$dist == "most_recent"){
data %>%
filter(Manufacturer %in% c("Chevrolet","Hyundai","Honda")) %>% group_by( Manufacturer) %>%
summarize(Quantity = n(), Sales = sum(Price))
}else{
data %>%
group_by( Manufacturer) %>%
summarize(Quantity = n(), Sales = sum(Price))
}
ifelse(data$Quantity == 2,200,data$Quantity)
data
})
#sales_by_mfr()$Quantity <- reactive(ifelse(sales_by_mfr()$Quantity == 2,200,sales_by_mfr()$Quantity))
#sales_by_mfr()[sales_by_mfr() == 2] <- reactive({200})
#Create columns in two rows (1-dat,2-diffs)
output$table <- renderReactable({
reactable(
sales_by_mfr(),#
# columns = columns(),columnGroups = columnGroups()
#defaultColDef = colDef(minWidth = 222,vAlign = "center"),
#defaultColDef = colDef(vAlign = "center", headerVAlign = "bottom"),
# Set a maximum width on the table:
#style = list(maxWidth = 650),
# Or a fixed width:
#width = 650,
)
})
}
shinyApp(ui = ui, server = server)

Filter a reactive object, based on other reactive object, while both depend on a third reactive object

I´m trying to filter a reactive object "#4" using other reactive object "#3" with no success, and I think the problem is that they both depend on another reactive "#2". This picture should help:
Here is the reprex:
library(shiny)
library(DT)
library(dplyr)
dat <- as.data.frame( list(
X = c("A", "A", "B", "B", "C"),
Y = c(1,2,3,4,5)
))
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("myinput", "Input:",min = 1, max = 5,value = 3)
),
mainPanel(
br(),
fluidRow(column(2, DTOutput('table_data'))),
br(),
fluidRow(column(2, DTOutput('table_filtered'))),
br(),
fluidRow(column(2, DTOutput('table_filtered_not_A'))),
br(),br(),
fluidRow(column(2, DTOutput('table_grouped')))
)
)
)
server <- function(input, output) {
dat_rv <- reactiveValues(df = dat)
dat_filtered <- reactive({
dat_rv$df %>%
filter(
!isTruthy( input$myinput ) | Y <= input$myinput
)
})
dat_not_A <- reactive({
dat_not_A <- dat_filtered() %>%
filter(X != "A") %>%
select(X)
})
dat_grouped <- reactive({
dat_grouped <- dat_filtered() %>%
filter(X %in% dat_not_A()) %>% # HERE IS THE PROBLEM?
group_by(X) %>%
summarise(Y = sum(Y))
return(dat_grouped)
})
output$table_data = renderDT(dat, options = list(dom = 't'), rownames = FALSE)
output$table_filtered = renderDT(dat_filtered(), options = list(dom = 't'), rownames = FALSE)
output$table_filtered_not_A = renderDT(dat_not_A(), options = list(dom = 't'), rownames = FALSE)
output$table_grouped = renderDT(dat_grouped(), options = list(dom = 't'), rownames = FALSE)
}
shinyApp(ui = ui, server = server)
I have also tried to use isolate but it has not work. Am i missing something?
Best regards.
You need to use:
dat_grouped <- reactive({
dat_grouped <- dat_filtered() %>%
filter(X %in% unique(dat_not_A()$X)) %>%
group_by(X) %>%
summarise(Y = sum(Y))
return(dat_grouped)
})
And not:
dat_grouped <- reactive({
dat_grouped <- dat_filtered() %>%
filter(X %in% dat_not_A()) %>%
group_by(X) %>%
summarise(Y = sum(Y))
return(dat_grouped)
})

How to copy tableOutput to clipboard?

I'm trying to copy the table output to the clipboard on a click of a button. I tried looking into the rclipboard package, but it doesn't appear to be able to copy output, in my limited understanding.
I added an actionButton with an icon to the screenshot to show what I'm trying to achieve. Right now the button doesn't do anything.
Code:
library(shiny)
library(dplyr)
df <- mtcars
one <- function(.data, var, na = TRUE) {
return({
.data %>%
group_by(.data[[var]]) %>%
filter(!is.na(.data[[var]])) %>%
tally() %>%
mutate(`%` = 100*n/sum(n))
})
}
ui <- fluidPage(
selectInput("var", label = "Select Variable", choices = c("", names(df))),
tableOutput("value")
)
server <- function(input, output) {
output$value <- renderTable({
if(input$var != '') {
data <- df %>% one(input$var, na = input$check)
return(data)
}
}, spacing = "xs", bordered = TRUE)
}
shinyApp(ui, server)
Perhaps you can use copy button from DT to copy the whole table. You can also copy only selected rows. Try this
library(shiny)
library(dplyr)
library(DT)
df <- mtcars
one <- function(.data, var, na = TRUE) {
return({
.data %>%
group_by(.data[[var]]) %>%
filter(!is.na(.data[[var]])) %>%
tally() %>%
mutate(`%` = 100*n/sum(n))
})
}
ui <- fluidPage(
selectInput("var", label = "Select Variable", choices = c("", names(df))),
DTOutput("valu", width = "15%")
#tableOutput("value")
)
server <- function(input, output) {
output$valu <- renderDT({
if(input$var != '') {
data <- df %>% one(input$var, na = input$check)
DT::datatable(data,
class = 'cell-border stripe',
rownames = FALSE,
extensions = c("Buttons", "Select"),
selection = 'none',
options =
list(
select = TRUE,
dom = "Bt", ## remove f to remove search ## Brftip
buttons = list(
list(
extend = "copy",
text = 'Copy'#,
#exportOptions = list(modifier = list(selected = TRUE))
)
)
)) %>% formatStyle(
0,
target = "row",
fontWeight = styleEqual(1, "bold")
)
}
}, server = FALSE)
output$value <- renderTable({
if(input$var != '') {
data <- df %>% one(input$var, na = input$check)
return(data)
}
}, spacing = "xs", bordered = TRUE)
}
shinyApp(ui, server)

Shiny table formatting

I am new to Shiny and have a basic shiny app using mtcars. I have multiple tabs with some input dropdowns and presenting the output as DT tables. This is all working fine, but I would now like to use some formatting like formattable. Some of the formatting I would like to include is basic percentage, decimal. Also, I would like to add some cell based highlighting. I have tried multiple formatting functions without any luck. I have added functions within the server side output, but I can not get the right combination. Below is my Shiny code:
library(shiny)
library(dplyr)
library(DT)
ui <- fluidPage(
titlePanel("mtcars"),
sidebarLayout(
sidebarPanel(
selectInput("cyl",
"cyl:",
c(unique(as.character(mtcars$cyl)))),
selectInput("gear",
"gear:",
c("All",
unique(as.character(mtcars$gear)))), width=2),
mainPanel(
tabsetPanel(
id = 'dataset',
tabPanel("Summary", DT::dataTableOutput("Summary")),
tabPanel("Detail", DT::dataTableOutput("Detail"))))))
server <- function(input, output) {
output$Detail <- renderDataTable(datatable({
data <- mtcars
if (input$cyl != "All") {
data <- data[data$cyl == input$cyl,]
}
if (input$gear != "All") {
data <- data[data$gear == input$gear,]
}
data
}))
output$Summary <- renderDataTable({
mtcars %>%
filter(cyl==input$cyl) %>%
group_by(gear) %>%
summarise(mpg = median(mpg),
count = n()) %>%
ungroup() %>%
arrange(desc(count))
})}
shinyApp(ui = ui, server = server)
I'm not sure what you've tried so far with formattable, but you should be able to use it with DT in your shiny app.
Here is a quick example you can try. This makes the mpg column a percentage. Also, if colors the count column a shade of green.
Other vignettes are available for other options with formattable package.
output$Summary <- renderDataTable({
my_data <- mtcars %>%
filter(cyl==input$cyl) %>%
group_by(gear) %>%
summarise(mpg = median(mpg),
count = n()) %>%
ungroup() %>%
arrange(desc(count))
# Make percent, for example
my_data$mpg <- percent(my_data$mpg)
# Return formattable datatable
return(
as.datatable(
formattable(
my_data,
list(
count = color_tile("transparent", "green")
)
)
)
)
})
To complete Ben's answer, even if you say you want to use formattable, I think there are enough options in DT to customize the tables the way you want.
Here's your example (randomly customized since you didn't specify the formatting of the cells):
library(shiny)
library(dplyr)
library(DT)
ui <- fluidPage(
titlePanel("mtcars"),
sidebarLayout(
sidebarPanel(
selectInput("cyl",
"cyl:",
c(unique(as.character(mtcars$cyl)))),
selectInput("gear",
"gear:",
c("All",
unique(as.character(mtcars$gear)))), width=2),
mainPanel(
tabsetPanel(
id = 'dataset',
tabPanel("Summary", DT::dataTableOutput("Summary")),
tabPanel("Detail", DT::dataTableOutput("Detail"))))))
server <- function(input, output) {
output$Detail <- renderDataTable(datatable({
data <- mtcars
if (input$cyl != "All") {
data <- data[data$cyl == input$cyl,]
}
if (input$gear != "All") {
data <- data[data$gear == input$gear,]
}
data
}))
output$Summary <- renderDataTable({
your_data <- mtcars %>%
filter(cyl==input$cyl) %>%
group_by(gear) %>%
summarise(mpg = median(mpg),
count = n()) %>%
ungroup() %>%
arrange(desc(count))
datatable(your_data) %>%
formatPercentage(columns = c("mpg", "gear")) %>%
formatRound(columns = c("count"), digits = 3) %>%
formatStyle(columns = "mpg",
valueColumns = "gear",
backgroundColor = styleEqual(c(3, 4, 5), c("red", "blue", "green")))
})}
shinyApp(ui = ui, server = server)
See here for more details, and here for several examples of color-styling.

Resources