Sunteți pe pagina 1din 15

Demonstrating the Shiny package in R by Mapping The Amazing Race

By Jonathan Fivelsdal
Background on Shiny
RStudio is a company that created the RStudio IDE, which is a popular IDE among R users
which provides a graphical user interface (GUI) and a variety of tools for R programmers to use.
The shiny package was also created by RStudio. Shiny is a package that allows R programmers
to create interactive web applications without using HTML, JavaScript, CSS, or any common
web development framework or language [4].

Background on The Amazing Race


The Amazing Race is a show on CBS where a number of teams travel the world in a race to win 1
million dollars. The race is broken up into a number of segments called a leg of the race.
Typically, each episode represents one leg of the race. While on the race, each team has to
compete a number of tasks before proceeding to the final destination of a leg of the race which is
known as the pit stop. The last team to finish the required leg tasks and reach the pit stop behind
all of the other teams is usually eliminated from the race (except for when a particular leg is
designated as a non-elimination leg). As of April 2015, twenty five complete seasons of the U.S.
version of The Amazing Race have been aired. Season 26 began airing in early 2015, however as
of April 2015, the whole 26th season has not been shown in full on television.

Background on The Amazing Race App


I created an app to map the locations that have been featured on The Amazing Race over the past
twenty five seasons of the show using the R programming language [3]. Two packages were
primarily used to create the app. The leaflet package was used to create the map and markers
used to identify where the teams on the show have travelled [2]. The shiny package was used to
create the app itself and the menus used to interact with the map [4]. To run the app in R, you
will need to install the leaflet package which can be installed by typing the command
devtools::install_github("rstudio/leaflet") into the R console. Properties of the shiny package will
be explained by demonstrating how the shiny code used in the app works. Within this report, the
names of functions will be indicated by using italicized text to denote an R function.
There are a couple of ways to access the app. One way is to download server.R, ui.R,
AmazingRace Locations.csv and AmazingRaceContestants.csv files and save them within a
folder (make sure that all of these files are in the same folder), set the working directory to the
folder that contains the server.R and ui.R files (use the setwd() command), load the shiny
package within the console window, and then type in runApp() in the console window in order to
load the application. The other way to access the app is by going to the following link
https://jonfivelsdal.shinyapps.io/AmazingRaceApp1/. Code from both the server.R and ui.R
included in the html document named AmazingRaceAppCode.html.

Getting Ready to Create a Shiny Application


After installing R and getting R setup for use, you need to install the shiny package before you
can create a shiny application. Shiny is on CRAN which is a large repository of R packages and
so you can use the command install.packages(shiny) in order to install shiny. Shiny
applications are composed of at least two R scripts, one which is called server.R and the other
script called ui.R. The ui in ui.R stands for user interface. The scripts server.R and ui.R are
required for any shiny application and should be placed within the same folder. The ui.R script
that you create for the application contains the code that describes the overall layout of the
application and how objects are to be displayed in the application that you create. The script
server.R controls how user input and data is processed by the application. In both the ui.R script
and the server.R script, you should include the command library(shiny) in order to access the
functionality of the Shiny package in both scripts. In the next two sections, the server.R function
and ui.R functions will be examined more closely.

