Create shiny dashboard sidebar menu from dataframe - r

I am trying to create menu items under the dashboard Sidebar automatically from a table without success. I am using the code below.
library(shiny)
library(shinydashboard)
header = dashboardHeader(title = "title")
sidebar = dashboardSidebar(sidebarMenuOutput("sidebarMenu"))
body = dashboardBody()
ui = dashboardPage(header, sidebar, body)
labels = data.frame(id = c(1,2,3),
name = c("lab1", "lab2", "lab3"))
server = function(input, output) {
output$sidebarMenu <- renderMenu({
sidebarMenu(id="tabs",
for (i in labels) {
menuItem(labels$name[i], tabName = labels$id[i])
})
})
}
shinyApp(ui, server)
data.frame labels contains the labels and id I need to use in the menu. I am running a for loop. How should I do it?

for (i in labels)
This loop does not work since you will always get the dataframe, not not a row of the dataframe. Anyhow, I did not get it to work with the loop, i normally use a combination of lapply to store all items in a list and use do.call to visualize it with the renderUI function.
library(shiny)
library(shinydashboard)
labels = data.frame(id = c(1,2,3),
name = c("lab1", "lab2", "lab3"))
header = dashboardHeader(title = "title")
sidebar = dashboardSidebar(sidebarMenu(id="mytabs",
uiOutput("sidebar_menu_UI")))
body = dashboardBody()
ui = dashboardPage(header, sidebar, body)
server = function(input, output) {
output$sidebar_menu_UI <- renderUI({
myTabs = lapply(1:nrow(labels) , function(i) {
menuItem(labels$name[i], tabName = labels$id[i])
})
print(myTabs)
do.call(sidebarMenu, myTabs)
})
}
shinyApp(ui, server)

Related

How to apply JS/ jQuery within the cell ids of a DT?

I would like to apply JS/Jquery within the cell ids of a DT.
I used .css() as an example, but I have other plans, so I asked the question. My intention is not to color the words, but to use other functions.
My code:
library(shiny)
library(shinydashboard)
library(DT)
header <- dashboardHeader(title = "DT")
sidebar <- dashboardSidebar(sidebarMenu(menuItem(text = "mydatatable", tabName = "dt1")))
body <- dashboardBody(
HTML(
"<head>
<script>
$(function() {
$('#stackid, #dtid').mouseover(function() {
$(this).css('color','red');
});
$('#stackid, #dtid').mouseout(function() {
$(this).css('color','#333333');
});
});
</script>
</head>"
),
tabItems(
tabItem(
tabName = "dt1",
fluidPage(
column(
width = 12,
HTML("<strong id='dtid' style='font-size:50px;'>DATATABLE</strong>"),
DTOutput(outputId = "outdt1")
)
)
)
)
)
ui <- dashboardPage(header, sidebar, body)
server <- function(input, output, session) {
df_1 <- data.frame(
x = c("<span id='stackid'>Stack</span>", "Over", "Flow"),
y = 1:3,
z = LETTERS[1:3]
)
output$outdt1 <- DT::renderDataTable({
datatable(
data = df_1,
escape = FALSE
)
})
}
shinyApp(ui, server)
I tried using JS/ jQuery inside tags$div() on server, but that didn't work either.
See that the effect is applied to dtid, as expected. But, my intention is to apply the effect within the id of the DT.

Empty the search bar of a datatable by default instead of including the highlighted text

Is there a way to make the Search bar of the datatable empty instead of having the 'setosa' inside it by default while keeping the 'setosa' highlighted inside the table? Or at least find another way to highlight or underline the 'setosa'?
library(DT)
ui <- dashboardPage(
dashboardHeader(title = "Dynamic sidebar"),
dashboardSidebar(
),
dashboardBody(
DT::dataTableOutput("t")
)
)
server <- function(input, output) {
output$t <- renderDT(
datatable(iris, options = list(searchHighlight = TRUE, search = list(search = 'setosa')))
)
}
shinyApp(ui, server)
Ok, you can do something like this.
library(DT)
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "Dynamic sidebar"),
dashboardSidebar(
),
dashboardBody(
DT::dataTableOutput("t")
)
)
server <- function(input, output) {
data <- reactive({
mydata <- iris
rownames(mydata) <- gsub("setosa",tags$span(style="color:red", "setosa"),rownames(mydata))
for(i in 1:ncol(mydata)){
mydata[,i] <- gsub("setosa",tags$span(style="color:red", "setosa"),mydata[,i])
}
mydata
})
output$t <- renderDT(
datatable(data(), options = list(searchHighlight = TRUE, search = list(search = '')), escape = F)
)
}
shinyApp(ui, server)

