I'm having trouble with the formats of conditional panels affecting other conditional panels. Below is reproducible code, and at the bottom are images better explaining the issue. In the fuller App this code derives from, the problem is more obvious and makes it look sloppy (in the fuller App, there are multiple screens the user clicks through as the user scrolls to the right along the shaded bar (Well Panel) at the top just underneath the tab label, and the misalignment gets more pronounced as the user scrolls to the right).
The problem is: as the user scrolls right through the Glide Controls / Well Panels to make selections, the Well Panels (at the top with radio buttons) begin to misalign with the table and/or plots that appear beneath. The misalignment gets more pronounced as the user scrolls right. This misalignment isn't as apparent in this reproducible example, but is more pronounced in the fuller App this derives from where there are multiple "screens" or Well Panels at the top for the user to scroll through and where there are data tables and/or plots presented underneath in the main panel.
For sake of simplicity all server code is eliminated in this example (no plots, no tables), as the issue still presents without the server code.
If I comment-out other conditional panels (marked "###" in the reproducible code) the misalignment goes away. So how can I make the conditional panels independent of one another, as a way of eliminating this misalignment? I'm open to any other suggestions for eliminating this misalignment.
The basic structure of the App is the user makes "big choices" along the sidebar panel, and makes more "refined choices" only the top bar underneath the tab label using Glide Controls/Well Panels etc. for a carousel affect.
Reproducible code:
library(shiny)
library(shinyglide)
library(shinyjs)
library(shinyWidgets)
ui <-
fluidPage(
useShinyjs(),
tags$style(".glide-controls { position: absolute; top: 8px; right: 14px; width: 160px; }"),
titlePanel("Hello"),
sidebarLayout(
sidebarPanel(selectInput("selectData", h5(strong("Select data to view:")),choices = list("Stratification","DnL balances"),selected = "Stratification")),
mainPanel(
tabsetPanel(
tabPanel("Private data", value = 1,
div(style = "margin-top:10px"),
conditionalPanel(condition = "input.selectData == 'Stratification'",
fluidRow(
column(12,
glide(
custom_controls = div(class = "glide-controls", glideControls()),
screen(
wellPanel(
radioButtons(
inputId = 'groupStrats',
label = NULL,
choiceNames = c('Calendar period','MOB'),
choiceValues = c('Period','MOB'),
selected = 'Period',
inline = TRUE),
style = "padding-top: 12px; padding-bottom: 0px;")
),
screen(
wellPanel(
radioButtons(
inputId = 'stratsView',
label = NULL,
choices = list("Table view" = 1,"Plot view" = 2),
selected = 1,
inline = TRUE),
style = "padding-top: 12px; padding-bottom: 0px;")
)
)
)
),
### Deleting next line resolves the well panel issue ###
conditionalPanel(condition = "input.stratsView == 2",fluidRow(column(12, plotOutput("stratPlot"))))
),
### Deleting the following conditional panel also resolves the well panel issue ###
conditionalPanel(condition = "input.selectData == 'DnL balances'",
fluidRow(
column(12,
glide(
custom_controls = div(class = "glide-controls", glideControls()),
screen(
wellPanel(
radioButtons(
inputId = 'groupBal',
label = NULL,
choiceNames = c('Calendar period','MOB'),
choiceValues = c('Period','MOB'),
selected = 'Period',
inline = TRUE),
style = "padding-top: 12px; padding-bottom: 0px;")
)
)
)
)
), # closes conditional panel
### Deleting the following conditional panel (or either checkbox... or selectize...) also resolves the well panel issue ###
conditionalPanel(condition = "input.selectData == 'Level 1 data'",
panel(
checkboxGroupInput(
inputId = "vars",
label = "Filter by (default view is all data):",
choices = c("Period", "MOB"),
selected = c("Period", "MOB"),
inline = TRUE),
selectizeGroupUI(
id = "my-filters",
params = list(Period = list(inputId = "Period", title = "Period:"),
MOB = list(inputId = "MOB", title = "MOB:"))
), # closes above selectize...
status = "primary"
)
) # closes conditional panel
), id = "tabselected"
)
)
)
)
server <- function(input, output, session) {}
shinyApp(ui, server)
Actually this is the same issue as here.
The conditionalPanels are visible for a very short time when first invoking the app.
This causes a vertical scrollbar to appear and leads to the misalignment.
Use style = "display: none;" to render the conditionalPanels hidden on startup (where needed) and please leave a thumbs up or other feedback here.
library(shiny)
library(shinyjs)
library(shinyglide)
library(shinyWidgets)
ui <-
fluidPage(
useShinyjs(),
tags$style(".glide-controls { position: absolute; top: 8px; right: 14px; width: 160px; }"),
titlePanel("Hello"),
sidebarLayout(
sidebarPanel(selectInput("selectData", h5(strong("Select data to view:")),choices = list("Stratification","DnL balances"),selected = "Stratification")),
mainPanel(
tabsetPanel(
tabPanel("Private data", value = 1,
div(style = "margin-top:10px"),
conditionalPanel(condition = "input.selectData == 'Stratification'",
fluidRow(
column(12,
glide(
custom_controls = div(class = "glide-controls", glideControls()),
screen(
wellPanel(
radioButtons(
inputId = 'groupStrats',
label = NULL,
choiceNames = c('Calendar period','MOB'),
choiceValues = c('Period','MOB'),
selected = 'Period',
inline = TRUE),
style = "padding-top: 12px; padding-bottom: 0px;")
),
screen(
wellPanel(
radioButtons(
inputId = 'stratsView',
label = NULL,
choices = list("Table view" = 1,"Plot view" = 2),
selected = 1,
inline = TRUE),
style = "padding-top: 12px; padding-bottom: 0px;")
)
)
)
),
### Deleting next line resolves the well panel issue ###
conditionalPanel(condition = "input.stratsView == 2", style = "display: none;", fluidRow(column(12, plotOutput("stratPlot"))))
),
### Deleting the following conditional panel also resolves the well panel issue ###
conditionalPanel(condition = "input.selectData == 'DnL balances'", style = "display: none;",
fluidRow(
column(12,
glide(
custom_controls = div(class = "glide-controls", glideControls()),
screen(
wellPanel(
radioButtons(
inputId = 'groupBal',
label = NULL,
choiceNames = c('Calendar period','MOB'),
choiceValues = c('Period','MOB'),
selected = 'Period',
inline = TRUE),
style = "padding-top: 12px; padding-bottom: 0px;")
)
)
)
)
), # closes conditional panel
### Deleting the following conditional panel (or either checkbox... or selectize...) also resolves the well panel issue ###
conditionalPanel(condition = "input.selectData == 'Level 1 data'", style = "display: none;",
panel(
checkboxGroupInput(
inputId = "vars",
label = "Filter by (default view is all data):",
choices = c("Period", "MOB"),
selected = c("Period", "MOB"),
inline = TRUE),
selectizeGroupUI(
id = "my-filters",
params = list(Period = list(inputId = "Period", title = "Period:"),
MOB = list(inputId = "MOB", title = "MOB:"))
), # closes above selectize...
status = "primary"
)
) # closes conditional panel
), id = "tabselected"
)
)
)
)
server <- function(input, output, session) {}
shinyApp(ui, server)
Related
How can I position the search bar to the top of the page here in Rshiny. I would prefer to do a solution using HTML within shiny.
Here is what it currently looks like. I also tried to position it left and that wasn't quite what I was looking for. I was looking to have the table take up the entire main page and have the filter up at the top.
Below is a reproducible example using R:
library(shiny)
library(DT)
ui <- fluidPage(
titlePanel("Tabsets"),
sidebarLayout(position = "right",
sidebarPanel(
textInput('search', "Search"),
tags$div(class="header", checked=NA,
tags$p("Ready to take the Shiny tutorial? If so"),
tags$a(href="shiny.rstudio.com/tutorial", "Click Here!")
)
),
mainPanel(
tabsetPanel(id = "tabsetPanelID",
type = "tabs",
tabPanel("Tab1", DTOutput('DT1')),
tabPanel("Tab2", DTOutput('DT2')),
tabPanel("Tab3", DTOutput('DT3'))
)
)
)
)
server <- function(input, output, session) {
output$DT1 = renderDT(iris)
DTProxy1 <- dataTableProxy("DT1")
output$DT2 = renderDT(iris)
DTProxy2 <- dataTableProxy("DT2")
output$DT3 = renderDT(iris)
DTProxy3 <- dataTableProxy("DT3")
observeEvent(c(input$search, input$tabsetPanelID), {
updateSearch(DTProxy1, keywords = list(global = input$search, columns = NULL))
updateSearch(DTProxy2, keywords = list(global = input$search, columns = NULL))
updateSearch(DTProxy3, keywords = list(global = input$search, columns = NULL))
})
}
shinyApp(ui, server)
The ui of the following example contains four selectInput. The last two of them are in a splitLayout. I noticed that, when I launch the app, the label of the last two would overlap if the window size is not large enough, as the first screenshot shows. Is it possible to make the label of the input in splitLayout dynamically change depends on the width of the window? A comparison would be the first two selectInput. As shown in the second screenshot, when I reduce the window width, the label would change to two lines. I would like to have the same behavior for the last two selectInput in splitLayout.
library(shiny)
# Define UI
ui <- fluidPage(
mainPanel(
selectInput(inputId = "A", label = "This is a long lebel with lots of words", choices = letters[1:5], selected = "a"),
selectInput(inputId = "B", label = "This is a long lebel with lots of words", choices = letters[1:5], selected = "a"),
splitLayout(
selectInput(inputId = "C", label = "This is a long lebel with lots of words", choices = letters[1:5], selected = "a"),
selectInput(inputId = "D", label = "This is a long lebel with lots of words", choices = letters[1:5], selected = "a"),
# Expand the menu in splitLayout
# From: https://stackoverflow.com/a/40098855/7669809
tags$head(tags$style(HTML("
.shiny-split-layout > div {
overflow: visible;
}
")))
)
)
)
# Server logic
server <- function(input, output, session){
}
# Complete app with UI and server components
shinyApp(ui, server)
First screenshot:
Sceond screenshot:
Update
#Simran has pointed out that overflow: visible is the cause of this issue. However, I need this to expand my menu in the selectInput based on this post: https://stackoverflow.com/a/40098855/7669809
I assume using fluidRow() with column() is an option for you.
Then you could use:
fluidRow(
column(width = 4,
selectInput(...)
),
column(width = 4,
selectInput(...)
)
)
Note 1:
You can control the width of an input by the width parameter of column().
Note 2:
Sidenote: If you want to use the full width of 12, you also have to set the mainPanel() to 12, see e.g. here:
https://stackoverflow.com/a/44214927/3502164
Full app - reproducible example:
library(shiny)
# Define UI
ui <- fluidPage(
mainPanel(
selectInput(inputId = "A", label = "This is a long lebel with lots of words", choices = letters[1:5], selected = "a"),
selectInput(inputId = "B", label = "This is a long lebel with lots of words", choices = letters[1:5], selected = "a"),
fluidRow(
column(width = 4,
selectInput(inputId = "C", label = "This is a long lebel with lots of words", choices = letters[1:5], selected = "a")
),
column(width = 4,
selectInput(inputId = "D", label = "This is a long lebel with lots of words", choices = letters[1:5], selected = "a")
)
),
# Expand the menu in splitLayout
# From: https://stackoverflow.com/a/40098855/7669809
tags$head(tags$style(HTML("
.shiny-split-layout > div {
display: inline-block;
}
")))
)
)
# Server logic
server <- function(input, output, session){
}
# Complete app with UI and server components
shinyApp(ui, server)
Remove overflow: visible. This is what is making the text spill over the div. I see that here in your code:
.shiny-split-layout > div {
overflow: visible;
}
I'm building a Shiny app with this UI. Here is nhl-logo.png
ui <- fluidPage(
titlePanel(tagList(
img(src = "nhl-logo.png", height = 60, width = 60),
"PLAY-BY-PLAY"),
windowTitle = "NHL Play-by-Play"),
div(style = "position:absolute;right:2em;",
actionButton('load_inputs', 'Load inputs'),
actionButton('save_inputs', 'Save inputs')
),
hr(),
fluidRow(...)
Unfortunately, the style is not what I want since it puts those actionButtons on a lower level than the title (NHL LOGO PLAY-BY-PLAY)
How do I change the style so that my actionButtons appear on the same horizontal level as the titlePanel?
You can add the title in a span which includes the buttons. The difference between a span and a div is that the span is inline (a div is a block).
ui <- fluidPage(
titlePanel(tagList(
img(src = "nhl-logo.png", height = 60, width = 60),
span("PLAY-BY-PLAY",
span(actionButton('load_inputs', 'Load inputs'),
actionButton('save_inputs', 'Save inputs'),
style = "position:absolute;right:2em;")
)
),
windowTitle = "NHL Play-by-Play"
),
hr(),
fluidRow()
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
I have this shiny app with 4 menuItem. One is named "Login" and tabA, tabB, and tabC are under a conditionalPanel and only appear when a login is successfully done.
Can someone give a hint on why the UI has changed? Because all 4 tabs should look exactly as the first one.
ui.R code:
menuItem('Login', tabName = 'Login', icon = icon('fa fa-address-book')),
conditionalPanel(" 'TRUE' === 'TRUE' ",
menuItem("tabA", tabName = "tabA", icon = icon("fa fa-book")),
menuItem("tabB", tabName = "tabB", icon = icon("fa fa-line-chart")),
menuItem("tabC", icon = icon("fa fa-database")))
Thank you in advance
One option should be to wrap with sidebarMenu
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(
title = "Shiny"
),
dashboardSidebar(
sidebarMenu(id="menu",
menuItem('Login', tabName = 'Login', icon = icon('user-o')),
conditionalPanel(" 'TRUE' === 'TRUE' ",
sidebarMenu(menuItem("tabA", tabName = "tabA", icon = icon("quora")),
menuItem("tabB", tabName = "tabB", icon = icon("superpowers")),
menuItem("tabC", tabName = "tabC", icon = icon("podcast"))))
)
),
dashboardBody(
tabItems(
tabItem("Login",h1("login")),
tabItem("tabA",h1("a")),
tabItem("tabB",h1("b")),
tabItem("tabC", h1("c"))
)
)
)
server <- function(input, output) {
observe(print(input$menu))
}
shinyApp(ui,server)
giving output
In my shiny app I want to add an option to let users jump to a specific element in the app (a table, a plot, just anything with an id), on current or different tab, by clicking on infoBox (or any other object I want).
My solution was to surround infoBox with div and add thehref=#id_of_element attribute. Unfortunately this solution works only for tabs with an extra "data-toggle" = "tab" attribute (it also does not change the opened tab to active), but that's not what I want.
My question is: how can I add the mentioned option and why this solution isn't working? Here is a small example what I want to do:
UI
library(shiny)
library(shinydashboard)
shinyUI(
dashboardPage(
skin = "blue",
dashboardHeader(title = "Example"),
dashboardSidebar(
sidebarMenu(id = "sidebarmenu",
menuItem("Tab1", icon = icon("line-chart"),
menuSubItem("SubTab1", tabName = "sub1", icon = icon("bar-chart")),
menuSubItem("SubTab2", tabName = "sub2", icon = icon("database"))),
menuItem("Tab2", tabName = "tab2", icon = icon("users"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "sub1",
tags$div(href="#s2t2",
infoBox(value = "Go to table 2 in SubTab2 (not working)",title = "Click me")),
tags$div(href="#shiny-tab-tab2", "data-toggle" = "tab",
infoBox(value = "Go to Tab2 (this works)",title = "Click me"))
),
tabItem(tabName = "sub2",
tableOutput("s2t1"),
tableOutput("s2t2")
),
tabItem(tabName = "tab2",
tableOutput("t2t1"),
tableOutput("t2t2")
)
)
)
)
)
SERVER:
shinyServer(function(input, output,session) {
output$s2t1<- renderTable(mtcars)
output$s2t2<- renderTable(mtcars)
output$t2t1<- renderTable(mtcars)
output$t2t2<- renderTable(mtcars)
} )
I found my answer:
$(document).ready(function() {
$("#div1").click(function() {
$(".sidebar-menu a[href=\'#shiny-tab-tab2\']").tab("show");
setTimeout(function(){
var top = $("#t2t2").position().top;
$(window).scrollTop( top );
}, 300);
});
});
where div1 is div around infoBox