Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
TL;DR
Nobody wants to use a slow dashboard. At Appsilon, we frequently hear this complaint from clients: “We’ve built a fantastic Shiny dashboard, but it’s incredibly slow and no one wants to use it.” No matter how complicated they are, Shiny dashboards do not have to be slow! One powerful way to speed up the performance of R Shiny applications is to leverage Shiny’s web nature and push actions to the browser. This article will show you how to omit the server bottleneck with updateInput, leverage CSS classes, and take advantage of JavaScript actions for smoother Shiny performance.
“The reason for Shiny’s slow action [is] usually not Shiny.” – Winston Chang
- Introduction: server.R Slows Down Shiny
- Speed Up R Shiny Performance with updateInput
- Enhance R Shiny UI with CSS Classes
- Using R Shiny with JavaScript Actions
- Learn More: Shiny Tutorials
Introduction: server.R Slows Down Shiny
It is easy to fall in love with R Shiny’s capacity for reactivity. The ability to parametrize every item in the server.R file can be particularly tempting for those with R programming rather than a web app development background. As always, with great power comes great responsibility, and overusing this feature may lead to significant application performance issues. This can lead to a long initial loading time, where elements slowly pop onto the screen one by one. Users might also be forced to wait a few seconds after each click. Slow performance is a primary reason that users lose interest in an application. No matter how great your application is, it needs to be fast to be a success!
This huge negative impact on performance might not become apparent until the product reaches maturity and is hard to refactor because the codebase is large and complex. Adhering to the rules and tips discussed in this article from the very start of your project is the key to developing efficient R Shiny apps whilst taking advantage of the reactivity feature.
Speed Up R Shiny Performance with updateInput
Anyone who has built their first Old Faithful Geyser R Shiny app is familiar with how a Shiny app is split into two parts – ui and server. Typically, application development begins with having these two worlds separated, i.e. widgets (UI elements) and logic are kept separate in the ui.R and server.R files respectively. However, the developer eventually gets to a point where the UI itself is dependent on the behavior of other widgets, user input, actions, and clicks. There is a temptation to pack everything into the renderUI function and let reactivity do the work. While tempting, relying too much on the renderUI function will slow down performance. The developer can speed up the R Shiny application significantly with just a bit more code, as I present in the following example.
Consider these two strategies to deploy two equivalent numeric inputs updated by a button:
At first glance their resulting behavior is identical:
Think about the problem this way: when Shiny spots a difference in the input, it goes through all the elements that react to it. The render solution recreates the entire widget, including the label, border and other features. In most cases we are only interested in modifying the value inside, so we should focus on this task only.
Also note what happens when the app starts (I’m refreshing the page in this graphic):
Enhance R Shiny UI with CSS Classes
It is possible (and even simple) to make use of JavaScript and CSS rules to style the content within an R Shiny app. Once the app is running in the browser, it should be looked at as any other web page from the UI perspective even if there is R code involved. Under the hood, an R Shiny app is in fact R code transformed into HTML. Therefore, R Shiny apps can be modified with CSS just like web apps. Using CSS allows you to enhance the style of your app beyond, for instance, the basic “primary-blue, warning-orange, danger-red” options in stock Shiny applications.
Here’s an open secret: under the hood, an R Shiny app is in fact R code transformed into HTML.
The most efficient way to assign styles are CSS classes. You can use them to e.g., wrap your content in `div(class = ‘myclass’, …)`. Using IDs for the various elements can help with constructing selectors – instructions for the browser that indicate which elements you are interested in modifying.
The ability to simply switch classes further streamlines the style modification process. If you are an R user I would recommend that you check out the excellent shinyjs package by Dean Attali. It will help you with web modifications starting at the code level, so the transition into frontend coding will be smooth.
Remember that you need to define classes before you start triggering them on and off. There is a comprehensive tutorial by R Studio on how to implement CSS within a Shiny app, but I would encourage you to go a step further and use SASS. Whilst SASS is beyond the scope of this article, I can recommend a nice overview of SASS by my colleague Pedro Silva. Pedro also has a great primer on getting started with CSS and R Shiny.
Using JavaScript Actions with R Shiny
Because Shiny applications can be treated like any other webpage once they are in the browser, we can also make use of JavaScript code to enhance them. Using JavaScript allows for keeping an action’s logic inside the browser rather than sending the action trigger to the server and slowing down the app. This is beneficial, because there is a resource overhead for passing information between the ui and the server. Therefore, it is best to avoid communicating with the server if there is no need to go beyond the UI code. Consider this equivalent buttons example:
Both buttons start with the arrow-up icon, but they are modified in a very different way.
After each click in the “classic” Shiny solution (shiny_update button), information is passed to the server, processed with R code and the whole button is re-rendered. In the JavaScript-based solution (js_update button) the information never exits the browser or communicates with the server, making it a very fast solution (note also that less code was used and that the entire logic is in a single file). In this example, JavaScript instructions are added inline to the R code. For more complicated solutions I recommend adding additional, independent JS scripts. You can learn more about connecting Shiny with JavaScript here.
In our example, the solutions are truly equivalent and while it’s technically still possible, it is very difficult to spot the difference. However, small changes like this will be crucial as your Shiny app grows in complexity!
These three simple tools – updateInput, CSS, and Javascript – will bring your Shiny projects to an entirely new level. Need help with an enterprise Shiny dashboard? Reach out to us at hello@appsilon.com!
Learn More
- Appsilon engineer Krystian Igras’s guest post on RStudio’s blog: 4 Tips to Make Your R Shiny Dashboard Faster
- Appsilon engineer Pedro Silva’s Guide to SASS
- Pedro Silva’s Guide to using CSS with Shiny
Article Make R Shiny Dashboards Faster with updateInput, CSS, and JavaScript comes from Appsilon Data Science | End to End Data Science Solutions.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.