Skip to content

Commit b33bb7e

Browse files
authored
Merge pull request #725 from ropensci/maps
Maps
2 parents 64abe0d + 81b27ab commit b33bb7e

File tree

15 files changed

+247
-112
lines changed

15 files changed

+247
-112
lines changed

NAMESPACE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ export(event_data)
9797
export(export)
9898
export(filter)
9999
export(filter_)
100-
export(geo)
101100
export(geom2trace)
102101
export(get_figure)
103102
export(gg2list)
@@ -111,11 +110,12 @@ export(hide_legend)
111110
export(knit_print.plotly_figure)
112111
export(last_plot)
113112
export(layout)
114-
export(mapbox)
115113
export(mutate)
116114
export(mutate_)
117115
export(offline)
116+
export(plot_geo)
118117
export(plot_ly)
118+
export(plot_mapbox)
119119
export(plotly)
120120
export(plotlyOutput)
121121
export(plotly_IMAGE)

NEWS.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
# 4.5.0 -- 21 September 2016
2+
3+
## NEW FEATURES
4+
5+
* Added the `plot_mapbox()` and `plot_geo()` functions, which make it easier to work with the "scattermapbox", "scattergeo", and "choropleth" trace types. See the maps chapter of the plotly book for examples -- <https://cpsievert.github.io/plotly_book/maps.html>
6+
* Added the `add_mesh3d()` and `add_pie()` functions as wrappers around the "mesh3d", and "pie" trace types.
7+
8+
## CHANGES
9+
10+
* The `add_scattergeo()` and `add_choropleth()` functions have been deprecated in favor of `plot_geo()`.
11+
* The `add_area(...)` function changed it's meaning from `add_lines(..., fill = 'tozeroy')` to a wrapper around the area trace <https://plot.ly/r/reference/#area>. This is more consistent with the naming conventions already in place for other `add_()` functions.
12+
* `add_ribbons()` now shows points (instead of fill) on hover.
13+
114
# 4.4.5 -- 19 September 2016
215

316
## NEW FEATURES

