From 9f164e43ee624ead4eff26b4151c6fe8c490d0d8 Mon Sep 17 00:00:00 2001 From: Eric R Date: Sun, 18 May 2025 13:22:50 -0700 Subject: [PATCH] Add marimekko plot --- NAMESPACE | 1 + R/marimekko.R | 59 +++++++++++++++++++++++++++++ README.md | 2 +- man/marimekko.Rd | 35 +++++++++++++++++ vignettes/mekko-vignette.Rmd | 5 +-- vignettes/mekko-vignette.md | 2 +- vignettes/second-mekko-vignette.Rmd | 3 +- 7 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 R/marimekko.R create mode 100644 man/marimekko.Rd diff --git a/NAMESPACE b/NAMESPACE index 7a9b91a..f9912fe 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,3 +1,4 @@ # Generated by roxygen2: do not edit by hand export(barmekko) +export(marimekko) diff --git a/R/marimekko.R b/R/marimekko.R new file mode 100644 index 0000000..668d499 --- /dev/null +++ b/R/marimekko.R @@ -0,0 +1,59 @@ +#' Create a marimekko plot. +#' +#' A 100\% stacked bar chart with variable widths. +#' +#' @param data A data frame. +#' @param x A categorical variable defining the width categories. +#' @param fill A categorical variable defining the stacked segments. +#' @param width A numeric variable defining the bar widths. +#' @param values A boolean indicating whether to show percent labels in bars. +#' @return A marimekko constructed with ggplot2. +#' @export +#' @examples +#' library(ggplot2) +#' df <- data.frame( +#' region = rep(c('East', 'West'), each = 2), +#' result = rep(c('Good', 'Bad'), 2), +#' share = c(60, 40, 80, 20), +#' sales = c(300, 300, 200, 200) +#' ) +#' marimekko(df, region, result, sales) +marimekko <- function(data, x, fill, width, values = FALSE) { + df <- data + xlabel <- as.character(substitute(x)) + filllabel <- as.character(substitute(fill)) + xval <- as.character(eval(substitute(x), df)) + fillval <- as.character(eval(substitute(fill), df)) + widthval <- eval(substitute(width), df) + + x_levels <- unique(xval) + width_map <- tapply(widthval, xval, function(z) z[1]) + widths <- as.numeric(width_map[x_levels]) + pos <- positions(widths) + + tbl <- as.data.frame(table(x = xval, fill = fillval), stringsAsFactors = FALSE) + tbl$prop <- tbl$Freq / ave(tbl$Freq, tbl$x, FUN = sum) + tbl$width <- width_map[tbl$x] + tbl$pos <- pos[match(tbl$x, x_levels)] + tbl$label_y <- ave(tbl$prop, tbl$x, FUN = function(z) cumsum(z) - z/2) + + p <- suppressWarnings( + ggplot2::ggplot(tbl) + + ggplot2::geom_bar( + ggplot2::aes(x = pos, y = prop, width = width, fill = fill), + stat = "identity" + ) + + ggplot2::scale_x_continuous(labels = x_levels, breaks = pos) + + ggplot2::xlab(xlabel) + + ggplot2::ylab("Proportion") + + ggplot2::guides(fill = ggplot2::guide_legend(title = filllabel)) + ) + if (values) { + labs <- round(tbl$prop * 100, 1) + p + ggplot2::geom_text( + ggplot2::aes(x = pos, y = label_y, label = labs), size = 3 + ) + } else { + p + } +} diff --git a/README.md b/README.md index 3d4768a..97dbcae 100644 --- a/README.md +++ b/README.md @@ -82,5 +82,5 @@ bmx + theme(axis.text.x = element_text(angle = 90, hjust = 1)) ### Appendix -- This package originally included a marimekko function as well, but the latter was discovered to be well covered in [other](https://CRAN.R-project.org/package=ggmosaic/vignettes/ggmosaic.html) [packages](https://www.semanticscholar.org/paper/Product-Plots-Wickham-Hofmann/0598a59354cb96161d68dab91fb0de21fb8671fd/figure/6), so it was removed to simplify maintenance +- The package now includes `marimekko()` to create 100% stacked mekko charts - While the barmekko is a ggplot object, your mileage may vary when attempting operations that normally would work on a ggplot object, as the data frame is deconstructed in the process of creating the graph diff --git a/man/marimekko.Rd b/man/marimekko.Rd new file mode 100644 index 0000000..50da665 --- /dev/null +++ b/man/marimekko.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/marimekko.R +\name{marimekko} +\alias{marimekko} +\title{Create a marimekko plot.} +\usage{ +marimekko(data, x, fill, width, values = FALSE) +} +\arguments{ +\item{data}{A data frame.} + +\item{x}{A categorical variable defining the width categories.} + +\item{fill}{A categorical variable defining the stacked segments.} + +\item{width}{A numeric variable defining the bar widths.} + +\item{values}{A boolean indicating whether to show percent labels in bars.} +} +\value{ +A marimekko constructed with ggplot2. +} +\description{ +A 100\% stacked bar chart with variable widths. +} +\examples{ +library(ggplot2) +df <- data.frame( + region = rep(c('East', 'West'), each = 2), + result = rep(c('Good', 'Bad'), 2), + share = c(60, 40, 80, 20), + sales = c(300, 300, 200, 200) +) +marimekko(df, region, result, sales) +} diff --git a/vignettes/mekko-vignette.Rmd b/vignettes/mekko-vignette.Rmd index cbf876c..de2ff63 100644 --- a/vignettes/mekko-vignette.Rmd +++ b/vignettes/mekko-vignette.Rmd @@ -91,6 +91,5 @@ bmx + theme(axis.text.x = element_text(angle = 90, hjust = 1)) ### Appendix -* This package originally included a marimekko function as well, but the latter -was discovered to be well covered in [other](https://CRAN.R-project.org/package=ggmosaic/vignettes/ggmosaic.html) [packages](https://www.semanticscholar.org/paper/Product-Plots-Wickham-Hofmann/0598a59354cb96161d68dab91fb0de21fb8671fd/figure/6), so it was removed to simplify maintenance -* While the barmekko is a ggplot object, your mileage may vary when attempting operations that normally would work on a ggplot object, as the data frame is deconstructed in the process of creating the graph \ No newline at end of file +* The package now includes `marimekko()` to create 100% stacked mekko charts +* While the barmekko is a ggplot object, your mileage may vary when attempting operations that normally would work on a ggplot object, as the data frame is deconstructed in the process of creating the graph diff --git a/vignettes/mekko-vignette.md b/vignettes/mekko-vignette.md index 4714cc7..e9449f8 100644 --- a/vignettes/mekko-vignette.md +++ b/vignettes/mekko-vignette.md @@ -82,5 +82,5 @@ bmx + theme(axis.text.x = element_text(angle = 90, hjust = 1)) ### Appendix -- This package originally included a marimekko function as well, but the latter was discovered to be well covered in [other](https://CRAN.R-project.org/package=ggmosaic/vignettes/ggmosaic.html) [packages](https://www.semanticscholar.org/paper/Product-Plots-Wickham-Hofmann/0598a59354cb96161d68dab91fb0de21fb8671fd/figure/6), so it was removed to simplify maintenance +- The package now includes `marimekko()` to create 100% stacked mekko charts - While the barmekko is a ggplot object, your mileage may vary when attempting operations that normally would work on a ggplot object, as the data frame is deconstructed in the process of creating the graph diff --git a/vignettes/second-mekko-vignette.Rmd b/vignettes/second-mekko-vignette.Rmd index 60e74f5..3cf58c0 100644 --- a/vignettes/second-mekko-vignette.Rmd +++ b/vignettes/second-mekko-vignette.Rmd @@ -122,6 +122,5 @@ state.x77 %>% ### Appendix -* This package originally included a marimekko function as well, but the latter -was discovered to be well covered in [other](https://CRAN.R-project.org/package=ggmosaic/vignettes/ggmosaic.html) [packages](https://www.semanticscholar.org/paper/Product-Plots-Wickham-Hofmann/0598a59354cb96161d68dab91fb0de21fb8671fd/figure/6), so it was removed to simplify maintenance +* The package now includes `marimekko()` to create 100% stacked mekko charts * While the barmekko is a ggplot object, your mileage may vary when attempting operations that normally would work on a ggplot object, as the data frame is deconstructed in the process of creating the graph