I am trying to create a shiny app that works like a look up table -- I am using multiple columns from my data frame as input variables in the sidebar and based on the inputs the user selects from the dropdown, I am trying to get a corresponding output for two variables (one numeric and one character) which exist in the same table.
However, when I try to link my input to get the matching output in the server code, I get the following error for my numeric output variable: "Warning: Error in writeImpl: Text to be written must be a length-one character vector" and the following error for my character output variable: "operations are possible only for numeric, logical or complex types".
I need help in resolving this, thank you! I have attached my simplified code and data with two input and two output variables for reference.
This is my data:
"input1","input2","NumericOutput","CharacterOutput"
"precarious","precarious",0,"precarious"
"precarious","precarious",2.950337429,"precarious"
"precarious","precarious",4.827824883,"precarious"
"precarious","precarious",8.314587299,"precarious"
"precarious","precarious",7.276345388,"precarious"
"precarious","precarious",10.22668282,"precarious"
"precarious","precarious",12.10417027,"precarious"
"precarious","precarious",15.59093269,"precarious"
"precarious","precarious",0.622945146,"precarious"
"precarious","precarious",3.573282575,"precarious"
"precarious","precarious",5.450770029,"precarious"
"precarious","precarious",8.937532445,"precarious"
"precarious","precarious",7.899290535,"precarious"
"precarious","precarious",10.84962796,"precarious"
"precarious","precarious",12.72711542,"precarious"
"precarious","precarious",16.21387783,"precarious"
"precarious","precarious",3.737670877,"precarious"
"precarious","moderate",6.688008306,"precarious"
"good","precarious",8.565495761,"precarious"
This is my code:
## loading packages
{
library(shiny)
library(shinydashboard)
library(htmltools)
library(rvest)
library(XML)
library(measurements)
library(ggplot2)
library(ggrepel)
library(plotly)
library(shinyjs)
library(shinyWidgets)
}
Test <- read.csv("Test.csv", stringsAsFactors = FALSE)
summary(Test)
lapply(Test,class)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
useShinyjs(),
selectInput ("a",label = colnames(Test[1]),
choices = (Test[[1]])),
selectInput("b",colnames(Test[2]),
choices = Test[[2]])
),
dashboardBody(
fluidRow(valueBoxOutput("info_box1", width = 6)),
fluidRow(valueBoxOutput("info_box2", width = 6))
)
)
server <- function(input, output) {
output$info_box1 <- renderValueBox({
valueBox(value = paste0("Score in %: ",
Test$NumericOutput[Test$input1 == input$a]
& Test$NumericOutput[Test$input2 == input$b]),
subtitle = NULL) })
output$info_box2 <- renderValueBox({
valueBox(value = paste0("Assessment: ",(Test$CharacterOutput[Test$input1 == input$a])&
(Test$CharacterOutput[Test$input2 == input$b])),
subtitle = NULL)
})
}
shinyApp(ui, server)
Welcome to stackoverflow! The problem with the above code is, that the choices you are providing to populate the selectInput's aren't identifying a single row of your data.frame. However, valueBox's value-argument expects a single string.
I'm not sure what your expected result is, but maybe the following helps to understand what the issue is:
## loading packages
{
library(shiny)
library(shinydashboard)
library(shinyjs)
}
Test <- data.frame(
stringsAsFactors = FALSE,
input1 = c("precarious","precarious",
"precarious","precarious","precarious","precarious",
"precarious","precarious","precarious","precarious",
"precarious","precarious","precarious","precarious",
"precarious","precarious","precarious","precarious","good"),
input2 = c("precarious","precarious",
"precarious","precarious","precarious","precarious",
"precarious","precarious","precarious","precarious",
"precarious","precarious","precarious","precarious",
"precarious","precarious","precarious","moderate",
"precarious"),
NumericOutput = c(0,2.950337429,4.827824883,
8.314587299,7.276345388,10.22668282,12.10417027,
15.59093269,0.622945146,3.573282575,5.450770029,8.937532445,
7.899290535,10.84962796,12.72711542,16.21387783,
3.737670877,6.688008306,8.565495761),
CharacterOutput = c("precarious","precarious",
"precarious","precarious","precarious","precarious",
"precarious","precarious","precarious","precarious",
"precarious","precarious","precarious","precarious",
"precarious","precarious","precarious","precarious",
"precarious")
)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
useShinyjs(),
selectInput("a", label = colnames(Test[1]),
choices = unique(Test[[1]])),
selectInput("b", colnames(Test[2]),
choices = unique(Test[[2]]))
),
dashboardBody(fluidRow(valueBoxOutput("info_box1", width = 6)),
fluidRow(valueBoxOutput("info_box2", width = 6)))
)
server <- function(input, output) {
output$info_box1 <- renderValueBox({
valueBox(
value = paste0("Score in %: ",
Test$NumericOutput[Test$input1 == input$a],
Test$NumericOutput[Test$input2 == input$b], collapse = ", "),
subtitle = NULL)
})
output$info_box2 <- renderValueBox({
valueBox(value = paste0(
"Assessment: ",
Test$CharacterOutput[Test$input1 == input$a],
Test$CharacterOutput[Test$input2 == input$b], collapse = ", "),
subtitle = NULL)
})
}
shinyApp(ui, server)
I basically needed an output value for both my output variables by checking all conditions and not just fulfilling any one condition.
Instead of using Test$NumericOutput[Test$input1 == input$a]
& Test$NumericOutput[Test$input2 == input$b]
I used Test$NumericOutput[Test$input1 == input$a & Test$input2 == input$b] and it worked.
I would like to update the colours of my pickerInput based on input from the colourInput in the below example.
This questions follows on from this question and replicating this with pickerInput instead of selectizeInput.
This works great with selectizeInput:
## load iris dataset
data(iris)
cats <- levels(iris$Species)
## colourInput ---- create list of shiny inputs for UI
ids <- paste0("col", seq(3))
cols <- c("red", "blue", "yellow")
foo <- function(x) {colourInput(ids[x], cats[x], cols[x])}
my_input <- lapply(seq(ids), foo)
## css styling for selectizeInput menu
CSS <- function(values, colors){
template <- "
.option[data-value=%s], .item[data-value=%s]{
background: %s !important;
color: white !important;
}"
paste0(
apply(cbind(values, colors), 1, function(vc){
sprintf(template, vc[1], vc[1], vc[2])
}),
collapse = "\n"
)
}
css <- CSS(cats, cols[seq(cats)])
## ------ shiny app ------
runApp(shinyApp(
ui = fluidPage(
tabsetPanel(type = "tabs",
tabPanel("Dataset", id = "data",
tags$head(
uiOutput("css")
),
selectizeInput("species", "Labels",
choices = cats,
multiple = TRUE,
selected = cats),
plotOutput("scatter")
),
tabPanel("Colour Menu", id = "colmenu",
my_input)
)
),
server = function(input, output, session) {
## get coords according to selectizeInput
mrkSel <- reactive({
lapply(input$species,
function(z) which(iris$Species == z))
})
## colours selected by user in colourPicker
cols_user <- reactive({
sapply(ids, function(z) input[[z]])
})
## update scatter colours
scattercols <- reactive({
cols_user()[sapply(input$species, function(z)
which(cats == z))]
})
## scatter plot is conditional on species selected
output$scatter <- renderPlot({
plot(iris$Petal.Length, iris$Petal.Width, pch=21)
if (!is.null(input$species)) {
for (i in 1:length(input$species)) {
points(iris$Petal.Length[mrkSel()[[i]]], iris$Petal.Width[mrkSel()[[i]]],
pch = 19, col = scattercols()[i])
}
}
})
## update colours
output$css <- renderUI({
tags$style(HTML(CSS(cats, cols_user())))
})
}
)
)
An attempt to replicate with pickerInput
## load iris dataset
data(iris)
cats <- levels(iris$Species)
## colourInput ---- create list of shiny inputs for UI
ids <- paste0("col", seq(3))
cols <- c("red", "blue", "yellow")
foo <- function(x) {colourInput(ids[x], cats[x], cols[x])}
my_input <- lapply(seq(ids), foo)
## css styling for selectizeInput menu
CSS <- function(values, colors){
template <- "
.dropdown-menu[data-value=%s] {
background: %s !important;
color: white !important;
}"
paste0(
apply(cbind(values, colors), 1, function(vc){
sprintf(template, vc[1], vc[1], vc[2])
}),
collapse = "\n"
)
}
css <- CSS(cats, cols[seq(cats)])
## ------ shiny app ------
runApp(shinyApp(
ui = fluidPage(
tabsetPanel(type = "tabs",
tabPanel("Dataset", id = "data",
tags$head(
uiOutput("css")
),
pickerInput("species", "Labels",
choices = cats,
multiple = TRUE,
selected = cats,
options = list(
`actions-box` = TRUE,
size = 10,
`selected-text-format` = "count > 3"
)),
plotOutput("scatter")
),
tabPanel("Colour Menu", id = "colmenu",
my_input)
)
),
server = function(input, output, session) {
## get coords according to selectizeInput
mrkSel <- reactive({
lapply(input$species,
function(z) which(iris$Species == z))
})
## colours selected by user in colourPicker
cols_user <- reactive({
sapply(ids, function(z) input[[z]])
})
## update scatter colours
scattercols <- reactive({
cols_user()[sapply(input$species, function(z)
which(cats == z))]
})
## scatter plot is conditional on species selected
output$scatter <- renderPlot({
plot(iris$Petal.Length, iris$Petal.Width, pch=21)
if (!is.null(input$species)) {
for (i in 1:length(input$species)) {
points(iris$Petal.Length[mrkSel()[[i]]], iris$Petal.Width[mrkSel()[[i]]],
pch = 19, col = scattercols()[i])
}
}
})
## update colours
output$css <- renderUI({
tags$style(HTML(CSS(cats, cols_user())))
})
}
)
)
I am not familiar with css styling and so I can assume my code is wrong when trying to style dropdown-menu.
Can someone tell me how to achieve colour coding of the drop down menu based on the colour selected in the Colour Menu tab? Bonus, if anyone knows of a cheatsheet they can share for css styling.
CSS <- function(colors){
template <- "
.dropdown-menu ul li:nth-child(%s) a {
background: %s !important;
color: white !important;
}"
paste0(
apply(cbind(seq_along(colors), colors), 1, function(vc){
sprintf(template, vc[1], vc[2])
}),
collapse = "\n"
)
}
and
output$css <- renderUI({
tags$style(HTML(CSS(cols_user())))
})
To deal with CSS, you should try the inspector tool (right-click on an element, then "Inspect").
For a shiny app, I'd like to go through a data frame row-wise and highlight (bold, color, or similiar) the selected row in renderTable. I was thinking of selecting the row by index. Can I do this with renderTable, or should I consider DT?
library(shiny)
ui <-
fluidRow(
actionButton(
"my_button",
"Go to next row"
),
tableOutput("my_table")
)
server <- function(input, output){
values <- reactiveValues()
values$index <- 1
values$dat <- iris
observeEvent(
input$my_button, {
values$index <- values$index + 1
})
output$my_table <-
renderTable(values$dat) # somehow highlight the row at the index
}
shinyApp(ui = ui, server = server)
This might get you started.
library(shiny)
library(DT)
library(dplyr)
ui <-
fluidRow(
actionButton(
"my_button",
"Go to next row"
),
dataTableOutput("my_table")
)
server <- function(input, output){
values <- reactiveValues()
values$index <- 1
values$dat <- iris
observeEvent(
input$my_button, {
values$index <- values$index + 1
})
output$my_table <-
renderDataTable({
values$dat %>%
mutate(row = row_number()) %>%
datatable() %>%
formatStyle(
"row",
target = 'row',
backgroundColor = styleEqual(values$index, c('yellow'))
)
}) # somehow highlight the row at the index
}
shinyApp(ui = ui, server = server)
I'm dealing with a quite complicated shiny app in which I would like to create an UI output inside server function. UI is not that easy and depends on many items created on a server side so I'm creating it concatenating HTML parts of UI. Everything works until I meet plotly chart.
I've created a simpler version of my app to make it easier to understand my problem.
Normally I'd do sth like that:
library("shiny")
library("plotly")
library("dplyr")
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
),
mainPanel(
plotlyOutput("distPlot1"),
plotOutput("distPlot2")
)
)
)
server <- function(input, output) {
output$distPlot1 <- renderPlotly({
x <- faithful[, 2]
plot_ly(x = x, type = "histogram")
})
output$distPlot2 <- renderPlot({
x <- faithful[, 2]
hist(x)
})
}
shinyApp(ui = ui, server = server)
to obtain this:
But when I start to create ui on server side like here (edited part with more divs inside ui):
library("shiny")
library("plotly")
library("dplyr")
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
),
mainPanel(
htmlOutput("ui1"),
uiOutput("ui2")
)
)
)
server <- function(input, output) {
output$distPlot1 <- renderPlotly({
x <- faithful[, 2]
plot_ly(x = x, type = "histogram")
})
output$distPlot2 <- renderPlot({
x <- faithful[, 2]
hist(x)
})
output$ui1 <- renderUI({
show <- h1("lfkhg")
show <- paste0(show, plotlyOutput("distPlot1") %>% as.character())
HTML(show)
})
output$ui2 <- renderUI({
show <- h1("lfkhg")
show <- paste0(show, plotOutput("distPlot2") %>% as.character())
HTML(show)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Plotly plot does not appear...
Do you know why and how to deal with this problem?
I dont know why you need %>% HTML() in there as it works for me without it. Also if you want to add more things into the renderUI then simply use tagList and combine them together, here I will add h1 as per your comment
library("shiny")
library("plotly")
library("dplyr")
ui <- fluidPage(
sidebarLayout(sidebarPanel(),
mainPanel(
uiOutput("ui1"),
uiOutput("ui2")
)
)
)
server <- function(input, output) {
output$distPlot1 <- renderPlotly({
x <- faithful[, 2]
plot_ly(x = x, type = "histogram")
})
output$distPlot2 <- renderPlot({
x <- faithful[, 2]
hist(x)
})
output$ui1 <- renderUI({
tagList(h1("lfkhg"),plotlyOutput("distPlot1"))
})
output$ui2 <- renderUI({
plotOutput("distPlot2")
})
}
# Run the application
shinyApp(ui = ui, server = server)
I'm trying to create a checkbox for which the choices are plots created through ggplot. In the result, the UI looks like the HTML code itself instead of evaluating the HTML code to show the chart. Any ideas how I can get the checkboxGroupInput to show ggplots?
Sample code below -
runApp(shinyApp(
ui = fluidPage(
headerPanel("Plot check box"),
mainPanel(
uiOutput("plotscheckboxes")
)
),
server = function(input, output, session) {
output$plot1 = renderPlot({
ggplot(mtcars)+geom_point(aes(x=mpg,y=mpg))
})
output$plot2 = renderPlot({
ggplot(mtcars)+geom_point(aes(x=mpg,y=mpg))
})
output$plotscheckboxes = renderUI({
plotlist = list(
plotOutput('plot1'),
plotOutput('plot2')
)
plotlist2 = do.call(tagList, plotlist)
# this just produces a list with 1,2, some sort of underlying value for the checkboxGroup
finaloptionlist = lapply(
seq(length(plotlist2)),
function(x) x
)
# the names of the list are what get used in the options so setting the names accordingly as the HTML code of the ggplot rendering
names(finaloptionlist) = sapply(plotlist2, function(x) paste(x, collapse = "\n"))
checkboxGroupInput("checkGroup", label = h3("Checkbox group"),
choices = finaloptionlist,
selected = 1)
})
}
))