From 3672a99f6e46552a4fe4d97d922eaf22a38885a7 Mon Sep 17 00:00:00 2001 From: David Gohel Date: Fri, 23 Feb 2024 20:50:16 +0100 Subject: [PATCH] update for ggplot2v3.5 - integrate Pana's updates; https://github.com/davidgohel/ggiraph/pull/269 - add new param `staplewidth` - remove copy of dapply - tests: remove failing tests (will fix and bring them back eventually later) - tests: dont use `ggiraphOutput()` - deprecate `ggiraph()` --- DESCRIPTION | 9 +- NAMESPACE | 17 +- NEWS.md | 7 + R/geom_boxplot_interactive.R | 21 ++ R/geom_label_interactive.R | 31 +- R/geom_path_interactive.R | 88 ++--- R/geom_pointrange_interactive.R | 12 +- R/geom_violin_interactive.R | 17 +- R/ggiraph.R | 8 +- R/guide_bins_interactive.R | 55 ++- R/guide_colourbar_interactive.R | 79 ++-- R/guide_coloursteps_interactive.R | 69 ++-- R/guide_interactive.R | 340 +++++++++++------- R/guide_legend_interactive.R | 61 +++- R/ipar.R | 85 +++-- R/labeller_interactive.R | 1 + R/layer_interactive.R | 44 +-- R/scale_interactive.R | 41 ++- R/utils.R | 6 - ...ale_gradient_guide_colourbar_interactive.R | 43 ++- .../scale_viridis_guide_bins_interactive.R | 83 ++++- inst/tinytest/setup.R | 4 +- inst/tinytest/test-ggiraph.R | 4 +- inst/tinytest/test-guide_bins_interactive.R | 217 ++++++++--- .../test-guide_colourbar_interactive.R | 69 ---- .../test-guide_coloursteps_interactive.R | 67 ---- inst/tinytest/test-guide_interactive.R | 96 ----- inst/tinytest/test-guide_legend_interactive.R | 225 +++++++++--- inst/tinytest/test-scale_interactive.R | 10 +- man/ggiraph-ggproto.Rd | 8 +- man/ggiraph.Rd | 4 - man/guide_bins_interactive.Rd | 104 ++++-- man/guide_colourbar_interactive.Rd | 64 ++-- man/guide_coloursteps_interactive.Rd | 21 +- man/guide_legend_interactive.Rd | 21 +- man/interactive_parameters.Rd | 21 +- man/scale_alpha_interactive.Rd | 21 +- man/scale_colour_brewer_interactive.Rd | 21 +- man/scale_colour_interactive.Rd | 21 +- man/scale_colour_steps_interactive.Rd | 21 +- man/scale_gradient_interactive.Rd | 64 ++-- man/scale_linetype_interactive.Rd | 21 +- man/scale_manual_interactive.Rd | 21 +- man/scale_shape_interactive.Rd | 21 +- man/scale_size_interactive.Rd | 21 +- man/scale_viridis_interactive.Rd | 21 +- 46 files changed, 1304 insertions(+), 1001 deletions(-) delete mode 100644 inst/tinytest/test-guide_colourbar_interactive.R delete mode 100644 inst/tinytest/test-guide_coloursteps_interactive.R delete mode 100644 inst/tinytest/test-guide_interactive.R diff --git a/DESCRIPTION b/DESCRIPTION index 3cdf98d1..b358f28c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,7 +2,7 @@ Package: ggiraph Type: Package Title: Make 'ggplot2' Graphics Interactive Description: Create interactive 'ggplot2' graphics using 'htmlwidgets'. -Version: 0.8.8 +Version: 0.8.9.002 Authors@R: c( person("David", "Gohel", role = c("aut", "cre"), email = "david.gohel@ardata.fr"), @@ -26,14 +26,14 @@ Copyright: See file COPYRIGHTS. Encoding: UTF-8 SystemRequirements: libpng Imports: - grid, ggplot2 (>= 3.4.0), + grid, ggplot2 (>= 3.5.0), htmlwidgets (>= 1.5), stats, htmltools, Rcpp (>= 1.0), systemfonts, purrr, rlang, uuid, - vctrs + vctrs, cli LinkingTo: Rcpp, systemfonts Suggests: knitr, @@ -51,8 +51,9 @@ Suggests: VignetteBuilder: knitr URL: https://davidgohel.github.io/ggiraph/ BugReports: https://github.com/davidgohel/ggiraph/issues -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.1 Roxygen: list(markdown = TRUE) +Remotes: tidyverse/ggplot2@rc/3.5.0 Collate: 'RcppExports.R' 'ipar.R' diff --git a/NAMESPACE b/NAMESPACE index e235c0cb..603b4424 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -13,18 +13,7 @@ S3method(drawDetails,interactive_text_grob) S3method(drawDetails,interactive_xspline_grob) S3method(element_grob,interactive_element) S3method(element_grob,interactive_element_text) -S3method(guide_gengrob,interactive_colourbar) -S3method(guide_gengrob,interactive_coloursteps) -S3method(guide_gengrob,interactive_guide) -S3method(guide_geom,interactive_bins) -S3method(guide_geom,interactive_guide) -S3method(guide_geom,interactive_legend) -S3method(guide_train,interactive_bins) -S3method(guide_train,interactive_colourbar) -S3method(guide_train,interactive_coloursteps) -S3method(guide_train,interactive_legend) S3method(makeContent,interactive_curve_grob) -S3method(makeContent,interactive_label_grob) S3method(makeContent,interactive_repeltree_grob) S3method(makeContent,interactive_roundrect_grob) S3method(makeContext,interactive_dotstack_grob) @@ -70,6 +59,10 @@ export(GeomInteractiveText) export(GeomInteractiveTile) export(GeomInteractiveViolin) export(GeomInteractiveVline) +export(GuideInteractiveBins) +export(GuideInteractiveColourbar) +export(GuideInteractiveColoursteps) +export(GuideInteractiveLegend) export(StatInteractiveBoxplot) export(annotate_interactive) export(annotation_raster_interactive) @@ -288,7 +281,6 @@ importFrom(htmlwidgets,createWidget) importFrom(htmlwidgets,shinyRenderWidget) importFrom(htmlwidgets,shinyWidgetOutput) importFrom(htmlwidgets,sizingPolicy) -importFrom(purrr,compact) importFrom(purrr,detect_index) importFrom(purrr,flatten) importFrom(purrr,imap) @@ -298,6 +290,7 @@ importFrom(rlang,arg_match) importFrom(rlang,caller_env) importFrom(rlang,env_get_list) importFrom(rlang,eval_tidy) +importFrom(rlang,inherits_any) importFrom(rlang,is_named) importFrom(rlang,is_scalar_character) importFrom(rlang,is_scalar_double) diff --git a/NEWS.md b/NEWS.md index b43b4913..bf06dc12 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,10 @@ +# ggiraph 0.8.9 + +## Changes + +- adapt guides to ggplot '3.5.0' +- deprecate ggiraph + # ggiraph 0.8.8 ## Issues diff --git a/R/geom_boxplot_interactive.R b/R/geom_boxplot_interactive.R index b0c692a1..0a55e573 100644 --- a/R/geom_boxplot_interactive.R +++ b/R/geom_boxplot_interactive.R @@ -171,6 +171,7 @@ GeomInteractiveBoxplot <- ggproto( outlier.alpha = NULL, notch = FALSE, notchwidth = 0.5, + staplewidth = 0, varwidth = FALSE, flipped_aes = FALSE, .ipar = IPAR_NAMES) { @@ -242,10 +243,30 @@ GeomInteractiveBoxplot <- ggproto( outliers_grob <- NULL } + if (staplewidth != 0) { + staples <- data_frame0( + x = rep((data$xmin - data$x) * staplewidth + data$x, 2), + xend = rep((data$xmax - data$x) * staplewidth + data$x, 2), + y = c(data$ymax, data$ymin), + yend = c(data$ymax, data$ymin), + alpha = c(NA_real_, NA_real_), + !!!common, + .size = 2 + ) + staples <- flip_data(staples, flipped_aes) + staple_grob <- GeomInteractiveSegment$draw_panel( + staples, panel_params, coord, + lineend = lineend, .ipar = .ipar + ) + } else { + staple_grob <- NULL + } + ggname( "geom_boxplot_interactive", grobTree( outliers_grob, + staple_grob, GeomInteractiveSegment$draw_panel(whiskers, panel_params, coord, lineend = lineend, .ipar = .ipar), GeomInteractiveCrossbar$draw_panel(box, fatten = fatten, panel_params, coord, lineend = lineend, diff --git a/R/geom_label_interactive.R b/R/geom_label_interactive.R index 0462695f..0ffd28a4 100644 --- a/R/geom_label_interactive.R +++ b/R/geom_label_interactive.R @@ -22,20 +22,21 @@ GeomInteractiveLabel <- ggproto( if (is.null(coords$tooltip_fill)) { coords$tooltip_fill <- coords$fill } - add_interactive_attrs(gr, coords, ipar = .ipar) + for (i in seq_along(gr$children)) { + for (j in seq_along(gr$children[[i]]$children)) { + if (inherits(gr$children[[i]]$children[[j]], "roundrect")) { + gr$children[[i]]$children[[j]] <- add_interactive_attrs( + gr$children[[i]]$children[[j]], + data = coords[i, ], ipar = .ipar + ) + } else if (inherits(gr$children[[i]]$children[[j]], "titleGrob")) { + gr$children[[i]]$children[[j]]$children[[1]] <- add_interactive_attrs( + gr$children[[i]]$children[[j]]$children[[1]], + data = coords[i, ], ipar = .ipar + ) + } + } + } + gr } ) - -#' @export -makeContent.interactive_label_grob <- function(x) { - gr <- NextMethod() - data <- get_interactive_data(x) - data_attr <- get_data_attr(x) - ipar <- get_ipar(x) - for (i in seq_along(gr$children)) { - gr$children[[i]] <- add_interactive_attrs( - gr$children[[i]], data = data, data_attr = data_attr, ipar = ipar - ) - } - gr -} diff --git a/R/geom_path_interactive.R b/R/geom_path_interactive.R index 8e1af6a7..cb5fbe6a 100644 --- a/R/geom_path_interactive.R +++ b/R/geom_path_interactive.R @@ -37,88 +37,39 @@ GeomInteractivePath <- ggproto( linemitre = 10, na.rm = FALSE, .ipar = IPAR_NAMES) { - if (!anyDuplicated(data$group)) { - message_wrap( - "geom_path: Each group consists of only one observation. ", - "Do you need to adjust the group aesthetic?" - ) + gr <- GeomPath$draw_panel( + data = data, + panel_params = panel_params, + coord = coord, + arrow = arrow, + lineend = lineend, + linejoin = linejoin, + linemitre = linemitre, + na.rm = na.rm) + + if (inherits(gr, "zeroGrob")) { + return(gr) } # must be sorted on group data <- data[order(data$group), , drop = FALSE] munched <- coord_munch(coord, data, panel_params) - - # Silently drop lines with less than two points, preserving order rows <- stats::ave(seq_len(nrow(munched)), munched$group, FUN = length) munched <- munched[rows >= 2, ] - if (nrow(munched) < 2) - return(zeroGrob()) - - # Work out whether we should use lines or segments - attr <- dapply(munched, "group", function(df) { - linetype <- unique(df$linetype) - new_data_frame(list( - solid = identical(linetype, 1) || identical(linetype, "solid"), - constant = nrow(unique(df[, c("alpha", "colour", "linewidth", "linetype")])) == 1 - ), - n = 1) - }) - solid_lines <- all(attr$solid) - constant <- all(attr$constant) - if (!solid_lines && !constant) { - abort( - "geom_path_interactive: If you are using dotted or dashed lines", - ", colour, size and linetype must be constant over the line", - call. = FALSE - ) - } # Work out grouping variables for grobs n <- nrow(munched) - group_diff <- munched$group[-1] != munched$group[-n] - start <- c(TRUE, group_diff) - end <- c(group_diff, TRUE) + constant <- length(gr$x0) == n if (!constant) { - gr <- segmentsGrob( - munched$x[!end], - munched$y[!end], - munched$x[!start], - munched$y[!start], - default.units = "native", - arrow = arrow, - gp = gpar( - col = alpha(munched$colour, munched$alpha)[!end], - fill = alpha(munched$colour, munched$alpha)[!end], - lwd = munched$linewidth[!end] * .pt, - lty = munched$linetype[!end], - lineend = lineend, - linejoin = linejoin, - linemitre = linemitre - ) - ) + group_diff <- munched$group[-1] != munched$group[-n] + end <- c(group_diff, TRUE) add_interactive_attrs(gr, munched, rows = !end, ipar = .ipar) } else { - id <- match(munched$group, unique(munched$group)) - gr <- polylineGrob( - munched$x, - munched$y, - id = id, - default.units = "native", - arrow = arrow, - gp = gpar( - col = alpha(munched$colour, munched$alpha)[start], - fill = alpha(munched$colour, munched$alpha)[start], - lwd = munched$linewidth[start] * .pt, - lty = munched$linetype[start], - lineend = lineend, - linejoin = linejoin, - linemitre = linemitre - ) - ) add_interactive_attrs(gr, munched, ipar = .ipar) } + } ) @@ -160,7 +111,10 @@ GeomInteractiveStep <- parameters = interactive_geom_parameters, draw_key = interactive_geom_draw_key, draw_panel = function(data, panel_params, coord, direction = "hv", .ipar = IPAR_NAMES) { - data <- dapply(data, "group", stairstep, direction = direction) + ldata <- split(data, data$group) + ldata <- lapply(ldata, stairstep, direction = direction) + data <- do.call(rbind, ldata) + row.names(data) <- NULL GeomInteractivePath$draw_panel(data, panel_params, coord, .ipar = .ipar) } ) @@ -199,5 +153,5 @@ stairstep <- function(data, direction = "hv") { data_attr <- data[xs, setdiff(names(data), c("x", "y"))] } - new_data_frame(c(list(x = x, y = y), data_attr)) + data_frame0(x = x, y = y, data_attr) } diff --git a/R/geom_pointrange_interactive.R b/R/geom_pointrange_interactive.R index e6366485..e8ce0290 100644 --- a/R/geom_pointrange_interactive.R +++ b/R/geom_pointrange_interactive.R @@ -17,17 +17,19 @@ GeomInteractivePointrange <- ggproto( panel_params, coord, fatten = 4, - flipped_aes = FALSE, + flipped_aes = FALSE, + na.rm = FALSE, .ipar = IPAR_NAMES) { - if (is.null(data[[flipped_names(flipped_aes)$y]])) + if (is.null(data[[flipped_names(flipped_aes)$y]])) { return( - GeomInteractiveLinerange$draw_panel(data, panel_params, coord, flipped_aes = flipped_aes, .ipar = .ipar) + GeomInteractiveLinerange$draw_panel(data, panel_params, coord, flipped_aes = flipped_aes, na.rm = na.rm, .ipar = .ipar) ) + } ggname("geom_pointrange", gTree( children = gList( - GeomInteractiveLinerange$draw_panel(data, panel_params, coord, flipped_aes = flipped_aes, .ipar = .ipar), - GeomInteractivePoint$draw_panel(transform(data, size = size * fatten), panel_params, coord, .ipar = .ipar) + GeomInteractiveLinerange$draw_panel(data, panel_params, coord, flipped_aes = flipped_aes, na.rm = na.rm, .ipar = .ipar), + GeomInteractivePoint$draw_panel(transform(data, size = size * fatten), panel_params, coord, na.rm = na.rm, .ipar = .ipar) ) )) } diff --git a/R/geom_violin_interactive.R b/R/geom_violin_interactive.R index 359c16d8..c5660d4d 100644 --- a/R/geom_violin_interactive.R +++ b/R/geom_violin_interactive.R @@ -79,4 +79,19 @@ GeomInteractiveViolin <- ggproto( } ) -create_quantile_segment_frame <- ggplot2:::create_quantile_segment_frame +create_quantile_segment_frame <- function(data, draw_quantiles) { + dens <- cumsum(data$density) / sum(data$density) + ecdf <- stats::approxfun(dens, data$y, ties = "ordered") + ys <- ecdf(draw_quantiles) # these are all the y-values for quantiles + + # Get the violin bounds for the requested quantiles. + violin.xminvs <- (stats::approxfun(data$y, data$xminv))(ys) + violin.xmaxvs <- (stats::approxfun(data$y, data$xmaxv))(ys) + + # We have two rows per segment drawn. Each segment gets its own group. + data_frame0( + x = vctrs::vec_interleave(violin.xminvs, violin.xmaxvs), + y = rep(ys, each = 2), + group = rep(ys, each = 2) + ) +} diff --git a/R/ggiraph.R b/R/ggiraph.R index a1ec041b..e6affc53 100644 --- a/R/ggiraph.R +++ b/R/ggiraph.R @@ -18,8 +18,6 @@ #' @param selection_type row selection mode ("single", "multiple", "none") #' when widget is in a Shiny application. #' @param selected_css css to apply when element is selected (shiny only). -#' @param dep_dir Deprecated; the path where the output files are stored. If `NULL`, -#' the current path for temporary files is used. #' @export #' @keywords internal ggiraph <- function(code, ggobj = NULL, @@ -35,12 +33,8 @@ ggiraph <- function(code, ggobj = NULL, zoom_max = 1, selection_type = "multiple", selected_css = NULL, - dep_dir = NULL, ...) { - message("Function `ggiraph()` is replaced by `girafe()` and will be removed soon.") - if( !missing(dep_dir) ){ - warning("argument `dep_dir` has been deprecated.") - } + .Deprecated(new = "girafe", old = "ggiraph") x <- girafe(code = code, ggobj = ggobj, pointsize = pointsize, width_svg = width_svg, height_svg = height_svg, ...) diff --git a/R/guide_bins_interactive.R b/R/guide_bins_interactive.R index aa4b76ef..acac6327 100644 --- a/R/guide_bins_interactive.R +++ b/R/guide_bins_interactive.R @@ -11,24 +11,43 @@ #' @example examples/scale_viridis_guide_bins_interactive.R #' @seealso [interactive_parameters], [girafe()] #' @export -guide_bins_interactive <- function(...) - guide_interactive(guide_legend, "interactive_bins", ...) - -#' @export -#' @importFrom purrr imap -guide_train.interactive_bins <- function(guide, - scale, - aesthetic = NULL) { - zz <- NextMethod() - if (is.null(zz)) - return(zz) - - copy_interactive_attrs_from_scale(zz, scale) +guide_bins_interactive <- function(...) { + guide_interactive(guide_bins, ...) } +#' @rdname ggiraph-ggproto +#' @format NULL +#' @usage NULL #' @export -guide_geom.interactive_bins <- function(guide, - layers, - default_mapping) { - check_guide_key_geoms(NextMethod()) -} +GuideInteractiveBins <- ggproto( + "GuideInteractiveBins", GuideBins, + train = function(self, params = self$params, scale, aesthetic = NULL, ...) { + parent <- ggproto_parent(GuideBins, self) + params <- parent$train(params = params, scale = scale, aesthetic = aesthetic, ...) + if (!is.null(params) && is.data.frame(params$key) && nrow(params$key)) { + parsed <- interactive_guide_parse_binned_breaks(scale, params) + params <- interactive_guide_train(params, scale, parsed$all_breaks) + } + params + }, + override_elements = function(params, elements, theme) { + elements <- GuideBins$override_elements(params, elements, theme) + interactive_guide_override_elements(elements) + }, + build_decor = function(decor, grobs, elements, params) { + decor <- interactive_guide_build_decor(decor, params) + GuideBins$build_decor(decor, grobs, elements, params) + }, + build_labels = function(key, elements, params) { + grobs <- GuideBins$build_labels(key, elements, params) + if (inherits(key$.label, "interactive_label") && !all(params$show.limits)) { + valid_ind <- setdiff(seq_len(nrow(key)), c(1, nrow(key))[!params$show.limits]) + idata <- grobs$labels$children[[1]]$.interactive + idata <- lapply(idata, function(a) { + a[valid_ind] + }) + grobs$labels$children[[1]]$.interactive <- idata + } + grobs + } +) diff --git a/R/guide_colourbar_interactive.R b/R/guide_colourbar_interactive.R index d57ebbcc..54dc1844 100644 --- a/R/guide_colourbar_interactive.R +++ b/R/guide_colourbar_interactive.R @@ -11,47 +11,50 @@ #' @example examples/scale_gradient_guide_colourbar_interactive.R #' @seealso [interactive_parameters], [girafe()] #' @export -guide_colourbar_interactive <- function(...) - guide_interactive(guide_colourbar, "interactive_colourbar", ...) +guide_colourbar_interactive <- function(...) { + guide_interactive(guide_colourbar, ...) +} #' @export #' @rdname guide_colourbar_interactive guide_colorbar_interactive <- guide_colourbar_interactive +#' @rdname ggiraph-ggproto +#' @format NULL +#' @usage NULL #' @export -guide_train.interactive_colourbar <- function(guide, - scale, - aesthetic = NULL) { - zz <- NextMethod() - if (is.null(zz)) - return(zz) - - # just copy them from scale to trained guide - ipar = get_ipar(scale) - data <- copy_interactive_attrs(scale, list(), ipar = ipar) - zz$.interactive <- data - zz$.ipar <- ipar - zz -} - -#' @export -#' @importFrom purrr compact -guide_gengrob.interactive_colourbar <- function(guide, theme) { - guide_gtable <- NextMethod() - ipar <- get_ipar(guide) - data <- get_interactive_data(guide) - # set them to the bar - barIndex <- which(guide_gtable$layout$name == "bar") - guide_gtable$grobs[[barIndex]] <- - add_interactive_attrs(guide_gtable$grobs[[barIndex]], - data, - data_attr = "key-id", - ipar = ipar) - - # or set them everywhere? - # guide_gtable$grobs <- lapply(guide_gtable$grobs, function(z) { - # # some grobs may already be set interactive, from theme elements - # add_interactive_attrs(z, data, data_attr = "key-id", overwrite = FALSE) - # }) - guide_gtable -} +GuideInteractiveColourbar <- ggproto( + "GuideInteractiveColourbar", GuideColourbar, + train = function(self, params = self$params, scale, aesthetic = NULL, ...) { + parent <- ggproto_parent(GuideColourbar, self) + params <- parent$train(params = params, scale = scale, aesthetic = aesthetic, ...) + if (!is.null(params) && is.data.frame(params$key) && nrow(params$key)) { + breaks <- Filter(is.finite, scale$get_breaks()) + label_breaks <- breaks + if (isTRUE(params$raster)) { + breaks <- 1 + } else { + breaks <- params$decor$value + } + params <- interactive_guide_train(params, scale, breaks, label_breaks = label_breaks) + } + params + }, + override_elements = function(params, elements, theme) { + elements <- GuideColourbar$override_elements(params, elements, theme) + interactive_guide_override_elements(elements) + }, + build_decor = function(decor, grobs, elements, params) { + result <- GuideColourbar$build_decor(decor, grobs, elements, params) + ipar <- get_ipar(params) + idata <- get_interactive_data(params) + if (length(idata)) { + result$bar <- add_interactive_attrs(result$bar, + idata, + data_attr = "key-id", + ipar = ipar + ) + } + result + } +) diff --git a/R/guide_coloursteps_interactive.R b/R/guide_coloursteps_interactive.R index ead61df8..1e3cd408 100644 --- a/R/guide_coloursteps_interactive.R +++ b/R/guide_coloursteps_interactive.R @@ -11,43 +11,44 @@ #' @example examples/scale_viridis_guide_coloursteps_interactive.R #' @seealso [interactive_parameters], [girafe()] #' @export -guide_coloursteps_interactive <- function(...) - guide_interactive(guide_coloursteps, "interactive_coloursteps", ...) +guide_coloursteps_interactive <- function(...) { + guide_interactive(guide_coloursteps, ..., interactive_guide = GuideInteractiveColoursteps) +} #' @export #' @rdname guide_coloursteps_interactive guide_colorsteps_interactive <- guide_coloursteps_interactive +#' @rdname ggiraph-ggproto +#' @format NULL +#' @usage NULL #' @export -#' @importFrom purrr imap -guide_train.interactive_coloursteps <- function(guide, - scale, - aesthetic = NULL) { - zz <- NextMethod() - if (is.null(zz)) - return(zz) - - # just copy them from scale to trained guide - ipar <- get_ipar(scale) - data <- copy_interactive_attrs(scale, list(), ipar = ipar) - zz$.interactive <- data - zz$.ipar <- ipar - zz -} - -#' @export -#' @importFrom purrr compact -guide_gengrob.interactive_coloursteps <- function(guide, theme) { - guide_gtable <- NextMethod() - ipar = get_ipar(guide) - data <- get_interactive_data(guide) - # set them to the bar - barIndex <- which(guide_gtable$layout$name == "bar") - guide_gtable$grobs[[barIndex]] <- - add_interactive_attrs(guide_gtable$grobs[[barIndex]], - data, - data_attr = "key-id", - ipar = ipar) - - guide_gtable -} +GuideInteractiveColoursteps <- ggproto( + "GuideInteractiveColoursteps", GuideColoursteps, + train = function(self, params = self$params, scale, aesthetic = NULL, ...) { + parent <- ggproto_parent(GuideColoursteps, self) + params <- parent$train(params = params, scale = scale, aesthetic = aesthetic, ...) + if (!is.null(params) && is.data.frame(params$key) && nrow(params$key)) { + parsed <- interactive_guide_parse_binned_breaks(scale, params) + breaks <- parsed$all_breaks + label_breaks <- parsed$breaks + if (params$even.steps || !is.numeric(parsed$scale_breaks)) { + show.limits <- params$show.limits %||% scale$show.limits %||% FALSE + if (show.limits && !(is.character(scale$labels) || is.numeric(scale$labels))) { + label_breaks <- parsed$all_breaks + } + } + params <- interactive_guide_train(params, scale, breaks, + label_breaks = label_breaks, max_len = length(breaks) - 1 + ) + } + params + }, + override_elements = function(params, elements, theme) { + elements <- GuideColoursteps$override_elements(params, elements, theme) + interactive_guide_override_elements(elements) + }, + build_decor = function(decor, grobs, elements, params) { + GuideInteractiveColourbar$build_decor(decor, grobs, elements, params) + } +) diff --git a/R/guide_interactive.R b/R/guide_interactive.R index a43efc4e..da62bba4 100644 --- a/R/guide_interactive.R +++ b/R/guide_interactive.R @@ -1,154 +1,252 @@ #' Calls a base guide function and returns an interactive guide. #' @noRd guide_interactive <- function(guide_func, - cl, - ...) { + ..., + interactive_guide = NULL) { args <- list(...) # Call default guide function - guide <- do.call(guide_func, args) - class(guide) <- c(cl, "interactive_guide", class(guide)) - guide -} - -#' @export -guide_geom.interactive_guide <- function(guide, - layers, - default_mapping) { - ipar <- get_ipar(guide) - # set the defaults for any extra parameter - default_aes_names <- names(default_mapping) - missing_names <- setdiff(ipar, default_aes_names) - if (length(missing_names) > 0) { - defaults <- Map(missing_names, f=function(x) NULL) - default_mapping <- append_aes(default_mapping, defaults) + if (is.function(guide_func)) { + guide <- do.call(guide_func, args) + } else if (inherits(guide_func, "Guide")) { + guide <- guide_func + } else { + abort("Invalid guide_func argument!") + } + if (is.null(interactive_guide)) { + interactive_guide <- find_interactive_class(guide, baseclass = "Guide") } - NextMethod() -} - -#' @export -guide_gengrob.interactive_guide <- function(guide, theme) { - # make title interactive - if (is.null(guide$title.theme)) - guide$title.theme <- calc_element("legend.title", theme) - guide$title.theme = as_interactive_element_text(guide$title.theme) - attr(guide$title.theme, "data_attr") <- "key-id" - # make labels interactive - if (is.null(guide$label.theme)) - guide$label.theme <- calc_element("legend.text", theme) - guide$label.theme = as_interactive_element_text(guide$label.theme) - attr(guide$label.theme, "data_attr") <- "key-id" - NextMethod() + ggproto( + NULL, interactive_guide, + params = guide$params, + elements = guide$elements, + available_aes = guide$available_aes + ) } -#' Used in guide_legend/guide_bins to copy the interactive attributes to guide keys +#' train interactive guide +#' @details +#' Copies the interactive parameters and labels from the scale to the guide. +#' Used in all interactive guides. +#' @param params trained guide params, the result of guide's train method +#' @param scale the guide's scale +#' @param breaks the breaks for guide keys/decor +#' @param label_breaks the breaks for the labels +#' @param max_len the max length of each interactive parameter vector +#' @return the altered guide params #' @noRd -copy_interactive_attrs_from_scale <- function(guide, scale, ipar = get_ipar(scale)) { - key <- guide$key - breaks <- scale$get_breaks() - - key_ipar = c() - - # copy attributes from scale to key - if (length(breaks) > 0) { - # process the interactive params one by one and check for names - # this way it works for both discrete and continuous scales - # with or without named vectors - for (a in ipar) { - if (!is.null(scale[[a]])) { - key_ipar <- c(key_ipar, a) - # check if it's function +interactive_guide_train <- function(params, scale, breaks, + label_breaks = breaks, + max_len = NULL) { + if (!is.null(params)) { + key <- params$key + if (is.data.frame(key) && nrow(key)) { + # copy interactive attributes from scale + ipar <- get_ipar(scale) + idata <- list() + # process the interactive params one by one and check for names + # this way it works for both discrete and continuous scales + # with or without named vectors + for (a in ipar) { if (is.function(scale[[a]])) { scale[[a]] <- do.call(scale[[a]], list(breaks)) } - # check if it's named vector - if (!is.null(names(scale[[a]]))) { - # If parameter have names, use them to match with breaks - values <- breaks - m <- match(names(scale[[a]]), values, nomatch = 0) - values[m] <- scale[[a]][m != 0] - key[[a]] <- values - } else { - values <- as.character(scale[[a]]) - # Need to ensure that if breaks were dropped, corresponding values are too - pos <- attr(breaks, "pos") - if (!is.null(pos)) { - values <- values[pos] - } else if (!scale$is_discrete()) { - #drop NAs - values <- values[!is.na(values)] + if (length(scale[[a]])) { + # check if it's named vector + if (!is.null(names(scale[[a]]))) { + # If parameter have names, use them to match with breaks + values <- breaks + m <- match(names(scale[[a]]), values, nomatch = 0) + values[m] <- scale[[a]][m != 0] + } else { + values <- as.character(scale[[a]]) + } + # length of values should be 1 or same as breaks + if (length(values) > 1 && length(values) != length(breaks)) { + warning(paste0( + "Cannot set the guide interactive attribute '", a, + "', because its length differs from the breaks length" + )) + } else { + # length of values must match provided max length or + # the rows of decor data frame or the rows of key data frame + max_len <- max_len %||% nrow(params$decor) %||% nrow(params$key) %||% 0 + if (max_len > 0 && length(values) > max_len) { + values <- values[seq_len(max_len)] + } + # special case for coloursteps guide, when the lengths may not match + if (!is.null(params$decor) && length(values) > 1 && + nrow(params$decor) > length(values) + ) { + # sort the breaks + sorted_breaks <- sort(breaks) + # find the bin index of the decor values + decor2break <- findInterval(params$decor$value, sorted_breaks, + rightmost.closed = TRUE, all.inside = TRUE + ) + if (!identical(breaks, sorted_breaks)) { + # map from sorted breaks to original breaks + m <- match(breaks, sorted_breaks[seq_len(max_len)], nomatch = 0) + m <- m[m != 0] + # remap the bin indices + decor2break <- sapply(decor2break, function(i) m[i]) + } + # spread the values accordingly + values <- sapply(decor2break, function(i) values[i]) + } + idata[[a]] <- values } - key[[a]] <- values } } - } - ipar = key_ipar - # handle labels - # continuous scales break the label_interactive struct - if (!scale$is_discrete()) { - labels <- scale$get_labels(breaks) - if (inherits(labels, "interactive_label")) { - lbl_ipar <- get_ipar(labels) - lbl_ip <- transpose(get_interactive_data(labels)) - extra_interactive_params <- setdiff(lbl_ipar, IPAR_NAMES) - - # get the rows of valid labels - limits <- scale$get_limits() - noob <- !is.na(breaks) & limits[1] <= breaks & breaks <= limits[2] + params$.ipar <- ipar + params$.interactive <- idata - # create a list of individual labels - labels <- lapply(which(noob), function(i) { - args <- c(list( - label = labels[[i]], - extra_interactive_params = extra_interactive_params - ), lbl_ip[[i]]) - do.call(label_interactive, args) - }) - if (guide$reverse) { - labels <- rev(labels) + # continuous scales might break the label_interactive struct + # and we need to replace the labels + if (is.numeric(label_breaks)) { + labels <- scale$get_labels(label_breaks) + if (inherits(labels, "interactive_label")) { + if (length(labels) != nrow(key)) { + warning(paste0( + "Cannot set the guide interactive labels, ", + "', because its length differs from the breaks length" + )) + } else { + key$.label <- labels + params$key <- key + } } - key$.label <- labels } } + } + params +} +parse_binned_breaks = function( + scale, breaks = scale$get_breaks(), + even.steps = TRUE) { + + breaks <- breaks[!is.na(breaks)] + if (length(breaks) == 0) { + return(NULL) + } + breaks <- sort(breaks) + if (is.numeric(breaks)) { + limits <- scale$get_limits() + if (!is.numeric(scale$breaks)) { + breaks <- breaks[!breaks %in% limits] + } + all_breaks <- unique0(c(limits[1], breaks, limits[2])) + bin_at <- all_breaks[-1] - diff(all_breaks) / 2 } else { - key <- copy_interactive_attrs(scale, key, ipar = ipar) + if (isFALSE(even.steps)) { + cli::cli_warn(paste0( + "{.code even.steps = FALSE} is not supported when used with a ", + "discrete scale." + )) + } + bin_at <- breaks + nums <- as.character(breaks) + nums <- strsplit(gsub("\\(|\\)|\\[|\\]", "", nums), ",\\s?") + nums <- as.numeric(unlist(nums, FALSE, FALSE)) + + if (anyNA(nums)) { + cli::cli_abort(c( + "Breaks are not formatted correctly for a bin legend.", + "i" = "Use {.code (, ]} format to indicate bins." + )) + } + all_breaks <- nums[c(1, seq_along(breaks) * 2)] + limits <- all_breaks[ c(1, length(all_breaks))] + breaks <- all_breaks[-c(1, length(all_breaks))] + } + list( + breaks = breaks, + limits = limits, + bin_at = bin_at + ) +} + + +#' Parse binned breaks of interactive guide +#' @details +#' Enhanced version of ggplot's parse_binned_breaks. +#' Provides all key breaks (breaks + limits) plus the original scale breaks. +#' Used in binned guides (bins and colorsteps). +#' @param scale the guide's scale +#' @param params the guide's parameters +#' @return A list +#' @noRd +interactive_guide_parse_binned_breaks <- function(scale, params) { + scale_breaks <- scale$get_breaks() + even.steps <- params$even.steps %||% TRUE + parsed <- parse_binned_breaks(scale, scale_breaks, even.steps) + parsed$scale_breaks <- scale_breaks + if (is.character(scale$labels) || is.numeric(scale$labels)) { + limit_breaks <- c(NA, NA) + } else { + limit_breaks <- parsed$limits + } + all_breaks <- parsed$breaks + if (!parsed$breaks[1] %in% parsed$limits) { + all_breaks <- c(limit_breaks[1], all_breaks) + } + if (!parsed$breaks[length(parsed$breaks)] %in% parsed$limits) { + all_breaks <- c(all_breaks, limit_breaks[2]) + } + if (params$reverse) { + all_breaks <- rev(all_breaks) } - # copy attributes from key to labels - # disabled for the moment, until css issue is resolved - # key$.label <- imap(key$.label, function(label, i) { - # key_ip <- copy_interactive_attrs(key, list(), rows = i) - # if (!inherits(label, "interactive_label")) { - # args <- c(label = label, key_ip) - # label = do.call(label_interactive, args) - # } else { - # label_ip = get_interactive_attrs(label) - # label_ip <- modify_list(label_ip, key_ip) - # attr(label, "interactive") <- label_ip - # } - # label - # }) - guide$key <- key - guide$.ipar <- ipar - guide + parsed$all_breaks <- all_breaks + parsed } -# checks that all key ipar is in guide$geoms data -check_guide_key_geoms <- function(guide) { - if (!is.null(guide)) { - ipar = get_ipar(guide) - guide$geoms <- lapply(guide$geoms, function(g) { - missing_names <- setdiff(ipar, names(g$data)) - missing_names <- intersect(missing_names, names(guide$key)) +#' Override elements in interactive guide +#' @details +#' Converts the theme elements of the guide to interactive theme elements. +#' Used in all interactive guides. +#' +#' @param elements The guide's elements, the result of guide's override_elements method +#' @return the altered guide elements +#' @noRd +interactive_guide_override_elements <- function(elements) { + # make title interactive + if (inherits(elements$title, "element_text") && !inherits(elements$title, "interactive_element_text")) { + elements$title <- as_interactive_element_text(elements$title) + attr(elements$title, "data_attr") <- "key-id" + } + # make labels interactive + if (inherits(elements$text, "element_text") && !inherits(elements$text, "interactive_element_text")) { + elements$text <- as_interactive_element_text(elements$text) + attr(elements$text, "data_attr") <- "key-id" + } + elements +} + +#' build_decor method +#' @details +#' Copies the interactive parameters from the guide to the decor data, +#' before the geoms build the legend keys. +#' Used in guides legend and bins. +#' +#' @param decor the guide's decor structure +#' @param params the guide's parameters +#' +#' @return the altered guide's decor structure +#' @noRd +interactive_guide_build_decor <- function(decor, params) { + # copy missing interactive columns to decor + idata <- get_interactive_data(params) + if (length(idata) && length(decor)) { + decor <- lapply(decor, function(g) { + missing_names <- setdiff(names(idata), names(g$data)) if (length(missing_names)) { for (name in missing_names) { - g$data[[name]] <- guide$key[[name]] + g$data[[name]] <- idata[[name]] } } g }) } - - guide + decor } - diff --git a/R/guide_legend_interactive.R b/R/guide_legend_interactive.R index 50479401..5ab77dee 100644 --- a/R/guide_legend_interactive.R +++ b/R/guide_legend_interactive.R @@ -14,24 +14,49 @@ #' @example examples/scale_viridis_guide_legend_continuous_interactive.R #' @seealso [interactive_parameters], [girafe()] #' @export -guide_legend_interactive <- function(...) - guide_interactive(guide_legend, "interactive_legend", ...) - -#' @export -#' @importFrom purrr imap -guide_train.interactive_legend <- function(guide, - scale, - aesthetic = NULL) { - zz <- NextMethod() - if (is.null(zz)) - return(zz) - - copy_interactive_attrs_from_scale(zz, scale) +guide_legend_interactive <- function(...) { + guide_interactive(guide_legend, ...) } +#' @rdname ggiraph-ggproto +#' @format NULL +#' @usage NULL #' @export -guide_geom.interactive_legend <- function(guide, - layers, - default_mapping) { - check_guide_key_geoms(NextMethod()) -} +GuideInteractiveLegend <- ggproto( + "GuideInteractiveLegend", GuideLegend, + train = function(self, params = self$params, scale, aesthetic = NULL, ...) { + parent <- ggproto_parent(GuideLegend, self) + params <- parent$train(params = params, scale = scale, aesthetic = aesthetic, ...) + if (!is.null(params) && is.data.frame(params$key) && nrow(params$key)) { + params <- interactive_guide_train(params, scale, breaks = params$key$.value) + } + params + }, + override_elements = function(params, elements, theme) { + elements <- GuideLegend$override_elements(params, elements, theme) + interactive_guide_override_elements(elements) + }, + build_decor = function(decor, grobs, elements, params) { + decor <- interactive_guide_build_decor(decor, params) + GuideLegend$build_decor(decor, grobs, elements, params) + }, + build_labels = function(key, elements, params) { + if (inherits(key$.label, "interactive_label")) { + # convert to individual labels + labels <- key$.label + lbl_ipar <- get_ipar(labels) + lbl_ip <- transpose(get_interactive_data(labels)) + extra_interactive_params <- setdiff(lbl_ipar, IPAR_NAMES) + labels <- lapply(seq_along(labels), function(i) { + args <- c(list( + label = labels[[i]], + extra_interactive_params = extra_interactive_params + ), lbl_ip[[i]]) + do.call(label_interactive, args) + }) + key$.label <- labels + } + # call super + GuideLegend$build_labels(key, elements, params) + } +) diff --git a/R/ipar.R b/R/ipar.R index 5fc7f9c1..0b50bf45 100644 --- a/R/ipar.R +++ b/R/ipar.R @@ -61,25 +61,24 @@ #' the type of the guide used. #' The guides do not accept any interactive parameter directly, they receive them from the scales. #' -#' \itemize{ -#' \item When guide of type `legend` or `bins` is used, it will be converted to a -#' [guide_legend_interactive()] or [guide_bins_interactive()] respectively, -#' if it's not already. -#' -#' The length of each scale interactive parameter vector should match the length of the breaks. -#' It can also be a named vector, where each name should correspond to the same break name. -#' It can also be defined as function that takes the breaks as input and returns a named or -#' unnamed vector of values as output. +#' When guide of type `legend`, `bins`, `colourbar` or `coloursteps` is used, +#' it will be converted to a [guide_legend_interactive()], [guide_bins_interactive()], +#' [guide_colourbar_interactive()] or [guide_coloursteps_interactive()] respectively, +#' if it's not already. #' -#' The interactive parameters here, give interactivity only to the key elements of the guide. +#' The length of each scale interactive parameter vector should match the length of the breaks. +#' It can also be a named vector, where each name should correspond to the same break name. +#' It can also be defined as function that takes the breaks as input and returns a named or +#' unnamed vector of values as output. #' -#' \item When guide of type `colourbar` or `coloursteps` is used, it will be converted to a -#' [guide_colourbar_interactive()] or [guide_coloursteps_interactive()] -#' respectively, if it's not already. +#' For binned guides like `bins` and `coloursteps` the breaks include the label breaks and the limits. +#' The number of bins will be one less than the number of breaks and the interactive parameters can be +#' constructed for each bin separately (look at the examples). +#' For `colourbar` guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +#' parameters should be scalar too. For `colourbar` guide in non-raster mode, the bar is drawn using +#' rectangles, and the breaks are the midpoints of each rectangle. #' -#' The scale interactive parameters in this case should be scalar values and give interactivity -#' to the colorbar only. -#' } +#' The interactive parameters here, give interactivity only to the key elements of the guide. #' #' To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), #' the relevant theme elements or relevant guide arguments can be used. @@ -229,8 +228,9 @@ add_interactive_attrs <- function(gr, anames <- Filter(x = get_interactive_attr_names(data, ipar = ipar), function(a) { !is.null(data[[a]]) }) - if (length(anames) == 0) + if (length(anames) == 0) { return(gr) + } # if passed grob is a gTree, loop through the children # note that some grobs (like labelgrob) inherit from gTree, @@ -253,7 +253,6 @@ add_interactive_attrs <- function(gr, ipar = anames ) } - } else if (children_len == data_len) { # pass the correct data row for (i in seq_along(gr$children)) { @@ -272,7 +271,6 @@ add_interactive_attrs <- function(gr, abort("Can't add interactive attrs to gTree", call = NULL) } return(gr) - } else { do_add_interactive_attrs( gr = gr, @@ -295,22 +293,24 @@ do_add_interactive_attrs <- function(gr, overwrite = TRUE, data_attr = "data-id", ipar = IPAR_NAMES) { - # check that is a grob - if (!is.grob(gr) || is.zero(gr)) + if (!is.grob(gr) || is.zero(gr)) { return(gr) + } # check if it's interactive grob already isInteractive <- length(grep("interactive_", class(gr))) > 0 ip <- get_interactive_data(gr) if (length(rows) == 0) { for (a in ipar) { - if (!isInteractive || isTRUE(overwrite) || is.null(ip[[a]])) + if (!isInteractive || isTRUE(overwrite) || is.null(ip[[a]])) { ip[[a]] <- data[[a]] + } } } else { for (a in ipar) { - if (!isInteractive || isTRUE(overwrite) || is.null(ip[[a]])) + if (!isInteractive || isTRUE(overwrite) || is.null(ip[[a]])) { ip[[a]] <- data[[a]][rows] + } } } gr$.ipar <- ipar @@ -330,11 +330,11 @@ do_add_interactive_attrs <- function(gr, } get_interactive_data <- function(x, default = list()) { - (if(!is.atomic(x)) x$.interactive) %||% attr(x, "interactive") %||% default + (if (!is.atomic(x)) x$.interactive) %||% attr(x, "interactive") %||% default } get_ipar <- function(x, default = IPAR_NAMES) { - ipar <- (if(!is.atomic(x)) x$.ipar) %||% attr(x, "ipar") + ipar <- (if (!is.atomic(x)) x$.ipar) %||% attr(x, "ipar") if (length(ipar) > 0 && is.character(ipar)) { ipar } else { @@ -343,7 +343,7 @@ get_ipar <- function(x, default = IPAR_NAMES) { } get_data_attr <- function(x, default = "data-id") { - data_attr <- (if(!is.atomic(x)) x$.data_attr) %||% attr(x, "data_attr") + data_attr <- (if (!is.atomic(x)) x$.data_attr) %||% attr(x, "data_attr") if (length(data_attr) == 1 && is.character(data_attr)) { data_attr } else { @@ -356,8 +356,9 @@ get_data_attr <- function(x, default = "data-id") { interactive_attr_toxml <- function(x, ids = character(0), rows = NULL) { - if (length(ids) < 1) + if (length(ids) < 1) { return(invisible()) + } ip <- get_interactive_data(x) ipar <- get_ipar(x) @@ -366,8 +367,9 @@ interactive_attr_toxml <- function(x, anames <- Filter(x = get_interactive_attr_names(ip, ipar = ipar), function(a) { !is.null(ip[[a]]) }) - if (length(anames) == 0) + if (length(anames) == 0) { return(invisible()) + } for (a in anames) { if (length(rows) == 0) { @@ -376,19 +378,24 @@ interactive_attr_toxml <- function(x, attrValue <- ip[[a]][rows] } attrValue <- switch(a, - tooltip = encode_cr(attrValue), - hover_css = check_css_attr(attrValue), - selected_css = check_css_attr(attrValue), - attrValue) - if (!is.character(attrValue)) + tooltip = encode_cr(attrValue), + hover_css = check_css_attr(attrValue), + selected_css = check_css_attr(attrValue), + attrValue + ) + if (!is.character(attrValue)) { attrValue <- as.character(attrValue) + } attrName <- switch(a, - tooltip = "title", - data_id = data_attr, - a) - set_attr(name = attrName, - ids = as.integer(ids), - values = attrValue) + tooltip = "title", + data_id = data_attr, + a + ) + set_attr( + name = attrName, + ids = as.integer(ids), + values = attrValue + ) } invisible() } diff --git a/R/labeller_interactive.R b/R/labeller_interactive.R index 6f59aa12..aa0f448d 100644 --- a/R/labeller_interactive.R +++ b/R/labeller_interactive.R @@ -28,6 +28,7 @@ #' @example examples/labeller_interactive.R #' @seealso [labeller()], [label_interactive()], [labellers] #' @importFrom rlang eval_tidy +#' @importFrom purrr imap labeller_interactive <- function(.mapping = NULL, ...) { # get interactive aesthetics, plus a label parameter dots <- list(...) diff --git a/R/layer_interactive.R b/R/layer_interactive.R index 87b7af3b..acb39ca4 100644 --- a/R/layer_interactive.R +++ b/R/layer_interactive.R @@ -19,7 +19,7 @@ layer_interactive <- function(layer_func, ipar <- get_default_ipar(extra_interactive_params) # check if it contains interactive aesthetics if (index > 0 && - has_interactive_attrs(args[[index]], ipar = ipar)) { + has_interactive_attrs(args[[index]], ipar = ipar)) { interactive_mapping <- get_interactive_attrs(args[[index]], ipar = ipar) args[[index]] <- @@ -62,7 +62,7 @@ layer_interactive <- function(layer_func, default_aes_names <- names(layer_$geom$default_aes) missing_names <- setdiff(ipar, default_aes_names) if (length(missing_names) > 0) { - defaults <- Map(missing_names, f=function(x) NULL) + defaults <- Map(missing_names, f = function(x) NULL) layer_$geom$default_aes <- append_aes(layer_$geom$default_aes, defaults) } @@ -75,34 +75,36 @@ layer_interactive <- function(layer_func, result } -#' Finds an interactive geom class derived from a ggplot2 geom class. +#' Finds an interactive class derived from a ggplot2 geom/guide class. #' @noRd -find_interactive_class <- function(geom, env = parent.frame()) { - if (inherits(geom, "Geom")) { - name <- class(geom)[1] - } else if (is.character(geom) && length(geom) == 1) { - name <- geom +find_interactive_class <- function(gg, baseclass = c("Geom", "Guide"), env = parent.frame()) { + baseclass <- arg_match(baseclass) + if (inherits(gg, baseclass)) { + name <- class(gg)[1] + } else if (is.character(gg) && length(gg) == 1) { + name <- gg if (name == "histogram") { name <- "bar" } } else { - abort("`geom` must be either a string or a Geom* object, ", - "not ", - obj_desc(geom), - call = NULL) + abort( + paste0("`gg` must be either a string or a ", baseclass, "* object, not ", obj_desc(gg)), + call = NULL + ) } - if (!startsWith(name, "Geom")) { - name <- paste0("Geom", camelize(name, first = TRUE)) + if (!startsWith(name, baseclass)) { + name <- paste0(baseclass, camelize(name, first = TRUE)) } - if (!startsWith(name, "GeomInteractive")) { - name <- sub("Geom", "GeomInteractive", name) + baseinteractive <- paste0(baseclass, "Interactive") + if (!startsWith(name, baseinteractive)) { + name <- sub(baseclass, baseinteractive, name) } obj <- find_global(name, env = env) - if (is.null(obj) || !inherits(obj, "Geom")) { - abort("Can't find interactive geom function called \"", - geom, - "\"", - call = NULL) + if (is.null(obj) || !inherits(obj, baseclass)) { + abort( + paste0("Can't find interactive ", baseclass, " function based on ", as_label(gg)), + call = NULL + ) } else { obj } diff --git a/R/scale_interactive.R b/R/scale_interactive.R index 316335d6..259cb3b9 100644 --- a/R/scale_interactive.R +++ b/R/scale_interactive.R @@ -1,5 +1,6 @@ #' Calls a base scale function and returns an interactive scale. #' @noRd +#' @importFrom rlang inherits_any scale_interactive <- function(scale_func, ..., extra_interactive_params = NULL) { @@ -14,19 +15,20 @@ scale_interactive <- function(scale_func, if (isFALSE(sc$guide) || is.null(sc$guide)) { # no guide return(sc) - } else if (is.character(sc$guide)) { if (sc$guide %in% c("none", "guide_none")) { # exit return(sc) } else if (sc$guide %in% c("legend", "bins", "colourbar", "colorbar", "coloursteps", "colorsteps")) { sc$guide <- paste0(sc$guide, "_interactive") - } else if (sc$guide %in% c("legend_interactive", - "bins_interactive", - "colourbar_interactive", - "colorbar_interactive", - "coloursteps_interactive", - "colorsteps_interactive")) { + } else if (sc$guide %in% c( + "legend_interactive", + "bins_interactive", + "colourbar_interactive", + "colorbar_interactive", + "coloursteps_interactive", + "colorsteps_interactive" + )) { # ok } else { # the name could be a guide set by guides() and it might be interactive, but also it might not. @@ -35,16 +37,23 @@ scale_interactive <- function(scale_func, } else if (inherits(sc$guide, "guide_none")) { # exit return(sc) - } else if (inherits(sc$guide, "interactive_guide")) { + } else if (inherits_any(sc$guide, c( + "GuideInteractiveLegend", "GuideInteractiveBins", "GuideInteractiveColourbar", "GuideInteractiveColoursteps" + )) + ) { # ok - } else if (inherits(sc$guide, "legend")) { - class(sc$guide) <- c("interactive_legend", "interactive_guide", class(sc$guide)) - } else if (inherits(sc$guide, "bins")) { - class(sc$guide) <- c("interactive_bins", "interactive_guide", class(sc$guide)) - } else if (inherits(sc$guide, "coloursteps") || inherits(sc$guide, "colorsteps")) { - class(sc$guide) <- c("interactive_coloursteps", "interactive_guide", class(sc$guide)) - } else if (inherits(sc$guide, "colourbar") || inherits(sc$guide, "colorbar")) { - class(sc$guide) <- c("interactive_colourbar", "interactive_guide", class(sc$guide)) + } else if (inherits_any(sc$guide, c( + "GuideLegend", "GuideBins", "GuideColourbar", "GuideColoursteps" + )) + ) { + interactive_guide <- NULL + if (inherits(sc$guide, "GuideColourbar")) { + # we must resolve if it's GuideColourbar or GuideColoursteps + if (!is.null(sc$guide$params$even.steps)) { + interactive_guide <- GuideInteractiveColoursteps + } + } + sc$guide <- guide_interactive(sc$guide, interactive_guide = interactive_guide) } else { warning("Only `legend`, 'bins', `colourbar` and `coloursteps` guides are supported for interactivity") return(sc) diff --git a/R/utils.R b/R/utils.R index 1336b26c..712b70aa 100644 --- a/R/utils.R +++ b/R/utils.R @@ -3,12 +3,6 @@ #' @include utils_ggplot2.R #' @include utils_ggplot2_performance.R -# FIXME -# dapply is in ggplot2/compat-plyr.R, but if we include that file, -# it causes more issues as it depends ggplot2 globals. -# dapply is only used in GeomInteractivePath. -dapply <- ggplot2:::dapply - # Include parameters #' @include ipar.R diff --git a/examples/scale_gradient_guide_colourbar_interactive.R b/examples/scale_gradient_guide_colourbar_interactive.R index 45b139c0..856744e9 100644 --- a/examples/scale_gradient_guide_colourbar_interactive.R +++ b/examples/scale_gradient_guide_colourbar_interactive.R @@ -8,9 +8,11 @@ p <- ggplot(df, aes(x, y, fill = z, tooltip = "tooltip")) + geom_raster_interactive() # add an interactive scale (guide is colourbar) -p1 <- p + scale_fill_gradient_interactive(data_id = "colourbar", - onclick = "alert(\"colourbar\")", - tooltip = "colourbar") +p1 <- p + scale_fill_gradient_interactive( + data_id = "colourbar", + onclick = "alert(\"colourbar\")", + tooltip = "colourbar" +) x <- girafe(ggobj = p1) if (interactive()) print(x) @@ -27,8 +29,10 @@ p2 <- p + scale_fill_gradient_interactive( ) ) x <- girafe(ggobj = p2) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) # make the legend labels interactive @@ -43,18 +47,19 @@ p3 <- p + scale_fill_gradient_interactive( tooltip = "colourbar" ), labels = function(breaks) { - br <- na.omit(breaks) - label_interactive( - as.character(breaks), - data_id = paste0("colourbar", br), + lapply(breaks, function(abreak) label_interactive( + as.character(abreak), + data_id = paste0("colourbar", abreak), onclick = "alert(\"colourbar\")", - tooltip = paste0("colourbar", br) - ) + tooltip = paste0("colourbar", abreak) + )) } ) x <- girafe(ggobj = p3) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) # also via the guide @@ -78,8 +83,10 @@ p4 <- p + scale_fill_gradient_interactive( ) ) x <- girafe(ggobj = p4) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) # make the legend background interactive @@ -91,6 +98,8 @@ p5 <- p4 + theme( ) ) x <- girafe(ggobj = p5) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) diff --git a/examples/scale_viridis_guide_bins_interactive.R b/examples/scale_viridis_guide_bins_interactive.R index bbdc3e55..b2576b81 100644 --- a/examples/scale_viridis_guide_bins_interactive.R +++ b/examples/scale_viridis_guide_bins_interactive.R @@ -2,29 +2,53 @@ library(ggplot2) library(ggiraph) set.seed(4393) -dsmall <- diamonds[sample(nrow(diamonds), 1000),] +dsmall <- diamonds[sample(nrow(diamonds), 1000), ] p <- ggplot(dsmall, aes(x, y)) + - stat_density_2d(aes( - fill = after_stat(nlevel), - tooltip = paste("nlevel:", after_stat(nlevel)) - ), - geom = "interactive_polygon") + + stat_density_2d( + aes( + fill = after_stat(nlevel), + tooltip = paste("nlevel:", after_stat(nlevel)) + ), + geom = "interactive_polygon" + ) + facet_grid(. ~ cut) # add interactive binned scale and guide -p1 <- p + scale_fill_viridis_b_interactive(data_id = "nlevel", - tooltip = "nlevel", - guide = "bins") +p1 <- p + scale_fill_viridis_b_interactive( + data_id = "nlevel", + tooltip = "nlevel", + guide = "bins" +) x <- girafe(ggobj = p1) if (interactive()) print(x) # set the keys separately p2 <- p + scale_fill_viridis_b_interactive( data_id = function(breaks) { - as.character(breaks) + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) }, tooltip = function(breaks) { - as.character(breaks) + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) }, guide = "bins" ) @@ -35,14 +59,36 @@ if (interactive()) print(x) # make the title and labels interactive p3 <- p + scale_fill_viridis_c_interactive( data_id = function(breaks) { - as.character(breaks) + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) }, tooltip = function(breaks) { - as.character(breaks) + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) }, guide = "bins", - name = label_interactive("nlevel", data_id = "nlevel", - tooltip = "nlevel"), + name = label_interactive("nlevel", + data_id = "nlevel", + tooltip = "nlevel" + ), labels = function(breaks) { label_interactive( as.character(breaks), @@ -53,7 +99,8 @@ p3 <- p + scale_fill_viridis_c_interactive( } ) x <- girafe(ggobj = p3) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) - diff --git a/inst/tinytest/setup.R b/inst/tinytest/setup.R index 78d5429d..82487f04 100644 --- a/inst/tinytest/setup.R +++ b/inst/tinytest/setup.R @@ -162,9 +162,9 @@ test_grob <- expression({ test_guide <- expression({ result <- do.call(name, list()) # is guide? - expect_inherits(result, "guide", info = "result inherits guide") + expect_inherits(result, "Guide", info = "result inherits guide") # is interactive_guide? - expect_inherits(result, "interactive_guide", info = "result inherits interactive_guide") + expect_true(startsWith(head(class(result), 1), "GuideInteractive"), info = "result inherits interactive guide") }) test_scale <- expression({ diff --git a/inst/tinytest/test-ggiraph.R b/inst/tinytest/test-ggiraph.R index bd016491..53b1ab45 100644 --- a/inst/tinytest/test-ggiraph.R +++ b/inst/tinytest/test-ggiraph.R @@ -13,14 +13,14 @@ library(xml2) # ggiraphOutput ---- { - result <- ggiraphOutput("foo") + result <- girafeOutput("foo") expect_inherits(result, "shiny.tag.list") } if (requireNamespace("httpuv", quietly = TRUE)) { # renderggiraph ---- { - result <- renderggiraph(ggiraph({ + result <- renderGirafe(ggiraph({ print(ggplot()) })) expect_inherits(result, "shiny.render.function") diff --git a/inst/tinytest/test-guide_bins_interactive.R b/inst/tinytest/test-guide_bins_interactive.R index 621d5c1a..ad2e45fc 100644 --- a/inst/tinytest/test-guide_bins_interactive.R +++ b/inst/tinytest/test-guide_bins_interactive.R @@ -8,54 +8,67 @@ source("setup.R") { eval(test_guide, envir = list(name = "guide_bins_interactive")) } +# continuous scale - bins guide { - scale <- scale_size_binned_interactive( - guide = guide_bins(), tooltip = "tooltip" - ) - result <- guide_train(guide = scale$guide, scale = scale, aesthetic = "size") - expect_null(result) -} -{ - doc <- dsvg_plot( - ggplot(mtcars) + - geom_point_interactive( - aes(disp, mpg, size = hp, info = I("test")), + p <- ggplot(mtcars) + + geom_point_interactive( + aes(disp, mpg, size = hp, info = I("test")), + extra_interactive_params = "info" + ) + + scale_size_binned_interactive( + data_id = function(breaks) { + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) + }, + tooltip = function(breaks) { + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) + }, + info = "scale", + extra_interactive_params = "info", + guide = "bins", + name = label_interactive("hp", + data_id = "hp", + tooltip = "hp", info = "title", extra_interactive_params = "info" - ) + - scale_size_binned_interactive( - data_id = function(breaks) { - as.character(breaks) - }, - tooltip = function(breaks) { - as.character(breaks) - }, - info = "scale", - extra_interactive_params = "info", - guide = "bins", - name = label_interactive("hp", - data_id = "hp", - tooltip = "hp", info = "title", + ), + labels = function(breaks) { + label_interactive( + as.character(breaks), + data_id = as.character(breaks), + tooltip = as.character(breaks), + info = rep("label", length(breaks)), extra_interactive_params = "info" - ), - labels = function(breaks) { - label_interactive( - as.character(breaks), - data_id = as.character(breaks), - tooltip = as.character(breaks), - info = rep("label", length(breaks)), - extra_interactive_params = "info" - ) - } - ) - ) + ) + } + ) + doc <- dsvg_plot(p) nodes <- xml_find_all(doc, ".//circle[@info='scale']") - expect_equal(length(nodes), 5, info = "legend keys") - tooltips <- sort(sapply(nodes, function(node) xml_attr(node, "title"))) - expect_equal(tooltips, c("100", "150", "200", "250", "300"), info = "legend keys tooltips") + expect_equal(length(nodes), 6, info = "legend keys") + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) + expect_equal(tooltips, c("50-100", "100-150", "150-200", "200-250", "250-300", "300-350"), info = "legend keys tooltips") nodes <- xml_find_all(doc, ".//text[@info='label']") expect_equal(length(nodes), 5, info = "legend labels") - tooltips <- sort(sapply(nodes, function(node) xml_attr(node, "title"))) + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) expect_equal(tooltips, c("100", "150", "200", "250", "300"), info = "legend labels tooltips") nodes <- xml_find_all(doc, ".//text[@info='title']") @@ -63,3 +76,125 @@ source("setup.R") tooltips <- unique(sapply(nodes, function(node) xml_attr(node, "title"))) expect_equal(tooltips, "hp", info = "legend title tooltip") } +# continuous scale - bins guide - reverse +{ + p <- ggplot(mtcars) + + geom_point_interactive( + aes(disp, mpg, size = hp, info = I("test")), + extra_interactive_params = "info" + ) + + scale_size_binned_interactive( + data_id = function(breaks) { + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) + }, + tooltip = function(breaks) { + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) + }, + info = "scale", + extra_interactive_params = "info", + guide = guide_bins(reverse = TRUE), + name = label_interactive("hp", + data_id = "hp", + tooltip = "hp", info = "title", + extra_interactive_params = "info" + ), + labels = function(breaks) { + label_interactive( + as.character(breaks), + data_id = as.character(breaks), + tooltip = as.character(breaks), + info = rep("label", length(breaks)), + extra_interactive_params = "info" + ) + } + ) + doc <- dsvg_plot(p) + nodes <- xml_find_all(doc, ".//circle[@info='scale']") + expect_equal(length(nodes), 6, info = "legend keys") + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) + expect_equal(tooltips, rev(c("50-100", "100-150", "150-200", "200-250", "250-300", "300-350")), info = "legend keys tooltips") + + nodes <- xml_find_all(doc, ".//text[@info='label']") + expect_equal(length(nodes), 5, info = "legend labels") + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) + expect_equal(tooltips, rev(c("100", "150", "200", "250", "300")), info = "legend labels tooltips") +} +# continuous scale - bins guide - show.limits +{ + p <- ggplot(mtcars) + + geom_point_interactive( + aes(disp, mpg, size = hp, info = I("test")), + extra_interactive_params = "info" + ) + + scale_size_binned_interactive( + data_id = function(breaks) { + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) + }, + tooltip = function(breaks) { + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) + }, + info = "scale", + extra_interactive_params = "info", + guide = guide_bins(show.limits = TRUE), + name = label_interactive("hp", + data_id = "hp", + tooltip = "hp", info = "title", + extra_interactive_params = "info" + ), + labels = function(breaks) { + label_interactive( + as.character(breaks), + data_id = as.character(breaks), + tooltip = as.character(breaks), + info = rep("label", length(breaks)), + extra_interactive_params = "info" + ) + } + ) + doc <- dsvg_plot(p) + + nodes <- xml_find_all(doc, ".//text[@info='label']") + expect_equal(length(nodes), 7, info = "legend labels") + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) + expect_equal(tooltips, c("50", "100", "150", "200", "250", "300", "350"), info = "legend labels tooltips") +} diff --git a/inst/tinytest/test-guide_colourbar_interactive.R b/inst/tinytest/test-guide_colourbar_interactive.R deleted file mode 100644 index 7391fd78..00000000 --- a/inst/tinytest/test-guide_colourbar_interactive.R +++ /dev/null @@ -1,69 +0,0 @@ -library(tinytest) -library(ggiraph) -library(ggplot2) -library(xml2) -source("setup.R") - -# guide_colourbar_interactive ---- -{ - eval(test_guide, envir = list(name = "guide_colourbar_interactive")) - eval(test_guide, envir = list(name = "guide_colorbar_interactive")) -} -{ - scale <- scale_colour_continuous_interactive( - guide = guide_colourbar(), tooltip = "tooltip" - ) - result <- guide_train(guide = scale$guide, scale = scale, aesthetic = "colour") - expect_null(result) -} -{ - dat <- expand.grid(x = 0:5, y = 0:5) - dat$z <- runif(nrow(dat)) - doc <- dsvg_plot( - ggplot(dat) + - geom_raster_interactive( - aes(x, y, fill = z, tooltip = "tooltip", data_id = "raster", info = "test"), - extra_interactive_params = "info" - ) + - scale_fill_gradient_interactive( - breaks = c(0.25, 0.5, 0.75), - data_id = "colourbar", - onclick = "alert(\"colourbar\")", - tooltip = "colourbar", - info = "scale", - extra_interactive_params = "info", - name = label_interactive( - "z", - data_id = "colourbar", - onclick = "alert(\"colourbar\")", - tooltip = "colourbar", - info = "title", - extra_interactive_params = "info" - ), - labels = function(breaks) { - br <- na.omit(breaks) - label_interactive( - as.character(breaks), - data_id = paste0("colourbar", br), - tooltip = br, - info = "label", - extra_interactive_params = "info" - ) - } - ) - ) - nodes <- xml_find_all(doc, ".//image[@info='scale']") - expect_equal(length(nodes), 1, info = "legend keys") - tooltips <- sort(sapply(nodes, function(node) xml_attr(node, "title"))) - expect_equal(tooltips, "colourbar", info = "legend keys tooltips") - - nodes <- xml_find_all(doc, ".//text[@info='label']") - expect_equal(length(nodes), 3, info = "legend labels") - tooltips <- sort(sapply(nodes, function(node) xml_attr(node, "title"))) - expect_equal(tooltips, c("0.25", "0.5", "0.75"), info = "legend labels tooltips") - - nodes <- xml_find_all(doc, ".//text[@info='title']") - expect_equal(length(nodes), 1, info = "legend title") - tooltips <- unique(sapply(nodes, function(node) xml_attr(node, "title"))) - expect_equal(tooltips, "colourbar", info = "legend title tooltip") -} diff --git a/inst/tinytest/test-guide_coloursteps_interactive.R b/inst/tinytest/test-guide_coloursteps_interactive.R deleted file mode 100644 index 992750ec..00000000 --- a/inst/tinytest/test-guide_coloursteps_interactive.R +++ /dev/null @@ -1,67 +0,0 @@ -library(tinytest) -library(ggiraph) -library(ggplot2) -library(xml2) -source("setup.R") - -# guide_coloursteps_interactive ---- -{ - eval(test_guide, envir = list(name = "guide_coloursteps_interactive")) - eval(test_guide, envir = list(name = "guide_colorsteps_interactive")) -} -# guide_train.interactive_coloursteps ---- -{ - scale <- scale_colour_continuous_interactive( - guide = guide_coloursteps(), tooltip = "tooltip" - ) - result <- guide_train(guide = scale$guide, scale = scale, aesthetic = "colour") - expect_null(result) -} -{ - dat <- expand.grid(X1 = 1:10, X2 = 1:10) - dat$value <- dat$X1 * dat$X2 - doc <- dsvg_plot( - ggplot(dat) + - geom_tile_interactive( - aes(X1, X2, fill = value, tooltip = paste(X1, X2), data_id = paste0(X1, X2), info = "test"), - extra_interactive_params = "info" - ) + - scale_fill_binned_interactive( - breaks = c(25, 50, 75), - tooltip = "coloursteps", - info = "scale", - extra_interactive_params = "info", - name = label_interactive( - "value", - data_id = "coloursteps.title", - tooltip = "value", - info = "title", - extra_interactive_params = "info" - ), - labels = function(breaks) { - br <- na.omit(breaks) - label_interactive( - as.character(breaks), - data_id = paste0("coloursteps", br), - tooltip = br, - info = "label", - extra_interactive_params = "info" - ) - } - ) - ) - nodes <- xml_find_all(doc, ".//rect[@info='scale']") - expect_equal(length(nodes), 4, info = "legend keys") - tooltips <- unique(sapply(nodes, function(node) xml_attr(node, "title"))) - expect_equal(tooltips, "coloursteps", info = "legend keys tooltips") - - nodes <- xml_find_all(doc, ".//text[@info='label']") - expect_equal(length(nodes), 3, info = "legend labels") - tooltips <- sort(sapply(nodes, function(node) xml_attr(node, "title"))) - expect_equal(tooltips, c("25", "50", "75"), info = "legend labels tooltips") - - nodes <- xml_find_all(doc, ".//text[@info='title']") - expect_equal(length(nodes), 1, info = "legend title") - tooltips <- unique(sapply(nodes, function(node) xml_attr(node, "title"))) - expect_equal(tooltips, "value", info = "legend title tooltip") -} diff --git a/inst/tinytest/test-guide_interactive.R b/inst/tinytest/test-guide_interactive.R deleted file mode 100644 index a70b23ae..00000000 --- a/inst/tinytest/test-guide_interactive.R +++ /dev/null @@ -1,96 +0,0 @@ -library(tinytest) -library(ggiraph) -library(ggplot2) - -# copy_interactive_attrs_from_scale ---- -{ - scale <- scale_colour_discrete_interactive( - guide = guide_legend(), tooltip = "tooltip" - ) - result <- ggiraph:::copy_interactive_attrs_from_scale(scale$guide, scale) - ipar <- ggiraph:::get_ipar(result) - ip <- ggiraph:::get_interactive_attrs(result$key, ipar = ipar) - expect_equal(ip$tooltip, "tooltip") -} -{ - scale <- scale_colour_manual_interactive( - guide = guide_legend(), - tooltip = list( - b = "tooltip 2", - a = "tooltip 1", - c = "tooltip 3" - ), - foo = rep("bar", 3), extra_interactive_params = "foo", - breaks = c("a", "b", "c"), - limits = c("a", "b", "c"), - values = list( - a = "black", - b = "white", - c = "grey" - ) - ) - result <- ggiraph:::copy_interactive_attrs_from_scale(scale$guide, scale) - ipar <- ggiraph:::get_ipar(result) - ip <- ggiraph:::get_interactive_attrs(result$key, ipar = ipar) - expect_equal(ip$tooltip, as.list(paste("tooltip", seq_len(3)))) -} -{ - scale <- scale_colour_manual_interactive( - guide = guide_legend(), - tooltip = function(x) { - ( - paste("tooltip", x) - ) - }, - foo = rep("bar", 3), extra_interactive_params = "foo", - breaks = c("a", "b", "c"), - limits = c("a", "b", "c"), - values = list( - a = "black", - b = "white", - c = "grey" - ) - ) - result <- ggiraph:::copy_interactive_attrs_from_scale(scale$guide, scale) - ipar <- ggiraph:::get_ipar(result) - ip <- ggiraph:::get_interactive_attrs(result$key, ipar = ipar) - expect_equal(ip$tooltip, paste("tooltip", c("a", "b", "c"))) -} -{ - scale <- scale_size_continuous_interactive( - guide = guide_legend(), - tooltip = function(x) { - ( - paste("tooltip", x) - ) - }, - labels = function(x) { - label_interactive(x, tooltip = paste("tooltip", x)) - }, - foo = rep("bar", 5), extra_interactive_params = "foo", - limits = c(1, 5) - ) - result <- ggiraph:::copy_interactive_attrs_from_scale(scale$guide, scale) - ipar <- ggiraph:::get_ipar(result) - ip <- ggiraph:::get_interactive_attrs(result$key, ipar = ipar) - expect_equal(ip$tooltip, paste("tooltip", seq_len(5))) -} -{ - scale <- scale_size_continuous_interactive( - guide = guide_legend(reverse = TRUE), - tooltip = function(x) { - ( - paste("tooltip", x) - ) - }, - labels = function(x) { - label_interactive(x, tooltip = paste("tooltip", x)) - }, - foo = rep("bar", 5), extra_interactive_params = "foo", - limits = c(1, 5) - ) - result <- ggiraph:::copy_interactive_attrs_from_scale(scale$guide, scale) - ipar <- ggiraph:::get_ipar(result) - ip <- ggiraph:::get_interactive_attrs(result$key, ipar = ipar) - expect_equal(ip$tooltip, paste("tooltip", seq_len(5))) -} diff --git a/inst/tinytest/test-guide_legend_interactive.R b/inst/tinytest/test-guide_legend_interactive.R index ba51defe..f50bd479 100644 --- a/inst/tinytest/test-guide_legend_interactive.R +++ b/inst/tinytest/test-guide_legend_interactive.R @@ -8,58 +8,51 @@ source("setup.R") { eval(test_guide, envir = list(name = "guide_legend_interactive")) } -{ - scale <- scale_colour_discrete_interactive( - guide = guide_legend(), tooltip = "tooltip" - ) - result <- guide_train(guide = scale$guide, scale = scale, aesthetic = "colour") - expect_null(result) -} +# discrete scale - legend guide { dat <- data.frame( name = c("Guy", "Ginette", "David", "Cedric", "Frederic"), gender = c("Male", "Female", "Male", "Male", "Male"), height = c(169, 160, 171, 172, 171) ) - doc <- dsvg_plot( - ggplot(dat, aes(x = name, y = height, fill = gender)) + - geom_bar_interactive( - stat = "identity", - extra_interactive_params = "info", - aes(info = I("test")) - ) + - scale_fill_manual_interactive( - guide = guide_legend(), - name = label_interactive("gender", - tooltip = "Gender levels", data_id = "legend.title", - info = "title", extra_interactive_params = "info" - ), - extra_interactive_params = "info", - values = c(Male = "#0072B2", Female = "#009E73"), - data_id = c(Female = "Female", Male = "Male"), - tooltip = c(Male = "Male", Female = "Female"), - info = c(Male = "scale", Female = "scale"), - labels = function(breaks) { - lapply(breaks, function(br) { - label_interactive( - as.character(br), - data_id = as.character(br), - tooltip = as.character(br), - info = "label", - extra_interactive_params = "info" - ) - }) - } - ) - ) + p <- ggplot(dat, aes(x = name, y = height, fill = gender)) + + geom_bar_interactive( + stat = "identity", + extra_interactive_params = "info", + aes(info = I("test")) + ) + + scale_fill_manual_interactive( + guide = "legend", + name = label_interactive("gender", + tooltip = "Gender levels", data_id = "legend.title", + info = "title", extra_interactive_params = "info" + ), + extra_interactive_params = "info", + values = c(Male = "#0072B2", Female = "#009E73"), + data_id = c(Female = "Female", Male = "Male"), + tooltip = c(Male = "Male", Female = "Female"), + info = c(Male = "scale", Female = "scale"), + labels = function(breaks) { + lapply(breaks, function(br) { + label_interactive( + as.character(br), + data_id = as.character(br), + tooltip = as.character(br), + info = "label", + extra_interactive_params = "info" + ) + }) + } + ) + doc <- dsvg_plot(p) nodes <- xml_find_all(doc, ".//rect[@info='scale']") expect_equal(length(nodes), 2, info = "legend keys") - tooltips <- sort(sapply(nodes, function(node) xml_attr(node, "title"))) + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) expect_equal(tooltips, c("Female", "Male"), info = "legend keys tooltips") nodes <- xml_find_all(doc, ".//text[@info='label']") expect_equal(length(nodes), 2, info = "legend labels") - tooltips <- sort(sapply(nodes, function(node) xml_attr(node, "title"))) + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) expect_equal(tooltips, c("Female", "Male"), info = "legend labels tooltips") nodes <- xml_find_all(doc, ".//text[@info='title']") @@ -67,3 +60,155 @@ source("setup.R") tooltips <- unique(sapply(nodes, function(node) xml_attr(node, "title"))) expect_equal(tooltips, "Gender levels", info = "legend title tooltip") } +# discrete scale - legend guide - reverse +{ + dat <- data.frame( + name = c("Guy", "Ginette", "David", "Cedric", "Frederic"), + gender = c("Male", "Female", "Male", "Male", "Male"), + height = c(169, 160, 171, 172, 171) + ) + p <- ggplot(dat, aes(x = name, y = height, fill = gender)) + + geom_bar_interactive( + stat = "identity", + extra_interactive_params = "info", + aes(info = I("test")) + ) + + scale_fill_manual_interactive( + guide = guide_legend(reverse = TRUE), + name = label_interactive("gender", + tooltip = "Gender levels", data_id = "legend.title", + info = "title", extra_interactive_params = "info" + ), + extra_interactive_params = "info", + values = c(Male = "#0072B2", Female = "#009E73"), + data_id = c(Female = "Female", Male = "Male"), + tooltip = c(Male = "Male", Female = "Female"), + info = c(Male = "scale", Female = "scale"), + labels = function(breaks) { + lapply(breaks, function(br) { + label_interactive( + as.character(br), + data_id = as.character(br), + tooltip = as.character(br), + info = "label", + extra_interactive_params = "info" + ) + }) + } + ) + doc <- dsvg_plot(p) + nodes <- xml_find_all(doc, ".//rect[@info='scale']") + expect_equal(length(nodes), 2, info = "legend keys") + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) + expect_equal(tooltips, c("Male", "Female"), info = "legend keys tooltips") + + nodes <- xml_find_all(doc, ".//text[@info='label']") + expect_equal(length(nodes), 2, info = "legend labels") + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) + expect_equal(tooltips, c("Male", "Female"), info = "legend labels tooltips") +} +# continuous scale - legend guide +{ + set.seed(4393) + dsmall <- diamonds[sample(nrow(diamonds), 1000), ] + p <- ggplot(dsmall, aes(x, y)) + + geom_density_2d_filled_interactive( + aes( + fill = after_stat(nlevel), + tooltip = paste("nlevel:", after_stat(nlevel)) + ), + extra_interactive_params = "info" + ) + + facet_grid(. ~ cut) + + scale_fill_viridis_c_interactive( + data_id = function(breaks) { + as.character(breaks) + }, + tooltip = function(breaks) { + as.character(breaks) + }, + info = "scale", + extra_interactive_params = "info", + labels = function(breaks) { + label_interactive( + as.character(breaks), + data_id = as.character(breaks), + onclick = paste0("alert(\"", as.character(breaks), "\")"), + tooltip = as.character(breaks), + info = rep("label", length(breaks)), + extra_interactive_params = "info" + ) + }, + name = label_interactive("nlevel", + data_id = "nlevel", tooltip = "nlevel", + info = "title", extra_interactive_params = "info" + ), + guide = "legend" + ) + girafe(ggobj = p) + doc <- dsvg_plot(p) + nodes <- xml_find_all(doc, ".//rect[@info='scale']") + expect_equal(length(nodes), 4, info = "legend keys") + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) + expect_equal(tooltips, c("0.25", "0.5", "0.75", "1"), info = "legend keys tooltips") + + nodes <- xml_find_all(doc, ".//text[@info='label']") + expect_equal(length(nodes), 4, info = "legend labels") + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) + expect_equal(tooltips, c("0.25", "0.5", "0.75", "1"), info = "legend labels tooltips") + + nodes <- xml_find_all(doc, ".//text[@info='title']") + expect_equal(length(nodes), 1, info = "legend title") + tooltips <- unique(sapply(nodes, function(node) xml_attr(node, "title"))) + expect_equal(tooltips, "nlevel", info = "legend title tooltip") +} +# continuous scale - legend guide - reverse +{ + set.seed(4393) + dsmall <- diamonds[sample(nrow(diamonds), 1000), ] + p <- ggplot(dsmall, aes(x, y)) + + geom_density_2d_filled_interactive( + aes( + fill = after_stat(nlevel), + tooltip = paste("nlevel:", after_stat(nlevel)) + ), + extra_interactive_params = "info" + ) + + facet_grid(. ~ cut) + + scale_fill_viridis_c_interactive( + data_id = function(breaks) { + as.character(breaks) + }, + tooltip = function(breaks) { + as.character(breaks) + }, + info = "scale", + extra_interactive_params = "info", + labels = function(breaks) { + label_interactive( + as.character(breaks), + data_id = as.character(breaks), + onclick = paste0("alert(\"", as.character(breaks), "\")"), + tooltip = as.character(breaks), + info = rep("label", length(breaks)), + extra_interactive_params = "info" + ) + }, + name = label_interactive("nlevel", + data_id = "nlevel", tooltip = "nlevel", + info = "title", extra_interactive_params = "info" + ), + guide = guide_legend(reverse = TRUE) + ) + girafe(ggobj = p) + doc <- dsvg_plot(p) + nodes <- xml_find_all(doc, ".//rect[@info='scale']") + expect_equal(length(nodes), 4, info = "legend keys") + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) + expect_equal(tooltips, rev(c("0.25", "0.5", "0.75", "1")), info = "legend keys tooltips") + + nodes <- xml_find_all(doc, ".//text[@info='label']") + expect_equal(length(nodes), 4, info = "legend labels") + tooltips <- sapply(nodes, function(node) xml_attr(node, "title")) + expect_equal(tooltips, rev(c("0.25", "0.5", "0.75", "1")), info = "legend labels tooltips") +} diff --git a/inst/tinytest/test-scale_interactive.R b/inst/tinytest/test-scale_interactive.R index cef039c3..829de5fe 100644 --- a/inst/tinytest/test-scale_interactive.R +++ b/inst/tinytest/test-scale_interactive.R @@ -15,7 +15,7 @@ scale_func <- scale_color_discrete_interactive expect_null(scale$tooltip) scale <- scale_func(guide = "guide_none", tooltip = "tooltip") expect_null(scale$tooltip) - scale <- scale_func(guide = guide_none(), tooltip = "tooltip") + expect_warning(scale <- scale_func(guide = guide_none(), tooltip = "tooltip")) expect_null(scale$tooltip) } @@ -29,13 +29,13 @@ scale_func <- scale_color_discrete_interactive # scale_interactive with guide as guide object, is working ---- { scale <- scale_func(guide = guide_legend(), tooltip = "tooltip") - expect_inherits(scale$guide, c("interactive_guide", "interactive_legend")) + expect_inherits(scale$guide, "GuideInteractiveLegend") scale <- scale_func(guide = guide_bins(), tooltip = "tooltip") - expect_inherits(scale$guide, c("interactive_guide", "interactive_bins")) + expect_inherits(scale$guide, "GuideInteractiveBins") scale <- scale_func(guide = guide_colorsteps(), tooltip = "tooltip") - expect_inherits(scale$guide, c("interactive_guide", "interactive_coloursteps")) + expect_inherits(scale$guide, "GuideInteractiveColoursteps") scale <- scale_func(guide = guide_colourbar(), tooltip = "tooltip") - expect_inherits(scale$guide, c("interactive_guide", "interactive_colourbar")) + expect_inherits(scale$guide, "GuideInteractiveColourbar") } # scale_interactive with unsupported guide, is working ---- diff --git a/man/ggiraph-ggproto.Rd b/man/ggiraph-ggproto.Rd index 4fb6df62..3de593f7 100644 --- a/man/ggiraph-ggproto.Rd +++ b/man/ggiraph-ggproto.Rd @@ -16,7 +16,9 @@ % R/geom_segment_interactive.R, R/geom_sf_interactive.R, % R/geom_smooth_interactive.R, R/geom_spoke_interactive.R, % R/geom_text_interactive.R, R/geom_tile_interactive.R, -% R/geom_violin_interactive.R, R/geom_vline_interactive.R +% R/geom_violin_interactive.R, R/geom_vline_interactive.R, +% R/guide_bins_interactive.R, R/guide_colourbar_interactive.R, +% R/guide_coloursteps_interactive.R, R/guide_legend_interactive.R \docType{data} \name{GeomInteractive} \alias{GeomInteractive} @@ -62,6 +64,10 @@ \alias{GeomInteractiveTile} \alias{GeomInteractiveViolin} \alias{GeomInteractiveVline} +\alias{GuideInteractiveBins} +\alias{GuideInteractiveColourbar} +\alias{GuideInteractiveColoursteps} +\alias{GuideInteractiveLegend} \title{ggproto classes for ggiraph} \description{ ggproto classes for ggiraph diff --git a/man/ggiraph.Rd b/man/ggiraph.Rd index 261705c4..01d06dd1 100644 --- a/man/ggiraph.Rd +++ b/man/ggiraph.Rd @@ -20,7 +20,6 @@ ggiraph( zoom_max = 1, selection_type = "multiple", selected_css = NULL, - dep_dir = NULL, ... ) } @@ -62,9 +61,6 @@ when widget is in a Shiny application.} \item{selected_css}{css to apply when element is selected (shiny only).} -\item{dep_dir}{Deprecated; the path where the output files are stored. If \code{NULL}, -the current path for temporary files is used.} - \item{...}{arguments passed on to \code{\link[=dsvg]{dsvg()}}} } \description{ diff --git a/man/guide_bins_interactive.Rd b/man/guide_bins_interactive.Rd index 1e6d698f..becfddde 100644 --- a/man/guide_bins_interactive.Rd +++ b/man/guide_bins_interactive.Rd @@ -23,9 +23,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -33,15 +33,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. @@ -57,29 +56,53 @@ library(ggplot2) library(ggiraph) set.seed(4393) -dsmall <- diamonds[sample(nrow(diamonds), 1000),] +dsmall <- diamonds[sample(nrow(diamonds), 1000), ] p <- ggplot(dsmall, aes(x, y)) + - stat_density_2d(aes( - fill = after_stat(nlevel), - tooltip = paste("nlevel:", after_stat(nlevel)) - ), - geom = "interactive_polygon") + + stat_density_2d( + aes( + fill = after_stat(nlevel), + tooltip = paste("nlevel:", after_stat(nlevel)) + ), + geom = "interactive_polygon" + ) + facet_grid(. ~ cut) # add interactive binned scale and guide -p1 <- p + scale_fill_viridis_b_interactive(data_id = "nlevel", - tooltip = "nlevel", - guide = "bins") +p1 <- p + scale_fill_viridis_b_interactive( + data_id = "nlevel", + tooltip = "nlevel", + guide = "bins" +) x <- girafe(ggobj = p1) if (interactive()) print(x) # set the keys separately p2 <- p + scale_fill_viridis_b_interactive( data_id = function(breaks) { - as.character(breaks) + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) }, tooltip = function(breaks) { - as.character(breaks) + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) }, guide = "bins" ) @@ -90,14 +113,36 @@ if (interactive()) print(x) # make the title and labels interactive p3 <- p + scale_fill_viridis_c_interactive( data_id = function(breaks) { - as.character(breaks) + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) }, tooltip = function(breaks) { - as.character(breaks) + sapply(seq_along(breaks), function(i) { + if (i < length(breaks)) { + paste( + min(breaks[i], breaks[i + 1], na.rm = TRUE), + max(breaks[i], breaks[i + 1], na.rm = TRUE), + sep = "-" + ) + } else { + NA_character_ + } + }) }, guide = "bins", - name = label_interactive("nlevel", data_id = "nlevel", - tooltip = "nlevel"), + name = label_interactive("nlevel", + data_id = "nlevel", + tooltip = "nlevel" + ), labels = function(breaks) { label_interactive( as.character(breaks), @@ -108,10 +153,11 @@ p3 <- p + scale_fill_viridis_c_interactive( } ) x <- girafe(ggobj = p3) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) - } \seealso{ \link{interactive_parameters}, \code{\link[=girafe]{girafe()}} diff --git a/man/guide_colourbar_interactive.Rd b/man/guide_colourbar_interactive.Rd index 1f18b010..d8563b67 100644 --- a/man/guide_colourbar_interactive.Rd +++ b/man/guide_colourbar_interactive.Rd @@ -26,9 +26,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -36,15 +36,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. @@ -66,9 +65,11 @@ p <- ggplot(df, aes(x, y, fill = z, tooltip = "tooltip")) + geom_raster_interactive() # add an interactive scale (guide is colourbar) -p1 <- p + scale_fill_gradient_interactive(data_id = "colourbar", - onclick = "alert(\"colourbar\")", - tooltip = "colourbar") +p1 <- p + scale_fill_gradient_interactive( + data_id = "colourbar", + onclick = "alert(\"colourbar\")", + tooltip = "colourbar" +) x <- girafe(ggobj = p1) if (interactive()) print(x) @@ -85,8 +86,10 @@ p2 <- p + scale_fill_gradient_interactive( ) ) x <- girafe(ggobj = p2) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) # make the legend labels interactive @@ -101,18 +104,19 @@ p3 <- p + scale_fill_gradient_interactive( tooltip = "colourbar" ), labels = function(breaks) { - br <- na.omit(breaks) - label_interactive( - as.character(breaks), - data_id = paste0("colourbar", br), + lapply(breaks, function(abreak) label_interactive( + as.character(abreak), + data_id = paste0("colourbar", abreak), onclick = "alert(\"colourbar\")", - tooltip = paste0("colourbar", br) - ) + tooltip = paste0("colourbar", abreak) + )) } ) x <- girafe(ggobj = p3) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) # also via the guide @@ -136,8 +140,10 @@ p4 <- p + scale_fill_gradient_interactive( ) ) x <- girafe(ggobj = p4) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) # make the legend background interactive @@ -149,8 +155,10 @@ p5 <- p4 + theme( ) ) x <- girafe(ggobj = p5) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) } \seealso{ diff --git a/man/guide_coloursteps_interactive.Rd b/man/guide_coloursteps_interactive.Rd index 9f2e9079..ec9bc540 100644 --- a/man/guide_coloursteps_interactive.Rd +++ b/man/guide_coloursteps_interactive.Rd @@ -26,9 +26,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -36,15 +36,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. diff --git a/man/guide_legend_interactive.Rd b/man/guide_legend_interactive.Rd index 15aabb8c..8ee90703 100644 --- a/man/guide_legend_interactive.Rd +++ b/man/guide_legend_interactive.Rd @@ -23,9 +23,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -33,15 +33,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. diff --git a/man/interactive_parameters.Rd b/man/interactive_parameters.Rd index 10349869..a4e4f2c7 100644 --- a/man/interactive_parameters.Rd +++ b/man/interactive_parameters.Rd @@ -70,9 +70,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -80,15 +80,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. diff --git a/man/scale_alpha_interactive.Rd b/man/scale_alpha_interactive.Rd index 76dfbec4..1e4693b8 100644 --- a/man/scale_alpha_interactive.Rd +++ b/man/scale_alpha_interactive.Rd @@ -49,9 +49,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -59,15 +59,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. diff --git a/man/scale_colour_brewer_interactive.Rd b/man/scale_colour_brewer_interactive.Rd index 63280949..a0afad6b 100644 --- a/man/scale_colour_brewer_interactive.Rd +++ b/man/scale_colour_brewer_interactive.Rd @@ -54,9 +54,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -64,15 +64,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. diff --git a/man/scale_colour_interactive.Rd b/man/scale_colour_interactive.Rd index dd9663ac..d99fa54b 100644 --- a/man/scale_colour_interactive.Rd +++ b/man/scale_colour_interactive.Rd @@ -99,9 +99,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -109,15 +109,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. diff --git a/man/scale_colour_steps_interactive.Rd b/man/scale_colour_steps_interactive.Rd index 26cfa56a..203f209d 100644 --- a/man/scale_colour_steps_interactive.Rd +++ b/man/scale_colour_steps_interactive.Rd @@ -54,9 +54,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -64,15 +64,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. diff --git a/man/scale_gradient_interactive.Rd b/man/scale_gradient_interactive.Rd index 9679e273..d943b79d 100644 --- a/man/scale_gradient_interactive.Rd +++ b/man/scale_gradient_interactive.Rd @@ -55,9 +55,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -65,15 +65,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. @@ -95,9 +94,11 @@ p <- ggplot(df, aes(x, y, fill = z, tooltip = "tooltip")) + geom_raster_interactive() # add an interactive scale (guide is colourbar) -p1 <- p + scale_fill_gradient_interactive(data_id = "colourbar", - onclick = "alert(\"colourbar\")", - tooltip = "colourbar") +p1 <- p + scale_fill_gradient_interactive( + data_id = "colourbar", + onclick = "alert(\"colourbar\")", + tooltip = "colourbar" +) x <- girafe(ggobj = p1) if (interactive()) print(x) @@ -114,8 +115,10 @@ p2 <- p + scale_fill_gradient_interactive( ) ) x <- girafe(ggobj = p2) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) # make the legend labels interactive @@ -130,18 +133,19 @@ p3 <- p + scale_fill_gradient_interactive( tooltip = "colourbar" ), labels = function(breaks) { - br <- na.omit(breaks) - label_interactive( - as.character(breaks), - data_id = paste0("colourbar", br), + lapply(breaks, function(abreak) label_interactive( + as.character(abreak), + data_id = paste0("colourbar", abreak), onclick = "alert(\"colourbar\")", - tooltip = paste0("colourbar", br) - ) + tooltip = paste0("colourbar", abreak) + )) } ) x <- girafe(ggobj = p3) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) # also via the guide @@ -165,8 +169,10 @@ p4 <- p + scale_fill_gradient_interactive( ) ) x <- girafe(ggobj = p4) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) # make the legend background interactive @@ -178,8 +184,10 @@ p5 <- p4 + theme( ) ) x <- girafe(ggobj = p5) -x <- girafe_options(x, - opts_hover_key(girafe_css("stroke:red", text="stroke:none;fill:red"))) +x <- girafe_options( + x, + opts_hover_key(girafe_css("stroke:red", text = "stroke:none;fill:red")) +) if (interactive()) print(x) } \seealso{ diff --git a/man/scale_linetype_interactive.Rd b/man/scale_linetype_interactive.Rd index a9e4d664..d8fe87af 100644 --- a/man/scale_linetype_interactive.Rd +++ b/man/scale_linetype_interactive.Rd @@ -37,9 +37,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -47,15 +47,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. diff --git a/man/scale_manual_interactive.Rd b/man/scale_manual_interactive.Rd index 4feb0276..daaf5554 100644 --- a/man/scale_manual_interactive.Rd +++ b/man/scale_manual_interactive.Rd @@ -53,9 +53,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -63,15 +63,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. diff --git a/man/scale_shape_interactive.Rd b/man/scale_shape_interactive.Rd index bd638e90..1e3ebe9d 100644 --- a/man/scale_shape_interactive.Rd +++ b/man/scale_shape_interactive.Rd @@ -41,9 +41,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -51,15 +51,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. diff --git a/man/scale_size_interactive.Rd b/man/scale_size_interactive.Rd index 48b9a682..d29c3620 100644 --- a/man/scale_size_interactive.Rd +++ b/man/scale_size_interactive.Rd @@ -61,9 +61,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -71,15 +71,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used. diff --git a/man/scale_viridis_interactive.Rd b/man/scale_viridis_interactive.Rd index 87fd013f..47b0bacd 100644 --- a/man/scale_viridis_interactive.Rd +++ b/man/scale_viridis_interactive.Rd @@ -66,9 +66,9 @@ and they can be scalar values or vectors, depending on the number of breaks (lev the type of the guide used. The guides do not accept any interactive parameter directly, they receive them from the scales. -\itemize{ -\item When guide of type \code{legend} or \code{bins} is used, it will be converted to a -\code{\link[=guide_legend_interactive]{guide_legend_interactive()}} or \code{\link[=guide_bins_interactive]{guide_bins_interactive()}} respectively, +When guide of type \code{legend}, \code{bins}, \code{colourbar} or \code{coloursteps} is used, +it will be converted to a \code{\link[=guide_legend_interactive]{guide_legend_interactive()}}, \code{\link[=guide_bins_interactive]{guide_bins_interactive()}}, +\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} respectively, if it's not already. The length of each scale interactive parameter vector should match the length of the breaks. @@ -76,15 +76,14 @@ It can also be a named vector, where each name should correspond to the same bre It can also be defined as function that takes the breaks as input and returns a named or unnamed vector of values as output. -The interactive parameters here, give interactivity only to the key elements of the guide. - -\item When guide of type \code{colourbar} or \code{coloursteps} is used, it will be converted to a -\code{\link[=guide_colourbar_interactive]{guide_colourbar_interactive()}} or \code{\link[=guide_coloursteps_interactive]{guide_coloursteps_interactive()}} -respectively, if it's not already. +For binned guides like \code{bins} and \code{coloursteps} the breaks include the label breaks and the limits. +The number of bins will be one less than the number of breaks and the interactive parameters can be +constructed for each bin separately (look at the examples). +For \code{colourbar} guide in raster mode, the breaks vector, is scalar 1 always, meaning the interactive +parameters should be scalar too. For \code{colourbar} guide in non-raster mode, the bar is drawn using +rectangles, and the breaks are the midpoints of each rectangle. -The scale interactive parameters in this case should be scalar values and give interactivity -to the colorbar only. -} +The interactive parameters here, give interactivity only to the key elements of the guide. To provide interactivity to the rest of the elements of a guide, (title, labels, background, etc), the relevant theme elements or relevant guide arguments can be used.