Dark mode switch doesn't work using navbarPage - shiny - r

I have a shiny app for which I'd like to add a dark mode switch. I've managed to do that after some research online but as I was trying to implement this bit of code in my app I encountered issues. I have been trying several things on a simpler app to try to identify what causes the switch to not work and I came to the conclusion that adding a navbarPage to my app is what makes it crash.
Below is a simple example:
library(shiny)
library(DT)
library(shinyWidgets)
library(bslib)
ui <- fluidPage(
theme=bs_theme(),
# navbarPage("TITLE",
sidebarLayout(
sidebarPanel(
numericInput("num", label = h3("Numeric input"), value = 1),
materialSwitch(inputId = "mode", label = icon("moon"), right=TRUE,status = "success")),
mainPanel(verbatimTextOutput("value")) #fin main panel
)
# )
)
server <- function(input, output,session) {
observe({
if(input$mode==TRUE)
session$setCurrentTheme(bs_theme_update(theme, bootswatch = "superhero"))
if(input$mode==FALSE)
session$setCurrentTheme(bs_theme_update(theme, bootswatch = "default"))
})
output$value <- renderPrint({ input$num })
}
shinyApp(ui, server)
As long as the navbar line and corresponding ")" is considered as a comment it works fine but as soon as I uncomment these two lines I get this error:
Warning: Navigation containers expect a collection of `bslib::nav()`/`shiny::tabPanel()`s and/or `bslib::nav_menu()`/`shiny::navbarMenu()`s. Consider using `header` or `footer` if you wish to place content above (or below) every panel's contents.
Listening on http://--.--
Warning: Error in : session$setCurrentTheme() cannot be used to change the Bootstrap version from to 4. Try using `bs_theme(version = 4)` for initial theme.
47: stop
46: session$setCurrentTheme
45: observe [C:/Users/user/Documents/shiny/SHINY-APP/app4.R#23]
44: <observer>
1: runApp
I am very new to shiny despite being familiar with R but I really don't understand this error. I have been trying to find answers in the documentation associated to the different functions I'm using as well as in previously asked questions on SO but I haven't been able to fix this yet.
Any help would be greatly appreciated!
Thank you !

You have to specify the theme both in the fluidPage and the navbarPage (maybe you can get rid of fluidPage, didn't test it)
library(shiny)
library(DT)
library(shinyWidgets)
library(bslib)
ui <- fluidPage(
theme=bs_theme(version = 4, bootswatch = "default"),
navbarPage("TITLE",
theme=bs_theme(version = 4, bootswatch = "default"),
tabPanel("Tab",
sidebarLayout(
sidebarPanel(
numericInput("num", label = h3("Numeric input"), value = 1),
materialSwitch(inputId = "mode", label = icon("moon"),
right=TRUE,status = "success")),
mainPanel(verbatimTextOutput("value")) #fin main panel
)
)
)
)
server <- function(input, output,session) {
observe(session$setCurrentTheme(
if(isTRUE(input$mode)){
bs_theme(bootswatch = "superhero")
} else {
bs_theme(bootswatch = "default")
}
))
output$value <- renderPrint({ input$num })
}
shinyApp(ui, server)

Related

Waiter for R shiny not showing properly when using it on renders of different tabPanel

I have an issue with the waiter which I need for an app built with R shiny.
The example below (based on the fantastic website on the waiter package by John Coene: https://waiter.john-coene.com/#/waiter/examples#on-render) helps me illustrate my issue.
The app is made of two tabPanels, the first one which shows a table, and the second one that shows a chart. The table and the chart will appear after some waiting time, and the waiter spinner should, in the meantime, appear in the middle of the rendering areas of both tabPanels.
However, what actually happen is that the waiter spinner only shows up in the middle of the rendering area of the tabPanel I open first, whereas in the other tabPanel it is stuck in the top-left corner of the page.
Many thanks in advance for whoever can help me fix this problem!
library(shiny)
library(highcharter)
library(shinythemes)
library(waiter)
ui <- fluidPage(
theme = shinytheme("cyborg"),
useWaiter(),
actionButton("draw", "render stuff"),
fluidPage(
tabsetPanel(
tabPanel("Table", tableOutput("table")),
tabPanel("Chart", highchartOutput("hc"))
)
)
)
server <- function(input, output){
# specify the id
w <- Waiter$new(id = c("hc", "table"))
dataset <- reactive({
input$draw
w$show()
Sys.sleep(8)
head(cars)
})
output$table <- renderTable(dataset())
output$hc <- renderHighchart({
hchart(dataset(), "scatter", hcaes(speed, dist))
})
}
shinyApp(ui, server)
I would recommend you use shinycssloaders instead. The reason is that loaders' positions in waiter are calculated by current visible height and width. However, there is no visible position in the second tab or the hidden tabs, so waiter can't add the loader to the right spot. There is no fix we can do here. This is a feature that waiter doesn't support currently.
library(shiny)
library(highcharter)
library(shinythemes)
library(shinycssloaders)
ui <- fluidPage(
theme = shinytheme("cyborg"),
actionButton("draw", "render stuff"),
fluidPage(
tabsetPanel(
tabPanel("Table", withSpinner(tableOutput("table"), type = 3, color.background = "#060606", color = "#EEEEEE")),
tabPanel("Chart", withSpinner(highchartOutput("hc"), type = 3, color.background = "#060606", color = "#EEEEEE"))
)
)
)
server <- function(input, output){
dataset <- reactive({
input$draw
Sys.sleep(4)
head(cars)
})
output$table <- renderTable(dataset())
output$hc <- renderHighchart({
hchart(dataset(), "scatter", hcaes(speed, dist))
})
}
shinyApp(ui, server)

Forcing updates to htmlOutput within a long running function

I have a Shiny application that runs a long process and I would like to alert the user that the process is actually running. In the example below, I have a toggle switch that executes a block of code with a 1 second delay (my actual application runs for about 20 seconds), and I have an HTMLoutput box that should let the user know something is happening. But, since the underlying bootstrap process only updates the UI elements after the function exits, users only see the last message, "Done".
I've seen other questions like this one with answers that suggest creating a reactive value and then wrapping the renderUI() function in an observe() function (here, for example), but this has the same problem.
I also tried wrapping the htmlOutput() in withSpinner() from the shinycssloaders package, but I get an error saying "missing value where TRUE/FALSE needed". I assume this is coming from shinydashboardPlus because it doesn't like the withspinner() output in the tagList() elements. I was hopeful that this would at least give me an animated spinner on the HTMLoutput indicating that it is running.
Any input on getting this specific setup to work or alternatives to give users some feedback that the process is active is greatly appreciated.
library(shiny)
library(shinycssloaders)
library(shinydashboard)
library(shinydashboardPlus)
library(shinyWidgets)
# Define UI for application that draws a histogram
ui <- dashboardPage(skin = 'blue',
shinydashboardPlus::dashboardHeader(title = 'Example',
leftUi = tagList(
switchInput(inputId = 'swtLabels', label = 'Labels', value = TRUE,
onLabel = 'Label 1', offLabel = 'Label 2',
onStatus = 'info', offStatus = 'info', size = 'mini',
handleWidth = 230),
htmlOutput(outputId = 'labelMessage')
#withSpinner(htmlOutput(outputId = 'labelMessage')) # leads to error noted in text
)
),
dashboardSidebar(),
dashboardBody()
)
server <- function(input, output) {
rv <- reactiveValues()
rv$labelMessage <- 'Start'
observeEvent(input$swtLabels, {
rv$labelMessage <- 'Updating labels...'
Sys.sleep(1)
rv$labelMessage <- 'Done'
})
output$labelMessage <- renderUI(HTML(rv$labelMessage))
}
# Run the application
shinyApp(ui = ui, server = server)
I found a workaround for this using the shinyjs package, code below. The take home message is that by using shinjs::html(), the effect on the htmlOutput is immediate. I even added a fancy fade out at the end to hide the message.
It does create yet another package dependency, but it solves the problem. I'm sure there is a way that one could write a small JavaScript function and add it to the Shiny application to accomplish this same result. Unfortunately, I don't know JavaScript. (References for including JS code in a Shiny app - JavaScript Events in Shiny, Add JavaScript and CSS in Shiny)
library(shiny)
library(shinycssloaders)
library(shinydashboard)
library(shinyjs)
library(shinydashboardPlus)
library(shinyWidgets)
# Define UI for application that draws a histogram
ui <- dashboardPage(skin = 'blue',
shinydashboardPlus::dashboardHeader(title = 'Example',
leftUi = tagList(
useShinyjs(),
switchInput(inputId = 'swtLabels', label = 'Labels', value = TRUE,
onLabel = 'Label 1', offLabel = 'Label 2',
onStatus = 'info', offStatus = 'info', size = 'mini',
handleWidth = 230),
htmlOutput(outputId = 'labelMessage')
#withSpinner(htmlOutput(outputId = 'labelMessage')) # leads to error noted in text
)
),
dashboardSidebar(),
dashboardBody()
)
server <- function(input, output) {
observeEvent(input$swtLabels, {
shinyjs::html(id = 'labelMessage', html = 'Starting...')
shinyjs::showElement(id = 'labelMessage')
Sys.sleep(1)
shinyjs::html(id = 'labelMessage', html = 'Done')
shinyjs::hideElement(id = 'labelMessage', anim = TRUE, animType = 'fade', time = 2.0)
})
}
# Run the application
shinyApp(ui = ui, server = server)

Using R Shiny for Multiple Linear Regression (SelectInput --> multiple=TRUE)

I'm having some trouble getting my R Shiny code to produce a dynamic dashboard where the user can select 1 or more independent variables in a linear regression model and print the results. I've been able to successfully follow examples where the user only inputted one independent variable, but with multiple independent variables, I have not found the same luck. I'm not sure what I am doing wrong, but I get an error that reads, "invalid term in model formula".
Below is the code I've used so far:
library(shinythemes)
library(shinyWidgets)
library(shiny)
library(shinydashboard)
#data(mtcars)
AttributeChoices=c("cyl","disp","hp","drat","wt","qsec","vs")
# Define UI for application
ui = fluidPage(
navbarPage("R Shiny Dashboard",
tabPanel("Welcome",
tabName = "welcome",
icon=icon("door-open"),
fluidPage(theme=shinytheme("cerulean"),
h1("Welcome to my Shiny Dashboard!"),
br(),
p(strong(tags$u("What is this dashboard all about?"))),
p("I'm going to do stuff."),
br(),
p(strong(tags$u("Here's another question."))),
p("Here's my answer."),
br(),
p(strong(tags$u("How can I use this dashboard?"))),
p("You can click on any of the tabs above to see a different analysis of the data.")
)),
tabPanel("Regression",
tabname="regression",
icon=icon("calculator"),
selectInput(inputId = "indep", label = "Independent Variables",
multiple = TRUE, choices = as.list(AttributeChoices), selected = AttributeChoices[1]),
verbatimTextOutput(outputId = "RegOut")
)
))
# Define server logic
server <- function(input, output) {
#-------------------REGRESSION-------------------#
lm_reg <- reactive(
lm(as.formula(paste(mtcars$mpg," ~ ",paste(input$indep,collapse="+"))),data=CFD)
)
output$RegOut = renderPrint({summary(lm_reg())})
}
# Run the application
shinyApp(ui = ui, server = server)
Reading similar posts on StackOverflow seem to suggest the problem might be with the column names having spaces, but that's not the case here in this example. I am not sure how to resolve this issue. Can anyone help point me in the right direction? Thank you!
Here you go, I like to use the recipe package for problems like this instead of relying on very hard string manipulation, the trick is to use the !!! operator, you can even get fancy and let the user pass some select helpers
library(shinythemes)
library(shinyWidgets)
library(shiny)
library(shinydashboard)
library(recipes)
#data(mtcars)
AttributeChoices=c("cyl","disp","hp","drat","wt","qsec","vs")
# Define UI for application
ui = fluidPage(
navbarPage("R Shiny Dashboard",
tabPanel("Welcome",
tabName = "welcome",
icon=icon("door-open"),
fluidPage(theme=shinytheme("cerulean"),
h1("Welcome to my Shiny Dashboard!"),
br(),
p(strong(tags$u("What is this dashboard all about?"))),
p("I'm going to do stuff."),
br(),
p(strong(tags$u("Here's another question."))),
p("Here's my answer."),
br(),
p(strong(tags$u("How can I use this dashboard?"))),
p("You can click on any of the tabs above to see a different analysis of the data.")
)),
tabPanel("Regression",
tabname="regression",
icon=icon("calculator"),
selectInput(inputId = "indep", label = "Independent Variables",
multiple = TRUE, choices = as.list(AttributeChoices), selected = AttributeChoices[1]),
verbatimTextOutput(outputId = "RegOut")
)
))
# Define server logic
server <- function(input, output) {
#-------------------REGRESSION-------------------#
recipe_formula <- reactive(mtcars %>%
recipe() %>%
update_role(mpg,new_role = "outcome") %>%
update_role(!!!input$indep,new_role = "predictor") %>%
formula())
lm_reg <- reactive(
lm(recipe_formula(),data = mtcars)
)
output$RegOut = renderPrint({summary(lm_reg())})
}
# Run the application
shinyApp(ui = ui, server = server)

How to highlight R or Python code in markdown chunk embedded in shiny app

I am trying to return a dynamic code chunk in R as part of a shiny app. A simple example of what I am trying to do is,
library(shiny)
runApp(list(
ui = bootstrapPage(
sliderInput("mu", "Mean", min=-30, max=30, value=0, step=0.2),
uiOutput('chunk')
),
server = function(input, output) {
output$chunk <- renderUI({
HTML(markdown::markdownToHTML(text=paste0("```{r}",
"\n dnorm(0, ", input$mu,", 2)"),
options=c("highlight_code"))) })
}
))
This produces an unformatted code chunk. I would like to be able to use pygments/another-solution to highlight this code, and also python/other-language code which will form part of a web app.
Any ideas?
Additional Languages
Here's a solution that works for highlighting many different languages. It's based on this answer, which uses Prism. We load the Prism dependencies and then load dependencies for each language we want to highlight.
## from: https://stackoverflow.com/a/47445785/8099834
## get prism dependencies
prismDependencies <- tags$head(
tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/prism/1.8.4/prism.min.js"),
tags$link(rel = "stylesheet", type = "text/css",
href = "https://cdnjs.cloudflare.com/ajax/libs/prism/1.8.4/themes/prism.min.css")
)
prismLanguageDependencies <- function(languages) {
lapply(languages, function(x) {
tags$head(
tags$script(
src = paste0("https://cdnjs.cloudflare.com/ajax/libs/prism/1.8.4/components/prism-",
x, ".min.js")
)
)
})
}
## format code with tags and language
prismAddTags <- function(code, language = "r") {
paste0("<pre><code class = 'language-", language, "'>",
code,
"</code></pre>")
}
prismCodeBlock <- function(code, language = "r") {
tagList(
HTML(prismAddTags(code, language = language)),
tags$script("Prism.highlightAll()")
)
}
## run app
library(shiny)
runApp(list(
ui = bootstrapPage(
prismDependencies,
prismLanguageDependencies(c("sql", "r", "python")),
sliderInput("mu", "Mean", min=-30, max=30, value=0, step=0.2),
uiOutput('r_chunk'),
uiOutput('python_chunk'),
uiOutput('sql_chunk')
),
server = function(input, output) {
output$r_chunk <- renderUI({
prismCodeBlock(
code = paste0("# this is R code\ndnorm(0, ", input$mu,", 2)"),
language = "r"
)
})
output$python_chunk <- renderUI({
prismCodeBlock(
code = '# this is python code
# Say hello, world.
print ("Hello, world!")',
language = "python"
)
})
output$sql_chunk <- renderUI({
prismCodeBlock(
code = "-- this is SQL code
SELECT * FROM mytable WHERE 1=2",
language = "sql"
)
})
}
))
Updated Answer
As pointed out in the comments, the original answer doesn't work. Turns out getting the highlighting to work takes a little more effort.
Fortunately, someone has already figured it out! They have written two functions: renderCode for the server and outputCode for the ui which seem to work well. The package is here and the relevant functions are here.
Here's an example:
## install the package
library(devtools)
install_github("statistikat/codeModules")
## run the app
library(codeModules)
library(shiny)
runApp(list(
ui = bootstrapPage(
sliderInput("mu", "Mean", min=-30, max=30, value=0, step=0.2),
codeOutput('chunk')
),
server = function(input, output) {
output$chunk <- renderCode({
paste0("dnorm(0, ", input$mu,", 2)")
})
}
))
Original Answer -- Doesn't work
highlight.js will format your code and is included in shiny. Per this answer, it supports 169 languages at this time.
You just need to tag your code. Try something like this:
library(shiny)
highlightCode <- function(code) {
HTML(
paste0("<pre><code class='html'>",
code,
"</code></pre>")
)
}
runApp(list(
ui = bootstrapPage(
sliderInput("mu", "Mean", min=-30, max=30, value=0, step=0.2),
uiOutput('chunk')
),
server = function(input, output) {
output$chunk <- renderUI({
highlightCode(paste0("dnorm(0, ", input$mu,", 2)"))
})
}
))

Shiny R, always-refreshing the code after input

I would ask. Does Shiny do like always-refreshing the code after input ?
First I code this in ui :
box( ##title="Quality Attributes",
selectInput("att_ViewChart", width = '100%',label="Quality Attributes",
##multiple = TRUE,
choices=list(
"-",
"Suitability",
"Security",
)
)
),
dataTableOutput("tabelstatus")
Then I code this in server :
server = function(input, output) {
withProgress(message = "AAAAA",{
DateStatus_Sui<-c(1,2,3,4,NA,5,6,NA,7)
TimeStatus_Sui<-c(11,22,33,44,NA,55,66,NA,88)
status_Sui<-c(11,22,44,55,66,77,88)
jumlah<-7
})
if(input$att_ViewChart=="Suitability"){
Date<-DateStatus_Sui[!is.na(DateStatus_Sui)]
Time<-TimeStatus_Sui[!is.na(TimeStatus_Sui)]
Status<-status_Sui
Observation<-1:jumlah
#output
tabelstatus<-data.frame(Observation,Date,Time,Status)
output$tabelstatus<-renderDataTable(tabelstatus)
}
I hope when I run the app. Shiny will process the code (shown by progress bar 'AAAAA') And after that, if I choose Suitability it will do a little more process and then show the table . But I found that the progress bar appears again. Seems to me it re-runs the code from the beginning. How to fix this? Thank you
In the abscence of a fully reproducible example, I'm guessing this is what you're trying to do (i.e, make the table reactive according to your input$att_ViewChart):
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
box( selectInput("att_ViewChart", width = '100%',label="Quality Attributes",
choices=c("-","Suitability","Security"))),
dataTableOutput("tablestatus")
)
)
server = function(input, output) {
withProgress(message = "AAAAA",{
DateStatus_Sui<-c(1,2,3,4,NA,5,6,NA,7)
TimeStatus_Sui<-c(11,22,33,44,NA,55,66,NA,88)
status_Sui<-c(11,22,44,55,66,77,88)
jumlah<-7
})
## make your table reactive on `input$att_ViewChart`
output$tablestatus <- renderDataTable({
if(input$att_ViewChart=="Suitability"){
Date<-DateStatus_Sui[!is.na(DateStatus_Sui)]
Time<-TimeStatus_Sui[!is.na(TimeStatus_Sui)]
Status<-status_Sui
Observation<-1:jumlah
tablestatus <- data.frame(Observation,Date,Time,Status)
}else{
tablestatus <-data.frame()
}
return(tablestatus)
})
}
shinyApp(ui = ui, server = server)

Resources