Working with Shiny

This is an R Markdown document created with examples of how to work with Shiny. Based on Coursera’s Data Products course.


About Shiny

It is a platform for creating simple interactive R programs embedded into a web page

Hello world and a bit more

A Shiny project is a directory containing at least two parts:

  • a file named ui.R (ui=user interface) which controls how it looks
  • a file named server.R, which controls what it does

Example:

  1. ui.R:
library(shiny)
shinyUI(pageWithSidebar(
  headerPanel("Data science FTW!"),
  sidebarPanel(
    h3('Sidebar text')
  ),
  mainPanel(
      h3('Main Panel text')
  )
))
  1. server.R
shinyServer(
  function(input, output) {
  }
)

Now to run the app all you have to do is go to the directory (say, s_project) where you have the ui.R and server.R files and type runApp()

setwd("./s_project")
runApp()

You will obtain something like this:

simplestApp

Ok, that’s as simple as it gets. What might we want to do more than absolute simplicity?

  • maybe play around with fonts on ui.R (ui, again, is user interface; controls how things look):
shinyUI(pageWithSidebar(
  headerPanel("Illustrating markup"),
  sidebarPanel(
      h1('Sidebar panel'),
      h1('H1 text'),
      h2('H2 Text'),
      h3('H3 Text'),
      h4('H4 Text')
      
  ),
  mainPanel(
      h3('Main Panel text'),
      code('x=c(1, 2, 3)
            y=cos(x)
            plot(x, y)'),
      p('some ordinary text')
  )
))

This is what you will obtain (again, remember you need a folder with ui.R and server.R. Set your working directory to that folder and run runApp()):

simplestApp

Mind you it is possible to only display the sidebar panel if you leave out the instructions (the five lines between the parenthesis) after mainPanel(,

  • actually have inputs and outputs! Remember it’s server.R that controls that.
  1. Let’s consider a simple predictor where the user inputs his level of glucose and the predictor function divides that value by 200. We will then obtain something like this:

simplestApp

The codes to obtain that are:

shinyUI(
  pageWithSidebar(
    # Application title
    headerPanel("Diabetes prediction"),
  
    sidebarPanel(
      numericInput('glucose', 'Glucose mg/dl', 90, min = 50, max = 200, step = 5),
      submitButton('Submit')
    ),
    mainPanel(
        h3('Results of prediction'),
        h4('You entered'),
        verbatimTextOutput("inputValue"),
        h4('Which resulted in a prediction of '),
        verbatimTextOutput("prediction")
    )
  )
)

and

diabetesRisk <- function(glucose) glucose / 200

shinyServer(
  function(input, output) {
    output$inputValue <- renderPrint({input$glucose})
    output$prediction <- renderPrint({diabetesRisk(input$glucose)})
  }
)
  1. Let’s consider a situation where the user can input a number, choose between 3 checkboxes and also choose a date. The app we want to build will accept that input and as an output it will state which choices were made. So we actually want to look at the code to do something like this:

simplestApp

The code is the following:

shinyServer(
  function(input, output) {
    output$oid1 <- renderPrint({input$id1})
    output$oid2 <- renderPrint({input$id2})
    output$odate <- renderPrint({input$date})
  }
)
shinyUI(pageWithSidebar(
  headerPanel("Illustrating inputs"),
  sidebarPanel(
    numericInput('id1', 'Numeric input, labeled id1', 0, min = 0, max = 10, step = 1),
    checkboxGroupInput("id2", "Checkbox",
                   c("Value 1" = "1",
                     "Value 2" = "2",
                     "Value 3" = "3")),
    dateInput("date", "Date:")
  ),
  mainPanel(
        h3('Illustrating outputs'),
        h4('You entered'),
        verbatimTextOutput("oid1"),
        h4('You entered'),
        verbatimTextOutput("oid2"),
        h4('You entered'),
        verbatimTextOutput("odate")
  )
))
  1. Finally, let’s look at a situation where the user is asked to guess the mean of a variable by visual observation of its histogram. He can do so by moving a slider. We will obtain something like this:

simplestApp

The code is the following:

library(UsingR)
data(galton)

shinyServer(
  function(input, output) {
    output$newHist <- renderPlot({
      hist(galton$child, xlab='child height', col='lightblue',main='Histogram')
      mu <- input$mu
      lines(c(mu, mu), c(0, 200),col="red",lwd=5)
      mse <- mean((galton$child - mu)^2)
      text(63, 150, paste("mu = ", mu))
      text(63, 140, paste("MSE = ", round(mse, 2)))
      })
    
  }
)
)
shinyUI(pageWithSidebar(
  headerPanel("Example plot"),
  sidebarPanel(
    sliderInput('mu', 'Guess at the mean',value = 70, min = 62, max = 74, step = 0.05,)
  ),
  mainPanel(
    plotOutput('newHist')
  )
))

More on Shiny

  • All of the style elements are handled through ui.R
  • Instead, you can create a www directory and then an index.html file in that directory
  • This link goes through the html needed
  • You just have to have specific js libraries and appropriately name ids and classes.
  • Shiny allow users:
  • to upload or download files
  • Have tabbed main panels
  • Have editable data tables
  • Have a dynamic UI (based on what you input, other controls may show, for instance)
  • User defined inputs and outputs
  • Put a submit button so that Shiny only executes complex code after user hits submit
  • Distributing a Shiny app:
  • The quickest way is to send (or put on github or gist or dropbox or whatever) someone the app directory and they can then call runApp
  • You could create an R package and create a wrapper that calls runApp
  • Another option is to run a (Shiny server)[http://www.rstudio.com/shiny/server/]
  • Groups are creating a Shiny hosting services that will presumably eventually be a fee for service or freemium service: https://www.shinyapps.io/
  • BTW, don’t put system calls in your code (this is one of the first things many of us do for fun, but it introduces security concerns)

Sharing your Shiny app on https://www.shinyapps.io/

Use library(shinyapps), go to the folder where your app is (make sure it’s running with runApp!) and then simply do deployApp(). You will need to input your token, which you can find in the website. If you run more than one account on shinyapps.io, you will have to type deployApp(account=“account_name”).

Reactivity

  • code you put in server.R before shinySever is run once when you do runApp()
  • code inside server.R(function(input, output)){} is run once for every new user/page refresh * except for code inside reactive functions (like render) which is run when new values are entered

To see how this works, first type

x=1000

and then run the following app:

library(shiny)
x  <<-  x+  1
y  <<-  0
shinyServer(
        function(input, output) {
                y  <<-  y+  1
                output $text1 <- renderText ({input $text1})
                output $text2 <- renderText ({input $text2})
                output $text3 <- renderText ({as.numeric (input$text1 )+1})
                output $text4 <- renderText (y)
                output $text5 <- renderText (x)
        }
)
shinyUI(pageWithSidebar(
        headerPanel( "Hello Shiny!"),
        sidebarPanel(
                textInput(inputId= "text1" ,  label =  "Input Text1" ),
                textInput(inputId= "text2" ,  label =  "Input Text2" )
        ),
        mainPanel(
                p('Output text1'),
                textOutput( 'text1'),
                p('Output text2'),
                textOutput( 'text2'),
                p('Output text3'),
                textOutput( 'text3'),
                p('Outsidetext'),
                textOutput( 'text4'),
                p('Inside text, but non-reactive'),
                textOutput( 'text5')
        )
))

You will obtain something like:

simplestApp

where you can see x+1 (remember you input x=1000) and y=1 (look inside server.R; y starts at 0 but is incremented inside shinyServer). Now note that:

  • If you type in text (say “5” in the first text box and “this example is stupid” in the second text box), you will get this:

simplestApp

All the rendertext’s in shinyServer reacted and updated the outputs in shinyUI. But now if you click refresh (top right, such as in the next picture), the value of y gets updated.

simplestApp

By the way, if you want to see all the magic happening while looking at where in the code it is happening, try running:

runApp(display.mode="showcase")

You’ll be able to see the code at the same time as the app is running (see next figure). If that ain’t cool, I don’t know what is…

simplestApp

Now, in some occasions you might want to accelerate your app, notably in the case in which the same computation is made for 2 different outputs. Imagine you have an app that takes one number x as input and outputs 2x and 2x+1. That’s pretty simple to do:

library(shiny)
shinyServer(
        function(input, output) {
                output $text1 <- renderText ({2*as.numeric(input$text1) })
                output $text2 <- renderText ({2*as.numeric(input$text1)+1})
        }
)
shinyUI(pageWithSidebar(
        headerPanel( "Hello Shiny!"),
        sidebarPanel(
                textInput(inputId= "text1" ,  label =  "Input Text1" )
        ),
        mainPanel(
                p('Output text1'),
                textOutput( 'text1'),
                p('Output text2'),
                textOutput( 'text2')
        )
))

If you run this app and input 5, you will obtain something like:

simplestApp

Now notice that you are computing the same quantity (2x) for both output$text1 and output$text2. If you want to pre-compute 2x before assigning it to output\(text1 and output\)text2, you can use the reactive function:

library(shiny)
shinyServer(
        function(input, output) {
                x  <- reactive ({ 2*as.numeric (input$text1 )}) 
                output $text1 <- renderText ({x() })
                output $text2 <- renderText ({x()+1})
        }
)

The app will work the same, but a bit faster because you pre-computed something. Of course the difference is not great in this toy example…

Something else you might want to do is to control which reactive elements are to happen immediately or which should wait for a button to be pushed. Say you want a situation where as soon as the user enters his input immediately they are displayed as output, but their sum will only be displayed as output after a button is pushed:

simplestApp

In the figure above, if the user presses the go button, a “5” will appear in the Output text 3. How to have that control? You have to use the isolate function:

shinyServer(
        function(input, output) {
                output$text1 <- renderText ({input$text1})
                output$text2 <- renderText ({input$text2})
                output$text3 <- renderText ({
                        input$goButton
                        isolate(as.numeric(input$text1)+as.numeric(input$text2)) # isolate makes this instruction depend on the goButton
                })
        }
)
shinyUI(pageWithSidebar(
        headerPanel( "Hello Shiny!"),
        sidebarPanel(
                textInput(inputId= "text1" ,  label =  "Input Text1" ),
                textInput(inputId= "text2" ,  label =  "Input Text2" ),
                actionButton( "goButton" ,  "Go!")
        ),
        mainPanel(
                p('Output text1'),
                textOutput( 'text1'),
                p('Output text2'),
                textOutput( 'text2'),
                p('Output text3'),
                textOutput( 'text3')
        )
))

This is cool. Or you can use a conditional statement:

shinyServer(
        function(input, output) {
                output$text1 <- renderText ({input$text1})
                output$text2 <- renderText ({input$text2})
                output$text3 <- renderText ({
                      if (input $goButton ==  0)  "You have not pressed the button"
                      else if (input $goButton ==  1)  "you pressed it once"
                      else "OK quit pressing it"
                })
        }
)

which of course will give you something a bit different (but it’s easy to see what…).

More on layouts:

  • The sidebar layout with a main panel is the easiest.
  • Using shinyUI(fluidpage( is much more flexible and allows tighter access to the bootstrap styles: examples here (http://shiny.rstudio.com/articles/layout-guide.html)
  • fluidRow statements create rows and then the column function from within it can create columns
  • Tabsets, navlists and navbars can be created for more complex apps

Directly using HTML

  • For more complex layouts, direct use of html is preferred (http://shiny.rstudio.com/articles/htmlui.html)
  • Create a directory called wwwin the same directory with server.R; have an index.htmlpage in that directory
  • Your named input variables will be passed to server.R \(\mbox{<input type="number" name="n" value="500" min="1" max="1000" />}\)
  • Your server.R output will have class definitions of the form shiny- \(\mbox{<pre id="summary" class="shiny-text-output"></pre>}\)

Debugging:

  • Using cat in your code displays output to stdout (so R console)
  • The browser() function can interrupt execution and can be called conditionally

Explore further:

Create interactive documents: http://rmarkdown.rstudio.com/authoring_shiny.html

Placing shiny apps on markdown example:

library(shiny)
## Warning: package 'shiny' was built under R version 3.0.3
shinyApp(
  
  ui = fluidPage(
    selectInput("region", "Region:", 
                choices = colnames(WorldPhones)),
    plotOutput("phonePlot")
  ),
  
  server = function(input, output) {
    output$phonePlot <- renderPlot({
      barplot(WorldPhones[,input$region]*1000, 
              ylab = "Number of Telephones", xlab = "Year")
    })
  },
  
  options = list(height = 500)
)

Shiny applications not supported in static R Markdown documents