Getting started
Overview
sketch
is an R package for creating animated and interactive
visualisations. It lets users develop JavaScript-style visualisations
using just the R syntax by transpiling R code into JavaScript code. It
is designed to help
- researchers create domain specific visualisation to support development and sharing of research,
- journalists and science communicators publish high-quality and engaging interactive graphics,
- business users make customised in-house reports, and
- general users learn generative arts and interactive data visualisation.
Installation
# install.packages("remotes")
remotes::install_github("kcf-jackson/sketch")
Running a sketch R file
There are two ways to run a sketch R file.
-
Save the sketch R file (with the usual .R extension), then call
sketch::source_r
with it. -
If you use RStudio, there is an add-in “source a sketch R file” listed under this package (consider binding that to the key combination alt-shift-s), and that sources the active tab in the editor. Alternatively, you can call the
source_active()
function.
First example with sketch
As the first example with sketch
, we will use
p5.js to make this animated visualisation:
-
An important aspect of this package is that “Apps” produced by
sketch
run in the browser natively without an R back-end. The App is live, and it supports interactivity. -
In fact, you can write sketch code directly in R Markdown documents, generate an HTML file, and share it online easily (just like this page you are reading right now!).
-
p5.js is picked because it has an user-friendly API and many good learning resources online.
i. Basic structure
The structure of a p5
application looks like this:
#! load_library("p5")
setup <- function() {
createCanvas(400, 300) # create a canvas of size 400 x 300 (w x h)
}
draw <- function() {
background(0, 0, 33) # paint the background with the RGB colour
fill("red") # change fill colour to "red"
circle(200, 150, 50) # draw a circle (x, y, diameter)
}
-
#! load_library
is used to load thep5
library. Despite being commented out, lines starting with#!
are actually processed by thesketch
package. -
p5.js looks for functions named (specifically)
setup
anddraw
, and it runssetup
once at the start of the App, anddraw
iteratively 60 times per second after the App starts.
-
createCanvas
,background
,fill
andcircle
are functions provided by p5.js for drawing on the screen.
ii. Add more circles
Let’s create a “person” object, and draw 50 of them on the screen. We
need an id
to identify the person and its coordinates x
and y
at
which a circle will be drawn.
#! load_library("p5")
# Make a "person" object
person <- function(id) {
declare(res) # New variable in a function must be declared before use!
res <- list(id = id,
x = runif(1, 0, 400), y = runif(1, 0, 300))
return(res) # Return must be explicit, or it will return "undefined".
}
# Set up variables
radius <- 5
people <- map(1:50, person)
setup <- function() {
createCanvas(400, 300)
}
draw <- function() {
background(0, 0, 33)
for (person in people) { # Use a for loop to draw one person at a time
fill(190, 128, 0)
circle(person$x, person$y, 2*radius)
}
}
iii. Add movements
To make the people move, we add two velocity states vx
and vy
to the
“person” object and a function that changes a person’s position based on
its velocity.
An important point to notice is that JavaScript* passes object by
reference, so when you pass an object to a function and make changes to
it, the changes applies to the object directly and no copying occurs. To
clarify this point, the super-assign symbol <<-
is used below to
indicate where one should expect object modification.
(*Did you notice you have been writing JavaScript?)
#! load_library("p5")
# Make a "person" object
person <- function(id) {
declare(res)
res <- list(id = id,
x = runif(1, 0, 400), y = runif(1, 0, 300),
vx = runif(1, -2, 2), vy = runif(1, -2, 2)) # Add velocity
return(res)
}
move <- function(person) {
declare (new_x, new_y) # Do not forget the variable declaration!
new_x <- person$x + person$vx # Update position
new_y <- person$y + person$vy
# If the new position is out of the screen, the person should turn back!
# Otherwise, move to the new position
if (new_x < 0 || new_x > 400) {
person$vx <<- person$vx * -1 # Turn back!
} else {
person$x <<- new_x # Move to the new position
}
# Do the same for y
if (new_y < 0 || new_y > 300) {
person$vy <<- person$vy * -1 # Turn back!
} else {
person$y <<- new_y # Move to the new position
}
}
# Set up variables
radius <- 5
people <- map(1:50, person)
setup <- function() {
createCanvas(400, 300)
}
draw <- function() {
background(0, 0, 33)
for (person in people) {
fill(190, 128, 0)
circle(person$x, person$y, 2*radius)
move(person) # Call `move` here
}
}
Summary
We have learnt that
#! load_library("p5")
is used to load the p5.js library,setup
anddraw
forms the basic structure of ap5
canvas,background
,fill
andcircle
are drawing functions from p5.js,- new variables inside a function must be declared before use, and
- JavaScript passes object by reference.
Next step
That’s it! You have successfully written a JavaScript App without
actually writing any Javascript! I hope you find the examples easy to
follow and are convinced that using JavaScript - even to a great
extent - does not need to be hard. Leveraging the existing JavaScript
libraries, sketch
opens up many new possibilities with visualisations.
For the next step,
-
see Concepts for the fundamentals of the package,
-
see Features for the other features of the package, or
-
follow the Tutorials to make some interactive visualisations!