|
1 | 1 | ---
|
2 | 2 | title: "An introduction to plotly's R API"
|
3 | 3 | author: "Carson Sievert"
|
4 |
| -output: html_document |
5 |
| -vignette: > |
6 |
| - %\VignetteEngine{knitr::rmarkdown} |
7 |
| - %\VignetteIndexEntry{Plotly DSL} |
| 4 | +output: |
| 5 | + pdf_document: |
| 6 | + toc: yes |
| 7 | + html_document: |
| 8 | + toc: yes |
| 9 | +vignette: | |
| 10 | + %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{Plotly DSL} |
8 | 11 | ---
|
9 | 12 |
|
10 | 13 | ```{r setup, echo = FALSE, message = FALSE}
|
11 | 14 | knitr::opts_chunk$set(eval = FALSE)
|
12 | 15 | ```
|
13 | 16 |
|
14 |
| -Version 1.0.0 of the [plotly R package](https://github.com/ropensci/plotly) introduces a new interface for creating plotly graphs in a [pure, predictable, and pipeable](https://dl.dropboxusercontent.com/u/41902/pipe-dsls.pdf) manner. This interface makes it a bit easier to work directly with the JavaScript graphing library by providing some high-level semantics and sensible defaults. |
| 17 | +Version 1.0.0 of the [plotly R package](https://github.com/ropensci/plotly) introduces a new high-level interface for working with plotly's JavaScript graphing library from R. The aim of this vignette is to explain the semantics of this interface, but I also recommend perusing [plotly's R homepage](https://plot.ly/r/) for more examples. |
15 | 18 |
|
16 | 19 | ## Creating and modifying plotlys
|
17 | 20 |
|
18 |
| -To initiate a plotly object, use `plot_ly()`. Here we use it to create a scatter trace (but there are many [other trace types](https://plot.ly/r/)). |
| 21 | +To initiate a plotly object, use `plot_ly()`. Here we turn the `economics` data frame (from the ggplot2 package) into a plotly visualization and store it as the object `p`. |
19 | 22 |
|
20 | 23 | ```{r}
|
21 | 24 | library(plotly)
|
22 |
| -p <- plot_ly(economics, x = date, y = uempmed, type = "scatter", showlegend = F) |
| 25 | +p <- plot_ly(economics, x = date, y = uempmed) |
23 | 26 | ```
|
24 | 27 |
|
25 |
| -If you have a plotly account, printing plotly objects in the R console will create a new plotly figure (via plotly's REST API). If you're using knitr/R Markdown with HTML output (like [this vignette]()), printing not only creates the plot, but also embeds it as an HTML iframe. If you want to create standalone HTML pages, check out [plotly offline](http://purchasing.plot.ly/) and the accompanying [vignette for R](). |
| 28 | +If you have a plotly account, printing plotly objects in the R console will create a new plotly figure, and open it in your web browser. If you're using knitr/R Markdown with HTML output (like [this vignette](https://github.com/ropensci/plotly/tree/master/vignettes/intro.Rmd)), printing not only creates the plot, but also embeds it as an HTML iframe. If you want to avoid iframes, check out [plotly offline](http://purchasing.plot.ly/) and the accompanying [vignette for R](https://cdn.rawgit.com/ropensci/plotly/master/vignettes/offline.html). |
26 | 29 |
|
27 | 30 | ```{r}
|
28 | 31 | p
|
29 | 32 | ```
|
30 | 33 |
|
| 34 | +<div align="center"> |
| 35 | + <a href="https://plot.ly/~agvd/450"> |
| 36 | + <img src="https://plot.ly/~agvd/450.png" height="300" width="600" /> |
| 37 | + </a> |
| 38 | +</div> |
| 39 | + |
31 | 40 | ## Using special arguments
|
32 | 41 |
|
33 |
| -`plot_ly()` has a number of arguments which are unique to the R package that make common visualization tasks a bit easier. These arguments are very much inspired by the semantics of ggplot2's `qplot()` in the sense that a scaling function is automatically applied these variables. |
| 42 | +`plot_ly()` has a number of arguments which are unique to the R package that make common visualization tasks a bit easier. These arguments are very much inspired by the semantics of ggplot2's `qplot()` in the sense that a scales are automatically applied these variables (scales map data to visual properties). |
34 | 43 |
|
35 | 44 | ### The color argument
|
36 | 45 |
|
37 |
| -If a ordinal variable (aka a non-ordered factor variable) is mapped to color, then a qualitative color pallete is used by default. |
| 46 | +#### Qualitative color mappings |
| 47 | + |
| 48 | +If a ordinal variable (aka a non-ordered factor variable) is mapped to color, then a qualitative color palette is used by default. |
38 | 49 |
|
39 | 50 | ```{r}
|
40 | 51 | plot_ly(iris, x = Petal.Length, y = Petal.Width,
|
41 | 52 | color = Species, mode = "markers")
|
42 | 53 | ```
|
43 | 54 |
|
44 |
| -<a href="https://plot.ly/~agvd/414"> |
45 |
| - <img src="https://plot.ly/~agvd/414.png"> |
46 |
| -</a> |
| 55 | +<div align="center"> |
| 56 | + <a href="https://plot.ly/~agvd/414"> |
| 57 | + <img src="https://plot.ly/~agvd/414.png" height="300" width="600" /> |
| 58 | + </a> |
| 59 | +</div> |
47 | 60 |
|
48 |
| -If you want to change the default pallette, you can give the colors argument either a <http://colorbrewer2.org> pallette name (e.g., "Set1" or "Blues"), or a vector of colors to interpolate in hexadecimal "#RRGGBB" format, or a color interpolation function like `grDevices::colorRamp()`. |
| 61 | +If you want to change the default palette, it's recommended that you provide a <http://colorbrewer2.org> qualitative pallette name (e.g., "Set1" or "Accent") to the colors argument. |
49 | 62 |
|
50 | 63 | ```{r}
|
51 | 64 | plot_ly(iris, x = Petal.Length, y = Petal.Width,
|
52 | 65 | color = Species, colors = "Set1", mode = "markers")
|
53 | 66 | ```
|
54 | 67 |
|
55 |
| -<a href="https://plot.ly/~agvd/428"> |
56 |
| - <img src="https://plot.ly/~agvd/428.png"> |
57 |
| -</a> |
| 68 | +<div align="center"> |
| 69 | + <a href="https://plot.ly/~agvd/428"> |
| 70 | + <img src="https://plot.ly/~agvd/428.png" height="300" width="600" /> |
| 71 | + </a> |
| 72 | +</div> |
| 73 | + |
| 74 | +In this case, the palette consists of 9 colors and the default behavior is to pick colors that are furthest apart ("#E41A1C", "#FF7F00", and "#999999"). |
58 | 75 |
|
59 | 76 | ```{r}
|
60 |
| -plot_ly(iris, x = Petal.Length, y = Petal.Width, z = Sepal.Width, |
61 |
| - color = Sepal.Length, type = "scatter3d", mode = "markers") |
| 77 | +cols <- RColorBrewer::brewer.pal(9, "Set1") |
| 78 | +scales::show_col(cols) |
62 | 79 | ```
|
63 | 80 |
|
| 81 | +<div align="center"> |
| 82 | + <a href="http://imgur.com/PpLch1T"> |
| 83 | + <img src="http://i.imgur.com/PpLch1T.png" /> |
| 84 | + </a> |
| 85 | +</div> |
64 | 86 |
|
65 |
| -### The symbol argument |
| 87 | +If you'd like more control over the mapping, you can provide a vector of colors (of appropriate length). |
66 | 88 |
|
| 89 | +```{r} |
| 90 | +cols <- RColorBrewer::brewer.pal(nlevels(iris$Species), "Set1") |
| 91 | +plot_ly(iris, x = Petal.Length, y = Petal.Width, |
| 92 | + color = Species, colors = cols, mode = "markers") |
| 93 | +``` |
67 | 94 |
|
| 95 | +<div align="center"> |
| 96 | + <a href="https://plot.ly/~agvd/434"> |
| 97 | + <img src="https://plot.ly/~agvd/434.png" height="300" width="600" /> |
| 98 | + </a> |
| 99 | +</div> |
68 | 100 |
|
69 |
| -### The group argument |
| 101 | +#### Sequential color mappings |
70 | 102 |
|
71 |
| -This can be useful when used in conjunction with `subplot()` (link to a separate vignette?) |
| 103 | +If either a numeric or an ordered factor is mapped to color, `plot_ly()` applies a sequential color scale by default. |
72 | 104 |
|
73 |
| -## Manually adding traces |
| 105 | +```{r} |
| 106 | +plot_ly(iris, x = Petal.Length, y = Petal.Width, |
| 107 | + color = as.ordered(Species), mode = "markers") |
| 108 | +``` |
74 | 109 |
|
75 |
| -Sometimes you want to add trace(s) to a plot that derive from a different data frame. |
| 110 | +<div align="center"> |
| 111 | + <a href="https://plot.ly/~agvd/456"> |
| 112 | + <img src="https://plot.ly/~agvd/456.png" height="300" width="600" /> |
| 113 | + </a> |
| 114 | +</div> |
76 | 115 |
|
77 |
| -To add more traces to your plotly, use `add_trace()`. By default, trace information created in `plot_ly()` will carry over to future traces, unless we explictly override it (this helps [avoid repeating yourself](http://en.wikipedia.org/wiki/Don%27t_repeat_yourself)). |
| 116 | +In the case of continuous numeric variables, `plot_ly()` performs a linear mapping between the data and an interpolated color pallette. |
78 | 117 |
|
79 | 118 | ```{r}
|
80 |
| -p2 <- add_trace(p, y = fitted(loess(uempmed ~ as.numeric(date)))) |
81 |
| -p2 |
| 119 | +plot_ly(iris, x = Petal.Length, y = Petal.Width, |
| 120 | + color = Sepal.Length, mode = "markers") |
82 | 121 | ```
|
83 | 122 |
|
84 |
| -To modify the styling of the plot, use `layout()`. |
| 123 | +<div align="center"> |
| 124 | + <a href="https://plot.ly/~agvd/458"> |
| 125 | + <img src="https://plot.ly/~agvd/458.png" height="300" width="600" /> |
| 126 | + </a> |
| 127 | +</div> |
| 128 | + |
| 129 | +The colors argument takes arbitrary color codes of arbitrary length. Here is how we could use it to replicate the default mapping in ggplot2. |
85 | 130 |
|
86 | 131 | ```{r}
|
87 |
| -(p3 <- layout(p2, title = "Median duration of unemployment (in weeks)")) |
| 132 | +plot_ly(iris, x = Petal.Length, y = Petal.Width, |
| 133 | + color = Sepal.Length, colors = c("#132B43", "#56B1F7"), |
| 134 | + mode = "markers") |
88 | 135 | ```
|
89 | 136 |
|
90 |
| -The documentation for valid arguments to `layout()` are under [plotly's R reference](https://plot.ly/r/reference/#layout). In addition to title (a string) , `layout()` also accepts [font](https://plot.ly/r/reference/#font) (a named list). Lets use this argument to change the default font family and size: |
| 137 | +<div align="center"> |
| 138 | + <a href="https://plot.ly/~agvd/438"> |
| 139 | + <img src="https://plot.ly/~agvd/438.png" height="300" width="600" /> |
| 140 | + </a> |
| 141 | +</div> |
91 | 142 |
|
92 |
| -```{r} |
93 |
| -layout(p3, font = list(family = "Courier New, monospace", size = 10)) |
94 |
| -``` |
95 | 143 |
|
96 |
| -If you look at the structure of plotly objects, they are data frames with a class of plotly and a special environment attached. |
| 144 | +#### Diverging color mappings |
| 145 | + |
| 146 | +To obtain a diverging color mapping, just provide a diverging palette to the colors argument. |
97 | 147 |
|
98 | 148 | ```{r}
|
99 |
| -str(p3) |
| 149 | +plot_ly(iris, x = Petal.Length, y = Petal.Width, |
| 150 | + color = Sepal.Length, colors = "PuOr", mode = "markers") |
100 | 151 | ```
|
101 | 152 |
|
102 |
| -This might seem strange, but it yields desirable results since it integrates nicely with other pipeable interfaces that use a data frame their central object (such as [dplyr](http://cran.r-project.org/web/packages/dplyr/index.html)). This means that we can incorporate data manipulation verbs into a sequence of steps leading to a visualization. Here, we take advantage of `dplyr::filter()` to label the highest peak in the time series: |
| 153 | +<div align="center"> |
| 154 | + <a href="https://plot.ly/~agvd/462"> |
| 155 | + <img src="https://plot.ly/~agvd/462.png" height="300" width="600" /> |
| 156 | + </a> |
| 157 | +</div> |
103 | 158 |
|
104 |
| -```{r, message = FALSE, warning = FALSE} |
105 |
| -economics %>% |
106 |
| - plot_ly(x = date, y = uempmed, type = "scatter", showlegend = F) %>% |
107 |
| - add_trace(y = fitted(loess(uempmed ~ as.numeric(date)))) %>% |
108 |
| - layout(title = "Median duration of unemployment (in weeks)") %>% |
109 |
| - dplyr::filter(uempmed == max(uempmed)) %>% |
110 |
| - # annotations is an array of objects (in R, that's a list of named list(s)) |
111 |
| - layout(annotations = list(list(x = date, y = uempmed, text = "Peak", showarrow = T))) |
| 159 | +### The symbol argument |
| 160 | + |
| 161 | +To encode values using symbols, use the symbol argument. |
| 162 | + |
| 163 | +```{r} |
| 164 | +plot_ly(iris, x = Petal.Length, y = Petal.Width, |
| 165 | + symbol = Species, mode = "markers") |
112 | 166 | ```
|
113 | 167 |
|
114 |
| -It's also important to note that plotly visualization don't _require_ a data frame. Chart types that accept a `z` argument |
| 168 | +<div align="center"> |
| 169 | + <a href="https://plot.ly/~agvd/490"> |
| 170 | + <img src="https://plot.ly/~agvd/490.png" height="300" width="600" /> |
| 171 | + </a> |
| 172 | +</div> |
| 173 | + |
| 174 | +To change the default symbols used, use the symbols argument. All the valid symbol types are listed [here](https://plot.ly/r/reference/#marker). |
115 | 175 |
|
116 | 176 | ```{r}
|
117 |
| -str(volcano) |
118 |
| -plot_ly(z = volcano, type = "surface") |
| 177 | +plot_ly(iris, x = Petal.Length, y = Petal.Width, mode = "markers", |
| 178 | + symbol = Species, symbols = c("cross", "square", "triangle-down")) |
119 | 179 | ```
|
120 | 180 |
|
121 |
| -### Figure objects |
| 181 | +<div align="center"> |
| 182 | + <a href="https://plot.ly/~brnvg/549"> |
| 183 | + <img src="https://plot.ly/~brnvg/549.png" height="300" width="600" /> |
| 184 | + </a> |
| 185 | +</div> |
| 186 | + |
| 187 | +### The group argument and `subplot()` |
122 | 188 |
|
123 |
| -Figure objects are plotly objects, but with a fixed location. That is, when you print a figure object, it modifies the already existing plotly (instead of creating a new one). The proper way to initiate a figure object is with `get_figure()`: |
| 189 | +Using the group argument splits the data into different plotly "traces". |
124 | 190 |
|
125 | 191 | ```{r}
|
126 |
| -fig <- get_figure("TestBot", "17555") |
127 |
| -layout(fig, title = paste("Last modified ", Sys.time())) |
| 192 | +plot_ly(iris, x = Petal.Length, y = Petal.Width, |
| 193 | + group = Species, mode = "markers") |
128 | 194 | ```
|
129 | 195 |
|
130 |
| -If you want to modify the styling of trace(s), use `style()`. |
131 | 196 |
|
132 |
| -### `ggplot2` objects |
| 197 | +<div align="center"> |
| 198 | + <a href="https://plot.ly/~brnvg/523"> |
| 199 | + <img src="https://plot.ly/~brnvg/523.png" height="300" width="600" /> |
| 200 | + </a> |
| 201 | +</div> |
133 | 202 |
|
134 |
| -The `ggplotly()` function converts a ggplot object to a plotly object. |
| 203 | +Although we haven't specified a coloring scheme, plotly will employ one on it's own default scheme. The group argument is quite powerful when used in conjunction with `subplot()` in order to anchor traces onto different axes. |
135 | 204 |
|
136 | 205 | ```{r}
|
137 |
| -library(ggplot2) |
138 |
| -(gg <- ggplotly(qplot(mpg, wt, data = mtcars))) |
| 206 | +iris$id <- as.integer(iris$Species) |
| 207 | +p <- plot_ly(iris, x = Petal.Length, y = Petal.Width, group = Species, |
| 208 | + xaxis = paste0("x", id), mode = "markers") |
| 209 | +subplot(p) |
139 | 210 | ```
|
140 | 211 |
|
141 |
| -This means we can alter (converted) ggplot(s) as if they were plotly object(s). |
| 212 | +<div align="center"> |
| 213 | + <a href="https://plot.ly/~brnvg/543"> |
| 214 | + <img src="https://plot.ly/~brnvg/543.png" height="300" width="600" /> |
| 215 | + </a> |
| 216 | +</div> |
| 217 | + |
| 218 | +Since `subplot()` does not assume x/y axes are on a common scale, it does not impose any restrictions on the range by default. However, you can change this by pre-specifying the range of the [axis objects](https://plot.ly/r/reference/#xaxis) via the `layout()` function. |
142 | 219 |
|
143 | 220 | ```{r}
|
144 |
| -layout(gg, font = list(family = "Courier New, monospace")) |
| 221 | +p2 <- layout(p, |
| 222 | + xaxis = list(range = range(Petal.Length) + c(-0.1, 0.1)), |
| 223 | + yaxis = list(range = range(Petal.Width) + c(-0.1, 0.1)) |
| 224 | +) |
| 225 | +subplot(p2) |
145 | 226 | ```
|
146 | 227 |
|
147 |
| -### Multiple plots |
| 228 | +<div align="center"> |
| 229 | + <a href="https://plot.ly/~brnvg/545"> |
| 230 | + <img src="https://plot.ly/~brnvg/545.png" height="300" width="600" /> |
| 231 | + </a> |
| 232 | +</div> |
| 233 | + |
| 234 | +[See here](https://plot.ly/r/map-subplots-and-small-multiples/) for another example of using the group argument to make small multiples (with maps!). |
148 | 235 |
|
149 |
| -ggplot2's `facet_wrap()` and `facet_grid()` are a nice way to produce [small multiples](http://en.wikipedia.org/wiki/Small_multiple), but sometimes you want more flexibility in laying out multiple plots in a single view. Advanced ggplot2 users might be familiar with using grid or [gridExtra package](http://lightonphiri.org/blog/ggplot2-multiple-plots-in-one-graph-using-gridextra) for this sort of thing, but these approaches communicate directly with R's graphics devices, so that approach won't work for plotly. |
| 236 | +## Manually adding traces |
150 | 237 |
|
151 |
| -Thankfully, plotly provides a `subplots()` function: |
| 238 | +Sometimes you may want multiple traces on a plot, but have different traces from different data sources. In this case, the `add_trace()` function and it's (optional) `data` argument come in handy. |
152 | 239 |
|
153 | 240 | ```{r}
|
154 |
| -a1 <- layout(p2, title = "Median duration of unemployment (in weeks)") |
155 |
| -a2 <- plot_ly(economics, x = date, y = unemploy, showlegend = F) |
156 |
| -subplot(a1, a2) |
| 241 | +m <- loess(uempmed ~ as.numeric(date), economics) |
| 242 | +efit <- data.frame(date = economics$date, yhat = fitted(m)) |
| 243 | +
|
| 244 | +plot_ly(economics, x = date, y = uempmed, name = "observed") %>% |
| 245 | + add_trace(y = yhat, name = "estimated", data = efit) |
157 | 246 | ```
|
158 | 247 |
|
159 |
| -By default, `subplot()` will assume you want all your plots in a single row. Use the `nrows` argument to change that default: |
| 248 | +<div align="center"> |
| 249 | + <a href="https://plot.ly/~brnvg/547"> |
| 250 | + <img src="https://plot.ly/~brnvg/547.png" height="300" width="600" /> |
| 251 | + </a> |
| 252 | +</div> |
| 253 | + |
| 254 | +Note that the date information carries over from the first trace to the second. In fact, by default, information from the first trace carries over to all subsequent traces unless the property is overwritten or if we set `inherit = FALSE` in `plot_ly()` (this helps [avoid repeating yourself](http://en.wikipedia.org/wiki/Don%27t_repeat_yourself)). |
| 255 | + |
| 256 | +## Mixing data manipulation and visualization verbs |
| 257 | + |
| 258 | +If you look at the structure of plotly objects, they are actually data frames with a class of plotly and a special environment attached (this environment tracks the mapping from data to visual properties). |
160 | 259 |
|
161 | 260 | ```{r}
|
162 |
| -subplot(a1, a2, nrows = 2) |
| 261 | +str(p <- plot_ly(economics, x = date, y = uempmed)) |
163 | 262 | ```
|
164 | 263 |
|
165 |
| -You can also manually add xaxis/yaxis domain information. In fact, this approach makes it fairly easy to create [inset plots](https://plot.ly/javascript-graphing-library/insets/). |
| 264 | +Doing this allows us to mix data manipulation and visualization verbs in a [pure(ly) functional, predictable and pipeable](https://dl.dropboxusercontent.com/u/41902/pipe-dsls.pdf) manner. Here, we take advantage of [dplyr](http://cran.r-project.org/web/packages/dplyr/index.html)'s `filter()` verb to label the highest peak in the time series: |
| 265 | + |
| 266 | +```{r, message = FALSE, warning = FALSE} |
| 267 | +p %>% |
| 268 | + add_trace(y = fitted(loess(uempmed ~ as.numeric(date)))) %>% |
| 269 | + layout(title = "Median duration of unemployment (in weeks)", |
| 270 | + showlegend = FALSE) %>% |
| 271 | + dplyr::filter(uempmed == max(uempmed)) %>% |
| 272 | + layout(annotations = list(x = date, y = uempmed, text = "Peak", showarrow = T)) |
| 273 | +``` |
| 274 | + |
| 275 | +<div align="center"> |
| 276 | + <a href="https://plot.ly/~brnvg/592"> |
| 277 | + <img src="https://plot.ly/~brnvg/592.png" height="300" width="600" /> |
| 278 | + </a> |
| 279 | +</div> |
| 280 | + |
| 281 | + |
| 282 | +Although data frames can be thought of as the central object in this package, plotly visualizations don't actually _require_ a data frame. This makes chart types that accept a `z` argument especially easy to use if you have a numeric matrix: |
166 | 283 |
|
167 | 284 | ```{r}
|
168 |
| -a2_small <- layout(a2, |
169 |
| - xaxis = list(domain = c(0.05, 0.35)), |
170 |
| - yaxis = list(domain = c(0.7, 1))) |
171 |
| -subplot(a1, a2_small) |
| 285 | +plot_ly(z = volcano, type = "surface") |
172 | 286 | ```
|
| 287 | + |
| 288 | +<div align="center"> |
| 289 | + <a href="https://plot.ly/~brnvg/594"> |
| 290 | + <img src="https://plot.ly/~brnvg/594.png" height="300" width="600" /> |
| 291 | + </a> |
| 292 | +</div> |
0 commit comments