Introduction to R Shiny Reactivity with Hands-on Examples

Estimated time:

R Shiny is all about reactivity. It's a paradigm that allows you to build responsive and interactive applications by implementing data-driven interfaces. Changes triggered by the user will be immediately reflected in the application. Long story short, <b>master R Shiny reactivity and you'll master Shiny</b>. But where do you start learning about reactivity in the R Shiny application? Well, reading this article might be a good idea. We'll provide you with insights into what reactivity is, why it's an essential concept in R Shiny, what are reactive inputs, expressions, and outputs, and much more. Let's dig in! <blockquote>R Programming and R Shiny can improve your business workflows - <a href="" target="_blank" rel="noopener">Here are 5 ways how</a>.</blockquote> Table of contents: <ul><li><a href="#introduction">Introduction to Reactivity and its Importance in R Shiny Apps</a></li><li><a href="#basic-reactivity">Basic Reactivity in R Shiny</a></li><li><a href="#reactive-inputs">R Shiny Reactivity with Reactive Inputs</a></li><li><a href="#reactive-expressions">Reactive Expressions - Everything You Need to Know</a></li><li><a href="#reactive-outputs">Reactive Outputs in R Shiny</a></li><li><a href="#summary">Summing up R Shiny Reactivity</a></li></ul> <hr /> <h2 id="introduction">Introduction to Reactivity and its Importance in R Shiny Apps</h2> So, the big question is - <b>What is reactivity in the context of R Shiny?</b> Well, it refers to the concept of powering the interactivity and responsiveness of Shiny applications. It means that everything you interact with, such as dropdowns and buttons, will automatically trigger a change in the user interface. It happens behind the scenes, and you don't have to wait for the page to reload. Here are a couple of fundamental principles on which R Shiny reactivity is based upon: <ul><li><b>Reactive inputs:</b> Input elements of an R Shiny app, such as text inputs, checkboxes, dropdowns, sliders, and so on. When a user interacts with these inputs, they generate reactive values.</li><li><b>Reactive outputs:</b> Components of an R Shiny application that display the results of reactive expressions. Think of these as charts, tables, or anything else that can be updated based on the change in reactive expressions or inputs.</li><li><b>Reactive expressions:</b> R expressions that take reactive inputs as inputs. They are used to perform calculations, transformations, or any sort of data manipulation.</li></ul> R Shiny will automatically detect which reactive expression depends on which input, and also automatically make changes when needed. Let's now see how R Shiny reactivity works in practice by going over reactive inputs. <h2 id="reactive-inputs">R Shiny Reactivity with Reactive Inputs</h2> In R Shiny, reactive inputs and outputs are closely tied together. It's challenging to talk about one without mentioning the other, so expect to see some reactive outputs in this section as well. It's needed to render the results of reactive inputs. Don't worry, we'll still cover reactive outputs in much more depth later in the article. <h3>Example 1: Handling Simple Input</h3> Let's get straight to business. R Shiny provides a ton of functions that end with <code>Input()</code>, such as <code>textInput()</code> or <code>numericInput()</code>. You can use these to create input elements and pass in adequate properties. The example you'll see below declares one textual and one numeric input, gives them IDs, labels, and default values, and also declares an output element for rendering the input values. Don't worry about the output portion - we'll cover it later in the article. For now, try to understand the input elements, and just copy/paste the output portion. The <code>server()</code> function of an R Shiny application is where the magic happens. Long story short, that's where you connect your inputs and outputs, and that's also where you can access the input values. Our example will only leverage the <code>paste()</code> function to display a simple message that depends on the current value of the input elements: <pre><code class="language-r">library(shiny) <br> ui &lt;- fluidPage(  # Note the inputId property  textInput(inputId = "inName", label = "Your name:", value = "Bob"),  numericInput(inputId = "inAge", label = "Your age:", value = 20),  tags$hr(),  # Note the outputId property  textOutput(outputId = "outResult") ) <br> server &lt;- function(input, output) {  # This is how we access output elements  output$outResult &lt;- renderText({    # This is how we access input elements    paste(input$inName, "is", input$inAge, "years old.")  }) } <br> shinyApp(ui = ui, server = server)</code></pre> Here's what you'll see when you run the Shiny application: <img class="size-full wp-image-20145" src="" alt="Image 1 - Simple input example 1" width="1090" height="572" /> Image 1 - Simple input example 1 As you would assume, the output message changes automatically as soon as you change one of the inputs: <img class="size-full wp-image-20147" src="" alt="Image 2 - Simple input example 2" width="1090" height="572" /> Image 2 - Simple input example 2 And that's basic reactivity for you. Let's take a look at a more detailed example next. <h3>Example 2: Handling UI Elements</h3> This example will show you how to leverage some additional input elements built into R Shiny. To be more precise, you'll learn how to work with dropdowns, sliders, and checkboxes. We'll tie everything into a simple employee evaluation example. You can add dropdowns, sliders, and checkboxes to your R Shiny app by using the built-in <code>selectInput()</code>, <code>sliderInput()</code>, and <code>checkboxInput()</code> functions. Keep in mind that each requires a different set of parameters. For example, the <code>selectInput()</code> function needs an array of values and the default value, while the <code>sliderInput()</code> needs the range of values (min and max). Inside the <code>server()</code> function, we'll once again use the <code>paste()</code> function to combine multiple strings. There's also an additional conditional statement, just to provide a better format for the output string. As before, don't worry about the <code>renderText()</code> reactive function: <pre><code class="language-r">library(shiny) <br> ui &lt;- fluidPage(  textInput(inputId = "inText", label = "Enter name:"),  selectInput(inputId = "inSelect", label = "Select department:", choices = c("IT", "Sales", "Marketing"), selected = "IT"),  sliderInput(inputId = "inSlider", label = "Years of experience:", min = 1, max = 20, value = 5),  checkboxInput(inputId = "inCbx", label = "Has R Shiny experience?"),  tags$hr(),  textOutput(outputId = "outResult") ) <br> server &lt;- function(input, output) {  # Determine different string value based on the checkbox  output$outResult &lt;- renderText({    text_addition &lt;- "" <br>    if (input$inCbx) {      text_addition &lt;- "has"    } else {      text_addition &lt;- "has no"    } <br>    paste(input$inText, "has worked in", input$inSelect, "department for", input$inSlider, "years and", text_addition, "experience in R Shiny.")  }) } <br> shinyApp(ui = ui, server = server)</code></pre> Here's what you'll see when you run the app: <img class="size-full wp-image-20149" src="" alt="Image 3 - UI elements example 1" width="1247" height="873" /> Image 3 - UI elements example 1 Note how the <code>inText</code> input doesn't have a default value, so nothing is shown. As before, you can change any of the inputs and the output string will reflect these changes automatically: <img class="size-full wp-image-20151" src="" alt="Image 4 - UI elements example 2" width="1346" height="882" /> Image 4 - UI elements example 2 And finally, let's also tackle an essential R data structure - <code>Data Frame</code>. <h3>Example 3: Handling Data Frames</h3> Data Frames are everywhere in R, and you're almost guaranteed to work with them when building a Shiny application. Think of them as of Excel spreadsheets, since they contain data organized into rows and columns. We'll keep the example fairly simple, and have a Data Frame with three columns. Users can select which one is displayed on the Y axis, and the chart is updated automatically upon change. To keep things even more simple, we'll use R's <code>ggplot2</code> for displaying data visualizations: <pre><code class="language-r">library(shiny) library(ggplot2) <br># Dummy data.frame data &lt;- data.frame(  X = 1:10,  Y1 = 1:10,  Y2 = 10:1 ) <br>ui &lt;- fluidPage(  selectInput(inputId = "inY", label = "Y column:", choices = c("Y1", "Y2"), selected = "Y1"),  plotOutput(outputId = "outChart") ) <br>server &lt;- function(input, output) {  output$outChart &lt;- renderPlot({    # Get the selected column    selected_col &lt;- input$inY    # Render the chart    ggplot(data, aes_string(x = "X", y = selected_col)) +      geom_point() +      labs(title = "Scatter plot")  }) } <br> shinyApp(ui = ui, server = server)</code></pre> This is what the app looks like when you first open it: <img class="size-full wp-image-20153" src="" alt="Image 5 - Chart example 1" width="1321" height="1210" /> Image 5 - Chart example 1 And as before, the output element is updated automatically when a change in input is detected: <img class="size-full wp-image-20155" src="" alt="Image 6 - Chart example 2" width="1321" height="1210" /> Image 6 - Chart example 2 Do you need more assistance in understanding <code>ggplot2</code> code? We have plenty of articles for you, covering <a href="" target="_blank" rel="noopener">bar charts</a>, <a href="" target="_blank" rel="noopener">line charts</a>, <a href="" target="_blank" rel="noopener">scatter plots</a>, <a href="" target="_blank" rel="noopener">box plots</a>, and <a href="" target="_blank" rel="noopener">histograms</a>. And that's it for a basic introduction to reactive inputs. Up next, we'll go over reactive expressions. <h2 id="reactive-expressions">Reactive Expressions - Everything You Need to Know</h2> There are two functions you must know about when learning reactive expressions - <code>reactive()</code> and <code>observe()</code>. The prior is used to create reactive expressions from a block of R code - as simple as that. What's neat about it is that you can reuse the result in multiple places. The latter is used to create a reactive observer, which is a piece of code that runs every time one of the inputs changes. It yields no output and can't be used as an input to other reactive expressions. <blockquote>Want to learn more about the Reactive observer in R Shiny? <a href="" target="_blank" rel="noopener">We have a full dedicated article on the topic</a>.</blockquote> Let's now go over a couple of examples demonstrating reactive expression in R Shiny. <h3>Example 1: Basic Reactive Calculation</h3> This first example if probably the easiest one you'll see. Ever! It simply takes two inputs, sums them, and stores the result inside a reactive expression. Note how the reactive expression is stored inside a set of curly brackets - this indicates it's an expression. Also, always remember to <i>call</i> the reactive expression when you want to access its value. Think of this as calling a function. It's not the same in theory, but the implementation is identical. Anyhow, here's the full code snippet for this basic example: <pre><code class="language-r">library(shiny) <br>ui &lt;- fluidPage(  numericInput("num1", "Number 1:", value = 3),  numericInput("num2", "Number 2:", value = 5),  tags$hr(),  textOutput("sum") ) <br>server &lt;- function(input, output) {  # Calculate the sum and store it as a reactive expression  sum_result &lt;- reactive({    input$num1 + input$num2  }) <br>  # Output to display the sum  output$sum &lt;- renderText({    paste("Sum:", sum_result())  }) } <br>shinyApp(ui = ui, server = server)</code></pre> You'll see the two input numbers summed and rendered when you first launch the app: <img class="size-full wp-image-20157" src="" alt="Image 7 - Simple reactive calculation example 1" width="896" height="559" /> Image 7 - Simple reactive calculation example 1 As before, you can change the input elements and the output will re-render automatically: <img class="size-full wp-image-20159" src="" alt="Image 8 - Simple reactive calculation example 2" width="896" height="559" /> Image 8 - Simple reactive calculation example 2 And that's a basic reactive expression for you. Up next, let's see how to implement a reactive observer. <h3>Example 2: Factorial Calculation and Reactive Observer</h3> As briefly mentioned at the beginning of this section, a <a href="" target="_blank" rel="noopener">reactive observer</a> is a simple piece of code that runs every time one of the inputs changes. They are only useful for their “side effects”, such as I/O, triggering a pop-up, and so on. In this example, we'll use a reactive observer to log a message to the console as soon as the numeric input changes. Further, we'll use this numeric input to calculate and display a factorial of it. Here's the full code snippet for both the reactive expression and reactive observer: <pre><code class="language-r">library(shiny) <br>ui &lt;- fluidPage(  numericInput("num", "Enter a number:", value = 3),  verbatimTextOutput("factorial") ) <br>server &lt;- function(input, output) {  # Calculate the factorial and store it as a reactive expression  factorial_result &lt;- reactive({    n &lt;- input$num    if (n == 0) {      return(1)    } else {      return(prod(1:n))    }  }) <br>  # Runs every time the input changes  observe({    n &lt;- input$num    cat("Calculating factorial of", n, "\n")  }) <br>  # Display the factorial  output$factorial &lt;- renderPrint({    factorial_result()  }) } <br>shinyApp(ui, server)</code></pre> Launching the app will display the input number and its factorial: <img class="size-full wp-image-20161" src="" alt="Image 9 - Reactive observer example 1" width="832" height="421" /> Image 9 - Reactive observer example 1 You can change the input value, and the output is re-rendered instantly: <img class="size-full wp-image-20163" src="" alt="Image 10 - Reactive observer example 2" width="832" height="421" /> Image 10 - Reactive observer example 2 The reactive observer logs our message to the R console. You'll see it in the <i>Console</i> tab of RStudio: <img class="size-full wp-image-20165" src="" alt="Image 11 - Reactive observer console output" width="508" height="146" /> Image 11 - Reactive observer console output Simple, right? Let's go over one more example. <h3>Example 3: Filtering Data Frames</h3> You've seen in the previous section that Data Frames are everywhere. Data science revolves around data, and data frames provide a convenient data structure for data storage and manipulation. It's essential for you to know how to manipulate data, and this example will show you how to select multiple columns that are displayed in table form to the user. We'll use the built-in <code>mtcars</code> dataset to keep the code short and tidy. The filtered data will be stored in a <code>filtered_data</code> reactive expression, which further uses the <code>req()</code> function to ensure that at least one column is selected before filtering the data: <pre><code class="language-r">library(shiny) <br>ui &lt;- fluidPage(  selectInput(inputId = "cols", label = "Columns to display:", choices = names(mtcars), selected = c("mpg"), multiple = TRUE),  tableOutput(outputId = "table") ) <br>server &lt;- function(input, output) {  # Filter the dataset based on selected columns and store it as a reactive expression  filtered_data &lt;- reactive({    req(input$cols)    selected_cols &lt;- input$cols    mtcars[, selected_cols, drop = FALSE]  }) <br>  # Display the output as a table  output$table &lt;- renderTable({    filtered_data()  }) } <br>shinyApp(ui, server)</code></pre> As you can see, a single column is selected by default when you launch the app: <img class="size-full wp-image-20167" src="" alt="Image 12 - Data Frame filtering example 1" width="1038" height="920" /> Image 12 - Data Frame filtering example 1 Since this is a multi-select dropdown menu, you can choose however many columns you want, and they'll be added to the output table immediately: <img class="size-full wp-image-20169" src="" alt="Image 13 - Data Frame filtering example 2" width="1038" height="920" /> Image 13 - Data Frame filtering example 2 These three examples will be enough to get your feet wet when it comes to reactive expressions. <h2 id="reactive-outputs">Reactive Outputs in R Shiny</h2> Truth be told, this is the section in which you'll learn the least. Not because there's not much to learn, but because we've been working with reactive outputs through the entire article. It's near impossible to demonstrate what reactive inputs and expressions do if you don't display their results - and that's where the output comes in. Still, we'll provide you with a couple of useful and practical examples. We'll also dive a bit deeper into how reactive outputs are structured. Every reactive output function begins with <code>render</code>, such as <code>renderText()</code>, <code>renderPlot()</code>, and so on. There are many built-in rendering functions, but some R packages will also bring their own. You'll see two such examples later in this section. But first, let's start with the basics. <h3>Example 1: Rendering Text</h3> If you've gone through the first section of this article, this example will feel like a recap. The idea is to allow the user to enter a number and then to render that number as a textual message. Simple! R Shiny uses the <code>textOutput()</code> function as a container for the textual output element. Inside the server function, you'll have to call the <code>renderText()</code> function and pass in the expression. And that's the general pattern - <code>xOutput()</code> function in the UI followed by <code>renderX()</code> function in the server. Something to keep in mind. Anyhow, here's the full code snippet: <pre><code class="language-r">library(shiny) <br>ui &lt;- fluidPage(  numericInput(inputId = "num", label = "Enter a number:", value = 5),  tags$hr(),  textOutput(outputId = "text") ) <br>server &lt;- function(input, output) {  # Use the renderText() reactive function in combination with textOutput()  output$text &lt;- renderText({    input_num &lt;- input$num    paste("You've entered:", input_num)  }) } <br>shinyApp(ui = ui, server = server)</code></pre> You've already seen a bunch of interesting examples, so this one will look a bit dull: <img class="size-full wp-image-20171" src="" alt="Image 14 - Text output example 1" width="1038" height="396" /> Image 14 - Text output example 1 As expected, the output message changes as you change the input: <img class="size-full wp-image-20173" src="" alt="Image 15 - Text output example 2" width="1038" height="396" /> Image 15 - Text output example 2 Let's now go over a much more interesting reactive output example. <h3>Example 2: Rendering Interactive Charts</h3> You're not limited to using Shiny's built-in output functions. Some external packages, such as Plotly, have their own set. This example will show you how to render an interactive Plotly scatter plot. To be more precise, the app will allow the user to control the number of data points and the amount of noise, and will then combine the <code>plotlyOutput()</code> and <code>renderPlotly()</code> functions to produce the chart. The rest of the code is simple R and R Shiny logic: <pre><code class="language-r">library(shiny) library(plotly) <br>ui &lt;- fluidPage(  sliderInput(inputId = "inPoints", label = "Number of Points:", min = 10, max = 100, value = 50),  sliderInput(inputId = "inNoise", label = "Noise Level:", min = 0, max = 1, value = 0.2, step = 0.1),  tags$hr(),  # Note how it's plotlyOutput()  plotlyOutput(outputId = "plot") ) <br>server &lt;- function(input, output) {  # Plotly has it's own reactive function  output$plot &lt;- renderPlotly({    points &lt;- input$inPoints    noise &lt;- input$inNoise <br>    set.seed(42)    x &lt;- 1:points    y &lt;- x + rnorm(points, sd = noise) <br>    plot_data &lt;- data.frame(x = x, y = y) <br>    plot_ly(plot_data,      x = ~x, y = ~y, type = "scatter", mode = "markers",      marker = list(size = 10), text = ~ paste("X:", x, " Y:", y)    ) %&gt;%      layout(        title = "Scatter Plot",        xaxis = list(title = "X"),        yaxis = list(title = "Y")      )  }) } <br>shinyApp(ui, server)</code></pre> This is what the app will look like when you first launch it: <img class="size-full wp-image-20175" src="" alt="Image 16 - Plotly output example 1" width="1363" height="1574" /> Image 16 - Plotly output example 1 Since Plotly is interactive, you can hover over individual data points to get more information: <img class="size-full wp-image-20177" src="" alt="Image 17 - Plotly output example 1" width="1363" height="1574" /> Image 17 - Plotly output example 1 You can see how an interactive R Shiny dashboard combined with an interactive charting library brings the best of both worlds. <h3>Example 3: Rendering Data Tables</h3> And finally, let's look at yet another specialized R package for rendering data tables. It's called <code>DT</code> and like Plotly, it brings its own set of functions - <code>DTOutput()</code> and <code>renderDT()</code>. We'll use both to create a simple application that allows the user to control how many rows and columns are shown in a table. The actual cell values are arbitrary, and you shouldn't look much into them. Here's the entire code snippet: <pre><code class="language-r">library(shiny) library(DT) <br>ui &lt;- fluidPage(  sliderInput(inputId = "inRows", label = "Number of Rows:", min = 5, max = 20, value = 5),  sliderInput(inputId = "inCols", label = "Number of Columns:", min = 2, max = 10, value = 2),  # Note the specific DTOutput() function  DTOutput(outputId = "table") ) <br>server &lt;- function(input, output) {  # DT has its own render function  output$table &lt;- renderDT({    rows &lt;- input$inRows    cols &lt;- input$inCols <br>    data &lt;- matrix(runif(rows * cols), nrow = rows, ncol = cols)    datatable(data)  }) } <br>shinyApp(ui, server)</code></pre> When launched, Shiny will show a data table with 5 rows and 2 columns: <img class="size-full wp-image-20179" src="" alt="Image 18 - DT output example 1" width="1363" height="1474" /> Image 18 - DT output example 1 But you can easily change that by manipulating the slider values: <img class="size-full wp-image-20181" src="" alt="Image 19 - DT output example 1" width="1665" height="1790" /> Image 19 - DT output example 1 The <code>DT</code> package is smart enough to not overflow the Shiny dashboard with too many rows. Instead, the table contents are paginated, which is one less thing for you to implement manually. <blockquote>DT is not the only R package for rendering table Data - <a href="" target="_blank" rel="noopener">Here's a bunch more you can try in R and R Shiny</a>.</blockquote> <hr /> <h2 id="summary">Summing up R Shiny Reactivity</h2> For a core concept, R Shiny reactivity is utterly simple. Sure, it takes some time to get used to the syntax and the paradigm, but there's not much to it in reality. It's just a matter of practice and thinking ahead when planning an R Shiny project. Getting a good share of practice with reactive inputs, expressions, and outputs is all you need to make <a href="" target="_blank" rel="noopener">amazing Shiny apps</a>. Where things get interesting is when you want to build your own reactive components. That's something we'll go over in the following article, so make sure to stay tuned to the Appsilon blog. <i>Have a question about reactivity or need help on your enterprise Shiny project?</i> Leave it to the experts - <a href="" target="_blank" rel="noopener">Make sure to drop us a message</a>. <blockquote>How does R Shiny handle state and what can you do when state is empty? <a href="">shiny.emptystate comes to the rescue</a>!</blockquote>

Contact us!
Damian's Avatar
Iwona Matyjaszek
Head of Sales
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Have questions or insights?
Engage with experts, share ideas and take your data journey to the next level!
Join Slack
Explore Possibilities

Take Your Business Further with Custom Data Solutions

Unlock the full potential of your enterprise with our data services, tailored to the unique needs of Fortune 500 companies. Elevate your strategy -connect with us today!

Talk to our Experts