An introduction to Shiny as a teaching resource
Abstract
The main goal of this session is to show a regular R
user how to develop his/her own interactive (web) application without much effort. For doing so, we introduce the Shiny
R
package that makes this task simple even for an R
programmer that has never heard about HTML
, CSS
or JavaScript
(or does not care about them at all). During the session, we will develop from scratch an interactive app that illustrates the law of large numbers. This will allow us to understand the input and output of a Shiny
app, as well as the whole workflow intuition for building Shiny
apps.
Required packages
We will need RStudio with R (>= 3.0.2) and the following package:
Introduction
New teaching methodologies have arisen during the last years and many of them have been leaded by the introduction of emerging technologies. Bright examples are Active Learning or Research-Informed Learning philosophies which aim to give a more participative role to the students and motivate the learning process by means of practical examples.
In addition to be a potentially more enjoyable approach, these methodologies have demonstrated to improve significantly the performance of the students in many areas of knowledge in high level education. Freeman et Al (2014) compared the performance in undergraduate science, technology, engineering, and mathematics courses under traditional lecturing versus Active Learning and concluded that “average examination scores improved by about 6% in Active Learning sections, and that students in classes with traditional lecturing were 1.5 times more likely to fail than were students in classes with Active Learning”. As another example, Fawcett (2018) introduced Interactive Shiny Apps for supporting Research-Informed Learning and Teaching. They studied its effect on students’ responses in data analysis work, and assignments that require the interpretation of methods in a recently published paper. For doing so, they compare the results of student who had access to the Apps versus student that did not and they concluded that the methods benefited students, not only in terms of their ability to understand and implement advanced techniques from the recent literature but also in terms of their confidence and overall satisfaction with the course. In the same direction, Williams and Williams (2017) and Doi et al (2016) used R Shiny App as support for their innovation teaching projects.
Universities and academic staff have noticed the potential of such as Shiny R Applications as a teaching tool and they have put effort on developing repositories with examples in different topics.
- http://stat.psu.edu/information/shiny-pilot
- https://statistics.calpoly.edu/shiny
- http://www.artofstat.com/home.html
- https://github.com/egarpor/ShinyServer
Despite the main motivation of the session is devoted to teaching and researching, Shiny App is becoming more and more employed in industry. Their usefulness and adaptability to different needs do not have limit as can be shown in these more ambitious examples and these others.
What is an Interactive Web R Shiny App?
What is a Web?
A web page is just a set of files HTML (HyperText Markup Language), CSS (Cascading Style Sheets) and JS (JavaScript) typically located in a server. We, as users, can request these data from our computer and display them with a browser. This process is outlined in the figure below.
Each of these files enumerated above has a different goal. HTML is in charge of including the information we want to visualize and building the structure of the web. CSS introduces the design of the web and how to present the information. Finally, JS is the programming language of HTML and allows to introduce dynamics.
As the abstracts says, today we do not need knowledge about these, but it is important to take it into account to value the work that Shiny is doing for us. Despite this, basic knowledge of web programming would increase exponentially your options.
What is an Interactive App?
The user can interact with the server in such a way he/she can lead the process behind the App. The user declares input or variables that the developer design for being modified by him/her. Afterwards, the server uses this input for conditionally returning the output.
This trade off between user and server is a key point and it is the difference between a dynamic App and a static document (.pdf) or a book. The following diagram illustrates this workflow for an App running on a server.
Today we will forget about the communication between user and server and our dynamic App will be running locally; the user and the files providing the web are in the same place as at the right panel of the sketch above.
What is R Shiny?
The Shiny package in CRAN is a web application framework for R. Obviously, the idea of creating an application with statistical purposes is not new at all, in fact, there are many projects related with the development of Applet. However, this tool requires high knowledge of web programming, while Shiny mitigates this drawback by nesting R functions that assemble a complete Application.
Developing a Shiny App
Baselines
In this section, we present a simple template with the skeleton of a Shiny App. It can be taken as a starting point for developing any other App. Mainly, it contains the following parts:
ui
(User Interface) - nested R functions that assemble an HTML user interface for the App. Is is in charge of the contents and style of the App,server
- a function with instructions on how to build and rebuild the R objects displayed in the UI. Its arguments are the inputs and the outputs of the App. In this part is where our R code is going to be included.shinyApp
- combinesui
andserver
into an App.
As the diagram below shows, the input and output trade off plays the role of being the communication link between user and server. In addition to that, thanks to the Shiny package, one could avoid web programming and simply install the package in a machine with RStudio.
Once we have understood the main workflow, we are going to develop an App from a simple R code. From my point view, a good strategy for building a Shiny R App is to thing about our R code in terms of input and output objects. In other words, what we want to be chosen by the user and what we want to show to the user given his/her inputs selection. As an illustration, we are going to build a Shiny App based on the next code that empirically demonstrates the Law of Large Numbers. For the moment, let us consider $N$ realizations of a $X\sim Bern(p)$, then sample mean $\sum_{i=1}^N \frac{x_i}{N} \rightarrow E[X]=p$ as $N \rightarrow \infty$.
The code below shows a bar plot of the realization, a cumulative mean plot versus the number of realizations and some statistics.
Which values from our code are going to be inputs and which one outputs?
Inputs Objects
In order to see that the empirical mean converges to the expected value, one would like to see how this sample mean behave when increasing the number of realizations $N$. In the same way, one could also think about modifying the parameter $p$ of the distribution. Therefore, we have two inputs values i.e. $p$ and $N$.
There are many different functions from Shiny that allows to collect these values from the user. In the following figure, we have a set of examples:
From Rbloggers Rblogger posts
These functions work as easy as a regular R function does and one could check their Description, Usage and Arguments by help('<functionName>')
. However, the key point here is to answer the following question: must this chunk of code be at the UI or in the server part of our template?
Among others, the most important and common argument in input functions is the inputId
. It is the name that will allow us to access to the declared current input value by input$<inputId>
.
Output Objects
Once we have the input values, we can use them to produce an output with R for being provided to the user in the interface. This last sentence has two parts 1) to produce and 2) to provide in the same way we have to program our App by 1) render*()
and 2) *Output()
functions.
These two functions work together and each output function has its own render function counterpart. The following image presents some of these functions.
From Shiny Cheat Sheet
But one more time: must these chunks of code be at the UI, at the server part of our template?
This trade off between render*()
and *Output()
functions is a cornerstone of reactivity. The server part would involve output$<myOutput> <- render*(expr,...)
, it produces the desired R output and it contains the R code in expr
. Then, the output can be called from the UI by *Output(outputId = '<myOutput>')
.
Modulating Reactivity
Up to here, we have designed very simple reactive relationship; each input is linked with a simple output. However, Shiny allows to have more complex connections through different functions. Some of them are the following,
1) reactive()
: this function generate a reactive expression i.e. each time one its inputs values is modified, all its code is re-run. Once we have created the reactive value example <- reactive({code})
, you can use the result by example()
.
What data set are the summary and the plot describing?
2) isolate()
: If we change any input object the code is right away completely re-run. We can isolate some input values in such a way the code is not re-run when modified but, of course, its effect will be taken into account.
Each time we modified the title we obtain a new data set. Can we isolate changes in the title of the plot?
3) Triggers: One could also introduce action buttons in our UI, actionButtom()
, for controlling the moment when the code reacts to an input change by using observeEvent()
. There is also an observe({})
that will re-run all the code inside its {}
if any of its inputs are modified, it is a reactive function.
4) Delay actions: we could also include a bottom that trigger reactive values just when clicked. rv <- eventReactive( input$go, {rnorm})
.
5) Creating your own list of reactive values with rv <- reativeEvent(data = , ...)
that can be overwritten if some event is observed with observeEvent(input$go, {rv$data = other data})
.
Some of these functions may appear so similar in this when applying to our example. However, each one satisfies one different need for more complex settings.
Polishing our App
Up to here, we have just messed inputs and outputs up without any structure at all. Now is the moment for making up our App and arranging the contents in a friendly and beautiful structure.
As explained at the beginning, the UI part of the code is in charge of the visualization aspect and therefore all the code related with these will be located at the fluidPage()
function.
Adding layouts
One possible option is to organize our input and output with layout functions. In the figure below, we have some examples.
From Shiny https://www.rstudio.com/resources/cheatsheets/
For our Shiny App example, we can define the layout with sidebarLayout()
as follows,
Adding tabs
One could also structure the App in diffent panels with simple functions. From Shiny https://www.rstudio.com/resources/cheatsheets/
Let’s suppose that we want to split the different outputs in different tabs with tabsetPanel
at our main panel layout section. And lets also add a table printing the generate data set.
UI is an HTML document!
Rstudio and Shiny converts our code inside fluidPage
into a HTML file for building our web App. One can observe this fact just by running the following code in the console,
The output is a translation of our Shiny R functions to their HTML counterparts. Then, one must suspect that is almost straightforward to add HTML code through tags. Moreover, it is also allowed to include CSS as well as JS files with includeCSS
and includeScript
.
Other handy features
Conditional Panels
Following with our App, one could be willing to proof empirically the Law of Large Number but for a random variable coming from another distribution rather than Bernoulli. This task brings the problem of including inputs that depends on the selected distribution. In other words, one would need conditional panels. For example, if the selected distribution is the univariate Gaussian, one would like to have as input $\mu$ and $\sigma ^2$ rather than $p$.
Fortunately, we can use the function conditionalPanel()
in addition to an extra input object for selecting the distribution. For now, let’s just include a binomial, $Bin(n,p)$ and an univariate Gaussian distribution, $N(\mu, \sigma)$.
Shiny themes
We could also like to use a nice style but we do not want to include a CSS file. In this case, there are pre-defined themes with the package shinythemes
.
References
- Scott Freeman, Sarah L. Eddy, Miles McDonough, Michelle K. Smith, Nnadozie Okoroafor, Hannah Jordt, and Mary Pat Wenderoth (2014). “Active Learning increases student performance in science, engineering, and mathematics”, PNAS. link
- Fawcett, Lee (2018). “Using Interactive Shiny Applications to Facilitate Research-Informed Learning and Teaching”, Journal of Statistical Education. link
- William, Immanuel James and William, Kelley Kim (2017). “Using an R shiny to enhance the learning experience of confidence intervals”, Teaching Statistics. link
- Doi, Jimmipotter, Gailwong, Jimmyalcaraz and Irvinchi, Peter (2016). “Web Application Teaching Tools for Statistics Using R and Shiny”, Open Access Publication from the University of California, Center for the Teaching of StatisticsTechnology Innovations in Statistics Education. link
The materials of this session were mainly motivated by Shiny Tutorial and the following Rblogger posts.