Scaling plotOutput height to fill the row in a sidebarLayout - shiny

I have a Shiny app with produces the following output. I would like the height of the graph to scale to fill the row which contains the sidebar, (down to some minimum dimension). This sidebar height changes depending on the data being examined.
The ui code I'm currently using is:
sidebarLayout(
sidebarPanel(
uiOutput("ridgeDates")
),
mainPanel(
plotOutput("ridgesPlot")
)
)
with the plot being rendered by renderPlot(...) This seems to adjust the /width/ automatically as I change the browser window width.
I've spent a while searching but can't find anything that does this. Is this possible?

We can use jQuery to track the height of the sidebar and set the height of the plot in css before creating the plotOutput. To do that, we need to use uiOutput in the UI, then render the plot dynamically.
So in the UI, the mainPanel will now have:
uiOutput("ridgePlot")
Then the plot is rendered in the server like so:
output$ridgePlot <- renderUI({
# plot data
output$ridges <- renderPlot({
# plot()
})
plotOutput("ridges")
})
Now we use shinyjs() to write a simple javascript function that sets the height value of the plot to the height of the sidebar. The sidebar is of class well, so we first get the height of the well, save it to a variable then set the ridges plot to the height of the variable, in javascript like this:
var newHeight = $('.well').outerHeight(); $('#ridges').height(newHeight)
I have used .outerHeight() because the well has extra padding that effectively gives it extra height than the height specified in the css rules for the well.
We can use this function in shiny using runjs() from shinyjs package. Since we need to get the height from the well after it has been rendered, we use observe and use it before the plotOutput inside the renderPlot, which is also inside the renderUI.
observe({
session$onFlushed(function() {
shinyjs::runjs("var newHeight = $('.well').outerHeight(); $('#ridges').height(newHeight)")
}, once=TRUE)
})
Putting it together in one Shiny app:
library(shiny)
library(shinyjs)
library(ggplot2)
ui = fluidPage(
useShinyjs(),
titlePanel("This is just a test!"),
sidebarLayout(
sidebarPanel(
uiOutput("ridgeDates")
),
mainPanel(
uiOutput("ridgePlot")
))
)
server = function(input, output, session) {
output$ridgeDates <- renderUI({
rng <- round(runif(1, 15, 21))
radioButtons("choose", "A changing list", choices = 1:rng)
})
output$ridgePlot <- renderUI({
datax <- matrix(c(1,2,3,4,5,6),6,1)
datay <- matrix(c(1,7,6,4,5,3),6,1)
titleplot<-"title"
summary <- "testing text"
output$ridges <- renderPlot({
# pl <- plot(datax, datay, main = titleplot, xlab = "input$axis1", ylab = "input$axis2", pch=18, col="blue")
ggplot(NULL, aes(datax, datay))+
geom_point(colour = "#1e90ff")
})
observe({
session$onFlushed(function() {
shinyjs::runjs("var newHeight = $('.well').outerHeight(); $('#ridges').height(newHeight)")
}, once=TRUE)
})
plotOutput("ridges")
})
}
# Run the application
shinyApp(ui = ui, server = server)
My example:

Related

shinycssloaders not working for updateSelectInput

