The Anatomy of a Shiny Application
Tags: shiny, rstats
Published: 2021-04-21 19:48:11

<p><em>By: <a href='https://hosting.analythium.io/author/peter/'>Peter Solymos</a></em></p><p>Shiny lets you quickly build web applications using the R programming language. In this post I will walk you through how a Shiny application is structured. The goal is simply to have the most basic and dependency free app that we can deploy. Let's get going!</p><h2 id="what-is-r-and-shiny">What is R and Shiny</h2><p><a href="https://www.r-project.org/" rel="noopener noreferrer">R</a> is a free software environment for statistical computing and graphics. It compiles and runs on a wide variety of operating systems. Visit the Comprehensive R Archive Network (<a href="https://cran.r-project.org/" rel="noopener noreferrer">CRAN</a>) for installation instructions.</p><p>R, either using its base functionality or the <a href="https://www.tidyverse.org/" rel="noopener noreferrer">tidyverse</a> packages, is superb for both interactive and non-interactive use. Oh, and R has a dedicated and welcoming user community. Look for the <a href="https://twitter.com/search?q=%23rstats&amp;src=typed_query">#rstats</a> hashtag on Twitter.</p><p><a href="https://shiny.rstudio.com/" rel="noopener noreferrer">Shiny</a> is an R extension package created by <a href="https://www.rstudio.com/speakers/joe-cheng/">Joe Cheng</a> of RStudio. Shiny makes it easy to build interactive web apps. This is the reason it is ideal for quickly making <a href="https://www.rstudio.com/resources/rstudioconf-2018/rapid-prototyping-data-products-using-shiny/">prototypes</a>, but it is also a decent choice for building <a href="https://engineering-shiny.org/">production-ready</a> applications.</p><p>Shiny combines the power of R with the interactivity of the modern web. See this <a href="https://shiny.rstudio.com/tutorial/" rel="noopener noreferrer">tutorial</a> and the <a href="https://mastering-shiny.org/"><em>Mastering Shiny</em> book</a> by Hadley Wickham for accessible introductions.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://hosting.analythium.io/content/images/2021/04/Screen-Shot-2021-04-01-at-10.16.55-PM.png" class="kg-image" alt="The RStudio Shiny website" loading="lazy" width="2402" height="1286"><figcaption>The RStudio Shiny website</figcaption></figure><h2 id="installing-shiny">Installing Shiny</h2><p>Once you have R installed, it is also useful to have an integrated development environment (IDE): pick either the free <a href="https://rstudio.com/products/rstudio/download/" rel="noopener noreferrer">RStudio Desktop</a> or <a href="https://code.visualstudio.com/download" rel="noopener noreferrer">VS Code</a> with <a href="https://github.com/Ikuyadeu/vscode-R" rel="noopener noreferrer">R language support</a>.</p><p>Install Shiny by running the following line in R:</p><pre><code class="language-R">install.packages("shiny")</code></pre><h2 id="the-structure-of-a-shiny-app">The structure of a Shiny app</h2><p>A Shiny app is made up of the user interface (UI) and the server function. The UI and the server can be written in pure R, but it can also incorporate JavaScript, CSS, or HTML code.</p><p>The app is served to the client (app user) through a host (Internet Protocol or IP address) and port number. The server then keeps a <a href="https://github.com/rstudio/httpuv">websocket connectio</a>n open to receive requests. The R session behind the app will make sure this request translates into the desired interactivity and sends back the response, usually and updated object, like a plot or a table.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://hosting.analythium.io/content/images/2021/04/3-blank.png" class="kg-image" alt="Structure of a Shiny web application" loading="lazy" width="3947" height="2219"><figcaption>Structure of a Shiny web application</figcaption></figure><p>The following simple example draws a histogram of randomly generated numbers from the Normal (Gaussian) distribution. As you increase the number of observations, the shape of the distribution changes slightly. Here is how it will look:</p>
![The simplest Shiny app](https://hub.analythium.io/img/shiny/shiny-hello.png)
<p>Let's see what's inside.</p><h3 id="the-ui">The UI</h3><p>The user interface (UI) object controls the layout and appearance of the Shiny app.</p><p>Load Shiny:</p><pre><code class="language-R">library(shiny)</code></pre><p>The UI is defined as:</p><pre><code class="language-R">ui &lt;- fluidPage(
    mainPanel(
        sliderInput("obs",
            "Number of observations",
            min = 1,
            max = 5000,
            value = 100),
        plotOutput("distPlot")
    )
)</code></pre><p>The <code>fluidPage()</code> function renders the main Shiny interface, a range slider input is nested inside of it alongside the plot output. The slider with the ID <code>"obs"</code> controls the number of observations (range between 1 and 5000, initial value set to 100). The plot with ID <code>"distPlot"</code> will show the distribution of the random numbers.</p><p>If we print the <code>ui</code> object, we get the following HTML output:</p><pre><code class="language-html">&lt;div class="container-fluid"&gt;
  &lt;div class="col-sm-8"&gt;
    &lt;div class="form-group shiny-input-container"&gt;
      &lt;label class="control-label" for="obs"&gt;
        Number of observations
      &lt;/label&gt;
      &lt;input class="js-range-slider" id="obs" data-min="1"
        data-max="5000" data-from="100" data-step="1"
        data-grid="true" data-grid-num="9.998"
        data-grid-snap="false" data-prettify-separator=","
        data-prettify-enabled="true" data-keyboard="true"
        data-data-type="number"
      /&gt;
    &lt;/div&gt;
    &lt;div id="distPlot" class="shiny-plot-output"
      style="width: 100% ; height: 400px"
    &gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</code></pre><p>You can see here the fluid container, a column, and inside the single column layout the range slider and the plot.</p><p>This is going to be added to the body of the HTML page rendered by Shiny. The final HTML page will also contain all the JavaScript and CSS dependencies required to make the app interactive and styled properly.</p><h3 id="the-server-function">The server function</h3><p>The server function contains the instructions for the reactivity needed for the Shiny app. The server function takes two arguments: <code>input</code> and <code>output</code> (sometimes also <code>session</code>). These reactive objects are created by Shiny and passed to the server function.</p><p><code>input</code> is used to pass the control values, in this case <code>input$obs</code> the number of observations. Notice how it is used to generate random numbers from the Normal distribution:</p><pre><code class="language-R">server &lt;- function(input, output) {
    output$distPlot &lt;- renderPlot({
        dist &lt;- rnorm(input$obs)
        hist(dist,
            col="purple",
            xlab="Random values")
    })
}</code></pre><p>The <code>output</code> object contains the output objects, in our case the rendered plot. <code>input</code> and <code>output</code> together describe the state of the app.</p><h3 id="the-shiny-app">The Shiny app</h3><p>With the <a href="https://hub.analythium.io/docs/shiny-ui">UI</a> and the <a href="https://hub.analythium.io/docs/shiny-server">server function</a>, we can run the Shiny app locally:</p><pre><code class="language-R">shinyApp(ui = ui, server = server)</code></pre><p>Running this line will start the Shiny server locally that you can visit at the host and port printed in the R console (e.g. http://127.0.0.1:3884).</p><p>To be precise, the <code>shinyApp()</code> function returns the app object which is run either by implicitly calling the <code>print()</code> method on it when running in the R console. You can also pass the app object to the <code>runApp()</code> function. </p><p>The app you just made is very similar to the Hello World Shiny app (i.e. running <code>runExample("01_hello")</code>). Check out the <a href="https://shiny.rstudio.com/gallery/">Shiny gallery</a> to see more apps in action. You might have noticed that we did not load any other R packages except for Shiny itself. This dependency free Shiny app will be used in future posts as the basic example for deployment.</p><h2 id="further-reading">Further reading</h2><p>Shiny UI:</p><ul><li><a href="https://shiny.rstudio.com/tutorial/written-tutorial/lesson2/" rel="noopener noreferrer">Layout of the the user interface</a></li><li><a href="https://shiny.rstudio.com/tutorial/written-tutorial/lesson3/" rel="noopener noreferrer">Control widgets</a></li><li><a href="https://mastering-shiny.org/basic-ui.html">Basic UI</a></li><li><a href="https://mastering-shiny.org/action-dynamic.html">Dynamic UI</a></li></ul><p>Server function:</p><ul><li><a href="https://shiny.rstudio.com/tutorial/written-tutorial/lesson4/" rel="noopener noreferrer">Reactive output</a></li><li><a href="https://mastering-shiny.org/basic-reactivity.html">Basic reactivity</a></li><li><a href="https://shiny.rstudio.com/tutorial/written-tutorial/lesson6/" rel="noopener noreferrer">Reactive expressions</a></li></ul><p></p><p></p><p><br></p>