Skip to content

Commit 4b1ada3

Browse files
committed
change meaning of add_area(); deprecate add_scattergeo() in favor of geo(); add mapbox(), add_pie(), add_mesh()
1 parent c207e70 commit 4b1ada3

File tree

9 files changed

+267
-34
lines changed

9 files changed

+267
-34
lines changed

NAMESPACE

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ export(add_histogram2d)
7272
export(add_histogram2dcontour)
7373
export(add_lines)
7474
export(add_markers)
75+
export(add_mesh)
7576
export(add_paths)
77+
export(add_pie)
7678
export(add_polygons)
7779
export(add_ribbons)
7880
export(add_scattergeo)
@@ -95,6 +97,7 @@ export(event_data)
9597
export(export)
9698
export(filter)
9799
export(filter_)
100+
export(geo)
98101
export(geom2trace)
99102
export(get_figure)
100103
export(gg2list)
@@ -108,6 +111,7 @@ export(hide_legend)
108111
export(knit_print.plotly_figure)
109112
export(last_plot)
110113
export(layout)
114+
export(mapbox)
111115
export(mutate)
112116
export(mutate_)
113117
export(offline)

R/add.R

Lines changed: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,20 @@ add_trace <- function(p, ..., color, symbol, size, linetype,
8282
attrs <- modify_list(p$x$attrs[[1]], attrs)
8383
}
8484

85+
if (is_mapbox(p) || is_geo(p)) {
86+
attrs[["x"]] <- attrs[["x"]] %||% attrs[["lat"]]
87+
attrs[["y"]] <- attrs[["y"]] %||% attrs[["lon"]]
88+
if (!grepl("scatter", attrs[["type"]])) {
89+
stop("Cant add a '", attrs[["type"]], "' trace to a map object", call. = FALSE)
90+
}
91+
if (is_mapbox(p)) {
92+
attrs[["type"]] <- "scattermapbox"
93+
}
94+
if (is_geo(p)) {
95+
attrs[["type"]] <- "scattergeo"
96+
}
97+
}
98+
8599
p$x$attrs <- c(
86100
p$x$attrs %||% list(),
87101
setNames(list(attrs), p$x$cur_data)
@@ -255,32 +269,57 @@ add_ribbons <- function(p, x = NULL, ymin = NULL, ymax = NULL, ...,
255269
)
256270
}
257271