I want to hide a selectInput so it doesnt let people try and use it before the data has loaded.
Snippet of UI code.
ui <- dashboardPage(
dashboardHeader(title = "TCS Adverse Event Search Tool"),
dashboardSidebar(
sidebarMenu(
shinycssloaders::withSpinner(
selectInput("ingredients",
label = "Select one or more Active Ingredients:",
choices = NULL,
multi=TRUE)
),
In my server function I have this:
server <- function(input, output, session) {
# get main data frame
ingredients_df <- reactive({
ingredients_df <- read.csv(file="/projects/other/pv_compliance/active_ingredients.csv")
print(paste(nrow(ingredients_df)," active ingredient rows returned"))
return(ingredients_df)
})
cases_df <- reactive({
cases_df <- read.csv(file="/projects/other/pv_compliance/adverse_events.csv")
print(paste(nrow(cases_df)," case rows returned"))
return(cases_df)
})
observeEvent(ingredients_df(), {
updateSelectInput(session,
"ingredients",
choices = ingredients_df()$PRIMARY_SUSPECT_KEY_INGREDIENT,
selected = NULL
)
})
Two things are happening...
the set of widgets now appear about halfway down the sidebar and not the top
the css loader does not display when the updateSelectInput is getting the data

Hide widgets created in a tagList in shiny

I am recently building a shiny app, somewhere in my app I am expecting an arbitrary number of inputs which the user can specify from a line of selectInput() widgets.
Since the number of selectInput() widgets may be large, I would like it to happen that the next selectInput() widget only shows when the pervious one is filled by the user.
My idea is that I will:
create all possible selectInput() widgets in a tagList,
hide them all by default, and
show the next one when the previous one is filled.
I am fine with the first and third step, but when I tried to hide them all using the shinyjs function hide, it seems it does not work for input objects created in a tagList, it only works for those widgets that is created with a specific name, please see the example below:
library(shiny)
library(shinyjs)
ui <- fluidPage(
# Application title
titlePanel("Hello Shiny!"),
sidebarLayout(
# Sidebar with a slider input
sidebarPanel(
sliderInput("obs",
"Number of observations:",
min = 0,
max = 1000,
value = 500)
),
# Show a plot of the generated distribution
mainPanel(
useShinyjs(),
uiOutput('comparisons')
)
)
server <- shinyServer(function(input, output, session) {
observe(1, shinyjs::hide('compare_1') )
output$comparisons=renderUI({
out=tagList()
out=lapply(1:6, function(x){
selectizeInput(paste0('compare_',x),
label = 'Condition 1',
c('aa','bb', 'cc'))
})
out
})
})
shinyApp(ui, server)
Say I'm creating 6 selectInput widgets, name them compare_1 to compare_6, I also created a sliderInput called obs just to show as an example. In Server if I just say shinyjs::hide('obs'), the sliderInput will be hidden, but when I call shinyjs::hide('compare_1'), the selectInput is still there. Any idea will be appreciated!
Hi you can do that with conditinalPanel quite easy
ui <- fluidPage(
# Application title
titlePanel("Hello Shiny!"),
sidebarLayout(
# Sidebar with a slider input
sidebarPanel(
sliderInput("obs",
"Number of observations:",
min = 0,
max = 1000,
value = 500)
),
# Show a plot of the generated distribution
mainPanel(
useShinyjs(),
uiOutput('comparisons')
)
)
)
server <- shinyServer(function(input, output, session) {
output$comparisons=renderUI({
out=tagList(
selectizeInput(paste0('compare_1'),
label = 'Condition 1',
c("",'aa','bb', 'cc')),
lapply(2:6, function(x){
conditionalPanel(
paste0("input.compare_",x-1," != ''"),
selectizeInput(paste0('compare_',x),
label = paste0('Condition ',x),
c("",'aa','bb', 'cc'))
)
})
)
out
})
})
shinyApp(ui, server)

Shiny interactive plotting with selected likert scale

I have created several likert scales with R package "likert" and would like to plot each one of them in shiny when the radio button of that one is selected.
The sample scales is:
a <- sample(rep((1:5),5))
b <- sample(rep((1:5),5))
c <- data.frame(sapply(data.frame(a), factor))
d <- data.frame(sapply(data.frame(b), factor))
scaledc <- likert(c)
scaledd <- likert(d)
The shiny codes are:
ui <- fluidPage(
titlePanel("Survey"),
sidebarLayout(
sidebarPanel(
selectInput("type",
"Plot Type",
choices = c("Likert"="bar",
"Density"="density",
"Heatmap"="heat"), selected="Likert"),
radioButtons("qtype",
"Question type:",
c("Agreement"="scaledc", "Helpfulness"="scaledd"),
selected="scaledc")
),
# Show a plot of the generated distribution
mainPanel(
tabsetPanel(
tabPanel("Yearly Data", plotOutput("distPlot1"))
)
)
)
)
#server
server <- function(input, output) {
output$distPlot1 <- renderPlot({plot(input$qtype, type=input$type)+
ggtitle("How agree are you with following statements?")}, height = 1000)
}
The shiny returned error "need finite 'ylim' values." I think it's becaue the input$qtype doesn't pass the correct information to the plot command, but I don't know how to fix it. Thank you for advance!
I've just solved the problem.
The missing codes in server are:
scale <- reactive({
get(input$qtype)
})
output$dat <- renderPrint({
scale()
})
And then do plot with scale() will show selected plot.

In Rshiny, How to replace old tabs with new one by selectInpout

Here is an existing example
library(shiny)
runExample("06_tabsets")
And you will see you can choose distribution type in radiobutton and there are three tabs "Plot", "Summary", and "Table".
My question is how can I add a selectInput under the sliderInput(number of observations) with two values. The default one is "NULL", the second one is "1". Once users select "1", the previous three tabs would disappear. Instead, a new tab would show whatever it content is.
This is the modified "06_tabsets". A select input is added and the UI is generated depending of the selection. The only difference is that is not using NULL, but two options. I could make it run with NULL. Let me know if this helps.
ui.R
library(shiny)
# Define UI for random distribution application
shinyUI(fluidPage(
# Application title
titlePanel("Tabsets"),
# Sidebar with controls to select the random distribution type
# and number of observations to generate. Note the use of the
# br() element to introduce extra vertical spacing
sidebarLayout(
sidebarPanel(
radioButtons("dist", "Distribution type:",
c("Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp")),
br(),
sliderInput("n",
"Number of observations:",
value = 500,
min = 1,
max = 1000),
selectInput("contentSelect", "Select content to dislay:", choices = c("1", "2"), selected = 1)
),
# Show a tabset that includes a plot, summary, and table view
# of the generated distribution
mainPanel(
uiOutput("content")
)
)
))
server.R
library(shiny)
# Define server logic for random distribution application
shinyServer(function(input, output) {
# Reactive expression to generate the requested distribution.
# This is called whenever the inputs change. The output
# functions defined below then all use the value computed from
# this expression
data <- reactive({
dist <- switch(input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm)
dist(input$n)
})
# Generate a plot of the data. Also uses the inputs to build
# the plot label. Note that the dependencies on both the inputs
# and the data reactive expression are both tracked, and
# all expressions are called in the sequence implied by the
# dependency graph
output$plot <- renderPlot({
dist <- input$dist
n <- input$n
hist(data(),
main=paste('r', dist, '(', n, ')', sep=''))
})
# Generate a summary of the data
output$summary <- renderPrint({
summary(data())
})
# Generate an HTML table view of the data
output$table <- renderTable({
data.frame(x=data())
})
output$textA <- renderText({
paste(input$contentSelect, " A")
})
observeEvent(input$contentSelect, {
if (input$contentSelect == "1") {
output$content <- renderUI({
tabsetPanel(type = "tabs",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
})
} else {
output$content <- renderUI({
tabsetPanel(type = "tabs",
tabPanel("A", textOutput("textA"))
)
})
}
})
})

Use Shiny to display bar graph by state

I'm trying to use shiny to create a bar graph for a state that is selected via drop-down box. I'm quite new to R and I've tried a variety of examples to no avail. I have three variables (state, claim #, total $) and for each state there are five values. So something like this:
state <- c("PA", "TX", "NY")
claim_num <- c(1:15)
total <- sample(1000:5000, 15)
df <- (state, claim_num, total)
I want to have something similar to https://beta.rstudioconnect.com/jjallaire/shiny-embedding/#inline-app but I don't know if I can format my data in that was since I would have a lot of NAs.
Do you mean something like this (you can download and run the example)?
library(shiny)
ui <- shinyUI(
fluidPage(
titlePanel("Sample Shiny App"),
sidebarLayout(
sidebarPanel(
uiOutput("stateInput")
),
mainPanel(
plotOutput("statePlot")
)
)
))
server <- shinyServer(function(input, output) {
state <- sample(state.abb, 3, replace = FALSE)
total <- sample(1000:5000, 15)
claimNumber <- 1:15
data <- data.frame(state, total, claimNumber)
output$stateInput <- renderUI({
selectInput(
inputId = "state",
label = "Select a State:",
choices = levels(data$state)
)
})
output$statePlot <- renderPlot({
hist(data$total[data$state == input$state])
})
})
shinyApp(ui = ui, server = server)
What we're doing is taking the list of unique states available in our data frame and passing those to our selectInput that renders as a dropdown in the UI. From here, we can access whatever value the user has selected through the input$state object. More generally, we can access inputs based on whatever we define the inputId to be (in this particular case, we call it state).
Having grabbed the user input, we can then subset the data frame to only return values that correspond to the user-defined state and, in this case, pass those totals values to a plot that we render as output.