Shiny: Using dynamic renderUI's with actionLinks and shinyJS

I am building a dashboard where I need to create a number of boxes (based on the dataset) provided and then have each box be able to click and show subset boxes.
I can do this if I knew the data beforehand but I am having trouble with creating link id's and showing and hiding content when creating things dynamically.
Below is the code of how it should function (but using static content)
library(shiny)
library(shinydashboard)
library(shinyjs)
#####/UI/####
header <- dashboardHeader()
sidebar <- dashboardSidebar()
body <- dashboardBody(
useShinyjs(),
fluidRow(
uiOutput("box1"),
uiOutput("box2"),
uiOutput("box3")
),
fluidRow(
div(id = "ILRow",
uiOutput("box1a"),
uiOutput("box1b"),
uiOutput("box1c")
),
div(id = "NCRow",
uiOutput("box2a"),
uiOutput("box2b")
),
div(id = "INRow",
uiOutput("box3a")
)
)
)
ui <- dashboardPage(header, sidebar, body)
#####/SERVER/####
server <- function(input, output) {
CSRbox <- function(description = NULL, linkName = NULL) {
# the box tags
withTags(
# col
div(
class = "col-md-2",
# Widget: user widget style 1
div(
class = "box",
## Box Header ##
div(
actionLink(linkName, NULL, icon = icon("plus-square-o", "fa-2x")),
h2(description)
)
)
)
)
}
dat <- data.frame(State = c("Illinois","Illinois","Illinois","North Carolina","North Carolina","Indiana"), City = c("Chicago","Niles","Evanston","Charlotte","Raleigh","West Lafayette"))
output$box1 <- renderUI({
CSRbox("Illinois", "Ill_Link")
})
output$box2 <- renderUI({
CSRbox("North Carolina", "NC_Link")
})
output$box3 <- renderUI({
CSRbox("Indiana", "IN_Link")
})
output$box1a <- renderUI({
CSRbox("Chicago", "CH_Link")
})
output$box1b <- renderUI({
CSRbox("Niles", "NI_Link")
})
output$box1c <- renderUI({
CSRbox("Evanston", "EV_Link")
})
output$box2a <- renderUI({
CSRbox("Charlotte", "CA_Link")
})
output$box2b <- renderUI({
CSRbox("Raleigh", "RL_Link")
})
output$box3a <- renderUI({
CSRbox("West Lafayette", "WL_Link")
})
shinyjs::hide("ILRow")
shinyjs::hide("NCRow")
shinyjs::hide("INRow")
observeEvent(input$Ill_Link, {
shinyjs::toggle("ILRow")
shinyjs::hide("NCRow")
shinyjs::hide("INRow")
})
observeEvent(input$NC_Link, {
shinyjs::toggle("NCRow")
shinyjs::hide("ILRow")
shinyjs::hide("INRow")
})
observeEvent(input$IN_Link, {
shinyjs::toggle("INRow")
shinyjs::hide("ILRow")
shinyjs::hide("NCRow")
})
}
shinyApp(ui, server)
Below is the code of creating the boxes dynamically but the functionality doesn't work (this is where I need help!):
library(shiny)
library(shinydashboard)
library(shinyjs)
#####/UI/####
header <- dashboardHeader()
sidebar <- dashboardSidebar()
body <- dashboardBody(
useShinyjs(),
fluidRow(
uiOutput("boxLevel1")
),
fluidRow(
div(id = "LevelDetail",
uiOutput("boxLevel2")
)
)
)
ui <- dashboardPage(header, sidebar, body)
#####/SERVER/####
server <- function(input, output) {
CSRbox <- function(description = NULL, linkName = NULL) {
# the box tags
withTags(
# col
div(
class = "col-md-2",
# Widget: user widget style 1
div(
class = "box",
## Box Header ##
div(
actionLink(linkName, NULL, icon = icon("plus-square-o", "fa-2x")),
h2(description)
)
)
)
)
}
dat <- data.frame(State = c("Illinois","Illinois","Illinois","North Carolina","North Carolina","Indiana"), City = c("Chicago","Niles","Evanston","Charlotte","Raleigh","West Lafayette"))
output$boxLevel1 <- renderUI({
lapply(sort(unique(dat$State)), function(name) {
CSRbox(name, paste0(name,"Link"))
})
})
output$boxLevel2 <- renderUI({
temp <- dat[dat$State == "Illinois",] #Should be based of off the input$Click of the Input Link. Ex: input$Illinois
lapply(sort(unique(temp$City)), function(name) {
CSRbox(name, paste0(name,"Link2"))
})
})
shinyjs::hide("LevelDetail")
observeEvent(input$IllinoisLink, { #Would need to loop through and make an observeEvent for each possible input$click
shinyjs::toggle("LevelDetail")
})
}
shinyApp(ui, server)
UPDATE
I have figured out how to track the input ID's which allows me to create the correct subset of boxes dynamically(woo!). I am still having trouble with the show and hide though. I have figured out how to show the subset of boxes but I can't figure out how to hide since I am using the input ID which doesn't change when pressing on the link twice so the observeEvent doesn't run. I tried to get just the input of the link which would tell me the count of it so I know if it's changed BUT I am getting errors when I use the input[[input$last_btn]] (which should be the same as ex: input$Illinois). Any help is appreciated! I could add another button separately that would do the hide but that is not ideal.
library(shiny)
library(shinydashboard)
library(shinyjs)
#####/UI/####
header <- dashboardHeader()
sidebar <- dashboardSidebar()
body <- dashboardBody(
useShinyjs(),
tags$head(tags$script(HTML("$(document).on('click', '.needed', function () {
Shiny.onInputChange('last_btn',this.id);
});"))),
fluidRow(
uiOutput("boxLevel1"),
textOutput("lastButtonCliked")
),
fluidRow(
div(id = "LevelDetail",
uiOutput("boxLevel2")
)
)
)
ui <- dashboardPage(header, sidebar, body)
#####/SERVER/####
server <- function(input, output) {
CSRbox <- function(description = NULL, linkName = NULL) {
# the box tags
withTags(
# col
div(
class = "col-md-2",
# Widget: user widget style 1
div(
class = "box",
## Box Header ##
div(
actionLink(linkName, NULL, icon = icon("plus-square-o", "fa-2x"), class="needed"),
h2(description)
)
)
)
)
}
dat <- data.frame(State = c("Illinois","Illinois","Illinois","North Carolina","North Carolina","Indiana"), City = c("Chicago","Niles","Evanston","Charlotte","Raleigh","West Lafayette"))
output$boxLevel1 <- renderUI({
lapply(sort(unique(dat$State)), function(name) {
CSRbox(name, paste0(name))
})
})
output$boxLevel2 <- renderUI({
temp <- dat[dat$State == input$last_btn,] #Should be based of off the input$Click of the Input Link. Ex: input$Illinois
lapply(sort(unique(temp$City)), function(name) {
CSRbox(name, paste0(name,"Link2"))
})
})
avs <- reactiveValues(
clickN = NA, #new click
clickO = NA, #original click
dataSame = TRUE #data sets are the same
)
observe({
avs$clickN <- input$last_btn
})
shinyjs::hide("LevelDetail")
observeEvent(input$last_btn, {
avs$dataSame <- identical(avs$clickN, avs$clickO)
if(!avs$dataSame) {
shinyjs::show("LevelDetail")
avs$clickO <- avs$clickN
} else {
shinyjs::hide("LevelDetail")
avs$clickO <- NULL
}
})
}
shinyApp(ui, server)

How to display reactive number of tables at once (with different results)? Shiny App

I have a problem with displaying reactive number of tables depending on my selection. What I'd like to do is to render as many tables as it's unique records in one column and display them one by one with results for each subgroup.
It'll be easier if I share this example:
dashboardHeader(title = "My App"),
dashboardSidebar(id="", sidebarMenu(
menuItem(strong("Tab1"), tabName = "T1", icon = icon("table")))),
dashboardBody(
tabItems(
tabItem(
tabName="T1",
fluidRow(tableOutput('tables'))
)
)
)
)
server <- function(input, output) {
observeEvent(length(unique(mtcars$gear)), {
lapply(1:length(unique(mtcars$gear)),
function(i){
output[[paste0('table', i)]]<-renderTable({
filtered<-mtcars
a<-list()
for (j in unique(filtered$gear)){
subd <- filtered[filtered$gear == j,]
a[[j]]<-subd
}
for(i in 1:length(a)){
a[[i]]
}
a[[3]]
})
})
})
output$tables <- renderUI({
lapply(1:length(unique(mtcars$gear)),
function(i) {
uiOutput(paste0('table', i))
})
})
}
shinyApp(ui = ui, server = server)
What I'd like to get out of this code is to have 3 tables (one with summary table for gear=3, one for gear=4 and one for gear=5). What I'm getting right now is 3 tables with results for gear=3.
I've tried to write a for loop which goes through the list but I don't know where I supposed to add this for loop to make it work correctly.
Thanks!
You can use split to make a list of tables based on the levels of a factor within the data frame. From there, slight modifications of your renderUI should get you the desired results. Note also that I changed the tables output to uiOutput instead of tableOutput because you populate that with renderUI.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "My App"),
dashboardSidebar(id = "", sidebarMenu(
menuItem(strong("Tab1"), tabName = "T1", icon = icon("table"))
)),
dashboardBody(tabItems(tabItem(
tabName = "T1",
fluidRow(uiOutput('tables'))
)))
)
server <- function(input, output) {
tables_in_list <- split(x = mtcars, f = mtcars$gear)
output$tables <- renderUI({
lapply(seq_along(tables_in_list), function(i)
renderTable(tables_in_list[[i]]))
})
}
shinyApp(ui = ui, server = server)

