Triggering alerts with validate-need in Shiny? - html

I am having difficulty triggering an alert in a Shiny app that I have created. The app itself is very simple, and displays one slider with numbers and a line plot. However, I would like for an alert to be triggered whenever the slider is set to a value above 5. Here is the code:
UI
library(shiny)
library(shinythemes)
library(shinyBS)
shinyUI(fluidPage(theme = shinytheme("superhero"),
tags$head(
tags$style(HTML("
.shiny-output-error-validation {
color: green;
}
"))
),
sidebarLayout(
sidebarPanel(
sliderInput("samplestat",
"Value:",
min = 1,
max = 10,
value = 1)
),
mainPanel(
h3("Graph", style = "font-family: 'Jura'; color: blue; font-size: 32px;"),
HTML("<p>Graph</p>"),
plotOutput("LinePlot")
)
)
))
SERVER
library(shiny)
library(ggplot2)
library(scales)
samplestat <- function(input) {
if (input > 5) {
"Choose another value. samplestat must be below 5!"
} else if (input < 4) {
FALSE
} else {
NULL
}
}
shinyServer(function(input, output) {
data <- reactive({
validate(
need(input$data != "", "Please select a value below 5")
)
get(input$data)
})
output$LinePlot <- renderPlot({
n=1:10
samplestat <- seq(min(n), max(n), length.out = input$samplestat)
plot(samplestat, type = "o", col = 'blue', border = 'white', xlab="X Axis", ylab ="Y Axis")
}
)
})
When I run this code, the line and slider displays, but I do not get any alert when I slide the slider to a value above 5. I am not sure if I am possibly using validate-need incorrectly, or whether I have overlooked something else.

You should place validate(...) insider renderPlot({...}). That is, your server.R should be something like:
function(input, output) {
output$LinePlot <- renderPlot({
validate(
need(input$samplestat <= 5, "Please select a value below 5")
)
n <- 1:10
samplestat <- seq(min(n), max(n), length.out = input$samplestat)
plot(samplestat, type = "o", col = 'blue',
fg = 'white', xlab= "X Axis", ylab = "Y Axis")
})
}
which produces this output:
Note that there should be no problem with wrapping your validation code in a reactive function. Suppose your function to test for a condition is
validate_samplestat <- function(input) {
if (input > 5) {
"Choose another value. samplestat must be below 5!"
} else {
NULL
}
}
You can wrap this in reactive in your main server function, and place the reactive function in your output rendering function. The main thing is to place the bit of code that calls validate in your output rendering function:
function(input, output) {
v <- reactive({
validate(validate_samplestat(input$samplestat))
})
output$LinePlot <- renderPlot({
v() # <--- validate here
n <- 1:10
samplestat <- seq(min(n), max(n), length.out = input$samplestat)
plot(samplestat, type = "o", col = 'blue',
fg = 'white', xlab= "X Axis", ylab = "Y Axis")
})
}

Related

Render vector as comma separated text in shiny app using htmlOutput

I want to use htmlOutput to render text in shiny app.
App works if I have just one object selected in the select input !
As soon as input$var has more than one object the result is not as I expected
require(shiny)
runApp(list(ui = pageWithSidebar(
headerPanel("Test"),
sidebarPanel(
selectInput("var",
label = "Choose a variable to display",
choices = c("Text01", "Text02",
"Text03", "Text04"),multiple = TRUE,
selected = "Text01"),
sliderInput("range",
label = "Range of interest:",
min = 0, max = 100, value = c(0, 100))
),
mainPanel(htmlOutput("text"))
),
server = function(input, output) {
output$text <- renderUI({
str1 <- paste("You have selected", input$var)
str2 <- paste("You have chosen a range that goes from",
input$range[1], "to", input$range[2])
HTML(paste(str1, str2, sep = '<br/>'))
})
}
)
)
How do I modify the code to hav output like :
You have selected Text01,Text02
You have chosen a range that goes from 0 to 100.
I'd recommend using the base R function toString() instead of a second paste:
library(shiny)
runApp(list(
ui = pageWithSidebar(
headerPanel("Test"),
sidebarPanel(
selectInput(
"var",
label = "Choose a variable to display",
choices = c("Text01", "Text02",
"Text03", "Text04"),
multiple = TRUE,
selected = "Text01"
),
sliderInput(
"range",
label = "Range of interest:",
min = 0,
max = 100,
value = c(0, 100)
)
),
mainPanel(htmlOutput("text"))
),
server = function(input, output) {
output$text <- renderUI({
str1 <- paste("You have selected", toString(input$var))
str2 <- sprintf("You have chosen a range that goes from %s to %s", input$range[1], input$range[2])
HTML(paste(str1, str2, sep = '<br/>'))
})
}
))
Just replace the line
str1 <- paste("You have selected", input$var)
with
str1 <- paste("You have selected", paste(input$var, collapse = ", "))
The problem is that paste() returns a vector of strings when input$var has more than 1 element. With collapse you reduce a string vector input$var to a single value.
library(shiny)
runApp(list(ui = pageWithSidebar(
headerPanel("Test"),
sidebarPanel(
selectInput("var",
label = "Choose a variable to display",
choices = c("Text01", "Text02",
"Text03", "Text04"), multiple = TRUE,
selected = "Text01"),
sliderInput("range",
label = "Range of interest:",
min = 0, max = 100, value = c(0, 100))
),
mainPanel(htmlOutput("text"))
),
server = function(input, output) {
output$text <- renderUI({
str1 <- paste(input$var, collapse = " ")
str2 <- paste("You have chosen a range that goes from",
input$range[1], "to", input$range[2])
tagList(
div("You have selected", str1),
div(str2))
})
}
)
)

How can I add background color and icon in title of modalDialog() function in R shiny?

I have the following code.
library(shiny)
library(dplyr)
library(DT)
app <- shinyApp(
ui = fluidPage(
tags$head(tags$style("#modal1 .modal-header {background-color: #339FFF}")),
DT::dataTableOutput("mydatatable")
),
server = shinyServer(function(input, output, session) {
mycars <- reactive({ head(mtcars)})
output$mydatatable = DT::renderDataTable(mycars(), selection = 'single',
rownames = FALSE, options = list(dom = 't'))
selected_row <- reactiveVal(value = NULL)
observeEvent(input$mydatatable_rows_selected,{
selected_row(input$mydatatable_rows_selected)
})
observeEvent(selected_row(), {
showModal(tags$div(id="modal1", modalDialog(
title = tags$a(style = "color: black", icon('robot'), br(), 'Query Text'),
tags$div(HTML(paste(
"cyl = ",
tags$span(mycars()$cyl[selected_row()],
style = paste("color:", if (mycars()$mpg[selected_row()] > 21) {
"red"
} else {
"blue"
})
)
)))
)))
})
})
)
app
My aim is to change background color of title similar to the color I have for cyl value in modalDialog() and also to add a robot icon in the title if cyl <= 6 and a user icon if cyl > 6, like below picture.
How is it possible in R shiny? Thanks in advance =)
library(shiny)
library(dplyr)
library(DT)
app <- shinyApp(
ui = fluidPage(
uiOutput("code"),
DT::dataTableOutput("mydatatable")
),
server = shinyServer(function(input, output, session) {
mycars <- reactive({ head(mtcars)})
output$mydatatable = DT::renderDataTable(mycars(), selection = 'single',
rownames = FALSE, options = list(dom = 't'))
selected_row <- reactiveVal(value = NULL)
observeEvent(input$mydatatable_rows_selected,{
selected_row(input$mydatatable_rows_selected)
})
output$code <- renderUI({
validate(need(!is.null(selected_row()) & nrow(mycars()) > 0, " "))
if (mycars()$mpg[selected_row()] > 21) {
tags$head(tags$style("#modal1 .modal-header {background-color: #FFD8D8; text-align: center}"))
} else {
tags$head(tags$style("#modal1 .modal-header {background-color: #339FFF; text-align: center}"))
}
})
f <- function(){
if (mycars()$mpg[selected_row()] > 21){
tags$a(style = "color: black", icon('robot'), br(), 'Query Text')
} else{
tags$a(style = "color: black", icon('users'), br(), 'Query Text')
}
}
observeEvent(selected_row(), {
showModal(tags$div(id="modal1", modalDialog(
title = f(),
tags$div(HTML(paste(
"cyl = ",
tags$span(mycars()$cyl[selected_row()],
style = paste("color:", if (mycars()$mpg[selected_row()] > 21) {
"red"
} else {
"blue"
})
)
)))
)))
})
})
)
app

Images for radiobutton r shiny

I am learning how to use images as radiobuttons.
I found this page and have been playing around with it:
Can you have an image as a radioButton choice in shiny?
The answer here has been very useful but the app doesn't load the Rlogo for the radiobutton (when using the second part of the answer using the functions). I have saved the image into a www file. I have tried different variations of writing the line '<img src="Rlogo.png">' = 'logo' like removing the quotations, replacing it with img(src='Rlogo.png') = 'logo' , replace it with the web link, but have been unsuccessful. Please can someone point out where I am going wrong or if the original code works for you!
logo is here: http://i1.wp.com/www.r-bloggers.com/wp-content/uploads/2016/02/Rlogo.png?resize=300%2C263
code is copied over from the page:
library(shiny)
radioButtons_withHTML <- function (inputId, label, choices, selected = NULL, inline = FALSE,
width = NULL)
{
choices <- shiny:::choicesWithNames(choices)
selected <- if (is.null(selected))
choices[[1]]
else {
shiny:::validateSelected(selected, choices, inputId)
}
if (length(selected) > 1)
stop("The 'selected' argument must be of length 1")
options <- generateOptions_withHTML(inputId, choices, selected, inline,
type = "radio")
divClass <- "form-group shiny-input-radiogroup shiny-input-container"
if (inline)
divClass <- paste(divClass, "shiny-input-container-inline")
tags$div(id = inputId, style = if (!is.null(width))
paste0("width: ", validateCssUnit(width), ";"), class = divClass,
shiny:::controlLabel(inputId, label), options)
}
generateOptions_withHTML <- function (inputId, choices, selected, inline, type = "checkbox")
{
options <- mapply(choices, names(choices), FUN = function(value,
name) {
inputTag <- tags$input(type = type, name = inputId, value = value)
if (value %in% selected)
inputTag$attribs$checked <- "checked"
if (inline) {
tags$label(class = paste0(type, "-inline"), inputTag,
tags$span(HTML(name)))
}
else {
tags$div(class = type, tags$label(inputTag, tags$span(HTML(name))))
}
}, SIMPLIFY = FALSE, USE.NAMES = FALSE)
div(class = "shiny-options-group", options)
}
choices <- c('\\( e^{i \\pi} + 1 = 0 \\)' = 'equation',
'<img src="Rlogo.png">' = 'logo')
ui <- shinyUI(fluidPage(
withMathJax(),
img(src='Rlogo.png'),
fluidRow(column(width=12,
radioButtons('test', 'Radio buttons with MathJax choices',
choices = choices, inline = TRUE),
br(),
h3(textOutput('selected'))
))
))
server <- shinyServer(function(input, output) {
output$selected <- renderText({
paste0('You selected the ', input$test)
})
})
shinyApp(ui = ui, server = server)
Here is a way.
library(shiny)
radioImages <- function(inputId, images, values){
radios <- lapply(
seq_along(images),
function(i) {
id <- paste0(inputId, i)
tagList(
tags$input(
type = "radio",
name = inputId,
id = id,
class = "input-hidden",
value = as.character(values[i])
),
tags$label(
`for` = id,
tags$img(
src = images[i]
)
)
)
}
)
do.call(
function(...) div(..., class = "shiny-input-radiogroup", id = inputId),
radios
)
}
css <- HTML(
".input-hidden {",
" position: absolute;",
" left: -9999px;",
"}",
"input[type=radio] + label>img {",
" width: 50px;",
" height: 50px;",
" transition: 500ms all;",
"}",
"input[type=radio]:checked + label>img {",
" border: 1px solid #fff;",
" box-shadow: 0 0 3px 3px #090;",
" transform: rotateZ(-10deg) rotateX(10deg);",
"}"
)
ui <- fluidPage(
tags$head(tags$style(css)),
br(),
wellPanel(
tags$label("Choose a language:"),
radioImages(
"radio",
images = c("java.svg", "javascript.svg", "julia.svg"),
values = c("java", "javascript", "julia")
)
),
verbatimTextOutput("language")
)
server <- function(input, output, session){
output[["language"]] <- renderPrint({
input[["radio"]]
})
}
shinyApp(ui, server)
Credit.
This will also work:
library(shiny)
library(shinyWidgets)
ui <- shinyUI(fluidPage(
withMathJax(),
tags$head(
tags$link(rel = "stylesheet", type = "text/css", href = "style.css")),
fluidRow(column(width=12,
radioGroupButtons('test', 'Radio buttons with MathJax choices',
choiceNames = c('\\( e^{i \\pi} + 1 = 0 \\)',
'<i class="icon_rlogo"></i>'),
choiceValues = c('equation', 'logo')),
br(),
h3(textOutput('selected'))
))
))
server <- shinyServer(function(input, output) {
output$selected <- renderText({
paste0('You selected the ', input$test)
})
})
shinyApp(ui = ui, server = server)
With in your www folder your Rlogo.png image and a style.css file with:
.icon_rlogo {background: url(Rlogo.png) no-repeat center;
background-size: contain;
display: inline-block;
width: 30px;
height: 20px;}
To be customised as you wish.

R Shiny table with horizontal scrollbar both at the top and at the bottom

please I have a R shiny application and one of the pages have a really big table. For this reason, I would need to have the horizontal scrollbar both at the top as well as the bottom of the table.
Please, bear in mind I'm very little familiar with HTML, CSS and JS.
Also, I already managed to move the horizontal scrollbar to the top of the table using solution:
R DT Horizontal scroll bar at top of the table
I'm literally using the example explained there and it works perfectly. I would just need some help in adding the scrollbar at the bottom as well.
css <- HTML(
"#flipped > .dataTables_wrapper.no-footer > .dataTables_scroll > .dataTables_scrollBody {
transform:rotateX(180deg);
}
#flipped > .dataTables_wrapper.no-footer > .dataTables_scroll > .dataTables_scrollBody table{
transform:rotateX(180deg);
}"
)
ui <- fluidPage(
tags$head(tags$style(css)),
fluidRow(column(width = 6,
h4("Flipped Scrollbar"),
br(),
DT::dataTableOutput("flipped")
),
column(width = 6,
h4("Regular Scrollbar"),
br(),
DT::dataTableOutput("regular")
)
)
)
server <- function(input, output, session) {
output$flipped <- DT::renderDataTable({
DT::datatable(mtcars, rownames = FALSE,
options = list(
scrollX = TRUE
)
)
})
output$regular <- DT::renderDataTable({
DT::datatable(mtcars, rownames = FALSE,
options = list(
scrollX = TRUE
)
)
})
}
shinyApp(ui, server)
I managed to find a similar question (horizontal scrollbar on top and bottom of table) however, I can't understand how to apply that css and JS code to a Shiny application.
Many thanks
Update (that still doesn't work) as a follow-up to Stéphane Laurent suggested solution.
My current code now is:
library(shiny)
library(DT)
wideTable <- as.data.frame(matrix(rnorm(1000), nrow = 10, ncol = 100))
js <- "
$(document).ready(function(){
$('#dtable').on('shiny:value', function(e){
setTimeout(function(){
$('#dtable table').wrap('<div id=\"scrolldiv\"></div>');
$('#scrolldiv').doubleScroll({
contentElement: $('table'),
scrollCss: {
'overflow-x': 'scroll',
'overflow-y': 'hidden'
},
contentCss: {
'overflow-x': 'scroll',
'overflow-y': 'hidden'
},
resetOnWindowResize: true
});
setTimeout(function(){$(window).resize();}, 100);
}, 0);
});
});
"
CSS <- "
.doubleScroll-scroll-wrapper {
clear: both;
}
"
ui <- fluidPage(
tags$head(
tags$script(src = "jquery.doubleScroll.js"),
tags$script(HTML(js)),
tags$style(HTML(CSS))
),
br(),
dataTableOutput("dtable")
)
server <- function(input, output, session){
output$dtable <- DT::renderDataTable({
datatable(wideTable,
rownames = T,
filter = 'top',
caption = paste0("All columns of CSV report")
)
})
}
shinyApp(ui, server)
Here is a solution using the DoubleScroll JavaScript library.
Download the file jquery.doubleScroll.js from here. Put it in the www subfolder of your shiny app.
Then here is the app:
library(shiny)
library(DT)
wideTable <- as.data.frame(matrix(rnorm(1000), nrow = 10, ncol = 100))
js <- "
$(document).ready(function(){
$('#dtable').on('shiny:value', function(e){
setTimeout(function(){
$('#dtable table').wrap('<div id=\"scrolldiv\"></div>');
$('#scrolldiv').doubleScroll({
contentElement: $('table'),
scrollCss: {
'overflow-x': 'scroll',
'overflow-y': 'hidden'
},
contentCss: {
'overflow-x': 'scroll',
'overflow-y': 'hidden'
},
resetOnWindowResize: true
});
setTimeout(function(){$(window).resize();}, 100);
}, 0);
});
});
"
CSS <- "
.doubleScroll-scroll-wrapper {
clear: both;
}
"
ui <- fluidPage(
tags$head(
tags$script(src = "jquery.doubleScroll.js"),
tags$script(HTML(js)),
tags$style(HTML(CSS))
),
br(),
DTOutput("dtable")
)
server <- function(input, output, session){
output[["dtable"]] <- renderDT({
datatable(wideTable)
})
}
shinyApp(ui, server)
If the output id of your datatable is not "dtable", then in the JS code (js) replace dtable (two occurences) with the output id of your datatable.

Coloring the checkboxGroupInput choices

In my Shiny UI I have
ui <- checkboxGroupInput("my_cbgi", "Choose Something", c("A", "B", "C", "D"))
And I would like it so that the choices (the text) A and B are colored red, but C and D are not. I tried HTML but then in the UI weird boxes like "attribs" and "children" showed up.
Thanks in advance
Since shiny_1.0.1, checkboxGroupInput have a choiceNames and choiceValues arguments for passing arbitrary UI to display to the user, check this example :
library("shiny")
ui <- fluidPage(
checkboxGroupInput(
inputId = "my_cbgi",
label = "Choose Something",
choiceNames = list(
tags$span("A", style = "color: red;"),
tags$span("B", style = "color: red;"),
tags$span("C", style = "color: blue;"),
tags$span("D", style = "font-weight: bold;")
),
choiceValues = c("A", "B", "C", "D")
)
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)
Great Victorp, I improved your answer adding a varying behaviour to it.
library("shiny")
my.options <- c('A', 'B', 'C')
my.colors <- c('red', 'green', 'blue')
my.fun <- function() {
res <- list()
for (o in my.options) {
res[[length(res)+1]] <- tags$span(o,
style = paste0('color: ', my.colors[which(my.options == o)],';'))
}
res
}
ui <- fluidPage(
checkboxGroupInput(inputId = "myId", label = "Options",
choiceNames = my.fun(),
choiceValues = my.colors
)
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)