Zhen Zhang's Blog

Shiny Introduction Summary

Today I learned how to build a simple shiny app using the package of “shiny” developed by RStudio. I must admit that this is a wonderful package which makes it interactive between the application itself and the user. Now I will share my reading summary of RStudio’s basic tutorial. This series of tutorial consists of seven parts, and I will mix them up in this article.

I strongly recommend you read this article after you read the basic tutorials on RStudio. This article is served as a summary and extension, not a tutorial.

Basic Structure

Shiny consists of two parts when we are building it:

  • The user-interface script (ui.R)

  • The server script (server.R)

From their name we can easily know their functions. The ui.R will control the user-interface, will the server.R will control the instructions that the computer needed when we are building. But I think it is not straightforward, since sometime we will include a helper.R script when we need to do some complicated calculations. Since I have read the later parts of the tutorial, I should point out that the server.R file is indeed constructing a bridge between the input and output by listening on their changes. It is confusing now if you first read this, but don’t worry, you will understand it afterwards.

After you finish writing all the files you need, you can launch it by running:

R runApp("my_app")

It is noted that the file path inside the runApp function is your R working directory. Then based on your given path, shiny will look for the ui.R file, server.R file, and other files or directories needed to build this application. So in general, a typical directory structure should look like this:

my_App ├── ui.R ├── server.R ├── helper.R ├── www | ├── pic1 | └── pic2 ├── data | ├── dataset1 | └── dataset2 ├── ...

The pictures are enclosed in the www folder while the datasets are included in the data folder. Remember, shiny will only see the files within the same directory level of ui.R and server.R.

There are three ways you can run your shiny app in RStudio: in a separate window of RStudio, in the view panel of RStudio, or in an external web browser of your system. You are free to press “Escape” whenever you want to exit shiny application and return to the R console.

ui.R

Basic

The basic structure of ui.R should look like this:

1
2
3
4
5
6
7
8
9
10
# ui.R
shinyUI(fluidPage(
titlePanel("title panel"),
sidebarLayout(
sidebarPanel( "sidebar panel"),
mainPanel("main panel")
)
))

And the ui will be:

sidebar-layout1

In case we want to move the sidebarPanel to right, we can add the position = "right" option to siderbarLayout function.

Style

We can modify the style of a html file with a css file, and in shiny, we can just modify them using the tags directly. The only difference is that, compared to the tags we use in html language, we use the corresponding functions, and shiny will convert them into html tags. For example, if you want to use <p> </p> tag, you can use the function of p() in shiny.

There are many options for each html tag, and we can use them as options of functions in shiny. For example, the <span> </span> tag, and if we want to set the style:color option, we can do this by span("text",style = "color:blue").

For plain text, you can just type “” or use the <p> </p> tag. The <code> </code> is free to use. The br() is used to break a line. When it comes to image, we can use image(src="",height=x,width=x) to configure it. As I have said, the folder contains image must be named www.

Between multiple tags, we need to separate them by comma.

Another Note here: If we want to split the panel into much more complicated parts, we can use options such as fluidRow. This will be talked in the advanced parts.

Widgets

The most important feature for shiny is that the user can interact with the application. This function is achieved by the use of widgets. The widgets can listen to the change of the users’s interests, and give the results to the corresponding part of server scripts, then generate the desired output on the user interface.

Shiny provides a lot of useful built-in widgets. Although we can find it on its website, I will list it here to simplify my own use.

function widget
actionButton Action Button
checkboxGroupInput A group of check boxes
checkboxInput A single check box
dateInput A calendar to aid date selection
dateRangeInput A pair of calendars for selecting a date range
fileInput A file upload control wizard
helpText Help text that can be added to an input form
numericInput A field to enter numbers
radioButtons A set of radio buttons
selectInput A box with choices to select from
sliderInput A slider bar
submitButton A submit button
textInput A field to enter text

To configure a widget, we need to specify the following parts:

1
sliderInput("name",label="label",...)

The first option, name, is the name used to specify the widget in our script. As we will see later, when we need to use the value of a specific widget, we need to refer to this widget. Then we can use its name. The label option, is used to display the text to the user. Since it is a label, we usually need to make the text bigger, so we can simply write label=h3("label") here. Sometimes we can leave it blank, and display the label in other way. The omitted options are variable between widgets.

If more help is needed when we are using the widgets, we can just refer it to the console by typing ?widget.

server.R

This is another basic script file needed. The basic template is:

