Skip to content

Commit daabc1a

Browse files
committed
new high-level args for better control over stroke; overhaul arg mapping for better modularity/readability; update docs
1 parent 87cb166 commit daabc1a

11 files changed

Lines changed: 580 additions & 256 deletions

File tree

NEWS.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
## NEW FEATURES & IMPROVEMENTS
44

55
* Upgraded to plotly.js v1.35.2. A _huge_ amount of features and improvements have been made since v1.29.2 (i.e., the version included in the last CRAN release of the R package - v4.7.1). Highlights include a complete re-write of `scattergl` to make it nearly feature complete with `scatter`, localization of text rendering (i.e., international translations), and two new trace types (`violin` & `table`). Read more about the v1.32.0 release [here](https://codeburst.io/notes-from-the-latest-plotly-js-release-b035a5b43e21) and the complete list of changes [here](https://github.com/plotly/plotly.js/releases).
6-
* The selection mode can now switch from 'transient' to 'persistent' by holding the 'shift' key. It's still possible to _force_ persistent selection by setting `persistent = TRUE` in `highlight()`, but `persistent = FALSE` (the default) is now recommended since it allows one to switch between [persistent/transient selection](https://plotly-book.cpsievert.me/linking-views-without-shiny.html#transient-versus-persistent-selection) in the browser, rather than at the command line.
6+
* Support for **sf** (simple feature) data structures was added to `plot_ly()`, `plot_mapbox()`, and `plot_geo()` (via the new `add_sf()` function). See [this blog post](https://blog.cpsievert.me/2018/02/12/visualizing-geo-spatial-data-with-sf-and-plotly) for an overview.
7+
* New "special arguments" `stroke`, `strokes`, `alpha_stroke`, `span`, and `spans` were added for easier control over the stroke (i.e., outline) appearance of various (filled) graphical marks. For an overview, see the **sf** blog post linked to in the bullet point above.
8+
* The selection (i.e., linked-brushing) mode can now switch from 'transient' to 'persistent' by holding the 'shift' key. It's still possible to _force_ persistent selection by setting `persistent = TRUE` in `highlight()`, but `persistent = FALSE` (the default) is now recommended since it allows one to switch between [persistent/transient selection](https://plotly-book.cpsievert.me/linking-views-without-shiny.html#transient-versus-persistent-selection) in the browser, rather than at the command line.
79
* Instead of an error, `ggplotly(NULL, "message")` and `plotly_build(NULL, "message")` now returns `htmltools::div("message")`, making it easier to relay messages in shiny when data isn't yet ready to plot (see #1116)
810
* The `animation_button()` function gains a `label` argument, making it easier to control the label of an animation button generated through the `frame` API (see #1205).
911

1012
## CHANGES
1113

12-
* The `color` argument now supplies a default `fillcolor` which makes it much easier to map data values to polygon fills (e.g., choropleth maps). For an example, `plot_mapbox(mn_res, color = ~INDRESNAME)` or `plot_mapbox(mn_res, split = ~INDRESNAME, color = ~AREA, showlegend = FALSE, line = list(color = "black"))`.
14+
* The `color` argument now maps to `fillcolor`, making it much easier to use polygon fills to encode data values (e.g., choropleth maps). For backwards-compatibilty reasons, when `color` maps to `fillcolor`, `alpha` defaults to 0.5 (instead of 1). For an example, `plot_mapbox(mn_res, color = ~INDRESNAME)` or `plot_mapbox(mn_res, split = ~INDRESNAME, color = ~AREA, showlegend = FALSE, stroke = I("black"))`.
1315
* The `color` argument no longer automatically add `"markers"` to the `mode` attribute for scatter/scattergl trace types. Those who wish to have the old behavior back, should add `"markers"` to the `mode` explicity (e.g., change `plot_ly(economics, x = ~pce, y = ~pop, color = ~as.numeric(date), mode = "lines")` to `plot_ly(economics, x = ~pce, y = ~pop, color = ~as.numeric(date), mode = "lines+markers")`)
1416
* The `elementId` field is no longer populated, which fixes the "Ignoring explicitly provided widget ID" warning in shiny applications (see #985).
1517

R/plotly.R

Lines changed: 86 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,85 @@
11
#' Initiate a plotly visualization
22
#'
3-
#' Transform data into a plotly visualization.
3+
#' This function maps R objects to [plotly.js](https://plot.ly/javascript/),
4+
#' an (MIT licensed) web-based interactive charting library. It provides
5+
#' abstractions for doing common things (e.g. mapping data values to
6+
#' fill colors (via `color`) or creating [animation]s (via `frame`)) and sets
7+
#' some different defaults to make the interface feel more 'R-like'
8+
#' (i.e., closer to [plot()] and [ggplot::qplot()]).
49
#'
5-
#' There are a number of "visual properties" that aren't included in the official
6-
#' Reference section (see below).
10+
#' @details Unless `type` is specified, this function just initiates a plotly
11+
#' object with 'global' attributes that are passed onto downstream uses of
12+
#' [add_trace()] (or similar). A [formula] must always be used when
13+
#' referencing column name(s) in `data` (e.g. `plot_ly(mtcars, x = ~wt)`).
14+
#' Formulas are optional when supplying values directly, but they do
15+
#' help inform default axis/scale titles
16+
#' (e.g., `plot_ly(x = mtcars$wt)` vs `plot_ly(x = ~mtcars$wt)`)
717
#'
818
#' @param data A data frame (optional) or [crosstalk::SharedData] object.
9-
#' @param ... These arguments are documented at \url{https://plot.ly/r/reference/}
10-
#' Note that acceptable arguments depend on the value of `type`.
11-
#' @param type A character string describing the type of trace.
12-
#' @param color A formula containing a name or expression.
13-
#' Values are scaled and mapped to color codes based on the value of
14-
#' `colors` and `alpha`. To avoid scaling, wrap with [I()],
15-
#' and provide value(s) that can be converted to rgb color codes by
16-
#' [grDevices::col2rgb()].
19+
#' @param ... Arguments (i.e., attributes) passed along to the trace `type`.
20+
#' See [schema()] for a list of acceptable attributes for a given trace `type`
21+
#' (by going to `traces` -> `type` -> `attributes`). Note that attributes
22+
#' provided at this level may override other arguments
23+
#' (e.g. `plot_ly(x = 1:10, y = 1:10, color = I("red"), marker = list(color = "blue"))`).
24+
#' @param type A character string specifying the trace type (e.g. `"scatter"`, `"bar"`, `"box"`, etc).
25+
#' If specified, it *always* creates a trace, otherwise
26+
#' @param color Values mapped to relevant 'fill-color' attribute(s)
27+
#' (e.g. [fillcolor](https://plot.ly/r/reference#scatter-fillcolor),
28+
#' [marker.color](https://plot.ly/r/reference#scatter-marker-color),
29+
#' [textfont.color](https://plot.ly/r/reference/#scatter-textfont-color), etc.).
30+
#' The mapping from data values to color codes may be controlled using
31+
#' `colors` and `alpha`, or avoided altogether via [I()] (e.g., `color = I("red")`).
32+
#' Any color understood by [grDevices::col2rgb()] may be used in this way.
1733
#' @param colors Either a colorbrewer2.org palette name (e.g. "YlOrRd" or "Blues"),
1834
#' or a vector of colors to interpolate in hexadecimal "#RRGGBB" format,
1935
#' or a color interpolation function like `colorRamp()`.
20-
#' @param alpha A number between 0 and 1 specifying the alpha channel applied to color.
21-
#' @param symbol A formula containing a name or expression.
22-
#' Values are scaled and mapped to symbols based on the value of `symbols`.
23-
#' To avoid scaling, wrap with [I()], and provide valid
24-
#' [pch()] values and/or valid plotly symbol(s) as a string
25-
#' @param symbols A character vector of symbol types.
26-
#' Either valid \link{pch} or plotly symbol codes may be supplied.
27-
#' @param linetype A formula containing a name or expression.
28-
#' Values are scaled and mapped to linetypes based on the value of
29-
#' `linetypes`. To avoid scaling, wrap with [I()].
30-
#' @param linetypes A character vector of line types.
31-
#' Either valid \link{par} (lty) or plotly dash codes may be supplied.
32-
#' @param size A formula containing a name or expression yielding a numeric vector.
33-
#' Values are scaled according to the range specified in `sizes`.
34-
#' @param sizes A numeric vector of length 2 used to scale sizes to pixels.
35-
#' @param split A formula containing a name or expression. Similar to
36-
#' [group_by()], but ensures at least one trace for each unique
37-
#' value. This replaces the functionality of the (now deprecated)
38-
#' `group` argument.
39-
#' @param frame A formula containing a name or expression. The resulting value
40-
#' is used to split data into frames, and then animated.
36+
#' @param stroke Similar to `color`, but values are mapped to relevant 'stroke-color' attribute(s)
37+
#' (e.g., [marker.line.color](https://plot.ly/r/reference#scatter-marker-line-color)
38+
#' and [line.color](https://plot.ly/r/reference#scatter-line-color)
39+
#' for filled polygons). If not specified, `stroke` inherits from `color`.
40+
#' @param strokes Similar to `colors`, but controls the `stroke` mapping.
41+
#' @param alpha A number between 0 and 1 specifying the alpha channel applied to `color`.
42+
#' Defaults to 0.5 when mapping to [fillcolor](https://plot.ly/r/reference#scatter-fillcolor) and 1 otherwise.
43+
#' @param alpha_stroke Similar to `alpha`, but applied to `stroke`.
44+
#' @param symbol (Discrete) values mapped to [marker.symbol](https://plot.ly/r/reference#scatter-marker-symbol).
45+
#' The mapping from data values to symbols may be controlled using
46+
#' `symbols`, or avoided altogether via [I()] (e.g., `symbol = I("pentagon")`).
47+
#' Any [pch] value or [symbol name](https://plot.ly/r/reference#scatter-marker-symbol) may be used in this way.
48+
#' @param symbols A character vector of [pch] values or [symbol names](https://plot.ly/r/reference#scatter-marker-symbol).
49+
#' @param linetype (Discrete) values mapped to [line.dash](https://plot.ly/r/reference#scatter-line-dash).
50+
#' The mapping from data values to symbols may be controlled using
51+
#' `linetypes`, or avoided altogether via [I()] (e.g., `linetype = I("dash")`).
52+
#' Any `lty` (see [par]) value or [dash name](https://plot.ly/r/reference#scatter-line-dash) may be used in this way.
53+
#' @param linetypes A character vector of `lty` values or [dash names](https://plot.ly/r/reference#scatter-line-dash)
54+
#' @param size (Numeric) values mapped to relevant 'fill-size' attribute(s)
55+
#' (e.g., [marker.size](https://plot.ly/r/reference#scatter-marker-size),
56+
#' [textfont.size](https://plot.ly/r/reference#scatter-textfont-size), etc).
57+
#' The mapping from data values to symbols may be controlled using
58+
#' `sizes`, or avoided altogether via [I()] (e.g., `size = I(30)`).
59+
#' @param sizes A numeric vector of length 2 used to scale `size` to pixels.
60+
#' @param span (Numeric) values mapped to relevant 'stroke-size' attribute(s)
61+
#' (e.g., [marker.line.width](https://plot.ly/r/reference#scatter-marker-line-width))
62+
#' The mapping from data values to symbols may be controlled using
63+
#' `spans`, or avoided altogether via [I()] (e.g., `span = I(30)`).
64+
#' @param spans A numeric vector of length 2 used to scale `span` to pixels.
65+
#' @param split (Discrete) values used to create multiple traces (one trace per value).
66+
#' @param frame (Discrete) values used to create animation frames.
4167
#' @param width Width in pixels (optional, defaults to automatic sizing).
4268
#' @param height Height in pixels (optional, defaults to automatic sizing).
4369
#' @param source a character string of length 1. Match the value of this string
4470
#' with the source argument in [event_data()] to retrieve the
4571
#' event data corresponding to a specific plot (shiny apps can have multiple plots).
4672
#' @author Carson Sievert
73+
#' @references <https://plotly-book.cpsievert.me/the-plotly-cookbook.html>
4774
#' @seealso \itemize{
48-
#' \item For initializing a plotly-geo object: [plot_geo()].
49-
#' \item For initializing a plotly-mapbox object: [plot_mapbox()].
50-
#' \item For translating a ggplot2 object to a plotly object: [ggplotly()].
75+
#' \item For initializing a plotly-geo object: [plot_geo()]
76+
#' \item For initializing a plotly-mapbox object: [plot_mapbox()]
77+
#' \item For translating a ggplot2 object to a plotly object: [ggplotly()]
5178
#' \item For modifying any plotly object: [layout()], [add_trace()], [style()]
52-
#' \item
79+
#' \item For linked brushing: [highlight()]
80+
#' \item For arranging multiple plots: [subplot()], [crosstalk::bscols()]
81+
#' \item For inspecting plotly objects: [plotly_json()]
82+
#' \item For quick, accurate, and searchable plotly.js reference: [schema()]
5383
#' }
5484
#' @export
5585
#' @examples
@@ -91,9 +121,14 @@
91121
#' }
92122
#'
93123
plot_ly <- function(data = data.frame(), ..., type = NULL,
94-
color, colors = NULL, alpha = 1, symbol, symbols = NULL,
95-
size, sizes = c(10, 100), linetype, linetypes = NULL,
96-
split, frame, width = NULL, height = NULL, source = "A") {
124+
color, colors = NULL, alpha = NULL,
125+
stroke, strokes = NULL, alpha_stroke = 1,
126+
size, sizes = c(10, 100),
127+
span, spans = c(1, 20),
128+
symbol, symbols = NULL,
129+
linetype, linetypes = NULL,
130+
split, frame,
131+
width = NULL, height = NULL, source = "A") {
97132

98133
if (!is.data.frame(data) && !crosstalk::is.SharedData(data)) {
99134
stop("First argument, `data`, must be a data frame or shared data.", call. = FALSE)
@@ -122,18 +157,25 @@ plot_ly <- function(data = data.frame(), ..., type = NULL,
122157

123158
# tack on variable mappings
124159
attrs$color <- if (!missing(color)) color
160+
attrs$stroke <- if (!missing(stroke)) stroke
161+
attrs$size <- if (!missing(size)) size
162+
attrs$span <- if (!missing(span)) span
125163
attrs$symbol <- if (!missing(symbol)) symbol
126164
attrs$linetype <- if (!missing(linetype)) linetype
127-
attrs$size <- if (!missing(size)) size
128165
attrs$split <- if (!missing(split)) split
129166
attrs$frame <- if (!missing(frame)) frame
130167

131168
# tack on scale ranges
132169
attrs$colors <- colors
170+
attrs$strokes <- strokes
133171
attrs$alpha <- alpha
172+
attrs$alpha_stroke <- alpha_stroke
173+
attrs$sizes <- sizes
174+
attrs$spans <- spans
134175
attrs$symbols <- symbols
135176
attrs$linetypes <- linetypes
136-
attrs$sizes <- sizes
177+
178+
# and, of course, the trace type
137179
attrs$type <- type
138180

139181
# id for tracking attribute mappings and finding the most current data
@@ -176,6 +218,9 @@ plot_ly <- function(data = data.frame(), ..., type = NULL,
176218
#'
177219
#' @examples \dontrun{
178220
#'
221+
#' plot_mapbox(res_mn)
222+
#' plot_mapbox(res_mn, color = ~INDRESNAME)
223+
#'
179224
#' map_data("world", "canada") %>%
180225
#' group_by(group) %>%
181226
#' plot_mapbox(x = ~long, y = ~lat) %>%

0 commit comments

Comments
 (0)