![braid](braid.jpg)

## Coming soon
- Integration with the `htmlwidgets` framework.
- This will allow WebGL displays within RStudio, integration
with Shiny, etc.
- A test version works, but with some problems.
- Caveat: Until recently, RStudio didn't display WebGL
on OS X, and seemed a little unstable on Windows. I
don't know if this was my fault or theirs...
# Writing Web Pages
## `writeWebGL`
- `WebGL` is a fairly new JavaScript API for rendering OpenGL
interactive 3D graphics in a web browser. (First stable release: March, 2013.)
- Support in web browsers is now widespread, though it may be disabled
by default.
- `rgl` has supported `WebGL` output since 2012.
- The `writeWebGL` function writes a JavaScript program to display
your scene!
- Side effect: I had to add R-level access to the data in a scene; you can
now save and replay using `scene3d`.
## Using `writeWebGL`
`writeWebGL` is quite easy to use. Just draw a scene in the normal
way, then call it. For example:
```{r eval=FALSE}
writeWebGL(dir = "outputdir", width = 500)
```
- There are optional arguments to allow you to embed the WebGL code
into an existing web page template, to choose fonts, size and shape, etc.
- The resulting web page includes an interactive 3D graphic.
- There's support for including these figures in HTML
documents prepared in `knitr` [@knitrbook] like this presentation.
- Very new: Functions to allow interaction with the scene from the
browser.
# Examples
## Likelihood Surface
```{r}
# from the MASS::fitdistr example
set.seed(123)
x <- rgamma(100, shape = 5, rate = 0.1)
print(fit <- MASS::fitdistr(x, dgamma, list(shape = 1, rate = 0.1),
lower = 0.001))
loglik <- Vectorize(function(shape, rate)
sum(dgamma(x, shape = shape, rate = rate, log = TRUE)))
xlim <- fit$estimate[1] + 4*fit$sd[1]*c(-1, 1)
ylim <- fit$estimate[2] + 4*fit$sd[2]*c(-1, 1)
zlim <- fit$loglik + c(-qchisq(0.99, 2)/2, 0)
```
## Likelihood Surface Output
```{r webgl=TRUE, rgl.newwindow=TRUE, fig.height=4}
persp3d(loglik,
xlim = xlim, ylim = ylim, zlim = zlim,
n = 30)
```
## Toronto Homicide model
Patrick Brown sent me some R objects containing smoothed homicide
rates by Toronto location from 1990 to 2013.
```{r}
load("trisk.RData")
library(mapmisc)
df <- as.data.frame(trisk, xy=TRUE)
x <- matrix(df$x, 23, 40, byrow=TRUE)
y <- matrix(df$y, 23, 40, byrow=TRUE)
t <- matrix(seq(1, 0, len=23), 23, 40)
s <- matrix(seq(0, 1, len=40), 23, 40, byrow=TRUE)
yrs <- paste0("y", 1990:2013)
ids <- integer(length(yrs)); r <- c()
```
## Toronto Homicides
```{r webgl=TRUE, fig.height=3, rgl.newwindow=TRUE}
for (i in seq_along(yrs)) {
z <- matrix(df[[yrs[i]]], 23, 40, byrow=TRUE)
r <- range(c(r, z))
ids[i] <- surface3d(x,y,z, texture="toronto2.png",
texture_s=s, texture_t=t, col="white", specular="black")
}
par3d(zoom=0.4); aspect3d(80,46,12)
```
## Need Interaction
- The previous plot showed all 24 years at once, but you can't see
the differences.
- 24 small maps shown all at once would be too many.
- It's better to let the user choose which years to show.
- New this year in rgl: R functions to write Javascript for interaction:
`subsetSlider()`, `clipplaneSlider()`, etc.
- Coming soon: Shiny support.
## Choose a Year and a Level
```{r choose, webgl=TRUE, fig.height=3, rgl.newwindow=FALSE, echo=FALSE}
clipid <- clipplanes3d(0,0,1,-r[1])
delFromSubscene3d(ids[-1])
```
```{r results="asis", echo=FALSE}
subsetSlider(subsets = as.list(ids), prefix = "choose", labels=1990:2013)
s <- seq(-r[1], -r[2], len=50)
clipplaneSlider(d=s, prefix = "choose", clipplaneid = clipid, labels = signif(-s, 2))
```
## Choose a Year and a Level
```{r plane, webgl=TRUE, fig.height=3, rgl.newwindow=FALSE, echo=FALSE}
delFromSubscene3d(clipid)
planeid <- planes3d(0,0,1,0, alpha=0.5, col="white")
```
```{r results="asis", echo=FALSE}
subsetSlider(subsets = as.list(ids), prefix = "plane", labels=1990:2013)
propertySlider(values=matrix(r, 2, ncol=6), entries=6*0:5+2,
param = r,
properties = "values", objid = planeid, prefix = "plane",
init = 0, step = 0.02)
```
## Seal Tracking Data
Kim Whoriskey and Joanna Mills Flemming sent me seal
tracking data; Vivian Chu and I put together this display:
```{r seal,webgl=TRUE, echo=FALSE,fig.height=4}
df <- read.csv("seal.csv")
#df <- df[60*seq_len(nrow(df) %/% 60) + 19,]
time <- seq_len(nrow(df)) - 1
xyz <- cbind(df[,6],df[,7],-df[,3])
okay <- complete.cases(xyz)
xyz <-xyz[okay,]
time <- time[okay]
lineid <-plot3d(xyz, xlab="Longitude", ylab="Latitude", zlab="Depth",
type="l", col = c("black", "black"))["data"]
aspect3d(5,5,1)
sphereid <- spheres3d(xyz[1, , drop=FALSE], radius = 3, col = "red")
show2d(filename="sable.png", z=0, alpha=0.7)
```
```{r, results='asis', echo=FALSE}
rxyz <- round(xyz, 2)
propertySlider( list(ageSetter(births = time, ages = c(0, 0, 1800),
colors = c("gray", "red", "gray"),
objids = lineid, prefixes = "seal"),
ageSetter(births = 0, ages = time,
vertices = xyz, objids = sphereid,
prefixes = "seal")),
labels = paste(df[okay,2],-rxyz[,1],"W",
rxyz[,2],"N", rxyz[,3]),
maxS = max(time))
```
## Shiny Example
Try some unreleased code now...
## Conclusion
* `rgl` is really fun to work with, and it's not hard
to construct illustrations in 3D.
* `rgl` still needs some additional features, which I'll eventually get to:
+ The HTML pages we write are really huge, with a lot
of repetitive text: this is recently improved, but still a problem.
+ It needs better separation of the "model" and "viewer", to allow you to
"fly" through scenes. That's possible now, but really hard.
+ It needs "3D textures", to show slices through 3D fields.
Modern OpenGL supports this, but `rgl` doesn't.
# References
## Bibliography