I want to scale a shiny plot to the height of the window. This related SO question only uses absolute height specifications in pixels, when a height = 100% would be preferable. I note in the documentation that absolutePanel can achieve this with its top, bottom, left, right arguments, but then you lose the side panel, and in any case the plot (while scaling to width) seems to ignore available height.
I'm guessing this relates to the html quirk that means you need to get the height with javascript innerHeight variable. But I'm unclear how to implement a solution in shiny to get ui.R to utilise this. Grateful for any pointers.
A basic app model for development:
ui.R
library(shiny)
shinyServer(
function(input, output) {
output$myplot <- renderPlot({
hist(rnorm(1000))
})
}
)
server.R
library(shiny)
pageWithSidebar(
headerPanel("window height check"),
sidebarPanel(),
mainPanel(
plotOutput("myplot")
)
)
Use CSS3. Declare your height in viewport units http://caniuse.com/#feat=viewport-units .
You should be able to declare them using the height argument in plotOutput however shiny::validateCssUnit doesnt recognise them so you can instead declare them in a style header:
library(shiny)
runApp(
list(server= function(input, output) {
output$myplot <- renderPlot({
hist(rnorm(1000))
})
}
, ui = pageWithSidebar(
headerPanel("window height check"),
sidebarPanel(
tags$head(tags$style("#myplot{height:100vh !important;}"))
),
mainPanel(
plotOutput("myplot")
)
)
)
)
This wont work in the shiny browser but should work correctly in a main browser.
Related
library(shiny)
ui <- fluidPage(
titlePanel("Hello"),
sidebarLayout(
sidebarPanel("Hello SideBar"),
mainPanel("Hello MainPanel")
)
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)
Just by eyeballing I can tell right now my sidebar panel takes up about 33% of the width of the screen. Any idea how I can reduce the width of the sidebar so that the main Panel is larger?
sidebarPanel has a width argument
width: The width of the sidebar. For fluid layouts this is out of 12
total units; for fixed layouts it is out of whatever the width of the
sidebar's parent column is.
The default width is 4, which confirms your eyeballing estimate that 4/12 is one third. So to make it e.g 1/2 the current width you would do:
ui <- fluidPage(
titlePanel("Hello"),
sidebarLayout(
sidebarPanel("Hello SideBar", width=2),
mainPanel("Hello MainPanel")
)
)
I want to plot the google map just next to the sliderBar, but when I try this code, I get a huge blank space between:
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
actionButton("bb","bb"),
sliderInput("aa","aa",value=1,min=0,max=10),
sliderInput("aa1","aa1",value=1,min=0,max=10),
sliderInput("aa2","aa2",value=1,min=0,max=10),
sliderInput("aa3","aa3",value=1,min=0,max=10)
)
,
mainPanel(
plotOutput("rys")
)
)
)
server <- function (input, output){
output$rys <- renderPlot({qmap('Europe',zoom=4)})
}
shinyApp(ui = ui, server = server)
how to remove this blank space?
The default appearance for plotOutput is width="100%" and height="400"
If you are on a desktop, 100% is about 1200 px and since the map is square, it is limited by the smallest dimension, height=400 to 400x400
It is centered so you have a whitespace of about 400px
To fix this issue, you can either use a bigger height, for example height="1000" or set both height and width :
plotOutput("rys", width = "400", height="400")
By default, using navbarPage() in shiny creates a 'static top' bootstrap page (example). If I were writing the html for a webpage, I could add a <ul> element with a class of nav navbar-nav navbar-right where the navbar-right would move the tabs/menus to the right side of the navbar.
There doesn't seem to be a way to coerce this behavior directly through the framework - is there a clever known way to accomplish this?
The solution provided by K. Rohde, especially the edit, works for keeping it nearly pure Shiny. I discovered the insertAdjacentHTML javascript function and used it to create a right-hand text label. I guess it should be possible to make tabs that Shiny knows about and can use. In my case, I was wanting to put version information on the navbar, on the right-hand side. So, adding the disabled class was to avoid confusion.
library(shiny)
app <- shinyApp(
ui = shinyUI(
fluidPage(
navbarPage("Site Title",
tabPanel("v0.1"),
tabPanel("tab1"),
tabPanel("tab2")
),
HTML("<script>var parent = document.getElementsByClassName('navbar-nav');
parent[0].insertAdjacentHTML( 'afterend', '<ul class=\"nav navbar-nav navbar-right\"><li class=\"disabled\">v0.1</li></ul>' );</script>")
)
),
server = function(input, output, session){}
)
runApp(app)
You can use shinyjs package
library(shiny)
ui <- shinyUI(
navbarPage(
'Test',
id = 'menus',
tabPanel('Test',
shinyjs::useShinyjs()),
tabPanel("Summary"),
tabPanel("Table", value = 'table')
))
server <- function(input, output, session) {
shinyjs::addClass(id = "menus", class = "navbar-right")
}
shinyApp(ui, server)
Depends on how low your expectations are.
You can add css to your UI which aligns either your tabsets or your header to the right. Code:
app <- shinyApp(
ui = shinyUI(
fluidPage(
tags$head(
tags$style(HTML("
.navbar .navbar-nav {float: right}
.navbar .navbar-header {float: right}
"))
),
navbarPage("header",
tabPanel("tab1"),
tabPanel("tab2")
)
)
),
server = function(input, output, session){}
)
runApp(app)
Edit: The header argument of navbarPage also accepts regular div-containers. (E.g. a logo instead of plain text.) This can be exploitet to fill whole UI-Elements (e.g. buttons) into the header spot. Then of course you can float that to the right, while your tabs are aligned to the left.
I have a plot which is set to 100% width (default) in the main panel of a two-panel page in R Shiny. The sidebar is hideable through a toggle action button.
When the sidebar is visible (default), the plot fills the width of the main panel. When the sidebar is hidden, I want the plot to expand to fill 100% of the space now available, i.e. the whole browser window. But this does not happen! It keeps the same size.
library(shiny)
library(shinyBS)
UI <- fluidPage(
bsButton("showpanel", "Show/hide sidebar", type = "toggle", value = TRUE),
sidebarLayout(
conditionalPanel(condition = "input.showpanel == true",
sidebarPanel("This is my sidebar.")
),
mainPanel(plotOutput("plot", width = "100%"))
)
)
SERVER <- function(input, output) {
output$plot <- renderPlot({
plot(1:10, main = "The width of this plot adjusts\nto window resizes but not to\nshow/hide sidepanel!")
})
}
runApp(shinyApp(UI,SERVER))
Attempted so far:
Defining the plot object from within the UI file, as above.
Defining the plot object from within the server file, as a renderUI object.
Set CSS tag in the page as per tags$head(tags$style("#myplot{height:100vh !important;}")) from this question, Scaling shiny plots to window height.
Possible work-arounds:
Make the width of the plot dynamic and depending on the state of the toggle button. Then I can make the plot e.g. 140% width when the sidebar is hidden. This does not generalise well, and loses the point of using the adaptability of fluidPage.
(fluidPage changes the layout dependent on the browser window size. For example, if you make your browser window about the size of a mobile phone, it will place the sidebar above the main panel.)
#konvas answer is really good and probably the way you wan't to do this but if you want to use the sidebarLayout (and for the sake of giving another answer) you can use jQuery to toggle the bootstrap columns like:
library(shiny)
ui <- fluidPage(
tags$head(
tags$script(
HTML("
$(document).ready(function(){
// Mark columns we want to toggle
$('body').find('div [class=col-sm-4]').addClass('sidebarPanel');
$('body').find('div [class=col-sm-8]').addClass('mainPanel');
})
Shiny.addCustomMessageHandler ('resize',function (message) {
$('.sidebarPanel').toggle();
$('.mainPanel').toggleClass('col-sm-8 col-sm-12');
$(window).trigger('resize')
});
")
)
),
actionButton("showpanel", "Show/hide sidebar"),
sidebarLayout(
sidebarPanel("This is my sidebar."),
mainPanel(plotOutput("plot", width = "100%"))
)
)
server <- function(input, output, session) {
observeEvent(input$showpanel,{
session$sendCustomMessage(type = 'resize', message = 1)
})
output$plot <- renderPlot({
plot(1:10, main = "The width of this plot adjusts\nto window resizes but not to\nshow/hide sidepanel!")
})
}
runApp(shinyApp(ui,server))
The same methodology would apply if you use columns in a fluidRow or something similar.
One way to do this would be to use a reactive layout (there are many questions on this eg Switch between layouts reactively with shiny). In your case that would be something like
library(shiny)
library(shinyBS)
UI <- shinyUI(
fluidPage(
bsButton("showpanel", "Show/hide sidebar", type = "toggle", value = TRUE),
uiOutput('ui')
)
)
SERVER <- function(input, output) {
output$ui <- renderUI({
if (input$showpanel) {
sidebarLayout(
sidebarPanel("This is my sidebar."),
mainPanel(plotOutput('plot'))
)
} else {
plotOutput('plot')
}
})
output$plot <- renderPlot({
plot(1:10, main = "The width of this plot adjusts\nto window resizes and to\nshow/hide sidepanel!")
})
}
runApp(shinyApp(UI,SERVER))
I have a lot of generated input fields on an shiny app and I want to make it more dense by lowering the height of the dateinput fields. However, the height tag only shrinks the box and make it overflow into the next input. So, how do I shrink the dateInput() fields so it is only a little higher than the text?
library(shiny)
ui <- fluidPage(
tags$style(".shiny-date-input {height : 30px;}")
,dateInput("date1","date1")
,dateInput("date2","date2")
,textInput("text","text")
)
shinyApp(ui, function(input, output, session){})
Update: To clearify, I want the dateInput (and possibly the textinput also) frame to be less tall without it extending into the blow input:
You can add the class input-sm to the widgets in order to make them a bit smaller. To do so, use shinyjs.
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
dateInput("date1","date1"),
br(),
dateInput("date2","date2"),
br(),
textInput("text","text")
)
shinyApp(ui,
function(input, output, session){
addClass("date1", "input-sm")
addClass("date2", "input-sm")
addClass("text", "input-sm")
}
)
Found the answer in .form_control :
library(shiny)
ui <- fluidPage(
tags$style(".shiny-input-container {line-height: 5px; height : 25px}")
,tags$style(".form-control {height: 25px;}")
,dateInput("date1","date1")
,dateInput("date2","date2")
,textInput("text","text")
)
shinyApp(ui, function(input, output, session){})