1
2
3
4
# server.R
shinyServer(function(input, output) {
})

We will talk more about the usage in the next part.

Interactive

Output & Input

It’s time to make our app interactive. The basic idea behind the design is: The server will listen to the input of the user by widget, and process the corresponding data defined by the user, then return the output to the panel which will be seen by the user. Each time the user change his input, the server will recalculate the data only for the changed part.

For the input part, the widgets constitute the inputs. We can use the value of input by input$nameOfWidget. In other words, our input is a list of inputs. For the widgets with more than one user inputs, we can treat them as vectors.

The output configuration is much more complicated.

ui configuration:

R is a object oriented programming language. Then UI needs a method to receive the output as an object. In shiny, we have some particular built-in functions. Each of them creates a specific type of output.

Output function creates
htmlOutput raw HTML
imageOutput image
plotOutput plot
tableOutput table
textOutput text
uiOutput raw HTML
verbatimTextOutput text

For instance, if we need a text output, we can put the following code in the proper place of ui.R:

1
textOutput("text1")

The name \”text1\” will be rendered to the output list. The output list has the same property with the input list.

server configuration:

The main task for server is to receive the inputs given by the user, process the data, and then give the outputs. To provide outputs, shiny also provide some built-in functions to achieve this task:

render function creates
renderImage images (saved as a link to a source file)
renderPlot plots
renderPrint any printed output
renderTable data frame, matrix, other table like structures
renderText character strings
renderUI a Shiny tag object or HTML

This functions will creates the corresponding outputs based on its type. The usage is a little different from other R functions: you need to enclose the contents of the function in {}:

1
2
3
4
5
6
7
8
9
10
11
# server.R
shinyServer(
function(input, output) {
output$text1 <- renderText({
paste("You have selected", input$var)
})
}
)

As is seen, the text1 label needs to match the label provided in the ui.R file. And the input list is used to generate dynamic output.

dynamic vs static

Split into parts

Think about this circumstance: you have many inputs, say, 10 inputs. Each time you change one input, all of the inputs will be calculated again. Oh! That’s terrible. We need a way to solve this issue.

This issue can be called as “dynamic vs static” (defined by me, haha).

I attached three pictures here downloaded from RStudio to illustrate this point:

run-once

run-once-per-user

run-many-times

So the device is designed as follows:

  • the server.R will run each time the application runs

  • the unnamed function contents inside shinyServer() will run once each time a user visits it

  • the R expressions inside render* functions will run many times. Shiny runs them once each time a user changes a widget.

So how do we place the contents in the proper parts? The library() command, and the source() command, some other commands like these, should run only once, then be placed outside the shinyServer() function.

Server defined objects, should be placed inside shinyServer(), but outside render*.

Only the codes needed to be run each time should be put into render*.

Reactive function

But this is not the end of the story, since our issue is still not solved completely. If only one input is changed, the render* will change, and then all the inputs inside the render* will change as well. So here is a new function: reactive():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# server.R
library(quantmod)
source("helpers.R")
shinyServer(function(input, output) {
dataInput <- reactive({
getSymbols(input$symb, src = "yahoo",
from = input$dates[1],
to = input$dates[2],
auto.assign = FALSE)
})
output$plot <- renderPlot({
chartSeries(dataInput(), theme = chartTheme("white"),
type = "line", log.scale = input$log, TA = NULL)
})
})

This example can be seen on the webpage of RStudio. Here the input$dates$ is out, independent of renderPlot(). Then each time the user changes the value of dates, the dataInput() will be called, but when the user only changes the value of input$log, the value of dataInput() will not change.

I also recommend to put all inputs outside the render* function, only leave it with the only function: to collect all the inputs, listen to their change, and ready to change itself when one of its inputs is changed. All the inputs should be put into reactive functions. Also, if one input value is determined by another input value, we should first calculate the second one inside reactive function, then calculate the first one inside the reactive function, and at last give them to the render* function.

To summarize, the reactive function will remember the values calculated last time. Each time it finds that its argument is changed, it will recalculate. All the procedures will be done automatically.

Now I want to share my thought on the code structure of server.R:

  1. Put library() and source() outside shinyServer().

  2. Put the input generation into reactive(), inside shinyServer() and outside render*().

  3. Put the objects generated by reactive() inside render*().

Publishing

Publishing is also an important part to show to clients. But I will not discuss it here, and I will talk about this part in subsequent articles about advanced shiny.

It’s time to finish this summary. I hope you get a much clear picture about shiny basics.