Getting R and D3.js to play nicely in R markdown

As there are already plenty of good resources made by people much better qualified to create them, this is not intended to be any kind of comprehensive tutorial on JavaScript, D3.js, R, or R markdown. Instead, its purpose is to show what experience has taught about working with all of them in a single file.

To keep this tutorial simple, let’s assume the data has been fully scienced and all that’s left is to create the D3 visualization(s). Have a look at the raw cars sample data set that comes packaged with R

head(cars)
##   speed dist
## 1 4 2
## 2 4 10
## 3 7 4
## 4 7 22
## 5 8 16
## 6 9 10

Passing data between languages is not as simple as referencing the name of the variable that contains them. If you try and add the JavaScript code console.log(cars); after the above R chunk, it will return a ReferenceError as cars has not yet been defined in JavaScript.

You could write the data to a new file that you would then read back in with the appropriate loading method in D3. However, it is possible to pass the data directly to JavaScript inside the .Rmd file.

cat(
paste(
'<script>
var data = ',cars,';
</script>'
, sep="")
)
## 
## <script>
## var data = c(4, 4, 7, ... 24, 24, 25);
## </script>
## <script>
## var data = c(2, 10, 4, ... 93, 120, 85);
## </script>

The above code will, indeed, pass the data into our JavaScript space; however, we have created two new problems for ourselves:

  • Each column in the data is being passed as an R vector, which JavaScript will interpret as being a call to some function c() with each of the values being passed as parameters.
  • The columns were passed one-by-one to the JavaScript data variable, overwriting the values in the speed column with those in the dist column.

To solve both problems at once, take advantage of D3’s assumption that the data it works with is in JSON format. R’s jsonlite library is lightweight with a simple toJSON() method that works perfectly for our purpose.

library("jsonlite")
cat(
paste(
'<script>
var data = ',toJSON(cars),';
</script>'
, sep="")
)
## <script>
## var data = [{"speed":4,"dist":2},
## {"speed":4,"dist":10},
## {"speed":7,"dist":4},
## ...
## {"speed":24,"dist":93},
## {"speed":24,"dist":120},
## {"speed":25,"dist":85}];
## </script>

**you have to include the results=“asis” option in the curly braces at the top of the code chunk to pass the data through**

Now JavaScript has the data, and in a format it can work with. It’s time to start D3ing!

There are two ways you can load the D3 library. Include <script src="https://d3js.org/d3.v4.min.js"></script> directly in your markdown file at any point before your visualization. Or else create a .html file with only that same script tag in the same directory as your .Rmd file and include it

You’re now free to visualize with D3.js in R markdown until your hearts content. Just add the code with a JavaScript code chunk, between script tags directly in the markdown, or in a separate file that you link to with a script tag.

I should add a word of caution. If you are the type to just copy/paste from https://bl.ocks.org, there is no shame–I don’t personally know anyone who uses D3 who doesn’t do it–but you have to keep in mind their data is always read in from external sources via D3’s loading methods. You’ll have to delete those lines of code, and substitute in your data variable inside of D3’s .data() method. Also, be sure to go through the D3 code to update all data references to your column names.

View the code on GitHub