Examining the Code in ui.R for the The Amazing Race App
The first function used in the ui.R script for The Amazing Race application is called shinyUI. All
the code in the script except for the main packages loaded at the top of the script are enclosed
within the parentheses of the shinyUI function. As of Shiny 0.10, the shinyUI function is no
longer required. In earlier versions of Shiny, the function shinyUI was used to register a user
interface. The shinyUI function is used for backward compatibility for older applications. It is
not necessary to include this function in newer Shiny applications.
The next function that is used in ui.R is called fluidPage. As the name suggests, fluidPage
creates a fluid page layout for the application that is being created. A fluid page layout is
composed of rows and columns. The rows of the layout are there to ensure the elements of a row
appear on the same line (provided the browser has an adequate width).The columns define the
amount of horizontal space within a 12-unit wide grid its elements should occupy. The
components in a fluid page are scaled to fill the width of an internet browser in real time. All of
the user interface elements created by shiny functions are enclosed within the fluidPage function.
Now a variety of functions used to create various menus and items displayed in the application
will be explained. The function titlePanel is used to display the title of the application at the top
of the internet browser in bold. The function has two parameters which are title and windowTitle.
The title parameter is required and when set it will show the value provided for the title attribute
at the top of the browser in bold. The windowTitle parameter is optional and by default is set
equal to the value of the title parameter. The windowTitle parameter controls what is displayed
in the title bar of the browser window. The way a sidebar is displayed by the sidebarLayout
function. The sidebarlLayout function has 4 parameters which are sidebarPanel, mainPanel,
position, and fluid. You can set what kind of input controls will be displayed on the sidebar using
the sidebarPanel parameter. The mainPanel parameter is used to define the kind of output that
will be displayed in the browser. The position parameter of the sidebarLayout function sets the
direction of the sidebar as to whether it will be placed to the left of the main area or to the right
of the main area (if the parameter is not explicitly set, the sidebar will be placed to the left of the

main area). The last parameter of sidebarLayout is named fluid. If fluid is set to true, the sidebar
will have a fluid layout and if fluid is set to false, then the sidebar will have a fixed layout. For
The Amazing Race app, the sidebarPanel parameter in the sidebarLayout function is set equal to
the sidebarPanel function, the mainPanel parameter in the sidebarLayout function is set equal to
the mainPanel function and the two remaining parameters are not explicitly set and so the
parameters have the default values (the sidebar is to the left of the main area and the sidebar
layout is fluid). As the names suggest, the design of the sidebar panel is made with the
sidebarPanel function and the output that is displayed on the main panel is defined in the
mainPanel function. First the contents of the mainPanel function will be discussed and then the
contents of the sidebarPanel function will be discussed.
Contents of the mainPanel Function
Output elements can be specified within the mainPanel function that will then be passed to
sidebarLayout. Below is code from The Amazing Race app demonstrating use of mainPanel.

A set of tabs are created within tabsetPanel. The tabset we create with the tabsetPanel function
helps to separate different types of output based on which tab is currently selected or activated.
Individual tabs are created by using the function tabPanel within the tabsetPanel. The arguments
of the tabPanel function are title, which allows user interface (UI) elements to be included
within the tab, value which is the value that is sent to tabsetPanel when a tab is selected, and
icon which allows an optional icon to appear on the tab. Only the first three arguments are used
in the tabs created in the app. Below is a picture of the tabs created by the tabPanel functions
that are implemented within tabsetPanel.

Below is a table of the value id of the tab, the text that appears on tab, and the output object that
corresponds to a tab

Value
mapTabSeason
mapTabLegSeason
teamSeason
winTab

Tab Text Name


Season Map
Season and Leg Map
Teams By Season
Winners

Name of Output Object


raceMap
raceMap
teamTable
winnerText

The names in the Value column are used as variable names in the code to control what happens
when a particular tab is selected. So mapTabSeason is used in the code to control what will
happen when the tab that has the label text Season Map is selected, mapTabLegSeason is
used in the code to control what will happen when the tab that has the label text Season and Leg
Map is selected, teamSeason is used in the code to control what will happen when the tab that
has the label text Teams By Season is selected and winTab is used in the code to control
what will happen when the tab that has the label text Winners is selected. The variable names
of the tabs that are in the Value column are used extensively in the code that is in sidebarPanel
and also the code in the server.R script. The last column gives the variable names of the outputs
that will be displayed by selecting the specified tab. Different functions are used to render
different types of output. For the Team By Season tab, the argument of the tabPanel
function contains the dataTableOutput function. As the name of the function suggests, this
function is used to render and display a data table on screen. The only parameter of
dataTableOutput is called outputId. The name used for the outputId argument is teamTable and
this output variable name represents a data table of each member of each team across the first
twenty five seasons. On the next page, a picture of the data table that is produced by
dataTableOutput is shown for the first season of The Amazing Race.
Output of the dataTableOuput function

