The ui
defines the look and feel of the app - the user interface
Use it to define where output "lives"
It also defines the inputs for the server
, where functions are actually
evaluated.
In the template/default case, a sliderInput
has been defined, which we're
calling "bins"
. It will take on values from 1 to 50, and will start at 30.
Access the specific value the user selects within the server
, through input$bins
.
Because this is base syntax, I'll give you the basics for the table, you focus on the shiny part
input_bins <- 30 # placeholder for whatever the input isx <- faithful[, 2] # data you're working withbins <- seq(min(x), max(x), length.out = input_bins + 1)h <- hist(x, breaks = bins, plot = FALSE)tibble(lower = lag(h$breaks), upper = h$breaks) %>% drop_na(lower) %>% mutate(counts = h$counts) %>% mutate_if(is.numeric, round, 2)
Instead of using a tabset with tabsetPanel
, you might want to have a navbar at the top of the page, which you can create with navbarPage
.
Can be a bit more complicated - each tabset
needs to include everything, including the sidebarPanel
(if present), could include tabsets, mainPanel
, etc.
Instead of using a tabset with tabsetPanel
, you might want to have a navbar at the top of the page, which you can create with navbarPage
.
Can be a bit more complicated - each tabset
needs to include everything, including the sidebarPanel
(if present), could include tabsets, mainPanel
, etc.
Essentially each tab from the navbar
becomes an entirely new page.
Can really help with organization/flexibility (you could even have tabs within a page)
Refactoring can help organization A LOT
library(shiny)library(shinydashboard)ui <- dashboardPage( dashboardHeader(title = "Basic dashboard"), dashboardSidebar(), dashboardBody( # Boxes need to be put in a row (or column) fluidRow( box(plotOutput("plot1", height = 250)), box( title = "Controls", sliderInput("slider", "Number of observations:", 1, 100, 50) ) ) ))
Probably the defining characteristic of the dashboard
sidebarMenu
with menuItem
ssidebarMenu( menuItem("Histogram", tabName = "histo", icon = icon("chart-bar")), menuItem("Bin Counts", tabName = "bins", icon = icon("table")))
You can also do things like put the slider in the sidebarMenu
[demo]
There's lots of extensions for shiny, and quite a few (but not as many) for shinydashboard
Consider themeing shiny apps with {shinythemes} and dashboards with {dashboardthemes}
Consider themeing figures to match your shiny theme with {thematic}
input
is a basically a list object that contains objects from the uiui <- fluidPage( numericInput("count", label = "Number of values", value = 100))
After writing this code, input$count
will be a available in the server, and the value it takes will depend on the browser input (starting at 100)
input
is a basically a list object that contains objects from the uiui <- fluidPage( numericInput("count", label = "Number of values", value = 100))
After writing this code, input$count
will be a available in the server, and the value it takes will depend on the browser input (starting at 100)
These are read-only, and cannot be modified
It must be in a reactive context, or it won't work.
That's why this results in an error
server <- function(input, output, session) { print(paste0("The value of input$count is ", input$count))}shinyApp(ui, server)# > Error in .getReactiveEnvironment()$currentContext() : # > Operation not allowed without an active reactive context. # > (You tried to do something that can only be done from inside a reactive expression or observer.)
From Mastering Shiny
Try this app. Type the letters in one at a time. Notice how it updates.
ui <- fluidPage( textInput("name", "What's your name?"), textOutput("greeting"))server <- function(input, output, session) { output$greeting <- renderText({ paste0("Hello ", input$name, "!") })}
Notice you don't have to "run" the code each time the input updates
Your app provides instructions to R. Shiny decides when it actually runs the code.
Normal R code is imperative programming - you decide when it's run. Declarative programming means you provide instructions, but don't actually run it.
Notice you don't have to "run" the code each time the input updates
Your app provides instructions to R. Shiny decides when it actually runs the code.
Normal R code is imperative programming - you decide when it's run. Declarative programming means you provide instructions, but don't actually run it.
you describe your overall goals, and the software figures out how to achieve them
(from Hadley)
image from Mastering Shiny
Normally, you understand R code by running it top to bottom
This doesn't work with shiny
Instead, we think through reactive graphs
library(shiny)library(reactlog)reactlog_enable()ui <- fluidPage( textInput("name", "What's your name?"), textOutput("greeting"))server <- function(input, output, session) { output$greeting <- renderText({ paste0("Hello ", input$name, "!") })}shinyApp(ui, server)# close app, thenreactlogShow()
Shiny is super customizable - almost limitless (see more examples here)
Great for building interactive plots, but you can use it for all sorts of other things too (including text and tables)
Really helpful and fun way to build data tools for practitioners
Takes some practice, but basically allows you to write normal R code, and get interactive websites
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
Number + Return | Go to specific slide |
b / m / f | Toggle blackout / mirrored / fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
t | Restart the presentation timer |
?, h | Toggle this help |
Esc | Back to slideshow |