258-
259272
#' @inheritParams add_trace
260273
#' @rdname add_trace
274+
#' @param r For polar chart only. Sets the radial coordinates.
275+
#' @param t For polar chart only. Sets the radial coordinates.
261276
#' @export
262277
#' @examples
263-
#' huron <- data.frame(year = 1875:1972, level = as.vector(LakeHuron))
264-
#' plot_ly(huron, x = ~year, ymax = ~level) %>% add_area()
265-
add_area <- function(p, x = NULL, ymax = NULL, ...,
278+
#' p <- plot_ly(plotly::wind, r = ~r, t = ~t) %>% add_area(color = ~nms)
279+
#' layout(p, radialaxis = list(ticksuffix = "%"), orientation = 270)
280+
add_area <- function(p, r = NULL, t = NULL, ...,
266281
data = NULL, inherit = TRUE) {
267-
268282
if (inherit) {
269-
x <- x %||% p$x$attrs[[1]][["x"]]
270-
ymax <- ymax %||% p$x$attrs[[1]][["ymax"]]
283+
r <- t %||% p$x$attrs[[1]][["r"]]
284+
t <- t %||% p$x$attrs[[1]][["t"]]
271285
}
272-
if (is.null(x) || is.null(ymax)) {
273-
stop("Must supply `x`/`ymax` attributes", call. = FALSE)
286+
if (is.null(r) || is.null(t)) {
287+
stop("Must supply `r`/`t` attributes", call. = FALSE)
274288
}
275289
add_trace_classed(
276-
p, class = c("plotly_area", "plotly_ribbon", "plotly_polygon"),
277-
x = x, ymax = ymax,
278-
type = "scatter", fill = "toself", mode = "lines", hoveron = "points",
290+
p, class = "plotly_area", r = r, t = t, type = "area",
279291
..., data = data, inherit = inherit
280292
)
281293
}
282294

283-
295+
#' @inheritParams add_trace
296+
#' @rdname add_trace
297+
#' @param values the value to associated with each slice of the pie.
298+
#' @param labels the labels (categories) corresponding to \code{values}.
299+
#' @export
300+
#' @examples
301+
#' ds <- data.frame(
302+
#' labels = c("A", "B", "C"),
303+
#' values = c(10, 40, 60)
304+
#' )
305+
#'
306+
#' plot_ly(ds, labels = ~labels, values = ~values) %>%
307+
#' add_pie() %>%
308+
#' layout(title = "Basic Pie Chart using Plotly")
309+
add_pie <- function(p, values = NULL, labels = NULL, ...,
310+
data = NULL, inherit = TRUE) {
311+
if (inherit) {
312+
values <- values %||% p$x$attrs[[1]][["values"]]
313+
labels <- labels %||% p$x$attrs[[1]][["labels"]]
314+
}
315+
if (is.null(values)) {
316+
stop("Must supply `values`", call. = FALSE)
317+
}
318+
add_trace_classed(
319+
p, class = "plotly_pie", values = values, labels = labels, type = "pie",
320+
..., data = data, inherit = inherit
321+
)
322+
}
284323

285324
#' @inheritParams add_trace
286325
#' @rdname add_trace
@@ -464,24 +503,37 @@ add_surface <- function(p, z = NULL, ..., data = NULL, inherit = TRUE) {
464503
)
465504
}
466505

467-
468506
#' @inheritParams add_trace
469507
#' @rdname add_trace
470-
#' @param geo anchor this trace on which geo object?
471508
#' @export
472509
#' @examples
473-
#' plot_ly() %>% add_scattergeo()
474-
add_scattergeo <- function(p, geo = NULL, ..., data = NULL, inherit = TRUE) {
510+
#' plot_ly(x = c(0, 0, 1), y = c(0, 1, 0), z = c(0, 0, 0)) %>% add_mesh()
511+
add_mesh <- function(p, x = NULL, y = NULL, z = NULL, ...,
512+
data = NULL, inherit = TRUE) {
475513
if (inherit) {
476-
geo <- geo %||% p$x$attrs[[1]][["geo"]] %||% "geo"
514+
x <- x %||% p$x$attrs[[1]][["x"]]
515+
y <- y %||% p$x$attrs[[1]][["y"]]
516+
z <- z %||% p$x$attrs[[1]][["z"]]
517+
}
518+
if (is.null(x) || is.null(y) || is.null(z)) {
519+
stop("Must supply `x`/`y`/`z` attributes", call. = FALSE)
477520
}
478521
add_trace_classed(
479-
p, class = "plotly_scattergeo", type = "scattergeo", geo = geo,
522+
p, class = "plotly_mesh", x = x, y = y, z = z, type = "mesh3d",
480523
..., data = data, inherit = inherit
481524
)
482525
}
483526

484527

528+
#' @inheritParams add_trace
529+
#' @rdname add_trace
530+
#' @export
531+
#'
532+
add_scattergeo <- function(p, ...) {
533+
.Deprecated("geo")
534+
p
535+
}
536+
485537
#' @inheritParams add_trace
486538
#' @rdname add_trace
487539
#' @export
@@ -515,12 +567,16 @@ add_trace_classed <- function(p, class = "plotly_polygon", ...) {
515567

516568
# retrieve the non-plotly.js attributes for a given trace
517569
special_attrs <- function(trace) {
518-
switch(
570+
attrs <- switch(
519571
class(trace)[[1]],
520-
plotly_area = c("ymax"),
521572
plotly_segment = c("xend", "yend"),
522573
plotly_ribbon = c("ymin", "ymax")
523574
)
575+
# for data training, we temporarily rename lat/lon as x/y
576+
if (isTRUE(trace[["type"]] %in% c("scattermapbox", "scattergeo"))) {
577+
attrs <- c(attrs, c("x", "y"))
578+
}
579+
attrs
524580
}
525581

526582

R/plotly.R

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ plot_ly <- function(data = data.frame(), ..., type = NULL,
8484
}
8585
# "native" plotly arguments
8686
attrs <- list(...)
87+
8788
# warn about old arguments that are no longer supported
8889
for (i in c("filename", "fileopt", "world_readable")) {
8990
if (is.null(attrs[[i]])) next
@@ -141,6 +142,60 @@ plot_ly <- function(data = data.frame(), ..., type = NULL,
141142
}
142143

143144

145+
#' Initiate a plotly-mapbox object
146+
#'
147+
#' Use this function instead of \code{\link{plot_ly}()} to initialize
148+
#' a plotly-mapbox object. This enforces the entire plot so use
149+
#' the scattermapbox trace type, and enables higher level geometries
150+
#' like \code{\link{add_polygons}()} to work
151+
#'
152+
#' @param ... arguments passed along to \code{\link{plot_ly}()}. They should be
153+
#' valid scattermapbox attributes - \url{https://plot.ly/r/reference/#scattermapbox}.
154+
#' Note that x/y can also be used in place of lat/lon.
155+
#' @export
156+
#' @examples \dontrun{
157+
#'
158+
#' map_data("world", "canada") %>%
159+
#' group_by(group) %>%
160+
#' mapbox(x = ~lat, y = ~long) %>%
161+
#' add_polygons() %>%
162+
#' layout(
163+
#' mapbox = list(
164+
#' center = list(lat = ~median(lat), lon = ~median(long))
165+
#' )
166+
#' )
167+
#' }
168+
#'
169+
mapbox <- function(data = data.frame(), ...) {
170+
p <- plot_ly(data, ...)
171+
p <- config(p, mapboxAccessToken = mapbox_token())
172+
p$x$mapType <- "mapbox"
173+
p
174+
}
175+
176+
#' Initiate a plotly-geo object
177+
#'
178+
#' Use this function instead of \code{\link{plot_ly}()} to initialize
179+
#' a plotly-geo object. This enforces the entire plot so use
180+
#' the scattergeo trace type, and enables higher level geometries
181+
#' like \code{\link{add_polygons}()} to work
182+
#'
183+
#' @param ... arguments passed along to \code{\link{plot_ly}()}.
184+
#' @export
185+
#' @examples
186+
#'
187+
#' map_data("world", "canada") %>%
188+
#' group_by(group) %>%
189+
#' geo(x = ~lat, y = ~long) %>%
190+
#' add_polygons()
191+
#'
192+
geo <- function(data = data.frame(), ...) {
193+
p <- plot_ly(data, ...)
194+
p$x$mapType <- "geo"
195+
p
196+
}
197+
198+
144199
#' Convert a list to a plotly htmlwidget object
145200
#'
146201
#' @param x a plotly object.

R/plotly_build.R

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ plotly_build.plotly <- function(p) {
108108
}
109109
}
110110
}
111-
111+
112112
if (inherits(trace, c("plotly_surface", "plotly_contour"))) {
113113
# TODO: generate matrix for users?
114114
# (1) if z is vector, and x/y are null throw error
@@ -269,6 +269,17 @@ plotly_build.plotly <- function(p) {
269269
)
270270
}
271271
}
272+
273+
# attribute naming correction for "geo-like" traces
274+
if (is_geo(p) || is_mapbox(p)) {
275+
p$x$layout[grepl("^[x-y]axis", names(p$x$layout))] <- NULL
276+
p$x$data <- lapply(p$x$data, function(tr) {
277+
tr[["lat"]] <- tr[["lat"]] %||% tr[["y"]]
278+
tr[["lon"]] <- tr[["lon"]] %||% tr[["x"]]
279+
tr[c("x", "y")] <- NULL
280+
tr
281+
})
282+
}
272283

273284
# polar charts don't like null width/height keys
274285
if (is.null(p$x$layout[["height"]])) p$x$layout[["height"]] <- NULL
@@ -298,9 +309,6 @@ plotly_build.plotly <- function(p) {
298309
# ----------------------------------------------------------------
299310

300311
train_data <- function(data, trace) {
301-
if (inherits(trace, "plotly_area")) {
302-
data$ymin <- 0
303-
}
304312
if (inherits(trace, "plotly_ribbon")) {
305313
data <- ribbon_dat(data)
306314
}

R/utils.R

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,29 @@ arrange_safe <- function(data, vars) {
7373
if (length(vars)) dplyr::arrange_(data, .dots = vars) else data
7474
}
7575

76+
is_mapbox <- function(p) {
77+
identical(p$x[["mapType"]], "mapbox")
78+
}
79+
80+
is_geo <- function(p) {
81+
identical(p$x[["mapType"]], "geo")
82+
}
83+
84+
# retrive mapbox token if one is set; otherwise, throw error
85+
mapbox_token <- function() {
86+
token <- Sys.getenv("MAPBOX_TOKEN", NA)
87+
if (is.na(token)) {
88+
stop(
89+
"No mapbox access token found. Obtain a token here\n",
90+
"https://www.mapbox.com/help/create-api-access-token/\n",
91+
"Once you have a token, assign it to an environment variable \n",
92+
"named 'MAPBOX_TOKEN', for example,\n",
93+
"Sys.setenv('MAPBOX_TOKEN' = 'secret token')", call. = FALSE
94+
)
95+
}
96+
token
97+
}
98+
7699
# make sure plot attributes adhere to the plotly.js schema
77100
verify_attr_names <- function(p) {
78101
# some layout attributes (e.g., [x-y]axis can have trailing numbers)

man/add_trace.Rd

Lines changed: 30 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)