The next output function that will be discussed is textOutput. This function is useful if you want
text to be displayed on the screen but not necessarily in the form of a table. For the Winners
tab, the argument contains the function textOutput. Similar to dataTableOutput, the only
parameter is outputId. In this case, the name of our output variable is winnerText and so that is
what the outputId is set equal to. Below is a picture of the output produced by textOutput when
the user selects the Winners tab.
Output of the textOutput function

The figure above shows the results of textOutput and displays the team that won season #7 of
The Amazing Race.
The final output function that will be discussed is leafletOutput. This function is actually not in
the shiny package, but it is a wrapper function in the leaflet package that integrates leaflet
functionality with the shiny package. Like the output functions found in the shiny package, the
function leafletOutput has the parameter outputId. Unlike the output functions in shiny, the
function leafletOutput has more parameters than just outputId. The other two parameters to
leafletOutput are width and height which controls the size of the map to be displayed. The name
of the output variable for the leaflet map is raceMap and is used frequently in the server.R file.
The variable raceMap is used as the outputId in leafletOutput to produce the map for the
application. Below is the map that is displayed using the leafletOutput function.

Before discussing the sidebar panel code, there are some more significant points to mention.
Look at the sample of code below:

Notice that leafletOutput is not directly included in the tabPanel function for the tab named
mapTabSeason and the other tab named mapTabLegSeason. The parameter of tabPanel for
both the mapTabSeason and mapTabLegSeason tabs was not set equal to leafletOutput since it is
included within the conditionalPanel function which in the code above controls the behavior of
both the mapTabSeason tab and the mapTabLegSeason tab. The function conditionalPanel
controls what output is displayed based on particular panel event. The conditionalPanel has a
condition argument in which you can add a JavaScript style logical expression that controls what
happens when a certain event is triggered (in the code above, the logical expression controls
what happens when certain tabs are selected). After the condition parameter is specified, output
elements can be added to conditionalPanel which will be displayed if the logical expression set
for the condition argument holds true. The input elements mentioned in the condition parameter
can be referenced by writing input. followed by the name of the input object (in the code
above, the id of the set of tabs is referred to as input.amazingRaceTabs). Note that the names of
the variables that are named to the right of the logical comparison operator == are in single
quotes. The | | operator in the above code represents logical or. So the code in conditionalPanel
above says that the map generated by leafletOutput will only be displayed if the mapTabSeason
and mapTabLegSeason tabs are selected. This means that if you select the tab that has the text
label Season Map or the tab that has the text label Season and Leg Map, then the map will be
displayed, however if any other tabs are selected (such as the tabs labeled Team By Season and
Winners), then the map will not be displayed.
Contents of the sidebarPanel Function
The function sidebarPanel includes the parameter which allows a number of user interface
(UI) elements to a sidebar and the other parameter is width which controls the size of the sidebar.
In the ui.R for the app, different input selectors are made to be displayed on the sidebar and this
input selectors are controlled by using the conditionalPanel function which controls what input
selectors are shown by the app depending on which tab is selected.
The first type of input selector mentioned in the code is the slider input. The code that creates the
slider input for the app is pictured below along with the slider input that is produced by the code.

