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))
})
}
)
)
Related
I am having a hard time understanding how the container argument from function VisNetwork::VisConfigure works. It seems as though one can move the configuration list in another HTML container but my understanding is too limited (and I found no examples online).
My goal would be to place the configuration list in a shinydashboardPlus::dropdownBlock (i.e., in the dashboardHeader leftUI argument), see reproducible example below:
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(visNetwork)
# Define the function to retrieve the parameters from VisConfigure
# See: https://github.com/datastorm-open/visNetwork/issues/333
visShinyGetOptionsFromConfigurator <- function (graph, input = paste0(graph$id, "_configurator")) {
if (!any(class(graph) %in% "visNetwork_Proxy")) {
stop("Can't use visGetPositions with visNetwork object. Only within shiny & using visNetworkProxy")
}
data <- list(id = graph$id, input = input)
graph$session$sendCustomMessage("visShinyGetOptionsFromConfigurator", data)
graph
}
ui <- dashboardPage(
dashboardHeader(title = "Test visConfigure container argument",
leftUi = tagList(
shinydashboardPlus::dropdownBlock(
id = "graphparams",
title = "Graph parameters",
icon = shiny::icon("gears"),
shinyWidgets::prettyRadioButtons(
inputId = "physics",
label = "Parameters should appear here",
choices = c("Yes","No"))))),
dashboardSidebar(width = 220),
dashboardBody(
fluidRow(box(id = "network",
title = "Network",
status = "primary",
width = 12,
solidHeader = TRUE,
collapsible = TRUE,
visNetworkOutput('network'))),
fluidRow(actionButton("ops", "Options"))))
server <- function(input, output, session) {
getDiagramPlot <- function(nodes, edges){
v <- visNetwork(
nodes,
edges) %>%
visIgraphLayout(layout = "layout_on_sphere", physics = TRUE, randomSeed = 1234) %>%
visPhysics(solver = "hierarchicalRepulsion",
hierarchicalRepulsion = list(springLength = 850, nodeDistance = 90),
stabilization = "onlyDynamicEdges") %>%
visOptions(highlightNearest = list(enabled = T, degree = 1, hover = F), autoResize = TRUE, collapse = FALSE) %>%
visEdges(color = list(highlight = "red")) %>%
visEdges(arrows = edges$arrows) %>%
visConfigure(enabled = TRUE, filter = "physics", container = NULL) %>%
visInteraction(multiselect = F)
return(v)
}
nodes <- data.frame(id = 0:20, label = LETTERS[1:21])
edges <- data.frame(from = 0, to = 1:20, value = seq(0.35, 0.5, length.out = 20))
output$network <- renderVisNetwork(
getDiagramPlot(nodes, edges)
)
# Send to console the settings from VisConfigure
# See: https://github.com/datastorm-open/visNetwork/issues/333
observeEvent(input$ops, { visNetworkProxy("network") %>% visShinyGetOptionsFromConfigurator() })
observe({ if(!is.null(input$network_configurator)) print(input$network_configurator)
})
session$onSessionEnded(stopApp)
}
shinyApp(ui, server)
Any idea?
Best,
C.
I tried to set container = input$graphparams but it didn't work.
I am trying with the below code.
library(shiny)
app <- shinyApp(
ui = fluidPage(
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(modalDialog(
title = "You have selected a row!",
ifelse(
mycars()$mpg[selected_row()] > 21,
tags$div(HTML(paste('cyl = ', tags$span(style = "color:red", mycars()$cyl[selected_row()]), sep = ""))),
tags$div(HTML(paste('cyl = ', tags$span(style = "color:blue", mycars()$cyl[selected_row()]), sep = "")))
)
))
})
})
)
app
Here I am trying to change color of 'cyl' value to red if 'mpg' value is greater than 21 else 'cyl' value will print in blue.
I have tried with few html codes but failed.
Thanks!
For this purpose the dataframe does not have to be reactive, so I removed that part in here. Make use of the formatStyle functionality:
app <- shinyApp(
ui = fluidPage(
DT::dataTableOutput("mydatatable")
),
server = shinyServer(function(input, output, session) {
mycars <- mtcars
output$mydatatable = DT::renderDataTable(datatable(mycars) %>%
formatStyle('cyl', 'mpg',
color = styleInterval(21.001, c('blue', 'red'))),
selection = 'single',
rownames = FALSE, options = list(dom = 't'))
})
)
app
I have generated few plots using plotly and saved them as offline html (I don't want to generate them live as it would take so long to generate them in the background). The followings are the two plots taken from plotly site and I saved them as html.
#Graph 1
Animals <- c("giraffes", "orangutans", "monkeys")
SF_Zoo <- c(20, 14, 23)
LA_Zoo <- c(12, 18, 29)
data <- data.frame(Animals, SF_Zoo, LA_Zoo)
p <- plot_ly(data, x = ~Animals, y = ~SF_Zoo, type = 'bar', name = 'SF Zoo') %>%
add_trace(y = ~LA_Zoo, name = 'LA Zoo') %>%
layout(yaxis = list(title = 'Count'), barmode = 'group')
htmlwidgets::saveWidget(p, file="zoo.html")
#Graph 2
x <- c('Product A', 'Product B', 'Product C')
y <- c(20, 14, 23)
text <- c('27% market share', '24% market share', '19% market share')
data <- data.frame(x, y, text)
p <- plot_ly(data, x = ~x, y = ~y, type = 'bar', text = text,
marker = list(color = 'rgb(158,202,225)',
line = list(color = 'rgb(8,48,107)',
width = 1.5))) %>%
layout(title = "January 2013 Sales Report",
xaxis = list(title = ""),
yaxis = list(title = ""))
htmlwidgets::saveWidget(p, file="product.html")
I have written some shiny codes that can show html output from Rmarkdown but not the html that i generated from plotly above. Note that the first choice(sample) in the selectInput() is what I generated from default Rmarkdown html and that works. I also generated multiple rmarkdown html and I could also switch between htmls in the shiny app but not for plotly html.
ui= fluidPage(
titlePanel("opening web pages"),
sidebarPanel(
selectInput(inputId='test',label=1,choices=c("sample","zoo","product"))
),
mainPanel(
htmlOutput("inc")
)
)
server = function(input, output) {
getPage<-function() {
return(includeHTML(paste0("file:///C:/Users/home/Documents/",input$test,".html")))
}
output$inc<-renderUI({getPage()})
}
shinyApp(ui, server)
You can use an iframe for this - also have a look at addResourcePath:
ui = fluidPage(
titlePanel("opening web pages"),
sidebarPanel(selectInput(
inputId = 'test',
label = 1,
choices = c("sample", "zoo", "product")
)),
mainPanel(htmlOutput("inc"))
)
server = function(input, output) {
myhtmlfilepath <- getwd() # change to your path
addResourcePath('myhtmlfiles', myhtmlfilepath)
getPage <- function() {
return(tags$iframe(src = paste0("myhtmlfiles/", input$test, ".html"), height = "100%", width = "100%", scrolling = "yes"))
}
output$inc <- renderUI({
req(input$test)
getPage()
})
}
shinyApp(ui, server)
After the success of the dynamic box in shiny here : R/Shiny : Color of boxes depend on select I need you to use these boxes but in a loop.
Example :
I have an input file which give this :
BoxA
BoxB
BoxC
I want in the renderUI loop these values as a variable to generate dynamically a Box A, B and C. (if I have 4 value, i will have 4 boxes etC.)
Here is my actually code:
for (i in 1:nrow(QRSList))
{
get(QRSOutputS[i]) <- renderUI({
column(4,
box(title = h3(QRSList[1], style = "display:inline; font-weight:bold"),
selectInput("s010102i", label = NULL,
choices = list("Non commencé" = "danger", "En cours" = "warning", "Terminé" = "success"),
selected = 1) ,width = 12, background = "blue", status = get(QRSIntputS[i])))
})
column(4,
observeEvent(input$s010102i,{
get(QRSOutputS[i]) <- renderUI({
box(title = h3(QRSList[1], style = "display:inline; font-weight:bold"),
selectInput("s010102i", label = NULL,
choices = list("Not good" = "danger", "average" = "warning", "good" = "success"),
selected = get(QRSIntputS[i])) ,width = 12, background = "blue",status = get(QRSIntputS[i]))
})
The aim is to replace these box names to a variable like input$s010102 for example. But get and assign function does not exist.
Any idea ?
Thanks a lot
Here is an example how to generate boxes dynamically
library(shinydashboard)
library(shiny)
QRSList <- c("Box1","Box2","Box3","Box4","Box5")
ui <- dashboardPage(
dashboardHeader(title = "render Boxes"),
dashboardSidebar(
sidebarMenu(
menuItem("Test", tabName = "Test")
)
),
dashboardBody(
tabItems(
tabItem(tabName = "Test",
fluidRow(
tabPanel("Boxes",uiOutput("myboxes"))
)
)
)
)
)
server <- function(input, output) {
v <- list()
for (i in 1:length(QRSList)){
v[[i]] <- box(width = 3, background = "blue",
title = h3(QRSList[i], style = "display:inline; font-weight:bold"),
selectInput(paste0("slider",i), label = NULL,choices = list("Not good" = "danger", "average" = "warning", "good" = "success"))
)
}
output$myboxes <- renderUI(v)
}
shinyApp(ui = ui, server = server)
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")
})
}