Browse Source

better waffle geom

pull/65/head
boB Rudis 4 years ago
parent
commit
42549ea326
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 1
      .gitignore
  2. 12
      DESCRIPTION
  3. 5
      NAMESPACE
  4. 66
      R/a-geom-rect.R
  5. 10
      R/aaa.r
  6. 467
      R/geom-pictogram.R
  7. 46
      R/geom-rtile.R
  8. 302
      R/geom-waffle.R
  9. 285
      R/stat-pictogram.R
  10. 195
      R/stat-waffle.R
  11. 355
      R/sw2.R
  12. 12
      R/utils.r
  13. 2
      README.Rmd
  14. 12
      README.md
  15. BIN
      README_files/figure-gfm/geoms-1.png
  16. BIN
      README_files/figure-gfm/waffle-bars-1.png
  17. 90
      man/geom_pictogram.Rd
  18. 31
      man/geom_waffle.Rd
  19. 2
      vignettes/.gitignore
  20. 332
      vignettes/building-waffle-charts.Rmd

1
.gitignore

@ -5,3 +5,4 @@
src/*.o
src/*.so
src/*.dll
inst/doc

12
DESCRIPTION

@ -26,10 +26,15 @@ Encoding: UTF-8
URL: https://gitlab.com/hrbrmstr/waffle
BugReports: https://gitlab.com/hrbrmstr/waffle/issues
Suggests:
testthat
testthat,
knitr,
rmarkdown,
dplyr,
hrbrthemes,
ggthemes
Depends:
R (>= 3.2.0),
ggplot2 (>= 2.0.0)
R (>= 3.5.0),
ggplot2 (>= 3.1.0)
License: GPL (>= 2)
Imports:
RColorBrewer,
@ -43,3 +48,4 @@ Imports:
htmlwidgets,
DT
RoxygenNote: 6.1.1
VignetteBuilder: knitr

5
NAMESPACE

@ -1,17 +1,12 @@
# Generated by roxygen2: do not edit by hand
export(GeomPictogram)
export(GeomWaffle)
export(StatPictogram)
export(StatWaffle)
export(draw_key_pictogram)
export(fa_grep)
export(fa_list)
export(geom_pictogram)
export(geom_waffle)
export(install_fa_fonts)
export(iron)
export(stat_pictogram)
export(stat_waffle)
export(theme_enhance_waffle)
export(waffle)

66
R/a-geom-rect.R

@ -0,0 +1,66 @@
geom_rrect <- function(mapping = NULL, data = NULL, # nocov start
stat = "identity", position = "identity",
radius = grid::unit(6, "pt"),
...,
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE) {
layer(
data = data,
mapping = mapping,
stat = stat,
geom = GeomRrect,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
radius = radius,
na.rm = na.rm,
...
)
)
}
GeomRrect <- ggplot2::ggproto(
"GeomRrect", ggplot2::Geom,
default_aes = ggplot2::aes(
fill = "grey35", size = 0.5, linetype = 1, alpha = NA#, colour = NA
),
required_aes = c("xmin", "xmax", "ymin", "ymax"),
draw_panel = function(self, data, panel_params, coord,
radius = grid::unit(6, "pt")) {
coords <- coord$transform(data, panel_params)
lapply(1:length(coords$xmin), function(i) {
grid::roundrectGrob(
coords$xmin[i], coords$ymax[i],
width = (coords$xmax[i] - coords$xmin[i]),
height = (coords$ymax[i] - coords$ymin)[i],
r = radius,
default.units = "native",
just = c("left", "top"),
gp = grid::gpar(
col = coords$colour[i],
fill = alpha(coords$fill[i], coords$alpha[i]),
lwd = coords$size[i] * .pt,
lty = coords$linetype[i],
lineend = "butt"
)
)
}) -> gl
grobs <- do.call(grid::gList, gl)
ggname("geom_rrect", grid::grobTree(children = grobs))
},
draw_key = ggplot2::draw_key_polygon
) # nocov end

10
R/aaa.r

@ -1 +1,9 @@
utils::globalVariables(c("x", "y", "value"))
utils::globalVariables(c("x", "y", "value"))
.dbg <- TRUE
msg <- function(...) {
if (.dbg) message(...)
}

467
R/geom-pictogram.R

@ -1,233 +1,234 @@
#' @export
draw_key_pictogram <- function(data, params, size) {
# message("Called draw_key_pictogram()")
# print(str(data, 1))
# print(str(params, 1))
# print(str(size, 1))
# return(draw_key_text(data, params, size))
data[["label"]] <- .fa_unicode[.fa_unicode[["name"]] %in% data[["fa_glyph"]], "unicode"]
fat <- .fa_unicode[.fa_unicode[["name"]] %in% data[["fa_glyph"]], "type"]
ftrans <- c(solid = "FontAwesome5Free-Solid", brands = "FontAwesome5Brands-Regular")
data[["family"]] <- ftrans[fat]
data[["size"]] <- data[["size"]] * 2
grid::textGrob(
data$label, 0.5, 0.25,
rot = data$angle %||% 0,
gp = grid::gpar(
col = alpha(data$colour %||% data$fill %||% "black", data$alpha),
fontfamily = data$family %||% "",
fontface = data$fontface %||% 1,
fontsize = (data$size %||% 3.88) * .pt
)
)
}
#' Isotype pictogram "waffle" charts
#'
#' There are two special/critical `aes()` mappings:
#' - `colour` (so the geom knows which column to map the country names/abbrevs to)
#' - `values` (which column you're mapping the filling for the squares with)
#'
#' @md
#' @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 n_rows how many rows should there be in the waffle chart? default is 10
#' @param flip If `TRUE`, flip x and y coords. n_rows then becomes n_cols.
#' Useful to achieve waffle column chart effect. Defaults is `FALSE`.
#' @param make_proportional compute proportions from the raw values? (i.e. each
#' value `n` will be replaced with `n`/`sum(n)`); default is `FALSE`.
#' @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 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
#' data.frame(
#' parts = factor(rep(month.abb[1:3], 3), levels=month.abb[1:3]),
#' values = c(10, 20, 30, 6, 14, 40, 30, 20, 10),
#' fct = c(rep("Thing 1", 3), rep("Thing 2", 3), rep("Thing 3", 3))
#' ) -> xdf
#'
#' ggplot(xdf, aes(fill = parts, values = values)) +
#' geom_pictogram() +
#' facet_wrap(~fct) +
#' coord_equal()
geom_pictogram <- function(
mapping = NULL, data = NULL,
n_rows = 10, flip = FALSE, make_proportional = FALSE,
na.rm = TRUE, show.legend = NA, inherit.aes = TRUE, ...) {
# message("Called geom_pictogram()")
ggplot2::layer(
data = data,
mapping = mapping,
stat = "pictogram",
geom = GeomPictogram,
position = "identity",
show.legend = show.legend,
inherit.aes = inherit.aes,
check.aes = FALSE,
params = list(
na.rm = na.rm,
n_rows = n_rows,
flip = flip,
make_proportional = make_proportional,
use = "colour",
...
)
)
}
#' @rdname geom_pictogram
#' @export
GeomPictogram <- ggplot2::ggproto(
`_class` = "GeomPictogram",
`_inherit` = ggplot2::Geom,
default_aes = ggplot2::aes(
fa_glyph = "circle", fa_type = "solid",
fill = NA, colour = "#b2b2b2", alpha = NA,
size = 2, linetype = 1, width = NA, height = NA
),
required_aes = c("x", "y", "values", "fa_glyph", "fa_type"),
extra_params = c("na.rm", "width", "height", "flip", "use"),
setup_data = function(data, params) {
# message("Called GeomPictogram::setup_data()")
# print(str(data, 1))
waf.dat <- data
# swap x and y values if flip is TRUE
if (params$flip) {
waf.dat$x_temp <- waf.dat$x
waf.dat$x <- waf.dat$y
waf.dat$y <- waf.dat$x_temp
waf.dat$x_temp <- NULL
}
# reduce all values by 0.5
# this allows for axis ticks to align _between_ square rows/cols
# rather than in the middle of a row/col
waf.dat$x <- waf.dat$x - 0.5
waf.dat$y <- waf.dat$y - 0.5
waf.dat$width <- waf.dat$width %||% params$width %||% ggplot2::resolution(waf.dat$x, FALSE)
waf.dat$height <- waf.dat$height %||% params$height %||% ggplot2::resolution(waf.dat$y, FALSE)
transform(
waf.dat,
xmin = x - width / 2,
xmax = x + width / 2,
width = NULL,
ymin = y - height / 2,
ymax = y + height / 2,
height = NULL
) -> xdat
# print(str(xdat, 1))
xdat
},
draw_group = function(self, data, panel_params, coord,
n_rows = 10, make_proportional = FALSE) {
# message("Called GeomPictogram::draw_group()")
# message("Called GEOM draw_group()")
tile_data <- data
# tile_data$size <- border_size
# tile_data$colour <- border_col
coord <- ggplot2::coord_equal()
# gg <- gg + geom_tile(
# color = "#00000000", fill = "#00000000", size = size,
# alpha = 0, show.legend = FALSE
# )
gtdat <- tile_data
gtdat[["colour"]] <- "#00000000"
gtdat[["color"]] <- "#00000000"
gtdat[["fill"]] <- "#00000000"
g_pgdat <<- tile_data
self$default_aes[["fa_glyph"]] <- tile_data[["fa_glyph"]][[1]]
pgdat <- tile_data
pgdat[["label"]] <- .fa_unicode[.fa_unicode[["name"]] %in% pgdat[["fa_glyph"]], "unicode"]
fat <- .fa_unicode[.fa_unicode[["name"]] %in% pgdat[["fa_glyph"]], "type"]
ftrans <- c(solid = "FontAwesome5Free-Solid", brands = "FontAwesome5Brands-Regular")
pgdat[["family"]] <- ftrans[fat]
pgdat[["size"]] <- pgdat[["size"]] * 2
pgdat[["angle"]] = 0
pgdat[["hjust"]] <- 0.5
pgdat[["vjust"]] <- 0.5
pgdat[["fontface"]] <- 1
pgdat[["lineheight"]] <- 1
# print(str(pgdat, 1))
# gg <- gg + geom_text(
# aes(color = value, label = fontlab),
# family = glyph_font_family,
# size = glyph_size,
# show.legend = FALSE
# )
grid::gList(
# GeomTile$draw_panel(gtdat, panel_params, coord),
GeomText$draw_panel(pgdat, panel_params, coord)
) -> grobs
ggname("geom_pictogram", grid::grobTree(children = grobs))
},
aesthetics = function(self) {
# message("Called GeomPictogram::aesthetics()")
c(union(self$required_aes, names(self$default_aes)), self$optional_aes, "group")
},
draw_key = draw_key_pictogram
)
# #' @export
# draw_key_pictogram <- function(data, params, size) {
#
# # message("Called draw_key_pictogram()")
#
# # print(str(data, 1))
# # print(str(params, 1))
# # print(str(size, 1))
#
# # return(draw_key_text(data, params, size))
#
# data[["label"]] <- .fa_unicode[.fa_unicode[["name"]] %in% data[["fa_glyph"]], "unicode"]
# fat <- .fa_unicode[.fa_unicode[["name"]] %in% data[["fa_glyph"]], "type"]
# ftrans <- c(solid = "FontAwesome5Free-Solid", brands = "FontAwesome5Brands-Regular")
# data[["family"]] <- ftrans[fat]
# data[["size"]] <- data[["size"]] * 2
#
# grid::textGrob(
# data$label, 0.5, 0.25,
# rot = data$angle %||% 0,
# gp = grid::gpar(
# col = alpha(data$colour %||% data$fill %||% "black", data$alpha),
# fontfamily = data$family %||% "",
# fontface = data$fontface %||% 1,
# fontsize = (data$size %||% 3.88) * .pt
# )
# )
# }
# #' Isotype pictogram "waffle" charts
# #'
# #' There are two special/critical `aes()` mappings:
# #' - `colour` (so the geom knows which column to map the country names/abbrevs to)
# #' - `values` (which column you're mapping the filling for the squares with)
# #'
# #' @md
# #' @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 n_rows how many rows should there be in the waffle chart? default is 10
# #' @param flip If `TRUE`, flip x and y coords. n_rows then becomes n_cols.
# #' Useful to achieve waffle column chart effect. Defaults is `FALSE`.
# #' @param make_proportional compute proportions from the raw values? (i.e. each
# #' value `n` will be replaced with `n`/`sum(n)`); default is `FALSE`.
# #' @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 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
# #' data.frame(
# #' parts = factor(rep(month.abb[1:3], 3), levels=month.abb[1:3]),
# #' values = c(10, 20, 30, 6, 14, 40, 30, 20, 10),
# #' fct = c(rep("Thing 1", 3), rep("Thing 2", 3), rep("Thing 3", 3))
# #' ) -> xdf
# #'
# #' ggplot(xdf, aes(fill = parts, values = values)) +
# #' geom_pictogram() +
# #' facet_wrap(~fct) +
# #' coord_equal()
# geom_pictogram <- function(
# mapping = NULL, data = NULL,
# n_rows = 10, flip = FALSE, make_proportional = FALSE,
# na.rm = TRUE, show.legend = NA, inherit.aes = TRUE, ...) {
#
# # message("Called geom_pictogram()")
#
# ggplot2::layer(
# data = data,
# mapping = mapping,
# stat = "pictogram",
# geom = GeomPictogram,
# position = "identity",
# show.legend = show.legend,
# inherit.aes = inherit.aes,
# check.aes = FALSE,
# params = list(
# na.rm = na.rm,
# n_rows = n_rows,
# flip = flip,
# make_proportional = make_proportional,
# use = "colour",
# ...
# )
# )
#
# }
#
# #' @rdname geom_pictogram
# #' @export
# GeomPictogram <- ggplot2::ggproto(
# `_class` = "GeomPictogram",
# `_inherit` = ggplot2::Geom,
#
# default_aes = ggplot2::aes(
# fa_glyph = "circle", fa_type = "solid",
# fill = NA, colour = "#b2b2b2", alpha = NA,
# size = 2, linetype = 1, width = NA, height = NA
# ),
#
# required_aes = c("x", "y", "values", "fa_glyph", "fa_type"),
#
# extra_params = c("na.rm", "width", "height", "flip", "use"),
#
# setup_data = function(data, params) {
#
# # message("Called GeomPictogram::setup_data()")
# # print(str(data, 1))
#
# waf.dat <- data
#
# # swap x and y values if flip is TRUE
# if (params$flip) {
# waf.dat$x_temp <- waf.dat$x
# waf.dat$x <- waf.dat$y
# waf.dat$y <- waf.dat$x_temp
# waf.dat$x_temp <- NULL
# }
#
# # reduce all values by 0.5
# # this allows for axis ticks to align _between_ square rows/cols
# # rather than in the middle of a row/col
# waf.dat$x <- waf.dat$x - 0.5
# waf.dat$y <- waf.dat$y - 0.5
#
# waf.dat$width <- waf.dat$width %||% params$width %||% ggplot2::resolution(waf.dat$x, FALSE)
# waf.dat$height <- waf.dat$height %||% params$height %||% ggplot2::resolution(waf.dat$y, FALSE)
#
# transform(
# waf.dat,
# xmin = x - width / 2,
# xmax = x + width / 2,
# width = NULL,
# ymin = y - height / 2,
# ymax = y + height / 2,
# height = NULL
# ) -> xdat
#
# # print(str(xdat, 1))
#
# xdat
#
# },
#
# draw_group = function(self, data, panel_params, coord,
# n_rows = 10, make_proportional = FALSE) {
#
# # message("Called GeomPictogram::draw_group()")
#
# # message("Called GEOM draw_group()")
#
# tile_data <- data
# # tile_data$size <- border_size
# # tile_data$colour <- border_col
#
# coord <- ggplot2::coord_equal()
#
# # gg <- gg + geom_tile(
# # color = "#00000000", fill = "#00000000", size = size,
# # alpha = 0, show.legend = FALSE
# # )
#
# gtdat <- tile_data
# gtdat[["colour"]] <- "#00000000"
# gtdat[["color"]] <- "#00000000"
# gtdat[["fill"]] <- "#00000000"
#
# g_pgdat <<- tile_data
#
# self$default_aes[["fa_glyph"]] <- tile_data[["fa_glyph"]][[1]]
#
# pgdat <- tile_data
# pgdat[["label"]] <- .fa_unicode[.fa_unicode[["name"]] %in% pgdat[["fa_glyph"]], "unicode"]
# fat <- .fa_unicode[.fa_unicode[["name"]] %in% pgdat[["fa_glyph"]], "type"]
# ftrans <- c(solid = "FontAwesome5Free-Solid", brands = "FontAwesome5Brands-Regular")
# pgdat[["family"]] <- ftrans[fat]
# pgdat[["size"]] <- pgdat[["size"]] * 2
# pgdat[["angle"]] = 0
# pgdat[["hjust"]] <- 0.5
# pgdat[["vjust"]] <- 0.5
# pgdat[["fontface"]] <- 1
# pgdat[["lineheight"]] <- 1
#
# # print(str(pgdat, 1))
#
# # gg <- gg + geom_text(
# # aes(color = value, label = fontlab),
# # family = glyph_font_family,
# # size = glyph_size,
# # show.legend = FALSE
# # )
#
# grid::gList(
# # GeomTile$draw_panel(gtdat, panel_params, coord),
# GeomText$draw_panel(pgdat, panel_params, coord)
# ) -> grobs
#
# ggname("geom_pictogram", grid::grobTree(children = grobs))
#
# },
#
# aesthetics = function(self) {
# # message("Called GeomPictogram::aesthetics()")
# c(union(self$required_aes, names(self$default_aes)), self$optional_aes, "group")
# },
#
# draw_key = draw_key_pictogram
#
# )
#

46
R/geom-rtile.R

@ -0,0 +1,46 @@
geom_rtile <- function(mapping = NULL, data = NULL,
stat = "identity", position = "identity",
radius = grid::unit(6, "pt"),
...,
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE) {
ggplot2::layer(
data = data,
mapping = mapping,
stat = stat,
geom = GeomRtile,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
radius = radius,
na.rm = na.rm,
...
)
)
}
GeomRtile <- ggplot2::ggproto("GeomRtile", GeomRrect,
extra_params = c("na.rm", "width", "height"),
setup_data = function(data, params) {
data$width <- data$width %||% params$width %||% ggplot2::resolution(data$x, FALSE)
data$height <- data$height %||% params$height %||% ggplot2::resolution(data$y, FALSE)
transform(data,
xmin = x - width / 2, xmax = x + width / 2, width = NULL,
ymin = y - height / 2, ymax = y + height / 2, height = NULL
)
},
default_aes = ggplot2::aes(
fill = "grey20", colour = NA, size = 0.1, linetype = 1, alpha = NA
),
required_aes = c("x", "y"),
draw_key = ggplot2::draw_key_polygon
)

302
R/geom-waffle.R

@ -1,152 +1,154 @@
#' Waffle (Square pie chart) Geom
#'
#' There are two special/critical `aes()` mappings:
#' - `fill` (so the geom knows which column to map the country names/abbrevs to)
#' - `values` (which column you're mapping the filling for the squares with)
#'
#' @md
#' @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 n_rows how many rows should there be in the waffle chart? default is 10
#' @param flip If `TRUE`, flip x and y coords. n_rows then becomes n_cols.
#' Useful to achieve waffle column chart effect. Defaults is `FALSE`.
#' @param make_proportional compute proportions from the raw values? (i.e. each
#' value `n` will be replaced with `n`/`sum(n)`); default is `FALSE`.
#' @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 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
#' data.frame(
#' parts = factor(rep(month.abb[1:3], 3), levels=month.abb[1:3]),
#' values = c(10, 20, 30, 6, 14, 40, 30, 20, 10),
#' fct = c(rep("Thing 1", 3), rep("Thing 2", 3), rep("Thing 3", 3))
#' ) -> xdf
#'
#' ggplot(xdf, aes(fill = parts, values = values)) +
#' geom_waffle() +
#' facet_wrap(~fct) +
#' coord_equal()
geom_waffle <- function(
mapping = NULL, data = NULL,
n_rows = 10, flip = FALSE, make_proportional = FALSE,
na.rm = TRUE, show.legend = NA, inherit.aes = TRUE, ...) {
# #' Waffle (Square pie chart) Geom
# #'
# #' There are two special/critical `aes()` mappings:
# #' - `fill` (so the geom knows which column to map the country names/abbrevs to)
# #' - `values` (which column you're mapping the filling for the squares with)
# #'
# #' @md
# #' @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 n_rows how many rows should there be in the waffle chart? default is 10
# #' @param flip If `TRUE`, flip x and y coords. n_rows then becomes n_cols.
# #' Useful to achieve waffle column chart effect. Defaults is `FALSE`.
# #' @param make_proportional compute proportions from the raw values? (i.e. each
# #' value `n` will be replaced with `n`/`sum(n)`); default is `FALSE`.
# #' @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 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
# #' data.frame(
# #' parts = factor(rep(month.abb[1:3], 3), levels=month.abb[1:3]),
# #' values = c(10, 20, 30, 6, 14, 40, 30, 20, 10),
# #' fct = c(rep("Thing 1", 3), rep("Thing 2", 3), rep("Thing 3", 3))
# #' ) -> xdf
# #'
# #' ggplot(xdf, aes(fill = parts, values = values)) +
# #' geom_waffle() +
# #' facet_wrap(~fct) +
# #' coord_equal()
# geom_waffle <- function(
# mapping = NULL, data = NULL,
# n_rows = 10, flip = FALSE, make_proportional = FALSE,
# na.rm = TRUE, show.legend = NA, inherit.aes = TRUE, ...) {
#
# ggplot2::layer(
# data = data,
# mapping = mapping,
# stat = "waffle",
# geom = GeomWaffle,
# position = "identity",
# show.legend = show.legend,
# inherit.aes = inherit.aes,
# params = list(
# na.rm = TRUE,
# n_rows = n_rows,
# flip = flip,
# make_proportional = make_proportional,
# use = "fill",
# ...
# )
# )
#
# }
#
# #' @rdname geom_waffle
# #' @export
# GeomWaffle <- ggplot2::ggproto(
# `_class` = "GeomWaffle",
# `_inherit` = ggplot2::Geom,
#
# default_aes = ggplot2::aes(
# values = "values",
# fill = NA, colour = "#b2b2b2", alpha = NA,
# size = 0.125, linetype = 1, width = NA, height = NA
# ),
#
# required_aes = c("x", "y"),
#
# extra_params = c("na.rm", "width", "height", "flip", "use"),
#
# setup_data = function(data, params) {
#
# # message("Called GEOM setup_data()")
#
# waf.dat <- data #data.frame(data)#, stringsAsFactors=FALSE)
#
# # swap x and y values if flip is TRUE
# if (params$flip) {
# waf.dat$x_temp <- waf.dat$x
# waf.dat$x <- waf.dat$y
# waf.dat$y <- waf.dat$x_temp
# waf.dat$x_temp <- NULL
# }
#
# # reduce all values by 0.5
# # this allows for axis ticks to align _between_ square rows/cols
# # rather than in the middle of a row/col
# waf.dat$x <- waf.dat$x - .5
# waf.dat$y <- waf.dat$y - .5
#
# waf.dat$width <- waf.dat$width %||% params$width %||% ggplot2::resolution(waf.dat$x, FALSE)
# waf.dat$height <- waf.dat$height %||% params$height %||% ggplot2::resolution(waf.dat$y, FALSE)
#
# transform(
# waf.dat,
# xmin = x - width / 2, xmax = x + width / 2, width = NULL,
# ymin = y - height / 2, ymax = y + height / 2, height = NULL
# ) -> xdat
#
# xdat
#
# },
#
# draw_group = function(self, data, panel_params, coord,
# n_rows = 10, make_proportional = FALSE) {
#
# # message("Called GEOM draw_group()")
#
# tile_data <- data
# # tile_data$size <- border_size
# # tile_data$colour <- border_col
#
# coord <- ggplot2::coord_equal()
#
# grid::gList(
# GeomTile$draw_panel(tile_data, panel_params, coord)
# ) -> grobs
#
# ggname("geom_waffle", grid::grobTree(children = grobs))
#
# },
#
# draw_key = ggplot2::draw_key_polygon
#
# )
ggplot2::layer(
data = data,
mapping = mapping,
stat = "waffle",
geom = GeomWaffle,
position = "identity",
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
na.rm = TRUE,
n_rows = n_rows,
flip = flip,
make_proportional = make_proportional,
use = "fill",
...
)
)
}
#' @rdname geom_waffle
#' @export
GeomWaffle <- ggplot2::ggproto(
`_class` = "GeomWaffle",
`_inherit` = ggplot2::Geom,
default_aes = ggplot2::aes(
values = "values",
fill = NA, colour = "#b2b2b2", alpha = NA,
size = 0.125, linetype = 1, width = NA, height = NA
),
required_aes = c("x", "y"),
extra_params = c("na.rm", "width", "height", "flip", "use"),
setup_data = function(data, params) {
# message("Called GEOM setup_data()")
waf.dat <- data #data.frame(data)#, stringsAsFactors=FALSE)
# swap x and y values if flip is TRUE
if (params$flip) {
waf.dat$x_temp <- waf.dat$x
waf.dat$x <- waf.dat$y
waf.dat$y <- waf.dat$x_temp
waf.dat$x_temp <- NULL
}
# reduce all values by 0.5
# this allows for axis ticks to align _between_ square rows/cols
# rather than in the middle of a row/col
waf.dat$x <- waf.dat$x - .5
waf.dat$y <- waf.dat$y - .5
waf.dat$width <- waf.dat$width %||% params$width %||% ggplot2::resolution(waf.dat$x, FALSE)
waf.dat$height <- waf.dat$height %||% params$height %||% ggplot2::resolution(waf.dat$y, FALSE)
transform(
waf.dat,
xmin = x - width / 2, xmax = x + width / 2, width = NULL,
ymin = y - height / 2, ymax = y + height / 2, height = NULL
) -> xdat
xdat
},
draw_group = function(self, data, panel_params, coord,
n_rows = 10, make_proportional = FALSE) {
# message("Called GEOM draw_group()")
tile_data <- data
# tile_data$size <- border_size
# tile_data$colour <- border_col
coord <- ggplot2::coord_equal()
grid::gList(
GeomTile$draw_panel(tile_data, panel_params, coord)
) -> grobs
ggname("geom_waffle", grid::grobTree(children = grobs))
},
draw_key = ggplot2::draw_key_polygon
)

285
R/stat-pictogram.R

@ -1,142 +1,143 @@
#' @rdname geom_pictogram
#' @export
stat_pictogram <- function(mapping = NULL, data = NULL,
n_rows = 10, make_proportional = FALSE,
na.rm = NA, show.legend = NA,
inherit.aes = TRUE, ...) {
layer(
stat = StatPictogram,
data = data,
mapping = mapping,
geom = "pictogram",
position = "identity",
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
na.rm = na.rm,
n_rows = n_rows,
make_proportional = make_proportional,
...
)
)
}
#' @rdname geom_pictogram
#' @export
StatPictogram <- ggplot2::ggproto(
`_class` = "StatPictogram",
`_inherit` = ggplot2::Stat,
required_aes = c("colour", "values", "fa_type", "fa_glyph"),
extra_params = c("na.rm", "width", "height", "flip", "use"),
setup_params = function(data, params) {
# message("Called StatPictogram::setup_params()")
params
},
setup_data = function(data, params) {
# message("Called StatPictogram::setup_data()")
# print(str(data, 1))
data
},
compute_layer = function(self, data, params, panels) {
# message("Called StatPictogram::compute_layer()")
# print(str(data, 1))
use <- params[["use"]]
if (inherits(data[[use]], "factor")) {
flvls <- levels(data[[use]])
} else {
flvls <- levels(factor(data[[use]]))
}
tr1 <- data[c(use, "fa_glyph", "fa_type")]
tr1 <- tr1[!duplicated(tr1), ]
gtrans <- tr1[, "fa_glyph"]
names(gtrans) <- tr1[, use]
ttrans <- tr1[, "fa_type"]
names(ttrans) <- tr1[, use]
# print(str(tr1, 1))
p <- split(data, data$PANEL)
lapply(p, function(.x) {
parts_vec <- unlist(sapply(1:length(.x[[use]]), function(i) {
rep(as.character(.x[[use]][i]), .x[["values"]][i])
}))
pgrp_vec <- unlist(sapply(1:length(.x[[use]]), function(i) {
rep(.x$group, .x[[use]][i])
}))
expand.grid(
y = 1:params$n_rows,
x = seq_len((ceiling(sum(.x[["values"]]) / params$n_rows)))#,
# stringsAsFactors = FALSE
) -> tdf
parts_vec <- c(parts_vec, rep(NA, nrow(tdf) - length(parts_vec)))
# tdf$parts <- parts_vec
tdf[["values"]] <- parts_vec
tdf[[use]] <- parts_vec
tdf[["fa_glyph"]] <- gtrans[tdf[[use]]]
tdf[["fa_type"]] <- ttrans[tdf[[use]]]
tdf[["PANEL"]] <- .x[["PANEL"]][1]
tdf[["group"]] <- 1:nrow(tdf)
tdf <- tdf[sapply(tdf[[use]], function(x) !is.na(x)),]
tdf
}) -> p
p <- plyr::rbind.fill(p)
p[[use]] <- factor(p[[use]], levels=flvls)
# print(str(p, 1))
p
},
finish_layer = function(self, data, params) {
# message("Called StatPictogram::finish_layer()")
self$default_aes[["fa_glyph"]] <- "square"
# print(str(data,1))
# print(str(params, 1))
data
},
compute_panel = function(self, data, scales, na.rm = FALSE,
n_rows = 10, make_proportional = FALSE) {
# message("Called StatPictogram::compute_panel()")
ggproto_parent(Stat, self)$compute_panel(
data, scales,
n_rows = n_rows,
make_proportional = make_proportional,
na.rm = na.rm
)
},
aesthetics = function(self) {
# message("Called StatPictogram::aesthetics()")
c(union(self$required_aes, names(self$default_aes)), "group")
}
)
# #' @rdname geom_pictogram
# #' @export
# stat_pictogram <- function(mapping = NULL, data = NULL,
# n_rows = 10, make_proportional = FALSE,
# na.rm = NA, show.legend = NA,
# inherit.aes = TRUE, ...) {
#
# layer(
# stat = StatPictogram,
# data = data,
# mapping = mapping,
# geom = "pictogram",
# position = "identity",
# show.legend = show.legend,
# inherit.aes = inherit.aes,
# params = list(
# na.rm = na.rm,
# n_rows = n_rows,
# make_proportional = make_proportional,
# ...
# )
# )
# }
#
# #' @rdname geom_pictogram
# #' @export
# StatPictogram <- ggplot2::ggproto(
# `_class` = "StatPictogram",
# `_inherit` = ggplot2::Stat,
#
# required_aes = c("colour", "values", "fa_type", "fa_glyph"),
# extra_params = c("na.rm", "width", "height", "flip", "use"),
#
# setup_params = function(data, params) {
# # message("Called StatPictogram::setup_params()")
# params
# },
#
# setup_data = function(data, params) {
# # message("Called StatPictogram::setup_data()")
# # print(str(data, 1))
# data
# },
#
# compute_layer = function(self, data, params, panels) {
#
# # message("Called StatPictogram::compute_layer()")
# # print(str(data, 1))
#
# use <- params[["use"]]
#
# if (inherits(data[[use]], "factor")) {
# flvls <- levels(data[[use]])
# } else {
# flvls <- levels(factor(data[[use]]))
# }
#
# tr1 <- data[c(use, "fa_glyph", "fa_type")]
# tr1 <- tr1[!duplicated(tr1), ]
#
# gtrans <- tr1[, "fa_glyph"]
# names(gtrans) <- tr1[, use]
#
# ttrans <- tr1[, "fa_type"]
# names(ttrans) <- tr1[, use]
#
# # print(str(tr1, 1))
#
# p <- split(data, data$PANEL)
#
# lapply(p, function(.x) {
#
# parts_vec <- unlist(sapply(1:length(.x[[use]]), function(i) {
# rep(as.character(.x[[use]][i]), .x[["values"]][i])
# }))
#
# pgrp_vec <- unlist(sapply(1:length(.x[[use]]), function(i) {
# rep(.x$group, .x[[use]][i])
# }))
#
# expand.grid(
# y = 1:params$n_rows,
# x = seq_len((ceiling(sum(.x[["values"]]) / params$n_rows)))#,
# # stringsAsFactors = FALSE
# ) -> tdf
#
# parts_vec <- c(parts_vec, rep(NA, nrow(tdf) - length(parts_vec)))
#
# # tdf$parts <- parts_vec
# tdf[["values"]] <- parts_vec
# tdf[[use]] <- parts_vec
#
# tdf[["fa_glyph"]] <- gtrans[tdf[[use]]]
# tdf[["fa_type"]] <- ttrans[tdf[[use]]]
#
# tdf[["PANEL"]] <- .x[["PANEL"]][1]
# tdf[["group"]] <- 1:nrow(tdf)
#
# tdf <- tdf[sapply(tdf[[use]], function(x) !is.na(x)),]
#
# tdf
#
# }) -> p
#
# p <- plyr::rbind.fill(p)
# p[[use]] <- factor(p[[use]], levels=flvls)
#
# # print(str(p, 1))
#
# p
#
# },
#
# finish_layer = function(self, data, params) {
# # message("Called StatPictogram::finish_layer()")
# self$default_aes[["fa_glyph"]] <- "square"
# # print(str(data,1))
# # print(str(params, 1))
# data
# },
#
# compute_panel = function(self, data, scales, na.rm = FALSE,
# n_rows = 10, make_proportional = FALSE) {
#
# # message("Called StatPictogram::compute_panel()")
#
# ggproto_parent(Stat, self)$compute_panel(
# data, scales,
# n_rows = n_rows,
# make_proportional = make_proportional,
# na.rm = na.rm
# )
#
# },
#
# aesthetics = function(self) {
# # message("Called StatPictogram::aesthetics()")
# c(union(self$required_aes, names(self$default_aes)), "group")
# }
#
#
# )
#

195
R/stat-waffle.R

@ -1,97 +1,98 @@
#' @rdname geom_waffle
#' @export
stat_waffle<- function(mapping = NULL, data = NULL,
n_rows = 10, make_proportional = FALSE,
na.rm = NA, show.legend = NA,
inherit.aes = TRUE, ...) {
layer(
stat = StatWaffle,
data = data,
mapping = mapping,
geom = "waffle",
position = "identity",
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
na.rm = na.rm,
n_rows = n_rows,
make_proportional = make_proportional,
...
)
)
}
#' @rdname geom_waffle
#' @export
StatWaffle <- ggplot2::ggproto(
`_class` = "StatWaffle",
`_inherit` = ggplot2::Stat,
required_aes = c("fill", "values"),
extra_params = c("na.rm", "width", "height", "flip", "use"),
compute_layer = function(self, data, params, panels) {
use <- params[["use"]]
if (inherits(data[[use]], "factor")) {
flvls <- levels(data[[use]])
} else {
flvls <- levels(factor(data[[use]]))
}
p <- split(data, data$PANEL)
lapply(p, function(.x) {
parts_vec <- unlist(sapply(1:length(.x[[use]]), function(i) {
rep(as.character(.x[[use]][i]), .x[["values"]][i])
}))
pgrp_vec <- unlist(sapply(1:length(.x[[use]]), function(i) {
rep(.x$group, .x[[use]][i])
}))
expand.grid(
y = 1:params$n_rows,
x = seq_len((ceiling(sum(.x[["values"]]) / params$n_rows)))#,
# stringsAsFactors = FALSE
) -> tdf
parts_vec <- c(parts_vec, rep(NA, nrow(tdf)-length(parts_vec)))
# tdf$parts <- parts_vec
tdf[["values"]] <- NA
tdf[[use]] <- parts_vec
tdf[["PANEL"]] <- .x[["PANEL"]][1]
tdf[["group"]] <- 1:nrow(tdf)
tdf <- tdf[sapply(tdf[[use]], function(x) !is.na(x)),]
}) -> p
p <- plyr::rbind.fill(p)
p[[use]] <- factor(p[[use]], levels=flvls)
# print(str(p))
p
},
compute_panel = function(self, data, scales, na.rm = FALSE,
n_rows = 10, make_proportional = FALSE) {
# message("Called STAT compute_panel()")
ggproto_parent(Stat, self)$compute_panel(
data, scales,
n_rows = 10,
make_proportional = FALSE
)
}
)
# #' @rdname geom_waffle
# #' @export
# stat_waffle<- function(mapping = NULL, data = NULL,
# n_rows = 10, make_proportional = FALSE,
# na.rm = NA, show.legend = NA,
# inherit.aes = TRUE, ...) {
#
# layer(
# stat = StatWaffle,
# data = data,
# mapping = mapping,
# geom = "waffle",
# position = "identity",
# show.legend = show.legend,
# inherit.aes = inherit.aes,
# params = list(
# na.rm = na.rm,
# n_rows = n_rows,
# make_proportional = make_proportional,
# ...
# )
# )
# }
#
# #' @rdname geom_waffle
# #' @export
# StatWaffle <- ggplot2::ggproto(
# `_class` = "StatWaffle",
# `_inherit` = ggplot2::Stat,
#
# required_aes = c("fill", "values"),
#
# extra_params = c("na.rm", "width", "height", "flip", "use"),
#
# compute_layer = function(self, data, params, panels) {
#
# use <- params[["use"]]
#
# if (inherits(data[[use]], "factor")) {
# flvls <- levels(data[[use]])
# } else {
# flvls <- levels(factor(data[[use]]))
# }
#
# p <- split(data, data$PANEL)
#
# lapply(p, function(.x) {
#
# parts_vec <- unlist(sapply(1:length(.x[[use]]), function(i) {
# rep(as.character(.x[[use]][i]), .x[["values"]][i])
# }))
#
# pgrp_vec <- unlist(sapply(1:length(.x[[use]]), function(i) {
# rep(.x$group, .x[[use]][i])
# }))
#
# expand.grid(
# y = 1:params$n_rows,
# x = seq_len((ceiling(sum(.x[["values"]]) / params$n_rows)))#,
# # stringsAsFactors = FALSE
# ) -> tdf
#
# parts_vec <- c(parts_vec, rep(NA, nrow(tdf)-length(parts_vec)))
#
# # tdf$parts <- parts_vec
# tdf[["values"]] <- NA
# tdf[[use]] <- parts_vec
# tdf[["PANEL"]] <- .x[["PANEL"]][1]
# tdf[["group"]] <- 1:nrow(tdf)
#
# tdf <- tdf[sapply(tdf[[use]], function(x) !is.na(x)),]
#
# }) -> p
#
# p <- plyr::rbind.fill(p)
# p[[use]] <- factor(p[[use]], levels=flvls)
#
# # print(str(p))
#
# p
#
# },
#
# compute_panel = function(self, data, scales, na.rm = FALSE,
# n_rows = 10, make_proportional = FALSE) {
#
# # message("Called STAT compute_panel()")
#
# ggproto_parent(Stat, self)$compute_panel(
# data, scales,
# n_rows = 10,
# make_proportional = FALSE
# )
#
# }
#
# )
#

355
R/sw2.R

@ -0,0 +1,355 @@
draw_key_waffle <- function(data, params, size, ...) { # nocov start
# msg("Called => draw_key_waffle()")
#
# print(str(data, 1))
# print(str(params, 1))
# print(str(size, 1))
# print(str(list(...), 1))
grid::roundrectGrob(
r = min(params$radius, unit(3, "pt")),
default.units = "native",
width = 0.9, height = 0.9,
name = "lkey",
gp = grid::gpar(
col = params[["color"]][[1]] %l0% params[["colour"]][1] %l0% data[["colour"]][[1]] %l0% "#00000000",
fill = alpha(data$fill %||% data$colour %||% "grey20", data$alpha),
lty = data$linetype %||% 1
)
)
} # nocov end
#' Waffle (Square pie chart) Geom
#'
#' There are two special/critical `aes()` mappings:
#' - `fill` (so the geom knows which column to map the country names/abbrevs to)
#' - `values` (which column you're mapping the filling for the squares with)
#'
#' @md
#' @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 n_rows how many rows should there be in the waffle chart? default is 10
#' @param flip If `TRUE`, flip x and y coords. n_rows then becomes n_cols.
#' Useful to achieve waffle column chart effect. Defaults is `FALSE`.
#' @param make_proportional compute proportions from the raw values? (i.e. each
#' value `n` will be replaced with `n`/`sum(n)`); default is `FALSE`.
#' @param radius radius
#' @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 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
#' data.frame(
#' parts = factor(rep(month.abb[1:3], 3), levels=month.abb[1:3]),
#' vals = c(10, 20, 30, 6, 14, 40, 30, 20, 10),
#' fct = c(rep("Thing 1", 3), rep("Thing 2", 3), rep("Thing 3", 3))
#' ) -> xdf
#'
#' ggplot(xdf, aes(fill = parts, values = vals)) +
#' geom_waffle() +
#' facet_wrap(~fct)
geom_waffle <- function(mapping = NULL, data = NULL,
n_rows = 10, make_proportional = FALSE,
na.rm = NA, show.legend = NA, flip = FALSE,
radius = grid::unit(0, "npc"),
inherit.aes = TRUE, ...) {
# msg("Called => geom_waffle::geom_waffle()")
# msg("Done With => geom_waffle::geom_waffle()")
layer(
stat = StatWaffle,
data = data,
mapping = mapping,
geom = GeomWaffle,
position = "identity",
show.legend = show.legend,
inherit.aes = inherit.aes,
check.param = FALSE,
params = list(
na.rm = na.rm,
n_rows = n_rows,
make_proportional = make_proportional,
flip = flip,
radius = radius,
...
)
)
}
#' @rdname geom_waffle
#' @export
GeomWaffle <- ggplot2::ggproto(
`_class` = "GeomWaffle",
`_inherit` = GeomRtile,
default_aes = ggplot2::aes(
fill = NA, alpha = NA, colour = NA,
size = 0.125, linetype = 1, width = NA, height = NA
),
draw_group = function(self, data, panel_params, coord,
n_rows = 10, make_proportional = FALSE, flip = FALSE,
radius = grid::unit(0, "npc")) {
# msg("Called => GeomWaffle::draw_group()")
coord <- ggplot2::coord_equal()
grobs <- GeomRtile$draw_panel(data, panel_params, coord, radius)
# msg("Done With => GeomWaffle::draw_group()")
ggname("geom_waffle", grid::grobTree(children = grobs))
},
draw_panel = function(self, data, panel_params, coord,
n_rows = 10, make_proportional = FALSE, flip = FALSE,
radius = grid::unit(0, "npc")) {
# msg("Called => GeomWaffle::draw_panel()")
coord <- ggplot2::coord_equal()
# grid::gList(
grobs <- GeomRtile$draw_panel(data, panel_params, coord, radius)
# ) -> grobs
# msg("Done With => GeomWaffle::draw_panel()")
ggname("geom_waffle", grid::grobTree(children = grobs))
},
draw_key = draw_key_waffle
)
#' @rdname geom_waffle
#' @export
stat_waffle <- function(mapping = NULL, data = NULL, geom = "blank",
n_rows = 10, make_proportional = FALSE, flip = FALSE,
radius = grid::unit(0, "npc"),
na.rm = NA, show.legend = NA,
inherit.aes = TRUE, ...) {
# msg("Called => stat_waffle::stat_waffle()")
# msg("Done With => stat_waffle::stat_waffle()")
layer(
stat = StatWaffle,
data = data,
mapping = mapping,
geom = geom,
position = "identity",
show.legend = show.legend,
inherit.aes = inherit.aes,
check.param = FALSE,
params = list(
na.rm = na.rm,
n_rows = n_rows,
make_proportional = make_proportional,
flip = flip,
radius = radius,
...
)
)
}
#' @rdname geom_waffle
#' @export
StatWaffle <- ggplot2::ggproto(
`_class` = "StatWaffle",
`_inherit` = ggplot2::Stat,
extra_params = c("na.rm", "n_rows", "make_proportional", "flip", "radius"),
required_aes = c("fill", "values", "colour"),
setup_params = function(data, params) {
# msg("Called => StatWaffle::setup_params()")
# msg("Done With => StatWaffle::setup_params()")
params
},
setup_data = function(data, params) {
# msg("Called => StatWaffle::setup_data()")
#
# print(str(data, 1))
# print(str(params, 1))
use <- "fill"
if (inherits(data[[use]], "factor")) {
flvls <- levels(data[[use]])
} else {
flvls <- levels(factor(data[[use]]))
}
if (inherits(data[["colour"]], "factor")) {
clvls <- levels(data[["colour"]])
} else {
clvls <- levels(factor(data[["colour"]]))
}
if (!("colour" %in% names(data))) {
data[["colour"]] <- "white"
} else {
if (any(is.na(as.character(data[["colour"]])))) {
data[["colour"]] <- "white"
} else {
data[["colour"]] <- as.character(data[["colour"]])
}
}
p <- split(data, data$PANEL)
lapply(p, function(.x) {
if (params[["make_proportional"]]) {
.x[["values"]] <- .x[["values"]] / sum(.x[["values"]])
.x[["values"]] <- round_preserve_sum(.x[["values"]], digits = 2)
.x[["values"]] <- as.integer(.x[["values"]] * 100)
}
parts_vec <- unlist(sapply(1:length(.x[[use]]), function(i) {
rep(as.character(.x[[use]][i]), .x[["values"]][i])
}))
pgrp_vec <- unlist(sapply(1:length(.x[[use]]), function(i) {
rep(.x$group, .x[["values"]][i])
}))
# print(str(.x, 1))
colour_vec <- unlist(sapply(1:length(.x[[use]]), function(i) {
rep(.x[["colour"]][i], .x[["values"]][i])
}))
expand.grid(
y = 1:params$n_rows,
x = seq_len((ceiling(sum(.x[["values"]]) / params$n_rows)))#,
# stringsAsFactors = FALSE
) -> tdf
parts_vec <- c(parts_vec, rep(NA, nrow(tdf)-length(parts_vec)))
colour_vec <- c(colour_vec, rep(NA, nrow(tdf)-length(colour_vec)))
# tdf$parts <- parts_vec
tdf