R/add.R

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,6 @@ 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-
9985
p$x$attrs <- c(
10086
p$x$attrs %||% list(),
10187
setNames(list(attrs), p$x$cur_data)
@@ -528,7 +514,6 @@ add_mesh <- function(p, x = NULL, y = NULL, z = NULL, ...,
528514
#' @inheritParams add_trace
529515
#' @rdname add_trace
530516
#' @export
531-
#'
532517
add_scattergeo <- function(p, ...) {
533518
.Deprecated("geo")
534519
p
@@ -537,24 +522,10 @@ add_scattergeo <- function(p, ...) {
537522
#' @inheritParams add_trace
538523
#' @rdname add_trace
539524
#' @export
540-
#' @examples
541-
#' density <- state.x77[, "Population"] / state.x77[, "Area"]
542-
#' plot_ly(z = ~density) %>%
543-
#' add_choropleth(locations = state.abb, locationmode = 'USA-states') %>%
544-
#' layout(geo = list(scope = "usa"))
545525
add_choropleth <- function(p, z = NULL, geo = NULL, ...,
546526
data = NULL, inherit = TRUE) {
547-
if (inherit) {
548-
z <- z %||% p$x$attrs[[1]][["z"]]
549-
geo <- geo %||% p$x$attrs[[1]][["geo"]] %||% "geo"
550-
}
551-
if (is.null(z)) {
552-
stop("Must supply `z` attribute", call. = FALSE)
553-
}
554-
add_trace_classed(
555-
p, class = "plotly_choropleth", z = z, type = "choropleth", geo = geo,
556-
..., data = data, inherit = inherit
557-
)
527+
.Deprecated("geo")
528+
p
558529
}
559530

560531
# attach a class to a trace which informs data processing in plotly_build

R/coord.R

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#' *** This won't be possible until plotly.js implements aspect ratios... ***
2+
#'
3+
#' #' Force the aspect ratio according to x and y scales
4+
#' #'
5+
#' #' When x and y are numeric variables measured on the same scale,
6+
#' #' or are related in some meaningful way, forcing the aspect ratio of the
7+
#' #' plot to be proportional to the ratio of a unit change in x versus y improves
8+
#' #' our ability to correctly perceive the data.
9+
#' #'
10+
#' #' @param p a plotly object
11+
#' #' @param ratio aspect ratio, expressed as y / x
12+
#' #' @export
13+
#' #' @examples
14+
#' #'
15+
#' #' canada <- map_data("world", "canada")
16+
#' #'
17+
#' #' canada %>%
18+
#' #' group_by(group) %>%
19+
#' #' plot_ly(x = ~long, y = ~lat, alpha = 0.2) %>%
20+
#' #' add_polygons(hoverinfo = "none", color = I("black")) %>%
21+
#' #' coord_fix()
22+
#' #'
23+
#' #' # works on (non-faceted) ggplot2 plots, too
24+
#' #' gg <- ggplot(canada, aes(long, lat, group = group)) +
25+
#' #' geom_polygon() + coord_fixed()
26+
#' #'
27+
#' #' gg %>%
28+
#' #' ggplotly() %>%
29+
#' #' coord_fix()
30+
#' #'
31+
#'
32+
#' coord_fix <- function(p, ratio = 1) {
33+
#' p <- plotly_build(p)
34+
#' # this won't work for subplots, or categorical data
35+
#' x <- grepl("^xaxis", names(p$x$layout))
36+
#' y <- grepl("^yaxis", names(p$x$layout))
37+
#' if (sum(x) > 1 || sum(y) > 1) {
38+
#' stop("Can not impose aspect ratio a plot with more than one x/y axis", call. = FALSE)
39+
#' }
40+
#' xDat <- unlist(lapply(p$x$data, "[[", "x"))
41+
#' yDat <- unlist(lapply(p$x$data, "[[", "y"))
42+
#' if (!is.numeric(xDat) || !is.numeric(yDat)) {
43+
#' stop("Must have numeric data on both x and y axes to enforce aspect ratios", call. = FALSE)
44+
#' }
45+
#'
46+
#' # warn about any pre-populated domains, they will get squashed
47+
#' xDom <- p$x$layout[["xaxis"]]$domain %||% c(0, 1)
48+
#' yDom <- p$x$layout[["yaxis"]]$domain %||% c(0, 1)
49+
#' if (!identical(yDom, c(0, 1)) || !identical(xDom, c(0, 1))) {
50+
#' warning(
51+
#' "coord_fix() won't respect prespecified axis domains (other than the default)",
52+
#' call. = FALSE
53+
#' )
54+
#' }
55+
#'
56+
#' xRng <- range(xDat, na.rm = TRUE)
57+
#' yRng <- range(yDat, na.rm = TRUE)
58+
#' asp <- ratio * diff(yRng) / diff(xRng)
59+
#' if (asp < 1) {
60+
#' p$x$layout[["yaxis"]]$domain <- c(0 + asp / 2, 1 - asp / 2)
61+
#' } else {
62+
#' asp <- 1 / asp
63+
#' p$x$layout[["xaxis"]]$domain <- c(0 + asp / 2, 1 - asp / 2)
64+
#' }
65+
#' p
66+
#' }

R/dev.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#' plotly_json(plot_ly())
1313
#' plotly_json(plot_ly(), FALSE)
1414

15-
plotly_json <- function(p = plot_ly(), jsonedit = interactive(), ...) {
15+
plotly_json <- function(p = last_plot(), jsonedit = interactive(), ...) {
1616
plotlyJSON <- to_JSON(plotly_build(p)$x, pretty = TRUE)
1717
if (jsonedit) {
1818
if (system.file(package = "listviewer") == "") {

R/plotly.R

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,14 @@
3434
#' @param width Width in pixels (optional, defaults to automatic sizing).
3535
#' @param height Height in pixels (optional, defaults to automatic sizing).
3636
#' @param source Only relevant for \link{event_data}.
37-
#' @seealso \code{\link{layout}()}, \code{\link{add_trace}()}, \code{\link{style}()}
3837
#' @author Carson Sievert
38+
#' @seealso \itemize{
39+
#' \item For initializing a plotly-geo object: \code{\link{plot_geo}()}.
40+
#' \item For initializing a plotly-mapbox object: \code{\link{plot_mapbox}()}.
41+
#' \item For translating a ggplot2 object to a plotly object: \code{\link{ggplotly}()}.
42+
#' \item For modifying any plotly object: \code{\link{layout}()}, \code{\link{add_trace}()}, \code{\link{style}()}
43+
#' \item
44+
#' }
3945
#' @export
4046
#' @examples
4147
#' \dontrun{
@@ -153,11 +159,14 @@ plot_ly <- function(data = data.frame(), ..., type = NULL,
153159
#' valid scattermapbox attributes - \url{https://plot.ly/r/reference/#scattermapbox}.
154160
#' Note that x/y can also be used in place of lat/lon.
155161
#' @export
162+
#' @author Carson Sievert
163+
#' @seealso \code{\link{plot_ly}()}, \code{\link{plot_geo}()}, \code{\link{ggplotly}()}
164+
#'
156165
#' @examples \dontrun{
157166
#'
158167
#' map_data("world", "canada") %>%
159168
#' group_by(group) %>%
160-
#' mapbox(x = ~lat, y = ~long) %>%
169+
#' plot_mapbox(x = ~long, y = ~lat) %>%
161170
#' add_polygons() %>%
162171
#' layout(
163172
#' mapbox = list(
@@ -166,10 +175,11 @@ plot_ly <- function(data = data.frame(), ..., type = NULL,
166175
#' )
167176
#' }
168177
#'
169-
mapbox <- function(data = data.frame(), ...) {
170-
p <- plot_ly(data, ...)
171-
p <- config(p, mapboxAccessToken = mapbox_token())
172-
p$x$mapType <- "mapbox"
178+
plot_mapbox <- function(data = data.frame(), ...) {
179+
p <- config(plot_ly(data, ...), mapboxAccessToken = mapbox_token())
180+
# not only do we use this for is_mapbox(), but also setting the layout attr
181+
# https://plot.ly/r/reference/#layout-mapbox
182+
p$x$layout$mapType <- "mapbox"
173183
p
174184
}
175185

@@ -182,16 +192,20 @@ mapbox <- function(data = data.frame(), ...) {
182192
#'
183193
#' @param ... arguments passed along to \code{\link{plot_ly}()}.
184194
#' @export
195+
#' @author Carson Sievert
196+
#' @seealso \code{\link{plot_ly}()}, \code{\link{plot_mapbox}()}, \code{\link{ggplotly}()}
185197
#' @examples
186198
#'
187199
#' map_data("world", "canada") %>%
188200
#' group_by(group) %>%
189-
#' geo(x = ~lat, y = ~long) %>%
190-
#' add_polygons()
201+
#' plot_geo(x = ~long, y = ~lat) %>%
202+
#' add_markers(size = I(1))
191203
#'
192-
geo <- function(data = data.frame(), ...) {
204+
plot_geo <- function(data = data.frame(), ...) {
193205
p <- plot_ly(data, ...)
194-
p$x$mapType <- "geo"
206+
# not only do we use this for is_geo(), but also setting the layout attr
207+
# https://plot.ly/r/reference/#layout-geo
208+
p$x$layout$mapType <- "geo"
195209
p
196210
}
197211

R/plotly_build.R

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ plotly_build.list <- function(p) {
2626

2727
#' @export
2828
plotly_build.gg <- function(p) {
29-
ggplotly(p)
29+
p <- ggplotly(p)
30+
supply_defaults(p)
3031
}
3132

3233
#' @export
@@ -71,6 +72,24 @@ plotly_build.plotly <- function(p) {
7172
p$x$attrs[[1]] <- NULL
7273
}
7374
}
75+
76+
# trace type checking and renaming for plot objects
77+
if (is_mapbox(p) || is_geo(p)) {
78+
p$x$attrs <- lapply(p$x$attrs, function(tr) {
79+
tr[["x"]] <- tr[["x"]] %||% tr[["lat"]]
80+
tr[["y"]] <- tr[["y"]] %||% tr[["lon"]]
81+
if (!grepl("scatter|choropleth", tr[["type"]] %||% "scatter")) {
82+
stop("Cant add a '", tr[["type"]], "' trace to a map object", call. = FALSE)
83+
}
84+
if (is_mapbox(p)) {
85+
tr[["type"]] <- "scattermapbox"
86+
}
87+
if (is_geo(p)) {
88+
tr[["type"]] <- if (!is.null(tr[["z"]])) "choropleth" else "scattergeo"
89+
}
90+
tr
91+
})
92+
}
7493

7594
dats <- Map(function(x, y) {
7695

@@ -270,16 +289,18 @@ plotly_build.plotly <- function(p) {
270289
}
271290
}
272291

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) {
292+
# supply trace anchor and domain information
293+
p <- supply_defaults(p)
294+
295+
# attribute naming corrections for "geo-like" traces
296+
p$x$data <- lapply(p$x$data, function(tr) {
297+
if (isTRUE(tr[["type"]] %in% c("scattermapbox", "scattergeo"))) {
277298
tr[["lat"]] <- tr[["lat"]] %||% tr[["y"]]
278299
tr[["lon"]] <- tr[["lon"]] %||% tr[["x"]]
279300
tr[c("x", "y")] <- NULL
280-
tr
281-
})
282-
}
301+
}
302+
tr
303+
})
283304

284305
# polar charts don't like null width/height keys
285306
if (is.null(p$x$layout[["height"]])) p$x$layout[["height"]] <- NULL

0 commit comments

Comments
 (0)