The first parameter is inputId which gives the name of the input variable, the second parameter is
label which provides the heading title that will be displayed on the input slider, the third
parameter is min which is the minimum value that can be selected (inclusive), the fourth
parameter is max which is the maximum value that can be selected (inclusive), the fifth
parameter is value which is the initial value that is selected on the slider and the sixth parameter
is step which represents the amount you can increment or decrement from the values on the
slider. The above code gives the name of the input variable that represents the slider is called
Season, the title name that is shown in bold is Season Number, the slider ranges from 1 to 25
inclusive (which represent season 1 to season 25 of The Amazing Race), the slider created starts
at the number 12, and the current number on the slider can be increased or decreased by 1 unit.
The next input selector that will be considered, is the input select menu. The input select menu is
created by the function selectInput. There are many parameters for selectInput, however, only the
first three parameters will be discussed. Like sliderInput, the first two parameters of selectInput
are inputId and label. The third parameter for selectInput is choices which includes the possible
choices that can be chosen from the selection menu. Below is a picture of the output from one of
the selectInput functions used in ui.R:

The code above creates a select menu that has an input variable name of seasonSL, displays the
title Season Number above the menu selector and allows the user to the numbers 1-25 inclusive
(which in this case the numbers represent the season number for the show).
The last type of input selector that will be discussed are radio buttons. In order to create radio
buttons, use the radioButtons function in shiny. The first three parameters of radioButtons are
exactly the same as the parameters for selectInput. The fourth parameter of radioButtons is called
selected and if this parameter is set, it will set which button is initial selected (if this parameter is
not selected, the first radio button from the top will be the button that is initially selected). The
fifth and last parameter of radioButtons is called inline. If the inline parameter is set equal to
TRUE, then the radio buttons will be displayed horizontally, however if the parameter is set
equal to FALSE, then the radio buttons will be displayed vertically (by default the inline

parameter is set equal to FALSE and so by default the radio buttons are displayed vertically).
The following is a code snippet that includes a radio button implemented in the app and also a
picture of the radio button created by the code:

The radio button created above has the input variable name of colorChoice, the bold title of
Marker Color Selection comes from the value that the label parameter is set equal to, the label
text for each of the radio buttons comes from the vector that is assigned to the choices parameter.
The named vector in radioButtons has thevalues which are the colors denoted in quotes that have
all lower case letters and the names of these values are the color names that have the first letter
capitalized. The names of the values in the vector of colors that are assigned to the choices
parameter in radioButtons show up as the text labels of the radio buttons in the output. The
values from the vector (the values are red, orange, yellow, purple, black) are passed to
functions from the leaflet package in the server.R file in order to change the color of the map
markers. Since the color of the typical marker pin cant be changed through a leaflet function, the
color values are only passed to the functions that produce the circle type of marker or the
line/path type of marker (these leaflet functions are addCircleMarkers and addPolyLines
respectively).

Examining the Code in server.R for the The Amazing Race App
At the beginning of the server.R script the Shiny and Leaflet packages are loaded. After loading
the main packages, data from comma separated value (csv) files is loaded into server.R. The csv
file named AmazingRace - LongitudeAndLatitudeList.csv stores the Latitude and Longitude
for the locations of each leg of the race for the first twenty five seasons of The Amazing Race and

the csv file named AmazingRaceContestants.csv stores the contestants for each of the first
twenty five seasons of Amazing Race. The data from each of these csv files are stored in objects
named amRaceDataCoords and amRaceContestants respectively.
After loading in the data and storing them in variables, the function shinyServer is used and the
remainder of the server.R code is contained within the shinyServer function. This function is
used to define the server-side logic of the Shiny application. Much of the code within the
shinyServer function involves code that states how data should be handled by the application.
The function shinyServer is called when the web browser first loads the application and it
includes the parameters input, output, and session (the session parameter is optional and is not
always used in the shinyServer function, but the session parameter is used to allow for greater
control over aspects of the application). As of Shiny 0.10, it is no longer required to include the
shinyServer function in the server.R script but the function has been retained for the purpose of
backward compatiblilty. Next, other functions used in sever.R will be discussed.
The server.R file for this application has a mix of functions from the Leaflet package and the
Shiny package. First, a map is created by the code leaflet() %>% addTiles() and is stored in an
object called amMap. The operator %>% is called the pipe operator (which is originally from the
magrittr package) and is used with functions in the Leaflet package. The leaflet() function creates
a map widget and the function addTiles creates the graphical layers for the map widget created
by leaflet(). The default layer for addTiles is used in this instance which is called OSM or the
Open Street Map layer. A vector called seasonWinners is created which contains the 25 teams
that won over the past 25 seasons. After these preliminary objects were created, a series of shiny
functions were used in order to define how certain output and input objects should be created and
how they should interact with the app. In the server.R file, the name of input variables are
prefixed with the notation input$ and the name of output variables are prefixed with the notation
output$. Below are tables that have the name of the input and output variables used in the
server.R file:
Table of Input Variables
Input Variable Names
seasonSL

