diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml
index 9fd3500247..bb0bf3c0f6 100644
--- a/.github/workflows/R-CMD-check.yaml
+++ b/.github/workflows/R-CMD-check.yaml
@@ -78,7 +78,7 @@ jobs:
if: runner.os == 'macOS'
run: |
# XQuartz is needed by vdiffr
- brew cask install xquartz
+ brew install xquartz
# Use only binary packages
echo 'options(pkgType = "binary")' >> ~/.Rprofile
diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml
index c1a0c04cb5..3ba34d271c 100644
--- a/.github/workflows/test-coverage.yaml
+++ b/.github/workflows/test-coverage.yaml
@@ -41,7 +41,7 @@ jobs:
- name: Install system dependencies on macOS
run: |
# XQuartz is needed by vdiffr
- brew cask install xquartz
+ brew install xquartz
- name: Install dependencies
run: |
diff --git a/DESCRIPTION b/DESCRIPTION
index f8eb4760de..cc79750ea0 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -46,6 +46,7 @@ Suggests:
ggplot2movies,
hexbin,
Hmisc,
+ interp,
knitr,
lattice,
mapproj,
diff --git a/R/geom-contour.r b/R/geom-contour.r
index 17ac1c1733..cc25a70da4 100644
--- a/R/geom-contour.r
+++ b/R/geom-contour.r
@@ -1,12 +1,16 @@
#' 2D contours of a 3D surface
#'
#' ggplot2 can not draw true 3D surfaces, but you can use `geom_contour()`,
-#' `geom_contour_filled()`, and [geom_tile()] to visualise 3D surfaces in 2D.
-#' To specify a valid surface, the data must contain `x`, `y`, and `z` coordinates,
-#' and each unique combination of `x` and `y` can appear exactly once. Contouring
-#' tends to work best when `x` and `y` form a (roughly) evenly
-#' spaced grid. If your data is not evenly spaced, you may want to interpolate
-#' to a grid before visualising, see [geom_density_2d()].
+#' `geom_contour_filled()`, and [geom_tile()] to visualise 3D surfaces in 2D. To
+#' specify a valid surface, the data must contain `x`, `y`, and `z` coordinates,
+#' and each unique combination of `x` and `y` can appear at most once.
+#' Contouring requires that the points can be rearranged so that the `z` values
+#' form a matrix, with rows corresponding to unique `x` values, and columns
+#' corresponding to unique `y` values. Missing entries are allowed, but contouring
+#' will only be done on cells of the grid with all four `z` values present. If
+#' your data is irregular, you can interpolate to a grid before visualising
+#' using the [interp::interp()] function from the `interp` package
+#' (or one of the interpolating functions from the `akima` package.)
#'
#' @eval rd_aesthetics("geom", "contour")
#' @eval rd_aesthetics("geom", "contour_filled")
@@ -15,9 +19,9 @@
#' @inheritParams geom_path
#' @param bins Number of contour bins. Overridden by `binwidth`.
#' @param binwidth The width of the contour bins. Overridden by `breaks`.
-#' @param breaks Numeric vector to set the contour breaks.
-#' Overrides `binwidth` and `bins`. By default, this is a vector of
-#' length ten with [pretty()] breaks.
+#' @param breaks Numeric vector to set the contour breaks. Overrides `binwidth`
+#' and `bins`. By default, this is a vector of length ten with [pretty()]
+#' breaks.
#' @seealso [geom_density_2d()]: 2d density contours
#' @export
#' @examples
@@ -47,6 +51,22 @@
#' v + geom_contour(colour = "red")
#' v + geom_raster(aes(fill = density)) +
#' geom_contour(colour = "white")
+#'
+#' # Irregular data
+#' if (requireNamespace("interp")) {
+#' # Use a dataset from the interp package
+#' data(franke, package = "interp")
+#' origdata <- as.data.frame(interp::franke.data(1, 1, franke))
+#' grid <- with(origdata, interp::interp(x, y, z))
+#' griddf <- subset(data.frame(x = rep(grid$x, nrow(grid$z)),
+#' y = rep(grid$y, each = ncol(grid$z)),
+#' z = as.numeric(grid$z)),
+#' !is.na(z))
+#' ggplot(griddf, aes(x, y, z = z)) +
+#' geom_contour_filled() +
+#' geom_point(data = origdata)
+#' } else
+#' message("Irregular data requires the 'interp' package")
#' }
geom_contour <- function(mapping = NULL, data = NULL,
stat = "contour", position = "identity",
diff --git a/R/position-jitterdodge.R b/R/position-jitterdodge.R
index 0e078e6cf9..abb5dd8ace 100644
--- a/R/position-jitterdodge.R
+++ b/R/position-jitterdodge.R
@@ -13,7 +13,7 @@
#' @inheritParams position_jitter
#' @export
#' @examples
-#' dsub <- diamonds[ sample(nrow(diamonds), 1000), ]
+#' dsub <- diamonds[sample(nrow(diamonds), 1000), ]
#' ggplot(dsub, aes(x = cut, y = carat, fill = clarity)) +
#' geom_boxplot(outlier.size = 0) +
#' geom_point(pch = 21, position = position_jitterdodge())
diff --git a/man/geom_contour.Rd b/man/geom_contour.Rd
index e3b0ee8f03..1277d9b84b 100644
--- a/man/geom_contour.Rd
+++ b/man/geom_contour.Rd
@@ -102,9 +102,9 @@ to the paired geom/stat.}
\item{binwidth}{The width of the contour bins. Overridden by \code{breaks}.}
-\item{breaks}{Numeric vector to set the contour breaks.
-Overrides \code{binwidth} and \code{bins}. By default, this is a vector of
-length ten with \code{\link[=pretty]{pretty()}} breaks.}
+\item{breaks}{Numeric vector to set the contour breaks. Overrides \code{binwidth}
+and \code{bins}. By default, this is a vector of length ten with \code{\link[=pretty]{pretty()}}
+breaks.}
\item{lineend}{Line end style (round, butt, square).}
@@ -130,12 +130,16 @@ the default plot specification, e.g. \code{\link[=borders]{borders()}}.}
}
\description{
ggplot2 can not draw true 3D surfaces, but you can use \code{geom_contour()},
-\code{geom_contour_filled()}, and \code{\link[=geom_tile]{geom_tile()}} to visualise 3D surfaces in 2D.
-To specify a valid surface, the data must contain \code{x}, \code{y}, and \code{z} coordinates,
-and each unique combination of \code{x} and \code{y} can appear exactly once. Contouring
-tends to work best when \code{x} and \code{y} form a (roughly) evenly
-spaced grid. If your data is not evenly spaced, you may want to interpolate
-to a grid before visualising, see \code{\link[=geom_density_2d]{geom_density_2d()}}.
+\code{geom_contour_filled()}, and \code{\link[=geom_tile]{geom_tile()}} to visualise 3D surfaces in 2D. To
+specify a valid surface, the data must contain \code{x}, \code{y}, and \code{z} coordinates,
+and each unique combination of \code{x} and \code{y} can appear at most once.
+Contouring requires that the points can be rearranged so that the \code{z} values
+form a matrix, with rows corresponding to unique \code{x} values, and columns
+corresponding to unique \code{y} values. Missing entries are allowed, but contouring
+will only be done on cells of the grid with all four \code{z} values present. If
+your data is irregular, you can interpolate to a grid before visualising
+using the \code{\link[interp:interp]{interp::interp()}} function from the \code{interp} package
+(or one of the interpolating functions from the \code{akima} package.)
}
\section{Aesthetics}{
@@ -236,6 +240,22 @@ v + geom_contour(aes(colour = after_stat(level)))
v + geom_contour(colour = "red")
v + geom_raster(aes(fill = density)) +
geom_contour(colour = "white")
+
+# Irregular data
+if (requireNamespace("interp")) {
+ # Use a dataset from the interp package
+ data(franke, package = "interp")
+ origdata <- as.data.frame(interp::franke.data(1, 1, franke))
+ grid <- with(origdata, interp::interp(x, y, z))
+ griddf <- subset(data.frame(x = rep(grid$x, nrow(grid$z)),
+ y = rep(grid$y, each = ncol(grid$z)),
+ z = as.numeric(grid$z)),
+ !is.na(z))
+ ggplot(griddf, aes(x, y, z = z)) +
+ geom_contour_filled() +
+ geom_point(data = origdata)
+} else
+ message("Irregular data requires the 'interp' package")
}
}
\seealso{
diff --git a/man/geom_density_2d.Rd b/man/geom_density_2d.Rd
index c9c0ea7511..c0daf09211 100644
--- a/man/geom_density_2d.Rd
+++ b/man/geom_density_2d.Rd
@@ -99,9 +99,9 @@ a call to a position adjustment function.}
\describe{
\item{\code{bins}}{Number of contour bins. Overridden by \code{binwidth}.}
\item{\code{binwidth}}{The width of the contour bins. Overridden by \code{breaks}.}
- \item{\code{breaks}}{Numeric vector to set the contour breaks.
-Overrides \code{binwidth} and \code{bins}. By default, this is a vector of
-length ten with \code{\link[=pretty]{pretty()}} breaks.}
+ \item{\code{breaks}}{Numeric vector to set the contour breaks. Overrides \code{binwidth}
+and \code{bins}. By default, this is a vector of length ten with \code{\link[=pretty]{pretty()}}
+breaks.}
}}
\item{contour_var}{Character string identifying the variable to contour
diff --git a/man/position_jitterdodge.Rd b/man/position_jitterdodge.Rd
index 5e31830ae8..49d0ad55d0 100644
--- a/man/position_jitterdodge.Rd
+++ b/man/position_jitterdodge.Rd
@@ -35,7 +35,7 @@ This is primarily used for aligning points generated through
a fill aesthetic supplied).
}
\examples{
-dsub <- diamonds[ sample(nrow(diamonds), 1000), ]
+dsub <- diamonds[sample(nrow(diamonds), 1000), ]
ggplot(dsub, aes(x = cut, y = carat, fill = clarity)) +
geom_boxplot(outlier.size = 0) +
geom_point(pch = 21, position = position_jitterdodge())
diff --git a/tests/figs/coord-sf/sf-polygons.svg b/tests/figs/coord-sf/sf-polygons.svg
index a3b1b6928c..62c30c94df 100644
--- a/tests/figs/coord-sf/sf-polygons.svg
+++ b/tests/figs/coord-sf/sf-polygons.svg
@@ -39,25 +39,25 @@
36.25
°
N
-36.3
+36.30
°
N
36.35
°
N
-36.4
+36.40
°
N
36.45
°
N
-36.5
+36.50
°
N
36.55
°
N
-36.6
+36.60
°
N
diff --git a/tests/figs/deps.txt b/tests/figs/deps.txt
index 0f64e23e67..8d7f66b6a1 100644
--- a/tests/figs/deps.txt
+++ b/tests/figs/deps.txt
@@ -1,3 +1,3 @@
- vdiffr-svg-engine: 1.0
-- vdiffr: 0.3.1
+- vdiffr: 0.3.3
- freetypeharfbuzz: 0.2.5
diff --git a/tests/figs/geom-sf/north-carolina-county-boundaries.svg b/tests/figs/geom-sf/north-carolina-county-boundaries.svg
index 805823d951..429a3d8696 100644
--- a/tests/figs/geom-sf/north-carolina-county-boundaries.svg
+++ b/tests/figs/geom-sf/north-carolina-county-boundaries.svg
@@ -39,25 +39,25 @@
36.25
°
N
-36.3
+36.30
°
N
36.35
°
N
-36.4
+36.40
°
N
36.45
°
N
-36.5
+36.50
°
N
36.55
°
N
-36.6
+36.60
°
N