1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
#' Add a vega legend specification to a ggvis plot
#'
#' Axis specifications allow you to either override the default legends,
#' or supply additional legends.
#'
#' More information about axes can be found in the "axes and legends" vignettes.
#'
#' @section Compared to ggplot2:
#'
#' In ggplot2, legend (and axis) properties are part of the scales
#' specification. In vega, they are separate, which allows the specification
#' of multiple legends, and more flexible linkage between scales and legends.
#'
#' @param vis A ggvis object.
#' @param scales The name of one or more scales for which to add a legend.
#' Typically one of "size", "shape", "fill", "stroke", although custom scale
#' names may also be used. Multiple names can also be used, like
#' \code{c("fill", "shape")}.
#' @param orient The orientation of the legend. One of "left" or "right". This
#' determines how the legend is positioned within the scene. The default is
#' "right".
#' @param title A title for the legend. By default, it uses the name the fields
#' used in the legend. Use \code{""} to suppress the title.
#' @param format The formatting pattern for axis labels. Vega uses D3's format
#' pattern: \url{https://github.com/mbostock/d3/wiki/Formatting}
#' @param values Explicitly set the visible legend values.
#' @param properties Optional mark property definitions for custom legend
#' styling. Should be an object created by \code{\link{legend_props}}, with
#' properties for title, label, symbols, gradient, legend.
#' @export
#' @examples
#' mtcars %>% ggvis(x = ~wt, y = ~mpg, fill = ~cyl) %>%
#' layer_points() %>%
#' add_legend("fill", title = "Cylinders")
#'
#' # Suppress legend with hide_legend
#' mtcars %>% ggvis(x = ~wt, y = ~mpg, fill = ~cyl) %>%
#' layer_points() %>%
#' hide_legend("fill")
#'
#' # Combining two properties in one legend
#' mtcars %>%
#' ggvis(x = ~wt, y = ~mpg, fill = ~factor(cyl), shape = ~factor(cyl)) %>%
#' layer_points() %>%
#' add_legend(c("fill", "shape"))
#'
#' # Control legend properties with a continuous legend, with x and y position
#' # in pixels.
#' mtcars %>% ggvis(x = ~wt, y = ~mpg, fill = ~cyl) %>%
#' layer_points() %>%
#' add_legend("fill", title = "Cylinders",
#' properties = legend_props(
#' title = list(fontSize = 16),
#' labels = list(fontSize = 12, fill = "#00F"),
#' gradient = list(stroke = "red", strokeWidth = 2),
#' legend = list(x = 500, y = 50)
#' )
#' )
#'
#' # Control legend properties with a categorical legend, with x and y position
#' # in the scaled data space.
#' mtcars %>% ggvis(x = ~wt, y = ~mpg, fill = ~factor(cyl)) %>%
#' layer_points() %>%
#' add_legend("fill", title = "Cylinders",
#' properties = legend_props(
#' title = list(fontSize = 16),
#' labels = list(fontSize = 14, dx = 5),
#' symbol = list(stroke = "black", strokeWidth = 2,
#' shape = "square", size = 200),
#' legend = list(
#' x = scaled_value("x", 4.5),
#' y = scaled_value("y", 30)
#' )
#' )
#' )
#'
#' # Control legend position using x_rel and y_rel which specify relative
#' # position, going from 0 to 1. (0, 0) is the bottom-left corner, and
#' # (1, 1) is the upper-right corner. The values control the position of
#' # the upper-left corner of the legend.
#' mtcars %>% ggvis(x = ~wt, y = ~mpg, fill = ~cyl) %>%
#' layer_points() %>%
#' add_relative_scales() %>%
#' add_legend("fill", title = "Cylinders",
#' properties = legend_props(
#' legend = list(
#' x = scaled_value("x_rel", 0.8),
#' y = scaled_value("y_rel", 1)
#' )
#' )
#' )
add_legend <- function(vis, scales = NULL, orient = "right", title = NULL,
format = NULL, values = NULL, properties = NULL) {
assert_that(!is.null(scale))
# Create an unfortified legend
legend <- structure(compact(list(
scales = scales, orient = orient, title = title, format = format,
values = values, properties = properties
)), class = "ggvis_legend")
append_ggvis(vis, "legends", legend)
}
#' @rdname add_legend
#' @export
hide_legend <- function(vis, scales) {
legend <- structure(list(scales = scales, hide = TRUE), class = "ggvis_legend")
append_ggvis(vis, "legends", legend)
}
#' Defunct function for adding a legend
#'
#' This function has been replaced with \code{\link{add_legend}}.
#' @param ... Other arguments.
#' @export
add_guide_legend <- function(...) {
stop("add_guide_legend() has been replaced by add_legend().")
}
# Given a ggvis object, find all the unfortified legend and fortify them.
# The fortification process requires examining the scales in the ggvis object.
fortify_legends <- function(vis) {
all_scales <- collapse_scales(gather_scales(vis))
# Get a named vector where names are scales, values are properties
scales_props <- vapply(all_scales, function(s) s$property, character(1))
vis$legends <- lapply(vis$legends, fortify_legend, scales_props)
vis
}
# Create a fortified legend object. An unfortified legend has only the names
# of the scales. A fortified legends maps those names of scales to property
# names.
# scales_props is a named list, where names are scales, values are properties
fortify_legend <- function(legend, scales_props) {
if (inherits(legend, "fortified_legend")) return(legend)
# Get scales and props that are actually used by this legend
scales_props <- scales_props[legend$scales]
assert_that(!is.null(scales_props) && length(scales_props) > 0)
assert_that(is.null(legend$properties) || is.legend_props(legend$properties))
legend <- structure(compact(list(
orient = legend$orient, title = legend$title, format = legend$format,
values = legend$values, properties = legend$properties,
hide = legend$hide
)), class = c("fortified_legend", "ggvis_legend"))
legend[scales_props] <- names(scales_props)
legend
}
add_missing_legends <- function(vis) {
legends <- vis$legends
scales <- vis$scales
legs <- c("size", "shape", "fill", "stroke")
# Get scales that are in some legend
present <- unlist(lapply(legends, function(x) x$scales))
# Find scales that don't have legend
missing <- setdiff(intersect(names(scales), legs), present)
for (scale in missing) {
vis <- add_legend(vis, scale)
}
vis
}
# Some legend settings require examining the scale
apply_legends_defaults <- function(vis) {
legends <- vis$legends
scales <- vis$scales
legs <- c("size", "shape", "fill", "stroke")
legends <- lapply(legends, function(legend) {
if (isTRUE(legend$hide)) return(legend)
present <- unlist(legend[legs])
present_scales <- scales[present]
# Use [[-indexing to avoid partial name matching of "titleOffset". (#269)
if (is.null(legend[["title"]])) {
legend$title <- present_scales[[1]]$label
}
legend
})
# Replace the original legends with the new ones
vis$legends <- legends
vis
}
#' @export
format.ggvis_legend <- format.ggvis_axis
#' @export
print.ggvis_legend <- print.ggvis_axis
|