---
title: "3D Graphics"
author: "Gregory Jefferis"
date: "`r Sys.Date()`"
output: 
  rmarkdown::html_vignette:
    toc_depth: 3
vignette: >
  %\VignetteIndexEntry{3D Graphics}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

## Introduction
### Comparing rgl and plotly
nat provides support for two different 3D graphics systems provided by the CRAN
packages [rgl](https://cran.r-project.org/package=rgl) and
[plotly](https://cran.r-project.org/package=plotly). These are quite different 
in style and pedigree and there are pros and cons to the use of each.

**rgl** is a much longer standing library, largely written in C++ to talk to your
graphics card's OpenGL functionality. In general it is more efficient for 
displaying large amounts of data (hundreds to thousands of neurons). Its main
weak point for interactive plotting is that transparent surfaces 
(i.e. with `alpha` < 1) are not efficiently handled especially when there 
is more than one such surface in a scene. It has
support for use in online web documents (via WebGL) but this is more restricted
and can result in very large html files. Its web support does have quite a 
flexible system for interacting with buttons/actions, which could be interesting
in some cases (see [WebGL vignette](https://cran.r-project.org/package=rgl/vignettes/WebGL.html))

You can use the **Plotly** library as an alternative to **rgl** for 3D display.
This is based on the commercially developed but open source 
[plotly.js](https://plotly.com/javascript/) java script library.
It is targeted at the web and particularly useful for interactive html documents.
For html output, it seems to me more efficient for medium numbers of neurons
(10s-100s) than **rgl**'s WebGL support. 
It has also has nice functionality e.g. interactive
"brushing" that continuously queries the inferred closest point to the cursor
and can display configurable information (including database queries). This can
identify e.g. individual neurons or brain region meshes shown in a busy plot.
One limitation of plotly is that it does not yet support orthographic
representations of 3D plots (but see [this PR](https://github.com/plotly/plotly.js/pull/3550)).

### Recommendation

* Use **rgl** for interactive use unless you need the plotly brushing capability
  or need to plot multiple overlapping transparent surfaces.
* Use **plotly** for html (e.g. rmarkdown) output unless you need orthographic 
  plots.

### Limitations

* Neither package provides good support for very large numbers of neurons in
  html output.
* Some rgl plot types are not yet supported in plotly e.g. `wire3d()`/`shade3d()`
  for surfaces/planes as `mesh3d()` objects and `alphashape3d::ashape3d()` objects.

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

## Plotly
Plotly can do a whole range of plots. See https://plotly.com/r/ for examples. The
standard approach looks like this:

```{r, eval=FALSE}
library(plotly)
plot_ly(midwest, x = ~percollege, color = ~state, type = "box")
```

## Plotly + nat

For nat we could add a specialised plot type for neurons etc to use with the
`plot_ly` interface, we have opted to keep things as close as possible to the 
`rgl::plot3d()` interface that we have already used.

### plotly setup

The only setup that is required in your rmarkdown document is to set the 
`nat.plotengine` option to make plotly the default 3d plot engine.
```{r, message=FALSE}
library(nat)
options(nat.plotengine = 'plotly')
```

### plotly examples
We can plot just one neuron:

```{r}
plot3d(Cell07PNs[[1]])
```

Or multiple neurons from a `neuronlist()` object.

```{r}
nclear3d()
plot3d(Cell07PNs[1:3])
```

You can set the figure size by specifying [chunk options](https://yihui.org/knitr/options/) like so

```
{r, fig.width=6, fig.height=4}
```

resulting in:
```{r, fig.width=6, fig.height=4, echo=FALSE}
nclear3d()
plot3d(Cell07PNs[1:3])
```

You can also display meshes and `dotprops` objects:

```{r}
nclear3d()
dummy=plot3d(MBL.surf, alpha=.4)
plot3d(kcs20, col=type)
```

### rgl setup

To set up a document to use rgl, you need to use the `rgl::setupKnitr()` 
function. You would normally do this at the top of your rmarkdown like so:

```{r, message=FALSE}
library(nat)
rgl::setupKnitr()
```

rgl is the default output for nat, so you do not need to choose it explicitly
unless you have previously chosen to use plotly as your default 3D plot engine.

```{r}
options(nat.plotengine = 'rgl')

```

Additional setup is required for each chunk. You must choose either to output a
2D snapshot of the 3D scene or to produce interactive output. Setting the chunk
option `rgl=TRUE` produces a static PNG snapshot.

```{r, rgl=TRUE}
plot3d(Cell07PNs)
```

Setting the chunk option `webgl=TRUE` produces an interactive webGL canvas
embedded in your html output document. Note that these can get quite large.

```{r, webgl=TRUE}
plot3d(Cell07PNs[1:3])
```

Inspect the `.Rmd` source code of this vignette to see how these options are set.
