Site icon R-bloggers

COVID-19 shiny / plotly dashboard

[This article was first published on Sebastian Engel-Wolf blog, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
< !-- wp:paragraph -->

Governments and COVID-19: Which one stops it faster, better, has fewer people dying? These questions get answered with my dashboard.

< !-- /wp:paragraph --> < !-- wp:paragraph -->

A contribution to the shiny-contest: https://community.rstudio.com/t/material-design-corona-covid-19-dashboard-2020-shiny-contest-submission/59690

< !-- /wp:paragraph --> < !-- wp:heading {"level":3} -->

Intro

< !-- /wp:heading --> < !-- wp:video -->
< video controls src="https://mail-wolf.de/documents/shinycontest2020/map.mp4">
How did Corona spread? Using the animation feature of R-shiny this can be easily tracked.
< !-- /wp:video --> < !-- wp:paragraph -->

COVID-19 is the major topic in all news channels. The place I live in is Munich, Germany. Within weeks Germany moved from 3 patients in the hospital next to my home, to have 20,000 patients. As a data-scientist, I did not only see the numbers but the exponential growth. I wanted to know:

< !-- /wp:paragraph --> < !-- wp:list --> < !-- /wp:list --> < !-- wp:paragraph -->

To enable this I got pretty fast using shiny. With shiny you can select countries, date-ranges, make flexible tables with datatable. Great! Additionally, I used plotly to zoom into all plots, get better legends, make it easy to browse through my data.
What else… shinymaterial makes the whole app look nice. It’s a great package and comes with easy use on mobile devices. I guess that’s it.
Now I can answer all my questions by browsing through the app. It’s easy to see how well South Korea managed Corona for example. You can also see how long it took for people to die in German hospitals, while the outbreak was rather fast in Italy. Moreover, the app shows, that in the US up-to now (Apr 3rd) the spread is not really stopped.

< !-- /wp:paragraph --> < !-- wp:paragraph -->

Go to the app to see how your country performs:

< !-- /wp:paragraph --> < !-- wp:image {"id":4634,"linkDestination":"custom"} -->
< !-- /wp:image --> < !-- wp:paragraph -->

If all this Corona data is too much for you, you can also check out the fun data section inside the app.

< !-- /wp:paragraph --> < !-- wp:heading {"level":3} -->

Implementation

< !-- /wp:heading --> < !-- wp:paragraph -->

I used the following packages to build the app:

< !-- /wp:paragraph --> < !-- wp:list --> < !-- /wp:list --> < !-- wp:paragraph -->

All code of this App is hosted on github:

< !-- /wp:paragraph --> < !-- wp:image {"id":4635,"linkDestination":"custom"} -->
< !-- /wp:image --> < !-- wp:paragraph -->

To clean the data I mainly wrote a script which does the following:

< !-- /wp:paragraph --> < !-- wp:list --> < !-- /wp:list --> < !-- wp:paragraph -->

All this code can be found in data_gen.R

< !-- /wp:paragraph --> < !-- wp:paragraph -->

To build up the app I used shiny-modules. How to build modular shiny apps I explained several times already: App – from Truck and Trailer. This time I used standard shiny modules without classes. Each of the pages shown inside the app is such a module. So one for the map, one for the timeline charts, one for Italy….

< !-- /wp:paragraph --> < !-- wp:paragraph -->

To render the plots I only used plotly. Plotly allows the user to select certain lines, scroll into the plot and move a round. With few lines of code it is possible to create a line chart which can be grouped and colored per group:

< !-- /wp:paragraph --> < !-- wp:syntaxhighlighter/code {"language":"r"} -->
plotly() %>% add_trace(
        data = simple_data,
        x = ~as.numeric(running_day),
        y = ~as.numeric(active),
        name = country_name,
        text="",
        type = if(type == "lines") NULL else type,
        line = list(color = palette_col[which(unique(plot_data_intern2$country) == country_name)])
)
< !-- /wp:syntaxhighlighter/code --> < !-- wp:paragraph -->

The result looks like this:

< !-- /wp:paragraph --> < !-- wp:video -->
< video controls src="https://mail-wolf.de/documents/shinycontest2020/charts.mp4">
< !-- /wp:video --> < !-- wp:paragraph -->

An important feature I wanted to build in was a table, where a lot of measurements per country are available. I set up these measurements:

< !-- /wp:paragraph --> < !-- wp:list --> < !-- /wp:list --> < !-- wp:paragraph -->

With the datatable package this table is scrollable and searchable. Even on mobile devices:

< !-- /wp:paragraph --> < !-- wp:video -->
< video controls src="https://mail-wolf.de/documents/shinycontest2020/phone_table2.mp4">
< !-- /wp:video --> < !-- wp:paragraph -->

Last but not least, I wanted to have a map that changes over time. This was enabled using the leaflet package. leafletProxy enables to add new circles everytime the data_for_display changes. The code for the map would look like this:

< !-- /wp:paragraph --> < !-- wp:syntaxhighlighter/code {"language":"r"} -->
leafletProxy(mapId = "outmap") %>%
       clearGroup(curr_date()) %>%
       addCircles(data = data_for_display,
                  lng = ~Long, lat = ~Lat,
                  radius = ~active_scaled,
                  popup = ~text,
                  fillColor = ~color, stroke = FALSE, fillOpacity = 0.5,
                  group = stringr::str_match(date_to_choose, "\\d{4}\\-\\d{2}\\-\\d{2}")[1,1]
     )
< !-- /wp:syntaxhighlighter/code --> < !-- wp:paragraph -->

With shiny, the date-slider could easily be animated

< !-- /wp:paragraph --> < !-- wp:syntaxhighlighter/code {"language":"r"} -->
shiny::sliderInput(inputId = session$ns("datum"),
                   min = as.POSIXct("2020-02-01"),
                   max = max(all_dates()),
                   value = max(all_dates()),
                   step = 86400,
                   label = "Date", timeFormat="%Y-%m-%d", 
                   animate = animationOptions(interval = 200))
)
< !-- /wp:syntaxhighlighter/code --> < !-- wp:paragraph -->

The result is the video from above:

< !-- /wp:paragraph --> < !-- wp:video -->
< video controls src="https://mail-wolf.de/documents/shinycontest2020/map.mp4">
< !-- /wp:video --> < !-- wp:heading {"level":3} -->

Links

< !-- /wp:heading --> < !-- wp:list --> < !-- /wp:list --> < !-- wp:paragraph -->

< !-- /wp:paragraph -->

To leave a comment for the author, please follow the link and comment on their blog: Sebastian Engel-Wolf blog.

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.