New and improved draw charts in shinysense

Background

I didn’t expect many people to use the you-draw-it charts (henceforth referred to as ‘drawrs’) I put into my shiny modules package shinysense but a decent number did, and with that usage came… bugs.

In an effort to fix the bugs I went back and tore the function down and re-wrote it entirely. This time I utilized the javascript and R development knowledge I gained from building it the first time ’round. Most importantly, in the javascript portion of the code, The javascript is actually it’s own library on NPM. I implemented unit tests for every function. Something non-trivial due to needing to run the code in a headless browser to simulate dom manipulation. (Javascripty post on this coming soon).

Changes

The main API for the shiny module shinydrawr and shinydrawrUI has remained unchanged. You can simply update to the newest version of the package and everything (should) Submit an issue if it doesnt work exactly the same. That being said, there are a few improvements that either improve previous results or add on new features:

Resizing: The visualization now will re-size as your window changes. Start your shiny app small and then full screen it? Now the plot will grow with it.

Multiple drawrs: You should always expect people to use your functions in ways you yourself never envisioned. A perfect example of this was the awesome Lousiville Crime Rates project done by Robert Kahne.

Turns out the way I originally coded shinydrawr The reveal portion of the code used a css clipping filter that was tied to a fixed css id and thus every other drawr tried to use the filter from the first plot.assumed there would only ever be a single drawr on the screen at once but people wanted more. Now you can create as many drawrs as your heart desires.

Time series support: It is kind of silly that the function didn’t support time series before, these visualizations are almost exclusively used with time on the x-axis so obviously that should be supported. Stick around for a demo.

Non-Shiny use: I took advantage of the wonderful work done by the creators and maintainers of the package htmlwidgets and wrapped the javascript visualization in a widget. This means that you can now use the function drawr_widget right inside of RStudio, RMarkdown, or even a shiny app (if you don’t care about the data the user draws). Here’s an example of how to do that along with some demonstrations of the new features.

Widget

Basic Usage

You can use the widget just like the old shinydrawr worked. Throw in your data, name a start point and you get a ‘you draw it’ style chart just like the now famous article from the New York Times.

#run this line if you need to install the package. 
#devtools::install_github('nstrayer/shinysense') 
library(tidyverse)
library(shinysense) 

random_data <- data_frame(time = 1:30,metric = time * sin(time / 6) + rnorm(30))
  
drawr_widget(
  data = random_data,
  draw_start = 15,
  x_key = "time",
  y_key = "metric",
  width="100%"
)

Time Series

Time series are supported and have intelligently labeled axes. (Thanks to d3.scaleTime()s wonderful defaults.) To make a drawr with a time axis you simply need to pass data in with the x column having the class Date (or at least inheriting properties of Date). The function will detect this and plot accordingly.

dates <- seq(as.Date("2017/1/1"), as.Date("2017/07/22"), "weeks")
numWeeks <- length(dates)
endDate <- dates[15]

timeData <- data_frame(
  date = dates,
  value = 50 + (1:numWeeks) * cos((1:numWeeks) / 6) + rnorm(numWeeks)
)
  
drawr_widget(
  data = timeData,
  draw_start = endDate,
  x_key = "date",
  y_key = "value",
  width="100%"
)

No Reveal

Say you want to plot a drawr with some data that you desire the user to draw their predictions for, but not have the plot reveal the rest of the data (for instance, if it’s not available). To do this you simply append to the end of the dataframe rows with NAs in the y column. The chart will then allow the user to draw, pinning the drawn results y value’s to the supplied corresponding x-values. This doesn’t make much sense for the widget version we’re showing here, but in a shiny app with the drawn values returned to the app it can be used for any number of things. Feature was developed to gather future predictions from domain experts.

timeDataNoReveal <- timeData %>% 
  mutate(
    value = ifelse(date > endDate, NA, value)
  )
  
drawr_widget(
  data = timeDataNoReveal,
  draw_start = endDate,
  x_key = "date",
  y_key = "value",
  y_min = 2,
  width="100%"
)

Free Drawing

While it’s not a new feature and is almost pointless outside of shiny, you can still do draw on a canvas with no plotted line: simply set raw_draw = TRUE and go to town. You could also do this by simply setting all your y-values to NA, your choice.

drawr_widget(
  data = timeDataNoReveal,
  draw_start = endDate,
  raw_draw = TRUE,
  x_key = "date",
  y_key = "value",
  y_min = 2,
  width="100%"
)

Next Steps

Obviously I didn’t fix all the bugs and most likely created more than I remedied. If you find any it would make me very happy if you’d submit an issue on the github page. In addition, if there is a feature that you’d like and isn’t implemented, also submit an issue (or if you’re feeling super adventurous a pull request).

Acknowledgements

I am incredibly lucky to be performing all of this package development while supported by the Johns Hopkins Data Science Lab. In particular John Muschelli who has provided PRs and chats about what the package should do.


Nick Strayer image
Nick Strayer

Randomly walking my way though a career in statistics

comments powered by Disqus