Designing Accessible Research with R/Shiny
R/Shiny is quite versatile from a developer’s perspective, and at Appsilon, we try our best to stretch those limits even further. That is what we did for the <a href="https://appsilon.com/data-for-good/" target="_blank" rel="noopener">Data for Good</a> project: <a href="http://go.appsilon.com/forests" target="_blank" rel="noopener">Future Forests</a>. Which, at first glance, doesn’t even appear to be an R/Shiny application. In fact, that was a critical point of discussion when we first spoke with the designers. We needed to move away from the average Shiny look, often cluttered with information and boxes. We had to eliminate boxes, selectInputs, and other elements that scream old-school Shiny. We needed a Shiny app that focused readers on what mattered most: the research and the data. TOC: <ul><li><a href="#projectstart">How the Future Forest Ranges Shiny project started</a></li><li><a href="#rhino">{Rhino} R framework in action</a></li><li><a href="#sentenceselector">Sentence Selector in a Shiny app with {shinyWidgets}</a></li><li><a href="#localization">Localization and Strings for Shiny translations with {shiny.i18n}</a></li><li><a href="#echarts4r">Plots in Shiny with {eCharts4r}</a></li><li><a href="#leaflet">Maps in a Shiny app with {leaflet}</a></li><li><a href="#viridis">Adding accessibility in Shiny apps with {viridis}</a></li><li><a href="#mobileui">Mobile UI for Shiny dashboards and applications</a></li><li><a href="#mobileRhino">Creating a Shiny mobile UI with {Rhino}</a></li></ul> <hr /> <h2 id="projectstart">Making scientific research accessible - how the Future Forest Ranges Shiny project started</h2> With the topic as critical as the future of our forests and climate change, we wanted the user to be able to enter, understand, and engage. The user should visit the application and browse through a simple yet valuable interface. <blockquote>There are several frameworks and dashboarding tools out there. <a href="https://appsilon.com/why-you-should-use-r-shiny-for-enterprise-application-development/" target="_blank" rel="noopener">Find out if R/Shiny is right for your use case</a>.</blockquote> The design that we received was already moving toward this idea: remove visual noise. But of course, all good things are built on the shoulders of what came before. If you look at Future Forests, you would be shocked that the current rework took only about a month. But this timeline was only possible due to the existing backend. The previous work done made sure we could focus on just one thing: a clean design. The app changed significantly after two iterations, and that is not a bad thing. In fact, the idea is always to keep improving things. <img class="size-full wp-image-17178" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01c2baebaad0dba40fa4d_Early-UI-Version-of-Future-Forests.webp" alt="first future forest trees design received from the design team - making scientific data exploration accessible with shiny" width="600" height="400" /> Initial dashboard design received from our design team. <h2 id="rhino">{Rhino} R framework in action</h2> We built the Future Forests application using {<a href="https://appsilon.github.io/rhino/" target="_blank" rel="noopener">Rhino</a>}, our opinionated framework for building production-grade R/Shiny apps. {Rhino} simplifies managing modules, complex styling through SASS, and nifty interaction through JavaScript. Additionally, we have a CI pipeline that directly talks to GitHub Actions, lints our code, and tests the app against an array of robust unit and E2E tests. All in all, without {Rhino}, doing all this would have increased our workload immensely. <img class="wp-image-17077" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01c59376223d164b79401_future-forest-ranges-research-shiny-application.webp" alt="final future forest ranges design -research shiny application" width="800" height="500" /> Current dashboard design. <blockquote>Already have a dashboard built? <a href="https://appsilon.com/redesign-dashboard-with-shiny-and-rhino/" target="_blank" rel="noopener">With {Rhino} you can easily redesign a dashboard in R/Shiny</a>.</blockquote> <h2 id="sentenceselector">Sentence Selector in a Shiny app with {shinyWidgets}</h2> If you notice, one of the key features of Future Forests is that the selection in the app looks like it is a sentence. It’s clean and it works! But how did we implement this? Well, a lot of creative CSS goes behind the scenes but a key element in creating this was <em>not</em> starting from scratch. <blockquote>Shiny apps can be slow. Learn how to <a href="https://appsilon.com/r-shiny-caching/" target="_blank" rel="noopener">speed things up by caching interactive elements in R/Shiny</a>.</blockquote> pickerInput from the {shinyWidgets} package has a parameter called options which takes a pickerOptions object with style = ‘link’ as a value. In other words, the pickerInput allows us to start with a specific style, which we then tweaked further using CSS. The text inputs are defined by something that looks like the following: <pre><code> pickerInput( inputId = ID_FOR_INPUT, label = "", choices = LIST_OF_CHOICES, selected = SELECTED_CHOICE_OR_OTHER_LOGIC, inline = TRUE, options = pickerOptions(style = "link") ) </code></pre> Then, you just play with the CSS and it starts to look like what you see on the app. The layout also heavily depends on flex and flex properties to make things look neat and tidy. The text form selector is one such example. <img class="alignnone wp-image-17075 size-full" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01c5aec1e575073dd2ecf_displaying-scientific-model-outputs-in-a-shiny-dashboard.gif" alt="displaying scientific model outputs in a shiny dashboard with sentence selector" width="600" height="504" /> <h2 id="localization">Localization and Strings for Shiny translations with {shiny.i18n}</h2> As you explore the app, especially when you do things like change scenarios, you will realize that a lot of text changes. For example, you can see this in the Scenario Description at the bottom of the Plot side of the card. This changeup occurs in several locations. <img class="alignnone wp-image-17085" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01c5b3c93260f451fd2e9_sentence-selector-response-for-displaying-scientific-data-in-shiny.gif" alt="sentence selector response for displaying scientific data in shiny dashboard" width="400" height="600" /> To achieve this, we use a <em>translations.json</em> file that we feed into a {shiny.i18n} object. {<a href="https://github.com/Appsilon/shiny.i18n" target="_blank" rel="noopener">shiny.i18n</a>} is another package that we developed and use at Appsilon which handles seamless translations. This enables us to do two things: <ol><li>Change strings fast</li><li>Support near-instantaneous translation between English and Polish</li></ol> <img class="alignnone size-full wp-image-17083" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01c5c2829666b590a64cd_internationalization-in-a-shiny-dashboard-with-i18n.gif" alt="internationalization in a shiny dashboard with i18n" width="600" height="57" /> The<em> translations.json</em> looks something like this, and of course, is longer than just one element. <pre><code> { "cultural_date_format": "%d-%m-%Y", "languages": [ "key", "en", "pl" ], "translation": [ { "key": "language_code", "en": "English", "pl": "Polish" }, { "key": "app_title", "en": "Forest ranges in 2070 under different climate scenarios", "pl": "Zasięg lasów w 2070 r. w różnych scenariuszach klimatycznych" }, … ] } </code></pre> Each key is mapped to each element, which then serves the text using a variance of HTML tags, textOutputs, and many other ways you can access text in R/Shiny. <h2 id="echarts4r">Plots in Shiny with {eCharts4r}</h2> If you notice in the above card GIF, the plot looks super neat and animated. That’s thanks to the {echarts4r} library. We use it to plug in the data used to plot (it is crunched to proportions at some point) and then use the e_bar() function with more customization. The text that changes on the card also takes in the highest proportion and reorders the Retraction, Overlap, and Expansion percentages. All that is simply using R/Shiny to split our output into multiple textOutputs depending upon their comparison of the largest. It gives us a nifty plot that looks great. In an earlier iteration, we had a pie chart in place of the bar chart. But at Appsilon, <a href="https://appsilon.com/dont-trust-pie-charts/" target="_blank" rel="noopener">we don’t trust pie charts</a>. So to ensure clear, unambiguous data-viz, we selected the bar chart. <h2 id="leaflet">Maps in a Shiny app with {leaflet}</h2> {leaflet} is so common, that I wonder if I’ve ever seen a map in an R/Shiny dashboard that was not made on {leaflet}? It is tried and tested and has a range of customization. In the Future Forests map, we use an <em>Esri.WorldTerrain</em> tile as the base leaflet layer, which we then use multiple layers to augment and each button toggles a specific <em>leafletProxy</em>. The labels come from <em>CartoDB.VoyagerOnlyLabels</em> tiles and the borders come from the <em>Stamen.TonerLines</em> tiles. <blockquote>Looking to build advanced R maps? Follow this <a href="https://appsilon.com/leaflet-geomaps/" target="_blank" rel="noopener">guide to building stunning Leaflet maps</a>.</blockquote> Each of these is standard and free to use. We use them in such a way that they all augment the map purposefully. We start with the borders and no labels, and then, the user can make it look as they choose. <img class="alignnone size-full wp-image-17090" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01c5d96d382f5b9cdac26_toggling-data-in-leaflet-shiny-dashboard.gif" alt="toggling data on leaflet map in a shiny dashboard" width="600" height="474" /> <h3>What is the disabled button in the app?</h3> There is a disabled button that serves a specific purpose. Our friends at the Polish Academy of Sciences were kind enough to give us data about the forest divisions in Poland. And since we only have that data in the Polish region, it made sense to enable this button only for the Polish version of the application. <img class="alignnone size-full wp-image-17069" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01c5e96d382f5b9cdacf8_adding-internationizationalization-in-an-r-shiny-application.gif" alt="toggling data layers in leaflet map in an r shiny application" width="600" height="512" /> This works as an independent layer that, again, works through <em>leafletProxy</em>. <h2 id="viridis">Adding accessibility in Shiny apps with {viridis}</h2> We have focused a bit on the accessibility of the application as well. We at Appsilon always try to be as inclusive as possible. Kindness is one of our values and we take it seriously. <blockquote>Building accessible Shiny apps is easier than you think. Explore how to <a href="https://appsilon.com/r-shiny-accessibility/" target="_blank" rel="noopener">make your apps accessible with design theory, open-source packages, and A11Y guidelines</a>.</blockquote> Since colors are a major part of this app and help separate key information—whether the forests Retract, Overlap or Expand—we wanted to make this accessible for all. To do so, we added a colorblindness palette that can be toggled using the partial visibility button on the menu. <img class="alignnone size-full wp-image-17067" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01c5fcb85d9eead736f92_adding-color-blind-accessible-colors-to-a-shiny-map.gif" alt="toggling color-blind accessible colors to a shiny map" width="600" height="463" /> This not only changes the map, but also the colors for the plot and the legend. <img class="alignnone size-full wp-image-17073" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01c2a96d382f5b9cd8398_displaying-scientific-data-in-color-blind-accessible-colors.gif" alt="displaying scientific data in color blind accessible colors after toggling viridis leaflet map input" width="550" height="852" /> All this is achieved by storing the colors in a <em>colors.yml</em> file, that looks something like this: <pre><code> expansion: "#0d70b9" overlap: "#39ba0c" retraction: "#fa825b" # viridis colorblind safe colors expansion_blindsafe: "#fde725" overlap_blindsafe: "#21908c" retraction_blindsafe: "#440154" </code></pre> <strong>What ensures that the colors are colorblind-safe?</strong> We got these colors from the viridis palette which is a standard for colorblind color usage. <h2 id="mobileui">Mobile UI for Shiny dashboards</h2> Standard R/Shiny dashboards are used and developed within a desktop web browser. But what if it was possible to see the future of our forests from the palm of our hands? We built the initial dashboard focusing on large to medium size desktop screens. But we wanted to reach a wider audience by bringing the dashboard to the smartphone. Inspired by the thought of engaging millions, the designers developed a wireframe for the mobile view of the dashboard. <img class="alignnone wp-image-17081" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01c6267ce14432ee4b4c7_mobile-shiny-app-for-communicating-scientific-research-to-mobile-users.webp" alt="mobile shiny app for communicating scientific research to mobile users" width="251" height="600" /> Instead of overloading the user with visual information in a tiny space, the mobile UI shows a simple card. The card holds information about a tree and its overall status based on the scenario selected above. Once curiosity sinks in, clicking on the top right corner of the card reveals the bar graph seen in the desktop UI. A little further below, a convenient "Toggle View" button allows you to switch to the map view and pan and zoom around Europe from your fingertips. If the urge to double-check with the image of the tree or the bar graph comes, you can click on Toggle View to jump right back into the card view. <h3 id="mobileRhino">Creating a Shiny mobile UI with {Rhino}</h3> Creating a mobile UI was straightforward using {Rhino}. With the power of SASS given to us by {Rhino}, we defined an extensive array of media queries to cater to a wide range of mobile devices. <blockquote>Ready for a unique Shiny UX? Discover how to <a href="https://appsilon.com/infinite-scrolling-in-r-shiny/" target="_blank" rel="noopener">add infinite scroll to your Shiny app</a>.</blockquote> To define a mobile UI, you would initially need to specify the dimensions you intend to support for your dashboard. With SASS, it was effortless to define breakpoints with variables and to iterate through each of them using ‘for loops’. For each component, we described the behavior within these breakpoints. As the final touch, we implemented a simple Javascript function to enable the switch between the card and the map. <img class="alignnone size-full wp-image-17071" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b01c2c832c47d67310773c_displaying-future-forest-models-on-shiny-mobile-app.gif" alt="displaying future forest models on Shiny mobile UI" width="384" height="798" /> <h2>Elevating research with Shiny applications and design -always room for improvement</h2> These are just a few highlights of what works in a well-thought-out Shiny app - from the science to the visualization. These are also some of the FAQs that we received once we released the app, and so we felt it important to share not just the what but also the how with the community. We believe in a culture where everyone learns and grows together. If you feel there were other methods to achieve similar results, we always welcome feedback! There is a plethora of what goes under the hood from lots of hacking with JavaScript to a lot of SASS that builds the application and makes it look the way it does. All in all, we believe this project has had a great impact on us and the community, by raising an important question for us all: <a href="https://futureforests.appsilon.com/" target="_blank" rel="noopener">what is happening to our forests</a>? We believe the urgency from awareness it creates also brings a certain hope: nothing is impossible to change if we give it our best.