Agile Data Science
  • Posts
  • Projects
  • Author
  • Github

On this page

  • Overview
  • Implementation in Your Own Package
  • Example
    • Why ggcall matters
    • Join the ggcall Community

ggcall: Transparent R Packages with ggplot2

Author

Maciej Nasinski

TL;DR Two functions in ggplot2 are overwritten (ggplot and +) to achieve code transparency and reproducibility when ggplot2 is used inside a function.
It is believed that merging ggcall-like into ggplot2 can significantly enhance its functionality and accessibility, benefiting the entire R community.
Powered by metaprogramming.

Overview

Transparency and reproducibility are fundamental principles in data analysis across various fields, from academic research to industry applications. The ggcall package enhances the functionality of ggplot2 by enabling users to retrieve the complete code used to generate a ggplot object inside a function. This package is beneficial for understanding and replicating complex ggplot2 plots returned by a function. From technical point of view, ggcall extends ggplot2 + operator and ggplot function to track the history of plot construction.

ggcall makes a developer’s life easier and limits the need to use base r metaprogramming or rlang.

patchwork ggplot2 related operators like +, -, *, |, & and / are optionally supported. patchwork is a package that expands the API to allow for arbitrarily complex composition of plots by, among others, providing mathematical operators for combining multiple plots.

An excellent implementation example is to create a bunch of ggplot templates, and we want them to be functions. Then, each template will generate the expected plot, and the ggplot2 code behind is easy to get. Please access such templates here.

Implementation in Your Own Package

The ggcall can be implemented as a standalone solution.

A “standalone” file implements a minimum set of functionality in such a way that it can be copied into another package. usethis::use_standalone() makes it easy to get such a file into your own repo/package and later update it if needed.
Example of standalone file in another package, rlang

The usethis >= 2.2.0 is required.

install.packages("usethis")

STANDALONE means copy paste the files and add dependencies to your own package.

Please create an R package if not having such yet.

usethis::create_package()

WITH patchwork support

# Add ggplot2, patchwork as your package dependencies
# copy paste the ggcall.R file to your own package R directory
# copy paste the patchwork.R file to your own package R directory

usethis::use_standalone("polkas/ggcall", "patchwork.R", ref = "v0.3.4")
# you may need to update the files time to time with usethis::use_standalone

WITHOUT patchwork support

# Add ggplot2as your package dependencies
# copy paste the ggcall.R file to your own package R directory

usethis::use_standalone("polkas/ggcall", "ggcall.R", ref = "v0.3.4")
# you may need to update the files time to time with usethis::use_standalone

GENERAL COMMENTS:

# Apply only if needed
# In your own code remove all ggplot2:: prefix-ing before ggplot function calls
# ggplot2::ggplot(...) -> ggplot(...)
# DO NOT import ggplot function from ggplot2
#' @rawNamespace import(ggplot2, except = c(ggplot))
# Combine ggcall +.gg operator with your own one if you already overwrited it in your package
# e.g. GGally package requires such step
# Consider moving the ggplot2 from DESCRIPTION Imports to Depends 
# if your users will benefit from extending results with further layers

Example

The ggcall_example repository contains a simple implementation of ggcall. forest_plot and barbell_plot functions are a part of ggcall.example package. Typically, it will be a function returning ggplot2 object from your own R package where you implemented ggcall.

remotes::install_github("https://github.com/Polkas/ggcall_example")
library(ggcall.example)

# Print the body of the function
forest_plot

df <- data.frame(
  Treatment = c("Treatment A", "Treatment B", "Treatment C"),
  Estimate = c(0.2, 0.5, -0.1),
  CI_lower = c(0.1, 0.3, -0.3),
  CI_upper = c(0.3, 0.7, 0.1)
)

# Call the function, gg_plot is a ggplot object
gg_forest <- forest_plot(df, "Estimate", "CI_lower", "CI_upper", "Treatment")
gg_forest

# Retrieve the plot construction code
call_forest <- ggcall(gg_forest)

# Optionally: Style the code with styler
# install.packages("styler")
styler::style_text(paste(deparse(call_forest), collapse = "\n"))

# Optionally: add assignments to call
styler::style_text(paste(deparse(ggcall_add_assignments(call_forest)), collapse = "\n"))

# Optionally: reevaulate the call
eval_ggcall(call_forest)

Why ggcall matters

For developers who build R packages that include functions generating ggplot2 plots, maintaining clarity over how each plot is constructed can be challenging. ggcall addresses this by enabling:

  • Code Tracking: Extends the + operator and the ggplot function to maintain a history of plot construction.
  • Accessible History: Users can effortlessly access a sequence of ggplot2 calls used to build plots, enhancing understanding and teaching opportunities.
  • Reproducibility: Facilitates the easy replication and modification of plots, which is essential for testing and extending visualizations.

Join the ggcall Community

Visit the GitHub repository to download ggcall, view detailed documentation, and start making your ggplot2 visualizations more transparent and reproducible today!

Your feedback and contributions are highly appreciated as they help to refine ggcall to better serve the R community.