diff --git a/DESCRIPTION b/DESCRIPTION index cd7029de..dfd20f26 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -20,6 +20,7 @@ Imports: Suggests: MASS, mgcv, + lubridate, testthat (>= 0.8.1), knitr (>= 1.6), rmarkdown diff --git a/R/compute_bin.R b/R/compute_bin.R index ca8af759..250fae13 100644 --- a/R/compute_bin.R +++ b/R/compute_bin.R @@ -4,17 +4,26 @@ #' grouped data frames and ggvis visualisations. #' @param x_var,w_var Names of x and weight variables. The x variable must be #' continuous. -#' @param binwidth The width of the bins. The default is \code{NULL}, which -#' yields 30 bins that cover the range of the data. You should always override -#' this value, exploring multiple widths to find the best to illustrate the -#' stories in your data. -#' @param origin The initial position of the left-most bin. If \code{NULL}, the -#' the default, will use the smallest value in the dataset. -#' @param right Should bins be right-open, left-closed, or -#' right-closed, left-open. -#' @param pad If \code{TRUE}, adds empty bins at either end of x. This -#' ensures frequency polygons touch 0, and adds padidng between the data -#' and axis for histograms. +#' @param width The width of the bins. The default is \code{NULL}, which yields +#' 30 bins that cover the range of the data. You should always override this +#' value, exploring multiple widths to find the best to illustrate the stories +#' in your data. +#' @param center The center of one of the bins. Note that if center is above or +#' below the range of the data, things will be shifted by an appropriate +#' number of \code{width}s. To center on integers, for example, use +#' \code{width=1} and \code{center=0}, even if \code{0} is outside the range +#' of the data. At most one of \code{center} and \code{boundary} may be +#' specified. +#' @param boundary A boundary between two bins. As with \code{center}, things +#' are shifted when \code{boundary} is outside the range of the data. For +#' example, to center on integers, use \code{width = 1} and \code{boundary = +#' 0.5}, even if \code{1} is outside the range of the data. At most one of +#' \code{center} and \code{boundary} may be specified. +#' @param closed One of \code{"right"} or \code{"left"} indicating whether right +#' or left edges of bins are included in the bin. +#' @param pad If \code{TRUE}, adds empty bins at either end of x. This ensures +#' frequency polygons touch 0, and adds padding between the data and axis for +#' histograms. #' @seealso \code{\link{compute_count}} For counting cases at specific locations #' of a continuous variable. This is useful when the variable is continuous #' but the data is granular. @@ -27,24 +36,38 @@ #' \item{width_}{width of bin} #' @examples #' mtcars %>% compute_bin(~mpg) -#' mtcars %>% compute_bin(~mpg, binwidth = 10) -#' mtcars %>% group_by(cyl) %>% compute_bin(~mpg, binwidth = 10) +#' mtcars %>% compute_bin(~mpg, width = 10) +#' mtcars %>% group_by(cyl) %>% compute_bin(~mpg, width = 10) #' #' # It doesn't matter whether you transform inside or outside of a vis #' mtcars %>% compute_bin(~mpg) %>% ggvis(~x_, ~count_) %>% layer_paths() #' mtcars %>% ggvis(~ x_, ~ count_) %>% compute_bin(~mpg) %>% layer_paths() -compute_bin <- function(x, x_var, w_var = NULL, binwidth = NULL, - origin = NULL, right = TRUE, pad = TRUE) { +compute_bin <- function(x, x_var, w_var = NULL, width = NULL, + center = NULL, boundary = NULL, + closed = c("right", "left"), pad = TRUE, + binwidth) { UseMethod("compute_bin") } #' @export -compute_bin.data.frame <- function(x, x_var, w_var = NULL, binwidth = NULL, - origin = NULL, right = TRUE, pad = TRUE) { +compute_bin.data.frame <- function(x, x_var, w_var = NULL, width = NULL, + center = NULL, boundary = NULL, + closed = c("right", "left"), pad = TRUE, + binwidth) { + + if (!missing(binwidth)) { + width <- binwidth + deprecated("binwidth", "width", version = "0.3.0") + } + + closed <- match.arg(closed) assert_that(is.formula(x_var)) x_val <- eval_vector(x, x_var) + params <- bin_params(range2(x_val), width = width, center = center, + boundary = boundary, closed = closed) + x_na <- is.na(x_val) if (any(x_na)) { message("compute_bin: NA values ignored for binning.") @@ -57,35 +80,53 @@ compute_bin.data.frame <- function(x, x_var, w_var = NULL, binwidth = NULL, w_val <- eval_vector(x, w_var) } - params <- bin_params(range2(x_val), binwidth = binwidth, origin = origin, - right = right) - - bin_vector(x_val, weight = w_val, binwidth = params$binwidth, - origin = params$origin, right = params$right, pad = pad) + bin_vector(x_val, weight = w_val, width = params$width, + origin = params$origin, closed = params$closed, pad = pad) } #' @export -compute_bin.grouped_df <- function(x, x_var, w_var = NULL, binwidth = NULL, - origin = NULL, right = TRUE, pad = TRUE) { +compute_bin.grouped_df <- function(x, x_var, w_var = NULL, width = NULL, + center = NULL, boundary = NULL, + closed = c("right", "left"), pad = TRUE, + binwidth) { + + if (!missing(binwidth)) { + width <- binwidth + deprecated("binwidth", "width", version = "0.3.0") + } + closed <- match.arg(closed) x_val <- eval_vector(x, x_var) - params <- bin_params(range2(x_val), binwidth = binwidth, origin = origin, - right = right) + + # We want to use the same boundary and width across groups, so calculate + # bin params here. + params <- bin_params(range2(x_val), width = width, center = center, + boundary = boundary, closed = closed) dplyr::do(x, compute_bin(., x_var, w_var = w_var, - binwidth = params$binwidth, - origin = params$origin, - right = params$right, - pad = pad)) + width = params$width, + center = NULL, + boundary = params$origin, + closed = params$closed, + pad = pad + )) } #' @export -compute_bin.ggvis <- function(x, x_var, w_var = NULL, binwidth = NULL, - origin = NULL, right = TRUE, pad = TRUE) { - args <- list(x_var = x_var, w_var = w_var, binwidth = binwidth, - origin = origin, right = right, pad = pad) +compute_bin.ggvis <- function(x, x_var, w_var = NULL, width = NULL, + center = NULL, boundary = NULL, + closed = c("right", "left"), pad = TRUE, + binwidth) { + if (!missing(binwidth)) { + width <- binwidth + deprecated("binwidth", "width", version = "0.3.0") + } + + closed <- match.arg(closed) + args <- list(x_var = x_var, w_var = w_var, width = width, + center = center, boundary = boundary, closed = closed, pad = pad) register_computation(x, args, "bin", function(data, args) { output <- do_call(compute_bin, quote(data), .args = args) @@ -95,79 +136,141 @@ compute_bin.ggvis <- function(x, x_var, w_var = NULL, binwidth = NULL, # Compute parameters ----------------------------------------------------------- -bin_params <- function(x_range, binwidth = NULL, origin = NULL, right = TRUE) { +bin_params <- function(x_range, width = NULL, center = NULL, boundary = NULL, + closed = c("right", "left")) { UseMethod("bin_params") } #' @export -bin_params.numeric <- function(x_range, binwidth = NULL, origin = NULL, - right = TRUE) { +bin_params.numeric <- function(x_range, width = NULL, center = NULL, + boundary = NULL, closed = c("right", "left")) { + closed <- match.arg(closed) + stopifnot(length(x_range) == 2) + if (!is.null(boundary) && !is.null(center)) { + stop("Only one of 'boundary' and 'center' may be specified.") + } - if (is.null(binwidth)) { - binwidth <- diff(x_range) / 30 - notify_guess(binwidth, "range / 30") + if (is.null(width)) { + width <- diff(x_range) / 30 + notify_guess(width, "range / 30") } - if (is.null(origin)) { - origin <- round_any(x_range[1], binwidth, floor) + if (is.null(boundary)) { + if (is.null(center)) { + # If neither edge nor center given, compute both using tile layer's + # algorithm. This puts min and max of data in outer half of their bins. + boundary <- tilelayer_origin(x_range, width) + + } else { + # If center given but not boundary, compute boundary. + boundary <- center - width / 2 + } } - list(binwidth = binwidth, origin = origin, right = right) + origin <- find_origin(x_range, width, boundary) + + list(width = width, origin = origin, closed = closed) } #' @export -bin_params.POSIXct <- function(x_range, binwidth = NULL, origin = NULL, - right = TRUE) { - - if (is.null(binwidth)) { - binwidth <- as.numeric(diff(x_range) / 30, units = "secs") - notify_guess(binwidth, "range / 30") +bin_params.integer <- function(x_range, width = NULL, + center = NULL, boundary = NULL, + closed = c("right", "left")) { + + if (is.null(width)) { + width <- max(pretty(round(diff(x_range) / 30))) + if (width < 1) width <- 1 + num_bins <- ceiling(diff(x_range) / width) + notify_guess(width, paste0("approximately range/", num_bins)) } - list(binwidth = binwidth, origin = origin, right = right) + bin_params.numeric(as.numeric(x_range), width, center, boundary, closed) } #' @export -bin_params.Date <- function(x_range, binwidth = NULL, origin = NULL, - right = TRUE) { - - if (is.null(binwidth)) { - binwidth <- as.numeric(diff(x_range) / 30) - notify_guess(binwidth, "range / 30") +bin_params.POSIXct <- function(x_range, width = NULL, center = NULL, + boundary = NULL, closed = c("right", "left")) { + if (!is.null(width)) { + # Period object from lubridate package - need lubridate::as.difftime to find + # the correct generic, instead of base::as.difftime. + if (is(width, "Period")) { + width <- as.numeric(lubridate::as.difftime(width, units = "secs")) + + } else { + width <- as.numeric(width, units = "secs") + } } - list(binwidth = binwidth, origin = origin, right = right) + bin_params( + as.numeric(x_range), + as_numeric(width), + as_numeric(center), + as_numeric(boundary), + closed + ) } #' @export -bin_params.integer <- function(x_range, binwidth = NULL, origin = NULL, - right = TRUE) { +bin_params.Date <- function(x_range, width = NULL, center = NULL, + boundary = NULL, closed = c("right", "left")) { + bin_params( + as.numeric(x_range), + as_numeric(width), + as_numeric(center), + as_numeric(boundary), + closed + ) +} - if (is.null(binwidth)) { - binwidth <- 1 - origin <- x_range[1] - 1/2 - notify_guess(binwidth) - } +# Compute origin from x_range and width +tilelayer_origin <- function(x_range, width) { + stopifnot(is.numeric(x_range) && length(x_range) == 2) + stopifnot(is.numeric(width) && length(width) == 1) + num_central_bins <- trunc(diff(x_range) / width) - 1 + # width of partial tiles on either side + side_width <- (diff(x_range) - num_central_bins * width) / 2 + x_range[1] + side_width - width + # adjust_breaks should be called to handle any round-off fuzziness issues +} - list(binwidth = binwidth, origin = origin, right = right) +# Find the left side of left-most bin +find_origin <- function(x_range, width, boundary) { + shift <- floor((x_range[1] - boundary) / width) + boundary + shift * width } # Bin individual vector -------------------------------------------------------- +#' Bin vectors +#' +#' A generic and several implementations for binning vectors. +#' +#' @param x A vector to bin +#' @param weight If specified, an integer vector of the same length as \code{x} +#' representing the number of occurances of each value in \code{x} +#' @param width The width of a bin +#' @param origin The left-most value for bins. +#' @param closed One of \code{"right"} or \code{"left"} indicating whether +#' right or left edges of bins are included in the bin. +#' @param pad A logical indicating whether the bins should be padded to include +#' an empty bin on each side. +#' @param ... additional arguments passed through to methods. +#' @keywords internal bin_vector <- function(x, weight = NULL, ...) { UseMethod("bin_vector") } #' @export -bin_vector.numeric <- function(x, weight = NULL, ..., binwidth = 1, - origin = NULL, right = TRUE, pad = TRUE) { +bin_vector.numeric <- function(x, weight = NULL, ..., width = 1, + origin = NULL, closed = c("right", "left"), + pad = TRUE) { if (length(na.omit(x)) == 0) { return(bin_out()) } + closed <- match.arg(closed) - stopifnot(is.numeric(binwidth) && length(binwidth) == 1) - stopifnot(is.null(origin) || (is.numeric(origin) && length(origin) == 1)) - stopifnot(is.flag(right)) + stopifnot(is.numeric(width) && length(width) == 1) + stopifnot(is.numeric(origin) && length(origin) == 1) if (is.null(weight)) { weight <- rep(1, length(x)) @@ -175,41 +278,49 @@ bin_vector.numeric <- function(x, weight = NULL, ..., binwidth = 1, weight[is.na(weight)] <- 0 } - if (is.null(origin)) { - origin <- round_any(min(x), binwidth, floor) - } + min_x <- origin + # Small correction factor so that we don't get an extra bin when, for + # example, origin=0, max(x)=20, width=10. + max_x <- max(x) + (1 - 1e-08) * width + breaks <- seq(min_x, max_x, width) + fuzzybreaks <- adjust_breaks(breaks, closed = closed) - breaks <- seq(origin, max(x) + binwidth, binwidth) - fuzzybreaks <- adjust_breaks(breaks, open = if (right) "right" else "left") - - bins <- cut(x, fuzzybreaks, include.lowest = TRUE, right = right) + bins <- cut(x, fuzzybreaks, include.lowest = TRUE, right = (closed == "right")) left <- breaks[-length(breaks)] right <- breaks[-1] - x <- (left + right)/2 - width <- diff(breaks) + x <- (left + right) / 2 + bin_widths <- diff(breaks) - count <- as.numeric(tapply(weight, bins, sum, na.rm = TRUE)) - count[is.na(count)] <- 0 + count <- as.integer(tapply(weight, bins, sum, na.rm = TRUE)) + count[is.na(count)] <- 0L if (pad) { - count <- c(0, count, 0) - width <- c(binwidth, width, binwidth) - x <- c(x[1] - binwidth, x, x[length(x)] + binwidth) + count <- c(0L, count, 0L) + bin_widths <- c(width, bin_widths, width) + x <- c(x[1] - width, x, x[length(x)] + width) } - bin_out(count, x, width) + bin_out(count, x, bin_widths) } #' @export -bin_vector.POSIXct <- function(x, weight = NULL, ..., binwidth = 1, - origin = NULL, right = TRUE, pad = TRUE) { +bin_vector.POSIXct <- function(x, weight = NULL, ..., width = 1, + origin = NULL, closed = c("right", "left"), + pad = TRUE) { - if (!is.null(origin)) - origin <- as.numeric(origin) + # Convert times to raw numbers (seconds since UNIX epoch) + if (is(width, "Period")) { + width <- as.numeric(lubridate::as.difftime(width, units = "secs")) + } - # Convert times to raw numbers (seconds since UNIX epoch), and call bin.numeric - results <- bin_vector(as.numeric(x), weight = weight, binwidth = binwidth, - origin = origin, right = right, pad = pad) + results <- bin_vector( + as.numeric(x), + weight = weight, + width = width, + origin = if (is.null(origin)) NULL else as.numeric(origin), + closed = closed, + pad = pad + ) # Convert some columns from numeric back to POSIXct objects tz <- attr(x, "tzone", TRUE) @@ -222,20 +333,24 @@ bin_vector.POSIXct <- function(x, weight = NULL, ..., binwidth = 1, } #' @export -bin_vector.Date <- function(x, weight = NULL, ..., binwidth = 1, - origin = NULL, right = TRUE, pad = TRUE) { - - if (!is.null(origin)) - origin <- as.numeric(origin) - - # Convert times to raw numbers, and call bin_vector.numeric - results <- bin_vector(as.numeric(x), weight = weight, binwidth = binwidth, - origin = origin, right = right, pad = pad) +bin_vector.Date <- function(x, weight = NULL, ..., width = 1, + origin = NULL, closed = c("right", "left"), + pad = TRUE) { + + results <- bin_vector( + as.numeric(x), + weight = weight, + width = width, + origin = if (is.null(origin)) NULL else as.numeric(origin), + closed = closed, + pad = pad + ) # Convert some columns from numeric back to Date objects time_cols <- c("x_", "xmin_", "xmax_") results[time_cols] <- lapply(results[time_cols], function(col) { - structure(col, class = "Date") + class(col) <- "Date" + col }) results @@ -247,7 +362,7 @@ bin_vector.default <- function(x, weight = NULL, ...) { stop("Don't know how to bin vector of type ", class(x)) } -bin_out <- function(count = numeric(0), x = numeric(0), width = numeric(0), +bin_out <- function(count = integer(0), x = numeric(0), width = numeric(0), xmin = x - width / 2, xmax = x + width / 2) { data.frame( count_ = count, @@ -261,11 +376,11 @@ bin_out <- function(count = numeric(0), x = numeric(0), width = numeric(0), # Adapt break fuzziness from base::hist - this protects from floating # point rounding errors -adjust_breaks <- function(breaks, open = "right") { - open <- match.arg(open, c("left", "right")) +adjust_breaks <- function(breaks, closed = "left") { + closed <- match.arg(closed, c("right", "left")) diddle <- 1e-08 * median(diff(breaks)) - if (open == "left") { + if (closed == "right") { fuzz <- c(-diddle, rep.int(diddle, length(breaks) - 1)) } else { fuzz <- c(rep.int(-diddle, length(breaks) - 1), diddle) diff --git a/R/layer_bars.R b/R/layer_bars.R index fc6bc228..028628e6 100644 --- a/R/layer_bars.R +++ b/R/layer_bars.R @@ -53,7 +53,7 @@ #' # unique values that you want to preserve. If you have many unique #' # values and you want to bin, use layer_histogram #' cocaine %>% ggvis(~price) %>% layer_bars() -#' cocaine %>% ggvis(~price) %>% layer_histograms(binwidth = 100) +#' cocaine %>% ggvis(~price) %>% layer_histograms(width = 100) #' #' # If you have unique x values, you can use layer_bars() as an alternative #' # to layer_points() diff --git a/R/layer_bins.R b/R/layer_bins.R index 8ce02dbd..28eaf073 100644 --- a/R/layer_bins.R +++ b/R/layer_bins.R @@ -10,8 +10,8 @@ #' @examples #' # Create histograms and frequency polygons with layers #' mtcars %>% ggvis(~mpg) %>% layer_histograms() -#' mtcars %>% ggvis(~mpg) %>% layer_histograms(binwidth = 2) -#' mtcars %>% ggvis(~mpg) %>% layer_freqpolys(binwidth = 2) +#' mtcars %>% ggvis(~mpg) %>% layer_histograms(width = 2) +#' mtcars %>% ggvis(~mpg) %>% layer_freqpolys(width = 2) #' #' # These are equivalent to combining compute_bin with the corresponding #' # mark @@ -19,12 +19,18 @@ #' #' # With grouping #' mtcars %>% ggvis(~mpg, fill = ~factor(cyl)) %>% group_by(cyl) %>% -#' layer_histograms(binwidth = 2) +#' layer_histograms(width = 2) #' mtcars %>% ggvis(~mpg, stroke = ~factor(cyl)) %>% group_by(cyl) %>% -#' layer_freqpolys(binwidth = 2) -layer_histograms <- function(vis, ..., binwidth = NULL, origin = NULL, - right = TRUE, stack = TRUE) { +#' layer_freqpolys(width = 2) +layer_histograms <- function(vis, ..., width = NULL, center = NULL, + boundary = NULL, closed = c("right", "left"), + stack = TRUE, binwidth) { + if (!missing(binwidth)) { + width <- binwidth + deprecated("binwidth", "width", version = "0.3.0") + } + closed <- match.arg(closed) new_props <- merge_props(cur_props(vis), props(...)) check_unsupported_props(new_props, c("x", "y", "x2", "y2"), @@ -38,8 +44,8 @@ layer_histograms <- function(vis, ..., binwidth = NULL, origin = NULL, label = "count") layer_f(vis, function(x) { - x <- compute_bin(x, x_var, binwidth = binwidth, origin = origin, - right = right, pad = FALSE) + x <- compute_bin(x, x_var, width = width, center = center, + boundary = boundary, closed = closed) if (stack) { x <- compute_stack(x, stack_var = ~count_, group_var = ~x_) @@ -63,8 +69,15 @@ layer_histograms <- function(vis, ..., binwidth = NULL, origin = NULL, #' @rdname layer_histograms #' @export -layer_freqpolys <- function(vis, ..., binwidth = NULL, origin = NULL, - right = TRUE) { +layer_freqpolys <- function(vis, ..., width = NULL, center = NULL, boundary = NULL, + closed = c("right", "left"), binwidth) { + if (!missing(binwidth)) { + width <- binwidth + deprecated("binwidth", "width", version = "0.3.0") + } + + closed <- match.arg(closed) + new_props <- merge_props(cur_props(vis), props(...)) check_unsupported_props(new_props, c("x", "y"), @@ -76,12 +89,13 @@ layer_freqpolys <- function(vis, ..., binwidth = NULL, origin = NULL, vis <- set_scale_label(vis, "x", prop_label(new_props$x.update)) vis <- set_scale_label(vis, "y", "count") - params <- bin_params(range(x_val, na.rm = TRUE), binwidth = value(binwidth), - origin = value(origin), right = value(right)) + params <- bin_params(range(x_val, na.rm = TRUE), width = value(width), + center = value(center), boundary = value(boundary), + closed = value(closed)) layer_f(vis, function(x) { - x <- compute_bin(x, x_var, binwidth = params$binwidth, - origin = params$origin, right = params$right) + x <- compute_bin(x, x_var, width = params$width, + boundary = params$origin, closed = params$closed) path_props <- merge_props(new_props, props(x = ~x_, y = ~count_)) x <- emit_paths(x, path_props) diff --git a/R/scales.R b/R/scales.R index 2a90f8ae..ffa587d8 100644 --- a/R/scales.R +++ b/R/scales.R @@ -277,7 +277,7 @@ scale_datetime <- function(vis, property, domain = NULL, range = NULL, #' #' p <- ToothGrowth %>% group_by(supp) %>% #' ggvis(~len, fill = ~supp) %>% -#' layer_histograms(binwidth = 4, stack = TRUE) +#' layer_histograms(width = 4, stack = TRUE) #' #' # Control range of fill scale #' p %>% scale_nominal("fill", range = c("pink", "lightblue")) diff --git a/R/utils.R b/R/utils.R index a04cf66c..efd8f955 100644 --- a/R/utils.R +++ b/R/utils.R @@ -228,6 +228,12 @@ vpluck <- function(x, name, type) { vapply(x, `[[`, name, FUN.VALUE = type) } +# Like as.numeric, except that as.numeric(NULL) returns numeric(0), whereas +# as_numeric(NULL) returns NULL. +as_numeric <- function(x) { + if (is.null(x)) NULL + else as.numeric(x) +} deprecated <- function(old, new = NULL, msg = NULL, version = NULL) { text <- paste0( @@ -236,5 +242,5 @@ deprecated <- function(old, new = NULL, msg = NULL, version = NULL) { msg, if (!is.null(version)) sprintf(" (Last used in version %s)", version) ) - warning(text) + warning(text, call. = FALSE) } diff --git a/demo/apps/brush-linked/server.r b/demo/apps/brush-linked/server.r index f5468bc8..a8336549 100644 --- a/demo/apps/brush-linked/server.r +++ b/demo/apps/brush-linked/server.r @@ -24,9 +24,9 @@ shinyServer(function(input, output, session) { cocaine %>% ggvis(~potency) %>% - layer_histograms(binwidth = 5, origin = 0) %>% + layer_histograms(width = 5, origin = 0) %>% add_data(cocaine_selected) %>% - layer_histograms(binwidth = 5, origin = 0, fill := "#dd3333") %>% + layer_histograms(width = 5, origin = 0, fill := "#dd3333") %>% set_options(width = 300, height = 300) %>% bind_shiny("plot2") }) diff --git a/demo/apps/linked-hover/server.r b/demo/apps/linked-hover/server.r index d2bc6ba0..bbddf578 100644 --- a/demo/apps/linked-hover/server.r +++ b/demo/apps/linked-hover/server.r @@ -6,7 +6,7 @@ shinyServer(function(input, output, session) { values <- reactiveValues(selected = rep(TRUE, nrow(diamonds))) diamonds %>% ggvis(~carat) %>% - layer_histograms(fill.hover := "red", binwidth = 0.1) %>% + layer_histograms(fill.hover := "red", width = 0.1) %>% handle_hover(function(data, ...) { values$selected <- diamonds$carat >= data$xmin_ & diamonds$carat < data$xmax_ @@ -17,7 +17,7 @@ shinyServer(function(input, output, session) { # Sub-histogram reactive(diamonds[values$selected, , drop = FALSE]) %>% ggvis(~carat) %>% - layer_histograms(binwidth = 0.01) %>% + layer_histograms(width = 0.01) %>% set_options(width = 400, height = 200) %>% bind_shiny("plot2") diff --git a/demo/histogram.r b/demo/histogram.r index 75aca7f9..a94850a1 100644 --- a/demo/histogram.r +++ b/demo/histogram.r @@ -2,17 +2,17 @@ library(ggvis) # Histogram, fully specified mtcars %>% ggvis(x = ~wt) %>% - compute_bin(~wt, binwidth = 1, pad = FALSE) %>% + compute_bin(~wt, width = 1, pad = FALSE) %>% layer_rects(x = ~xmin_, x2 = ~xmax_, y = ~count_, y2 = 0) # Or using shorthand layer mtcars %>% ggvis(x = ~wt) %>% layer_histograms() -mtcars %>% ggvis(x = ~wt) %>% layer_histograms(binwidth = 1) +mtcars %>% ggvis(x = ~wt) %>% layer_histograms(width = 1) # Histogram, filled by cyl mtcars %>% ggvis(x = ~wt, fill = ~factor(cyl)) %>% group_by(cyl) %>% - layer_histograms(binwidth = 1) + layer_histograms(width = 1) # Bigger dataset data(diamonds, package = "ggplot2") @@ -21,7 +21,7 @@ diamonds %>% ggvis(x = ~table) %>% layer_histograms() # Stacked histogram diamonds %>% ggvis(x = ~table, fill = ~cut) %>% group_by(cut) %>% - layer_histograms(binwidth = 1) + layer_histograms(width = 1) # Histogram of dates set.seed(2934) diff --git a/demo/rmarkdown/interactive_doc.Rmd b/demo/rmarkdown/interactive_doc.Rmd index 6ac55ad6..9d63b5f7 100644 --- a/demo/rmarkdown/interactive_doc.Rmd +++ b/demo/rmarkdown/interactive_doc.Rmd @@ -16,7 +16,7 @@ An interactive plot: ```{r, message = FALSE, fig.width = 6, fig.height = 4} cocaine %>% ggvis(x = ~potency) %>% - layer_histograms(binwidth = input_slider(1, 20, value = 5)) + layer_histograms(width = input_slider(1, 20, value = 5)) ``` diff --git a/demo/rmarkdown/linked_brush.Rmd b/demo/rmarkdown/linked_brush.Rmd index 9dc8a47c..abfdcaf5 100644 --- a/demo/rmarkdown/linked_brush.Rmd +++ b/demo/rmarkdown/linked_brush.Rmd @@ -31,9 +31,9 @@ cocaine_selected <- reactive({ cocaine %>% ggvis(~potency) %>% - layer_histograms(binwidth = 5, origin = 0) %>% + layer_histograms(width = 5, origin = 0) %>% add_data(cocaine_selected) %>% - layer_histograms(binwidth = 5, origin = 0, fill := "#dd3333") + layer_histograms(width = 5, origin = 0, fill := "#dd3333") ``` A summary of the selected points: diff --git a/man/bin_vector.Rd b/man/bin_vector.Rd new file mode 100644 index 00000000..5463d494 --- /dev/null +++ b/man/bin_vector.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2 (4.0.2): do not edit by hand +\name{bin_vector} +\alias{bin_vector} +\title{Bin vectors} +\usage{ +bin_vector(x, weight = NULL, ...) +} +\arguments{ +\item{x}{A vector to bin} + +\item{weight}{If specified, an integer vector of the same length as \code{x} +representing the number of occurances of each value in \code{x}} + +\item{...}{additional arguments passed through to methods.} + +\item{width}{The width of a bin} + +\item{origin}{The left-most value for bins.} + +\item{closed}{One of \code{"right"} or \code{"left"} indicating whether +right or left edges of bins are included in the bin.} + +\item{pad}{A logical indicating whether the bins should be padded to include +an empty bin on each side.} +} +\description{ +A generic and several implementations for binning vectors. +} +\keyword{internal} + diff --git a/man/compute_bin.Rd b/man/compute_bin.Rd index 9e831fde..ce195077 100644 --- a/man/compute_bin.Rd +++ b/man/compute_bin.Rd @@ -3,8 +3,8 @@ \alias{compute_bin} \title{Bin data along a continuous variable} \usage{ -compute_bin(x, x_var, w_var = NULL, binwidth = NULL, origin = NULL, - right = TRUE, pad = TRUE) +compute_bin(x, x_var, w_var = NULL, width = NULL, center = NULL, + boundary = NULL, closed = c("right", "left"), pad = TRUE) } \arguments{ \item{x}{Dataset-like object to bin. Built-in methods for data frames, @@ -13,20 +13,30 @@ grouped data frames and ggvis visualisations.} \item{x_var,w_var}{Names of x and weight variables. The x variable must be continuous.} -\item{binwidth}{The width of the bins. The default is \code{NULL}, which -yields 30 bins that cover the range of the data. You should always override -this value, exploring multiple widths to find the best to illustrate the -stories in your data.} +\item{width}{The width of the bins. The default is \code{NULL}, which yields +30 bins that cover the range of the data. You should always override this +value, exploring multiple widths to find the best to illustrate the stories +in your data.} -\item{origin}{The initial position of the left-most bin. If \code{NULL}, the -the default, will use the smallest value in the dataset.} +\item{center}{The center of one of the bins. Note that if center is above or +below the range of the data, things will be shifted by an appropriate +number of \code{width}s. To center on integers, for example, use +\code{width=1} and \code{center=0}, even if \code{0} is outside the range +of the data. At most one of \code{center} and \code{boundary} may be +specified.} -\item{right}{Should bins be right-open, left-closed, or -right-closed, left-open.} +\item{boundary}{A boundary between two bins. As with \code{center}, things +are shifted when \code{boundary} is outside the range of the data. For +example, to center on integers, use \code{width = 1} and \code{boundary = +0.5}, even if \code{1} is outside the range of the data. At most one of +\code{center} and \code{boundary} may be specified.} -\item{pad}{If \code{TRUE}, adds empty bins at either end of x. This -ensures frequency polygons touch 0, and adds padidng between the data -and axis for histograms.} +\item{closed}{One of \code{"right"} or \code{"left"} indicating whether right +or left edges of bins are included in the bin.} + +\item{pad}{If \code{TRUE}, adds empty bins at either end of x. This ensures +frequency polygons touch 0, and adds padding between the data and axis for +histograms.} } \value{ A data frame with columns: @@ -41,8 +51,8 @@ Bin data along a continuous variable } \examples{ mtcars \%>\% compute_bin(~mpg) -mtcars \%>\% compute_bin(~mpg, binwidth = 10) -mtcars \%>\% group_by(cyl) \%>\% compute_bin(~mpg, binwidth = 10) +mtcars \%>\% compute_bin(~mpg, width = 10) +mtcars \%>\% group_by(cyl) \%>\% compute_bin(~mpg, width = 10) # It doesn't matter whether you transform inside or outside of a vis mtcars \%>\% compute_bin(~mpg) \%>\% ggvis(~x_, ~count_) \%>\% layer_paths() diff --git a/man/layer_bars.Rd b/man/layer_bars.Rd index d315dc4a..6fac923b 100644 --- a/man/layer_bars.Rd +++ b/man/layer_bars.Rd @@ -59,7 +59,7 @@ cocaine \%>\% ggvis(~month, ~weight) \%>\% layer_bars() # unique values that you want to preserve. If you have many unique # values and you want to bin, use layer_histogram cocaine \%>\% ggvis(~price) \%>\% layer_bars() -cocaine \%>\% ggvis(~price) \%>\% layer_histograms(binwidth = 100) +cocaine \%>\% ggvis(~price) \%>\% layer_histograms(width = 100) # If you have unique x values, you can use layer_bars() as an alternative # to layer_points() diff --git a/man/layer_histograms.Rd b/man/layer_histograms.Rd index 274fa4d1..5f2bf06c 100644 --- a/man/layer_histograms.Rd +++ b/man/layer_histograms.Rd @@ -4,26 +4,37 @@ \alias{layer_histograms} \title{Display binned data} \usage{ -layer_histograms(vis, ..., binwidth = NULL, origin = NULL, right = TRUE, - stack = TRUE) +layer_histograms(vis, ..., width = NULL, center = NULL, boundary = NULL, + closed = c("right", "left"), stack = TRUE) -layer_freqpolys(vis, ..., binwidth = NULL, origin = NULL, right = TRUE) +layer_freqpolys(vis, ..., width = NULL, center = NULL, boundary = NULL, + closed = c("right", "left")) } \arguments{ \item{vis}{Visualisation to modify} \item{...}{Visual properties used to override defaults.} -\item{binwidth}{The width of the bins. The default is \code{NULL}, which -yields 30 bins that cover the range of the data. You should always override -this value, exploring multiple widths to find the best to illustrate the -stories in your data.} +\item{width}{The width of the bins. The default is \code{NULL}, which yields +30 bins that cover the range of the data. You should always override this +value, exploring multiple widths to find the best to illustrate the stories +in your data.} -\item{origin}{The initial position of the left-most bin. If \code{NULL}, the -the default, will use the smallest value in the dataset.} +\item{center}{The center of one of the bins. Note that if center is above or +below the range of the data, things will be shifted by an appropriate +number of \code{width}s. To center on integers, for example, use +\code{width=1} and \code{center=0}, even if \code{0} is outside the range +of the data. At most one of \code{center} and \code{boundary} may be +specified.} -\item{right}{Should bins be right-open, left-closed, or -right-closed, left-open.} +\item{boundary}{A boundary between two bins. As with \code{center}, things +are shifted when \code{boundary} is outside the range of the data. For +example, to center on integers, use \code{width = 1} and \code{boundary = +0.5}, even if \code{1} is outside the range of the data. At most one of +\code{center} and \code{boundary} may be specified.} + +\item{closed}{One of \code{"right"} or \code{"left"} indicating whether right +or left edges of bins are included in the bin.} \item{stack}{If \code{TRUE}, will automatically stack overlapping bars.} } @@ -33,8 +44,8 @@ Display binned data \examples{ # Create histograms and frequency polygons with layers mtcars \%>\% ggvis(~mpg) \%>\% layer_histograms() -mtcars \%>\% ggvis(~mpg) \%>\% layer_histograms(binwidth = 2) -mtcars \%>\% ggvis(~mpg) \%>\% layer_freqpolys(binwidth = 2) +mtcars \%>\% ggvis(~mpg) \%>\% layer_histograms(width = 2) +mtcars \%>\% ggvis(~mpg) \%>\% layer_freqpolys(width = 2) # These are equivalent to combining compute_bin with the corresponding # mark @@ -42,9 +53,9 @@ mtcars \%>\% compute_bin(~mpg) \%>\% ggvis(~x_, ~count_) \%>\% layer_paths() # With grouping mtcars \%>\% ggvis(~mpg, fill = ~factor(cyl)) \%>\% group_by(cyl) \%>\% - layer_histograms(binwidth = 2) + layer_histograms(width = 2) mtcars \%>\% ggvis(~mpg, stroke = ~factor(cyl)) \%>\% group_by(cyl) \%>\% - layer_freqpolys(binwidth = 2) + layer_freqpolys(width = 2) } \seealso{ \code{\link{layer_bars}} For bar graphs of counts at each unique diff --git a/man/scale_ordinal.Rd b/man/scale_ordinal.Rd index e606ad71..9db8cb90 100644 --- a/man/scale_ordinal.Rd +++ b/man/scale_ordinal.Rd @@ -90,7 +90,7 @@ p \%>\% scale_nominal("x", reverse = TRUE) p <- ToothGrowth \%>\% group_by(supp) \%>\% ggvis(~len, fill = ~supp) \%>\% - layer_histograms(binwidth = 4, stack = TRUE) + layer_histograms(width = 4, stack = TRUE) # Control range of fill scale p \%>\% scale_nominal("fill", range = c("pink", "lightblue")) diff --git a/tests/specs/layer.r b/tests/specs/layer.r index 3e2c35f5..dedc84d0 100644 --- a/tests/specs/layer.r +++ b/tests/specs/layer.r @@ -2,13 +2,13 @@ library(ggvis) mtcars %>% ggvis(x = ~wt) %>% - layer_histograms(binwidth = 1) %>% + layer_histograms(width = 1) %>% save_spec("layer/histogram.json") mtcars %>% ggvis(x = ~wt, stroke = ~cyl) %>% group_by(cyl) %>% - layer_freqpolys(binwidth = 1) %>% + layer_freqpolys(width = 1) %>% save_spec("layer/freqpoly-grouped.json") mtcars %>% diff --git a/tests/specs/line/layer-line-nominal-x.json b/tests/specs/line/layer-line-nominal-x.json index 5339fb12..9fa3e221 100644 --- a/tests/specs/line/layer-line-nominal-x.json +++ b/tests/specs/line/layer-line-nominal-x.json @@ -25,16 +25,14 @@ { "name" : "scale/stroke", "format" : { - "type" : "csv", - "parse" : {} + "type" : "csv" }, "values" : "\"domain\"\n\"1\"\n\"2\"\n\"3\"" }, { "name" : "scale/x", "format" : { - "type" : "csv", - "parse" : {} + "type" : "csv" }, "values" : "\"domain\"\n\"a\"\n\"b\"\n\"c\"\n\"d\"" }, @@ -146,16 +144,13 @@ "title" : "y" } ], - "padding" : null, "ggvis_opts" : { "width" : 600, "height" : 400, "keep_aspect" : false, "resizable" : true, - "padding" : {}, "duration" : 250, "renderer" : "svg", "hover_duration" : 0 - }, - "handlers" : null + } } diff --git a/tests/specs/line/layer-line.json b/tests/specs/line/layer-line.json index 549fe2a1..1052e2e4 100644 --- a/tests/specs/line/layer-line.json +++ b/tests/specs/line/layer-line.json @@ -26,8 +26,7 @@ { "name" : "scale/stroke", "format" : { - "type" : "csv", - "parse" : {} + "type" : "csv" }, "values" : "\"domain\"\n\"1\"\n\"2\"\n\"3\"" }, @@ -148,16 +147,13 @@ "title" : "y" } ], - "padding" : null, "ggvis_opts" : { "width" : 600, "height" : 400, "keep_aspect" : false, "resizable" : true, - "padding" : {}, "duration" : 250, "renderer" : "svg", "hover_duration" : 0 - }, - "handlers" : null + } } diff --git a/tests/testthat/test-compute-bin.r b/tests/testthat/test-compute-bin.r index 0edf7e8b..6482cc47 100644 --- a/tests/testthat/test-compute-bin.r +++ b/tests/testthat/test-compute-bin.r @@ -1,37 +1,158 @@ context("compute_bin") -test_that("bin_vector preserves dates and times", { - dates <- as.Date("2013-07-01") + 1:100 - res <- bin_vector(dates, binwidth = 30) +comp_bin <- function(...) { + suppressMessages(compute_bin(...)) +} + +test_that("compute_bin preserves dates and times", { + dates <- data.frame(val = as.Date("2013-06-01") + 0:100) + NYtimes <- data.frame( + val = as.POSIXct('2001-06-01 21:00', tz = 'America/New_York') + 0:10 * 100 + ) + UTCtimes <- data.frame( + val = as.POSIXct('2001-06-01 21:00', tz = 'UTC') + seq(0, 1000, by = 10) + ) + + res <- comp_bin(dates, ~val, width = 30) expect_true(inherits(res$x_, "Date")) expect_true(inherits(res$xmin_, "Date")) expect_true(inherits(res$xmax_, "Date")) - expect_identical(sum(res$count_), 100) + expect_identical(sum(res$count_), length(dates$val)) - times <- as.POSIXct('2001-06-11 21:00', tz = 'America/New_York') + 1:10 * 100 - res <- bin_vector(times, binwidth = 120) + res <- comp_bin(NYtimes, ~val, width = 120) expect_true(inherits(res$x_, "POSIXct")) expect_true(inherits(res$xmin_, "POSIXct")) expect_true(inherits(res$xmax_, "POSIXct")) - expect_identical(sum(res$count_), 10) - expect_identical(attr(times, "tzone"), attr(res$x_, "tzone")) - - times <- as.POSIXct('2001-06-11 21:00', tz = 'UTC') + seq(1, 1000, by = 10) - res <- bin_vector(times, binwidth = 120) - expect_identical(sum(res$count_), 100) - expect_identical(attr(times, "tzone"), attr(res$x_, "tzone")) - - - # Can set origin - dates <- as.Date("2013-07-01") + 1:100 - res <- bin_vector(dates, binwidth = 30, origin = as.Date("2013-06-01"), - pad = FALSE) - expect_identical(sum(res$count_), 100) - expect_identical(res$xmin_[1], as.Date("2013-06-01")) - - res <- bin_vector(times, binwidth = 120, - origin = as.POSIXct('2001-06-11 21:00', tz = 'UTC'), - pad = FALSE) - expect_identical(sum(res$count_), 100) - expect_identical(res$xmin_[1], as.POSIXct('2001-06-11 21:00', tz = 'UTC')) + expect_identical(sum(res$count_), length(NYtimes$val)) + expect_identical(attr(NYtimes$val, "tzone"), attr(res$x_, "tzone")) + + res <- comp_bin(UTCtimes, ~val, width = 120) + expect_identical(sum(res$count_), length(UTCtimes$val)) + expect_identical(attr(UTCtimes$val, "tzone"), attr(res$x_, "tzone")) +}) + +test_that("width in lubridate::Period", { + UTCtimes <- data.frame( + val = as.POSIXct('2001-06-01 21:00', tz = 'UTC') + seq(0, 1000, by = 10) + ) + + # width specified as a Period from lubridate + expect_identical( + comp_bin(UTCtimes, ~val, width = lubridate::ms("1 42")), + comp_bin(UTCtimes, ~val, width = 102) + ) +}) + +test_that("Closed left or right", { + dat <- data.frame(x = c(0, 10)) + + res <- comp_bin(dat, ~x, width = 10, pad = FALSE) + expect_identical(res$count_, c(1L, 1L)) + res <- comp_bin(dat, ~x, width = 10, boundary = 5, pad = FALSE) + expect_identical(res$count_, c(1L, 1L)) + res <- comp_bin(dat, ~x, width = 10, boundary = 0, pad = FALSE) + expect_identical(res$count_, 2L) + res <- comp_bin(dat, ~x, width = 5, boundary = 0, pad = FALSE) + expect_identical(res$count_, c(1L, 1L)) + + res <- comp_bin(dat, ~x, width = 10, pad = FALSE, closed = "left") + expect_identical(res$count_, c(1L, 1L)) + res <- comp_bin(dat, ~x, width = 10, boundary = 5, pad = FALSE, closed = "left") + expect_identical(res$count_, c(1L, 1L)) + res <- comp_bin(dat, ~x, width = 10, boundary = 0, pad = FALSE, closed = "left") + expect_identical(res$count_, c(2L)) + res <- comp_bin(dat, ~x, width = 5, boundary = 0, pad = FALSE, closed = "left") + expect_identical(res$count_, c(1L, 1L)) +}) + + +test_that("Setting boundary and center", { + # numeric + dat <- data.frame(x = c(0, 30)) + + # Error if both boundary and center are specified + expect_error(comp_bin(dat, ~x, width = 10, bondary = 5, center = 0, pad = FALSE)) + + res <- comp_bin(dat, ~x, width = 10, boundary = 0, pad = FALSE) + expect_identical(res$count, c(1L, 0L, 1L)) + expect_identical(res$xmin_[1], 0) + expect_identical(res$xmax_[3], 30) + + res <- comp_bin(dat, ~x, width = 10, center = 0, pad = FALSE) + expect_identical(res$count, c(1L, 0L, 0L, 1L)) + expect_identical(res$xmin_[1], dat$x[1] - 5) + expect_identical(res$xmax_[4], dat$x[2] + 5) + + + # Date + dat <- data.frame(x = as.Date("2013-06-01") + c(0, 30)) + + res <- comp_bin(dat, ~x, width = 10, boundary = as.Date("2013-06-01"), pad = FALSE) + expect_identical(res$count_, c(1L, 0L, 1L)) + expect_identical(res$xmin_[1], dat$x[1]) + expect_identical(res$xmax_[3], dat$x[2]) + + res <- comp_bin(dat, ~x, width = 10, center = as.Date("2013-06-01"), pad = FALSE) + expect_identical(res$count, c(1L, 0L, 0L, 1L)) + expect_identical(res$xmin_[1], dat$x[1] - 5) + expect_identical(res$xmax_[4], dat$x[2] + 5) + + + # POSIXct + dat <- data.frame( + x = as.POSIXct('2001-06-01 21:00', tz = 'America/New_York') + c(0, 30000) + ) + + res <- comp_bin(dat, ~x, width = 10000, boundary = dat$x[1], pad = FALSE) + expect_identical(res$count_, c(1L, 0L, 1L)) + expect_identical(res$xmin_[1], dat$x[1]) + expect_identical(res$xmax_[3], dat$x[2]) + + res <- comp_bin(dat, ~x, width = 10000, center = dat$x[1], pad = FALSE) + expect_identical(res$count, c(1L, 0L, 0L, 1L)) + expect_identical(res$xmin_[1], dat$x[1] - 5000) + expect_identical(res$xmax_[4], dat$x[2] + 5000) +}) + + +test_that("Automatic width", { + dat <- data.frame( + num = c(0, 25.0), + num2 = c(0, 50.0), + int = c(1L, 25L), + int2 = c(1L, 50L), + date = as.Date("2013-06-01") + c(0, 100), + posixct = as.POSIXct('2001-06-01 21:00', tz = 'UTC') + c(0, 1000) + ) + + # numeric + res <- suppressMessages(compute_bin(dat, ~num)) + # Need to use expect_equal to deal with FP error + expect_equal(res$width_, rep(25/30, length(res$width_))) + res <- suppressMessages(compute_bin(dat, ~num2)) + expect_equal(res$width_, rep(50/30, length(res$width_))) + + # integer + res <- suppressMessages(compute_bin(dat, ~int)) + expect_true(all(res$width_ == 1L)) + res <- suppressMessages(compute_bin(dat, ~int2)) + expect_true(all(res$width_ == 2L)) + + # Date + res <- suppressMessages(compute_bin(dat, ~date)) + expect_equal(res$width_, rep(100/30, length(res$width_))) + + # POSIXct + res <- suppressMessages(compute_bin(dat, ~posixct)) + expect_equal(res$width_, rep(1000/30, length(res$width_))) +}) + + +test_that("Bin boundaries across groups", { + # Bins should be the same across groups + dat <- data.frame(x = c(0:2, 0:2+0.5), g=c('a','a','a', 'b','b','b')) + res <- dat %>% group_by(g) %>% compute_bin(~x, width = 1, pad = FALSE) + expect_identical(range(res$x_[res$g =='a']), range(res$x_[res$g =='b'])) + expect_identical(dplyr::groups(res), list(quote(g))) + expect_identical(res$count_, rep(1L, 6)) }) diff --git a/vignettes/cookbook.Rmd b/vignettes/cookbook.Rmd index 9fcb069b..afb7d115 100644 --- a/vignettes/cookbook.Rmd +++ b/vignettes/cookbook.Rmd @@ -148,18 +148,46 @@ Basic histogram: faithful %>% ggvis(~eruptions) %>% layer_histograms() ``` -Modify the fill color and binwidth: + +The bin selection can be controled by specifying `width` and at most one of `center` or +`boundary` of one of the bins. `boundary` and `center` may be outside the range of +the data. + +```{r, message = FALSE} +faithful %>% ggvis(~eruptions) %>% layer_histograms(width=0.5, boundary=0) +faithful %>% ggvis(~eruptions) %>% layer_histograms(width=0.5, center=0) +``` + +Modify the fill color and bin width, and add titles for the axes, since the automatic titles aren't very informative: + ```{r, message = FALSE} faithful %>% ggvis(~eruptions, fill := "#fff8dc") %>% - layer_histograms(binwidth = 0.25) + layer_histograms(width = 0.25) ``` +By default, when the number of integer values is small, bins will +be centered at integers and have a width of 1: +```{r, message = FALSE} +cocaine %>% ggvis(~month, fill := "#fff8dc") %>% + layer_histograms() %>% + add_axis("x", title = "month") %>% + add_axis("y", title = "count") +``` + +This can be forced with +```{r, message = FALSE} +cocaine %>% ggvis(~month, fill := "#fff8dc") %>% + layer_histograms(width = 1, center = 0) %>% + add_axis("x", title = "month") %>% + add_axis("y", title = "count") +``` ## Box plots ```{r} -# For now, if you use a categ mtc <- mtcars %>% mutate(cyl = factor(cyl)) mtc %>% ggvis(~cyl, ~mpg) %>% layer_boxplots() ``` + + diff --git a/vignettes/ggvis-basics.Rmd b/vignettes/ggvis-basics.Rmd index 48fd00bb..8383d4fd 100644 --- a/vignettes/ggvis-basics.Rmd +++ b/vignettes/ggvis-basics.Rmd @@ -115,12 +115,14 @@ mtcars %>% layer_points() ``` -You can also connect interactive components to other plot parameters like the binwidth of a histogram: +You can also connect interactive components to other plot parameters like the width +and centers of histogram bins: ```{r} mtcars %>% ggvis(~wt) %>% - layer_histograms(binwidth = input_slider(0, 2, step = 0.1)) + layer_histograms(width = input_slider(0, 2, step = 0.10, label = "width"), + center = input_slider(0, 2, step = 0.05, label = "center")) ``` Behind the scenes, interactive plots are built with [shiny](http://www.rstudio.com/shiny/), and you can currently only have one running at a time in a given R session. To finish with a plot, press the stop button in Rstudio, or close the browser window and then press Escape or Ctrl + C in R. diff --git a/vignettes/overview.Rmd b/vignettes/overview.Rmd index 14f968ea..1f5efaae 100644 --- a/vignettes/overview.Rmd +++ b/vignettes/overview.Rmd @@ -37,7 +37,7 @@ Histogram: ```{r, echo = FALSE, fig.width = 4} # Histogram faithful %>% ggvis(~eruptions, fill := "#ffffdd", fill.hover := "#eebbbb") %>% - layer_histograms(binwidth = 0.2) %>% + layer_histograms(width = 0.2) %>% add_axis("x", title = "eruptions") %>% add_axis("y", title = "count") ```