Left align checkboxgroups to a single column in a shiny sidebar

New to R/Shiny, I'm attempting to create checkboxgroups in a Shiny sidebar where choices are in a single column and left aligned.
Additionally, is there any way to remove the break/space between the first and second checkboxinputs?
I've tried turning "inline" on and off, but it doesn't seem related. From what I can see in the forums, the answer might require HTML/CSS, but I'm not sure how to integrate that into a sidebar/checkbox group.
Here's how the code looks currently:
library(shiny)
library(shinydashboard)
sidebar <- dashboardSidebar(
checkboxGroupInput( inputId='ABC', label='ABC', choices= c('A','B','C'), inline=TRUE )
,checkboxInput('bar0','All/None', value=TRUE))
header <- header <- dashboardHeader(
title = "aligned column",titleWidth = 300)
body <- dashboardBody()
ui <- dashboardPage(title = 'aligned column', header, sidebar, body)
server <- function(input, output,session) {
## All/None buttons on selections ----
observeEvent( input$bar0, {
updateCheckboxGroupInput(
session, 'ABC', choices = c('A','B','C'), inline=TRUE,
selected = if (input$bar0) choices = c('A','B','C'))})
}
shinyApp(ui, server)
Thanks!
Hello Adam have you tried changing inline = FALSE in the server section? Like so:
server <- function(input, output,session) {
## All/None buttons on selections ----
observeEvent( input$bar0, {
updateCheckboxGroupInput(
session, 'ABC', choices = c('A','B','C'), inline=FALSE,
selected = if (input$bar0) choices = c('A','B','C'))})
}
This seems to have worked for me. If I am understanding your question, this is what you wanted to do right? Screenshot

Resources