R/geom-econodist.R

Defines functions draw_key_econodist geom_econodist

Documented in geom_econodist

draw_key_econodist <- function(data, params, size) {

  grobTree(
    rectGrob(
      height = 0.5, width = 0.75,
      gp = gpar(
        fill = alpha(
          data$fill %||% params$fill %||% NA,
          data$alpha %||% params$alpha %||% NA
        ),
        col = data$colour %||% params$colour %||% NA
      )
    ),
    pointsGrob(
      x = 0.5, y = 0.5, size = unit(0.25, "npc"),
      pch = data$shape,
      gp = gpar(
        col = data$median_col %||% params$median_col %||% NA
      )
    ),
    rectGrob(
      x = 0.25,
      height = 0.75, width = 0.125,
      gp = gpar(
        fill = data$tenth_col %||% params$tenth_col %||% NA,
        col = NA
      )
    ),
    rectGrob(
      x = 0.75,
      height = 0.75, width = 0.125,
      gp = gpar(
        fill = data$ninetieth_col %||% params$ninetieth_col %||% NA,
        col = NA
      )
    )
  )

}

#' Econodist geom / stat
#'
#' Like [ggplot2::geom_boxplot()] you can either pass in pre-computed
#' values for "ymin", "median", and "ymax" or a single y column
#' which will then use [stat_econodist()] to compute the needed
#' statistics.
#'
#' @param mapping Set of aesthetic mappings created by `aes()` or
#'   `aes_()`. If specified and `inherit.aes = TRUE` (the
#'   default), it is combined with the default mapping at the top level of the
#'   plot. You must supply `mapping` if there is no plot mapping.
#' @param data The data to be displayed in this layer. There are three
#'    options:
#'
#'    If `NULL`, the default, the data is inherited from the plot
#'    data as specified in the call to `ggplot()`.
#'
#'    A `data.frame`, or other object, will override the plot
#'    data. All objects will be fortified to produce a data frame. See
#'    `fortify()` for which variables will be created.
#'
#'    A `function` will be called with a single argument,
#'    the plot data. The return value must be a `data.frame.`, and
#'    will be used as the layer data.
#' @param stat ggplot2 stat to use
#' @param geom ggplot2 geom to use
#' @param position Position adjustment, either as a string, or the result of a call to a position adjustment function.
#' @param tenth_col,median_col,ninetieth_col,median_point_size colors for geom components
#' @param endcap_adjust multipler to make endcaps wider/thinner
#' @param na.rm If `FALSE`, the default, missing values are removed with
#'   a warning. If `TRUE`, missing values are silently removed.
#' @param show.legend logical. Should this layer be included in the legends?
#'   `NA`, the default, includes if any aesthetics are mapped.
#'   `FALSE` never includes, and `TRUE` always includes.
#'   It can also be a named logical vector to finely select the aesthetics to
#'   display.
#' @param inherit.aes If `FALSE`, overrides the default aesthetics,
#'   rather than combining with them. This is most useful for helper functions
#'   that define both data and aesthetics and shouldn't inherit behaviour from
#'   the default plot specification, e.g. `borders()`.
#' @param ... other arguments passed on to `layer()`. These are
#'   often aesthetics, used to set an aesthetic to a fixed value, like
#'   `color = "red"` or `size = 3`. They may also be parameters
#'   to the paired geom/stat.
#' @export
#' @examples
#' ggplot(mammogram_costs, aes(x = city)) +
#'   geom_econodist(
#'     aes(
#'       ymin = tenth,
#'       median = median,
#'       ymax = ninetieth
#'    ),
#'     stat = "identity",
#'   ) +
#'   scale_y_continuous(
#'     expand = c(0,0),
#'     position = "right",
#'     limits = range(0, 800),
#'     label = scales::comma
#'   ) +
#'   coord_flip() +
#'   labs(
#'     x = NULL, y = NULL
#'   )
geom_econodist <- function(mapping = NULL,
                           data = NULL,
                           stat = "econodist",
                           position = "dodge2",
                           tenth_col = econ_tenth,
                           median_col = econ_median,
                           ninetieth_col = econ_ninetieth,
                           median_point_size = NULL,
                           endcap_adjust = 1.5,
                           ...,
                           na.rm = FALSE,
                           show.legend = NA,
                           inherit.aes = TRUE) {

  layer(
    data = data,
    mapping = mapping,
    stat = stat,
    geom = GeomEconodist,
    position = position,
    show.legend = show.legend,
    inherit.aes = inherit.aes,
    params = list(
      na.rm = na.rm,
      tenth_col = tenth_col,
      median_col = median_col,
      ninetieth_col = ninetieth_col,
      median_point_size = median_point_size,
      endcap_adjust = endcap_adjust,
      ...
    )
  )
}

#' @rdname geom_econodist
#' @export
GeomEconodist <- ggproto(
  `_class` = "GeomEconodist",
  `_inherit` = Geom,

  extra_params = c("na.rm", "width",
                   "tenth_col", "median_col", "ninetieth_col",
                   "median_point_size", "endcap_adjust"),

  default_aes = aes(
    colour = NA, fill = econ_main, size = 1, weight = 1,
    alpha = 0.2, shape = 19, linetype = "solid", stroke = 1
  ),

  required_aes = c("x", "ymin", "median", "ymax"),

  setup_data = function(data, params) {

    data$width <- data$width %||%
      params$width %||% (ggplot2::resolution(data$x, FALSE) * 0.6)

    data$xmin <- data$x - data$width / 2
    data$xmax <- data$x + data$width / 2

    data

  },

  draw_group = function(data, panel_params, coord,
                        tenth_col = econ_tenth,
                        median_col = econ_median,
                        ninetieth_col = econ_ninetieth,
                        median_point_size = NULL,
                        endcap_adjust = 1.5) {

    if (nrow(data) != 1) {
      stop(
        "It looks like you may have forgotten a grouping aesthetic, i.e. aes(group = ...)",
        call. = FALSE
      )
    }

    transform(
      data,
      y = median,
      fill = alpha(fill, alpha)
    ) -> d_range

    transform(
      data,
      y = median,
      alpha = 1,
      colour = median_col,
      size = median_point_size %||% (width * 3),
      fill = alpha(fill, alpha),
      shape = "circle"
    ) -> d_median

    transform(
      data,
      x = xmin,
      xend = xmax,
      y = ymin,
      yend = ymin,
      size = size * (endcap_adjust %||% 1.5),
      alpha = NA,
      colour = tenth_col
    ) -> d_tenth

    transform(
      data,
      x = xmin,
      xend = xmax,
      y = ymax,
      yend = ymax,
      size = size * (endcap_adjust %||% 1.5),
      alpha = NA,
      colour = ninetieth_col
    ) -> d_ninetieth

    ggname("geom_econodist", grobTree(
      GeomRect$draw_panel(d_range, panel_params, coord),
      GeomSegment$draw_panel(d_tenth, panel_params, coord),
      GeomSegment$draw_panel(d_ninetieth, panel_params, coord),
      GeomPoint$draw_panel(d_median, panel_params, coord)
    ))

  },

  draw_key = draw_key_econodist

)
hrbrmstr/ggeconodist documentation built on Nov. 4, 2019, 1:46 p.m.