|
| 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 | +#' } |
0 commit comments