legSL

amazingRaceTabs
Season

Description
seasonSL is the season menu selector that
appears when the Season and Leg Map,
Teams By Season or Winners tab is
selected.
legSL is the leg menu selector that appears
when the Season and Leg Map tab is
selected.
amazingRaceTabs is the input ID for the set of
tabs (the tabset panel) created in ui.R
This is the slider input selector that appears
only when the Season Map tab is selected

markerType

Table of Output Variables


Output Variable Names
winnerText

teamTable

raceMap

This is the type of marker that will be


displayed on the map to represent a particular
location. The three types of markers are pin,
circle, and path.

Description
This stores the season winner based on which
season number is selected from the menu
created by the variable seasonSL. The team
that won a particular season comes from the
seasonWinners vector.
This variable stores the teams that were in a
particular season based on the season number
selected by the menu created by the seasonSL
input variable.
The markers that are placed on the map and
the map itself is stored in this variable.

The first variable created in server.R is winnerText. The code to create this variable is presented
below.

The function renderText creates a reactive variable that stores text that can be used by the
textOutput function in the ui.R script. Recall the following code from ui.R

The Winners tab uses the textOutput function. Notice that the output ID that is used in the
textOutput is the same as the name of the reactive variable (without the prefix output$) that is

defined in server.R. It doesnt matter whether or not the output ID is defined first or the reactive
output variable (whether you declare the output ID name first in the output function you use in
ui.R or if you create the reactive output variable first in server.R by using a render function
before creating the output ID to be used by a shiny output function in ui.R as long as the output
variable name and the corresponding output ID are named in a consistent manner).
The next function that will be discussed is the observe function. Reactive expressions and
observers are more dynamic expressions than regular R expressions. Observers have a different
execution strategy than reactive expressions. When the dependencies of a reactive expression
change, the reactive expression does not automatically re-execute. Unlike reactive expressions,
observers will automatically re-execute as soon as an observers dependencies change. To learn
more about the differences between reactive expressions and observers, the reader is directed to
the documentation found here http://shiny.rstudio.com/reference/shiny/latest/observe.html [1].
Below is how the observe function was used in the server.R code:

The function updateSelectInput is used to change the available choices on the leg menu (the
menu that corresponds to the input variable legSL) based on the season number (the number
selected on the select menu represented by the input variable seasonSL). The reason for updating
the leg menu based on the season number is that not all seasons of The Amazing Race have the
same number of legs (some seasons have 11 legs, some have 12 legs and some seasons have 13
legs). The updateSelectInput function is given the session variable that was used in shinyServer
and a text heading of Leg Name is passed to the label parameter. The interesting parameter of
updateSelectInput is the choices parameter. For the choices parameter, the rows of the
amRaceDataCoords data frame are the rows in which the Season column matches the season
number that is selected by the menu that is created by the seasonSL object and the leg numbers
from the Leg column of the matching rows are selected. The leg numbers repeat for each location
in the leg and so the unique function is used to get distinct leg numbers for each season. The
updateSelectInput function is placed within the observe function in order to create an observer.
Therefore, using the created observer, every time the season menu changes value the respective
choices for the possible leg numbers in the leg menu also change.
The next function that will be discussed is renderDataTable. The only required parameter is expr
which is an expression that return a matrix or a data frame. For the table created in this
application, all of the defaults were accepted for all of the other parameters. Below is the code
for the data table created in server.R for this application.

