Skip to content

Commit f140752

Browse files
committed
first pass at getting mapbox working in subplot()
1 parent 2ea4a2e commit f140752

File tree

3 files changed

+39
-71
lines changed

3 files changed

+39
-71
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)

R/subplots.R

Lines changed: 33 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -32,84 +32,49 @@
3232
subplot <- function(..., nrows = 1, widths = NULL, heights = NULL, margin = 0.02,
3333
shareX = FALSE, shareY = FALSE, titleX = shareX,
3434
titleY = shareY, which_layout = "merge") {
35-
# are the dots a list of plotly objects?
3635
dotz <- list(...)
37-
if (length(dotz) == 1 && is.list(dotz[[1]]) && !is.plotly(dotz[[1]])) {
38-
dotz <- dotz[[1]]
39-
}
40-
# build each plot
41-
plotz <- lapply(dotz, function(d) plotly_build(d)$x)
42-
# ensure "axis-reference" trace attributes are properly formatted
43-
# TODO: should this go inside plotly_build()?
44-
plotz <- lapply(plotz, function(p) {
45-
p$data <- lapply(p$data, function(tr) {
46-
if (length(tr[["geo"]])) {
47-
tr[["geo"]] <- sub("^geo1$", "geo", tr[["geo"]][1]) %||% NULL
48-
tr[["xaxis"]] <- NULL
49-
tr[["yaxis"]] <- NULL
50-
} else {
51-
tr[["geo"]] <- NULL
52-
tr[["xaxis"]] <- sub("^x1$", "x", tr[["xaxis"]][1] %||% "x")
53-
tr[["yaxis"]] <- sub("^y1$", "y", tr[["yaxis"]][1] %||% "y")
54-
}
55-
tr
56-
})
57-
p
58-
})
59-
# Are any traces referencing "axis-like" layout attributes that are missing?
60-
# If so, move those traces to a "new plot", and inherit layout attributes,
61-
# which makes this sort of thing possible:
62-
# https://plot.ly/r/map-subplots-and-small-multiples/
63-
plots <- list()
64-
for (i in seq_along(plotz)) {
65-
p <- plots[[i]] <- plotz[[i]]
66-
layoutAttrs <- c(names(p$layout), c("geo", "xaxis", "yaxis"))
67-
xTraceAttrs <- sub("^x", "xaxis", sapply(p$data, function(tr) tr[["geo"]] %||% tr[["xaxis"]]))
68-
yTraceAttrs <- sub("^y", "yaxis", sapply(p$data, function(tr) tr[["geo"]] %||% tr[["yaxis"]]))
69-
missingAttrs <- setdiff(c(xTraceAttrs, yTraceAttrs), layoutAttrs)
70-
# move to next iteration if trace references are complete
71-
if (!length(missingAttrs)) next
72-
# remove each "missing" trace from this plot
73-
missingTraces <- xTraceAttrs %in% missingAttrs | yTraceAttrs %in% missingAttrs
74-
plots[[i]]$data[missingTraces] <- NULL
75-
# move traces with "similar missingness" to a new plot
76-
for (j in missingAttrs) {
77-
newPlot <- list(
78-
data = p$data[xTraceAttrs %in% j | yTraceAttrs %in% j],
79-
layout = p$layout
36+
if (tibble::is_tibble(dotz)) {
37+
# if dots is a tibble, search for one column with a list of plotly objects
38+
idx <- which(vapply(dotz, function(x) is.plotly(x[[1]]), logical(1)))
39+
if (length(idx) != 1) {
40+
stop(
41+
"If you supply a tibble to subplot(), \n",
42+
"it must have _one_ column with a list of plotly objects",
43+
call. = FALSE
8044
)
81-
# reset the anchors
82-
newPlot$data <- lapply(newPlot$data, function(tr) {
83-
for (k in c("geo", "xaxis", "yaxis")) {
84-
tr[[k]] <- sub("[0-9]+", "", tr[[k]]) %||% NULL
85-
}
86-
tr
87-
})
88-
plots <- c(plots, list(newPlot))
8945
}
46+
dotz <- dotz[[idx]]
47+
} else if (length(dotz) == 1 && is.list(dotz[[1]]) && !is.plotly(dotz[[1]])) {
48+
# if ... is a list of plotly objects, list(...) is a (length 1) list
49+
# containing a list of plotly objects
50+
dotz <- dotz[[1]]
9051
}
91-
# main plot objects
52+
# build each plot
53+
plots <- lapply(dotz, function(d) plotly_build(d)[["x"]])
54+
55+
# grab main plot objects
9256
traces <- lapply(plots, "[[", "data")
9357
layouts <- lapply(plots, "[[", "layout")
9458
shapes <- lapply(layouts, "[[", "shapes")
9559
annotations <- lapply(layouts, function(x) {
96-
# keep non axis title annotations
60+
# keep non axis title annotations (for rescaling)
9761
axes <- vapply(x$annotations, function(a) identical(a$annotationType, "axis"), logical(1))
9862
x$annotations[!axes]
9963
})
100-
# collect axis objects (note a _single_ geo object counts a both an x and y)
101-
geoDomainDefault <- list(x = c(0, 1), y = c(0, 1))
64+
# collect axis objects (note a _single_ geo/mapbox object counts a both an x and y)
10265
xAxes <- lapply(layouts, function(lay) {
103-
keys <- grep("^geo|^xaxis", names(lay), value = TRUE) %||% "xaxis"
66+
keys <- grep("^geo|^mapbox|^xaxis", names(lay), value = TRUE) %||% "xaxis"
10467
for (k in keys) {
105-
lay[[k]]$domain <- lay[[k]]$domain %||% if (grepl("^geo", k)) geoDomainDefault else c(0, 1)
68+
dom <- lay[[k]]$domain %||% c(0, 1)
69+
if ("x" %in% names(dom)) dom <- dom[["x"]]
10670
}
10771
lay[keys]
10872
})
10973
yAxes <- lapply(layouts, function(lay) {
110-
keys <- grep("^geo|^yaxis", names(lay), value = TRUE) %||% "yaxis"
74+
keys <- grep("^geo|^mapbox|^yaxis", names(lay), value = TRUE) %||% "yaxis"
11175
for (k in keys) {
112-
lay[[k]]$domain <- lay[[k]]$domain %||% if (grepl("^geo", k)) geoDomainDefault else c(0, 1)
76+
dom <- lay[[k]]$domain %||% c(0, 1)
77+
if ("y" %in% names(dom)) dom <- dom[["y"]]
11378
}
11479
lay[keys]
11580
})
@@ -168,17 +133,17 @@ subplot <- function(..., nrows = 1, widths = NULL, heights = NULL, margin = 0.02
168133
yAxes[[i]] <- setNames(yAxes[[i]], names(yMap))
169134
# for cartesian, bump corresponding axis anchor
170135
for (j in seq_along(xAxes[[i]])) {
171-
if (grepl("^geo", names(xAxes[[i]][j]))) next
136+
if (grepl("^geo|^mapbox", names(xAxes[[i]][j]))) next
172137
map <- yMap[yMap %in% sub("y", "yaxis", xAxes[[i]][[j]]$anchor %||% "y")]
173138
xAxes[[i]][[j]]$anchor <- sub("axis", "", names(map))
174139
}
175140
for (j in seq_along(yAxes[[i]])) {
176-
if (grepl("^geo", names(yAxes[[i]][j]))) next
141+
if (grepl("^geo|^mapbox", names(yAxes[[i]][j]))) next
177142
map <- xMap[xMap %in% sub("x", "xaxis", yAxes[[i]][[j]]$anchor %||% "x")]
178143
yAxes[[i]][[j]]$anchor <- sub("axis", "", names(map))
179144
}
180145
# map trace xaxis/yaxis/geo attributes
181-
for (key in c("geo", "xaxis", "yaxis")) {
146+
for (key in c("geo", "subplot", "xaxis", "yaxis")) {
182147
oldAnchors <- unlist(lapply(traces[[i]], "[[", key))
183148
if (!length(oldAnchors)) next
184149
axisMap <- if (key == "yaxis") yMap else xMap
@@ -226,7 +191,9 @@ subplot <- function(..., nrows = 1, widths = NULL, heights = NULL, margin = 0.02
226191
p$layout$annotations <- Reduce(c, annotations)
227192
p$layout$shapes <- Reduce(c, shapes)
228193
# merge non-axis layout stuff
229-
layouts <- lapply(layouts, function(x) x[!grepl("^[x-y]axis|^geo", names(x))] %||% list())
194+
layouts <- lapply(layouts, function(x) {
195+
x[!grepl("^[x-y]axis|^geo|^mapbox|annotations|shapes", names(x))] %||% list()
196+
})
230197
if (which_layout != "merge") {
231198
if (!is.numeric(which_layout)) warning("which_layout must be numeric")
232199
if (!all(idx <- which_layout %in% seq_along(plots))) {
@@ -240,7 +207,9 @@ subplot <- function(..., nrows = 1, widths = NULL, heights = NULL, margin = 0.02
240207
if (length(sources) > 1) {
241208
stop("Can have multiple source values in a single subplot")
242209
}
210+
p$config <- Reduce(modify_list, lapply(plots, "[[", "config")) %||% NULL
243211
p$source <- sources[1]
212+
p$subplot <- TRUE
244213
as_widget(p)
245214
}
246215

tests/testthat/test-plotly-subplot.R

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ s <- subplot(
8383
)
8484

8585
test_that("Row/column height/width", {
86-
l <- expect_traces(s, 3, "width-height")
86+
l <- expect_traces(s, 4, "width-height")
8787
expect_equal(diff(l$layout$xaxis$domain), 0.8 - 0.005)
8888
expect_equal(diff(l$layout$xaxis2$domain), 0.2 - 0.005)
8989
expect_equal(diff(l$layout$yaxis$domain), 0.2 - 0.005)
@@ -145,10 +145,9 @@ test_that("geo+cartesian behaves", {
145145
)
146146
# create a map of population density
147147
density <- state.x77[, "Population"] / state.x77[, "Area"]
148-
map <- plot_ly(
149-
z = ~density,
150-
text = state.name, locations = state.abb,
151-
type = 'choropleth', locationmode = 'USA-states', geo = "geo"
148+
map <- plot_geo(
149+
z = ~density, text = state.name,
150+
locations = state.abb, locationmode = 'USA-states'
152151
) %>% layout(geo = g)
153152
# create a bunch of horizontal bar charts
154153
vars <- colnames(state.x77)

0 commit comments

Comments
 (0)