Within renderDataTable the names of each team member for each team along with the
relationship between each team member for all the teams are accessed from the
amRaceContestants data frame for the season selected by the select menu represented by the
input variable seasonSL. The information gleaned from the amRaceContestants data frame is
then transferred to the output variable teamTable and is turned into a data table. The name of the
data table teamTable is then used in the function dataTableOutput in the ui.R script in order to
display the data table on screen in the app (the relevant code from ui.R where dataTableOutput
appears is shown below).
The ui.R code that uses the teamTable variable created in server.R

The next variable in server.R that will be discussed is the reactive variable markerProp. The first
part of the reactive expression that defines the variable markerProp is an else if statement. The
following is the code that was used for the conditional statements:

This code controls how the latitude and longitude are defined based on what tab is selected.
Recall that amazingRaceTabs is the input ID for the set of tabs defined in the mainPanel function
in ui.R. The first if statement says that if neither of the Season Map tab (mapTabSeason) or the
Season and Leg Map tab set the longitude and latitude variables to zero (the map is not
displayed for the Winners and Teams By Season tabs and so none of the latitude and
longitude values from the amRaceDataCoords data frame are needed). The first else if statement
states that the latitude and longitude values come from the rows of amRaceDataCoords where the
season number equals the season number value selected on the slider input selector that is
displayed when the Season Map tab is selected. The second else if statement states that when
the Season and Leg Map tab is selected, the latitude and longitude values come from the rows
of amRaceDataCoords where the season number equals the season number value selected on the
season select menu (represented by the input variable seasonSL) and the leg number selected on

the leg select menu (represented by the input variable legSL). The next set of code that defines
the markerProp variable is the following:
The 2nd part of the markerType code in the server.R file

The following is code from ui.R that relates to the markerType variable:

The first if statement in the server.R code snippet above states that if the choice Pin is chosen
from the marker type menu (the input that had input ID markerType), marker pins will put on the
map where teams on The Amazing Race have travelled by means of addMarkers from the leaflet
package. The first else if statement says that if the choice Circle is chosen from the marker
type menu, circles will be put on the map (instead of lines or pins) for the different race
locations. The last else if statement says that if the choice Path is chosen from the marker type,
lines will be placed in between race locations. Observe that addMarkers, addCircleMarkers and
addPolylines uses the map object amRace that was created at the top of the server.R script and
the second and third parameters of each of these functions take the latitude and longitude values
that were created in the first part of the code that defines the markerType input variable . Note
that input$colorChoice which is the value of the color parameter for addMarkers,
addCircleMarkers and addPolylines corresponds to the inputId parmeter value of radioButtons
in ui.R. So for each type of marker that identifies the race locations, the color of the marker can
be changed by means of the radio buttons that were created in ui.R. After creating the

markerProp variable, the markerProp variable is used placed in the renderLeaflet function to
create the output variable raceMap (the code is shown below).

The raceMap created from the variable markerProp variable is then is referred to in the
leafletOutput function which is placed in the ui.R script and is ultimately the function that
displays the map in the application.

References
[1] Create a reactive observer. RStudio, 2014. <URL:
http://shiny.rstudio.com/reference/shiny/latest/observe.html>.
[2] J. Cheng and Y. Xie. leaflet: Create Interactive Web Maps with the JavaScript
LeafLet Library. R package version 0.0.10. 2014. <URL:
https://github.com/rstudio/leaflet>.
[3] R Core Team. R: A Language and Environment for Statistical Computing. R Foundation
for Statistical Computing. Vienna, Austria, 2014. <URL: http://www.R-project.org/>.
[4] W. Chang, J. Cheng, J. Allaire, et al. shiny: Web Application Framework for R. R
package version 0.11.1. 2015. <URL: http://CRAN.R-project.org/package=shiny>.

S-ar putea să vă placă și