Turns 3D point clouds into surface hulls consisting of triangular polygons, using either convex hull or alpha shape algorithms.
Usage
geom_hull_3d(
mapping = NULL,
data = NULL,
stat = StatHull3D,
position = "identity",
...,
method = "convex",
radius = NULL,
singular = FALSE,
light = NULL,
cull_backfaces = TRUE,
sort_method = NULL,
scale_depth = TRUE,
inherit.aes = TRUE,
show.legend = TRUE
)
stat_hull_3d(
mapping = NULL,
data = NULL,
geom = GeomPolygon3D,
position = "identity",
...,
method = "convex",
radius = NULL,
singular = FALSE,
light = NULL,
cull_backfaces = TRUE,
sort_method = NULL,
scale_depth = TRUE,
inherit.aes = TRUE,
show.legend = TRUE
)Arguments
- mapping
Set of aesthetic mappings created by
aes(). The required aesthetics arex,y, andz. Additional aesthetics can use computed variables withggplot2::after_stat().- data
The data to be displayed in this layer.
- stat
The statistical transformation to use on the data. Defaults to
StatHull3D.- position
Position adjustment, defaults to "identity". To collapse the result onto one 2D surface, use
position_on_face().- ...
Other arguments passed on to the layer function (typically GeomPolygon3D), such as aesthetics like
colour,fill,linewidth,annotate = annotate_3d(...), etc.- method
Triangulation method. Either:
"convex": Convex hull triangulation (default). Requires the geometry package."alpha": Alpha shape triangulation (can capture non-convex topologies)
- radius
The "alpha" parameter when alpha method is used. A face is included in the resulting alpha shape if it can be "exposed" by a sphere of this radius. If NULL (the default), a simple heuristic based on the data scale is used to calculate a radius value. Note that alpha shapes are quite sensitive to the coordinate scales of your data. See Details section.
- singular
Whether to include "singular" faces when
method = "alpha". These are faces that do not bound any enclosed volume, appearing as isolated sheets dangling from the surface, and are usually a sign thatradiusis slightly too small. Because they enclose nothing, they have no well-defined outward direction: their lighting is arbitrary and they are never culled. Defaults toFALSE.- light
A lighting specification object created by
light(),light("none")or the string"none"to disable lighting, orNULLto inherit plot-level lighting. Set plot-level lighting by addinglight()to the plot, and layer-specific lighting via thelightargument ofgeom_*_3d()functions, which takes precedence.- cull_backfaces
Logical indicating whether to remove back-facing polygons from rendering. This is primarily for performance optimization but may be useful for aesthetic reasons in some situations. Backfaces are determined using screen-space winding order after 3D transformation. Defaults vary by geometry type: FALSE for open surface-type geometries, TRUE for solid objects (hulls, voxels, etc. where backfaces are generally hidden unless frontfaces are transparent or explicitly disabled).
- sort_method
Depth sorting algorithm. See sorting_methods for details.
- scale_depth
Logical indicating whether polygon linewidths should be scaled to make closer lines wider and farther lines narrower. Default is TRUE. Scaling is based on the mean depth of a polygon.
- inherit.aes
If
FALSE, overrides the default aesthetics.- show.legend
Logical indicating whether this layer should be included in legends.
- geom
The geometric object used to display the data. Defaults to
GeomPolygon3D.
Grouping
Hulls respect ggplot2 grouping aesthetics. To create separate hulls for different
subsets of your data, use aes(group = category_variable) or similar grouping aesthetics.
Each group will get its own independent hull.
Alpha scale sensitivity
Alpha shape method is highly sensitive to coordinate scales. radius is expressed
in data units, so a value that works for data scaled 0-1 will likely fail for data
scaled 0-1000.
Guidelines for choosing radius:
Start at a small fraction of your data's overall extent and adjust based on results
For data with mixed scales (e.g., x: 0-1, y: 0-1000), consider rescaling your data first
Larger radius values → smoother, more connected surfaces
Smaller radius values → more detailed surfaces, but may fragment
If you get no triangles, try increasing radius by 10x
If surface fills unwanted holes, try decreasing radius by 10x
Aesthetics
stat_hull_3d() requires the following aesthetics:
x: X coordinate
y: Y coordinate
z: Z coordinate
See also
coord_3d() for 3D coordinate systems, geom_polygon_3d for the
default geometry with depth sorting, light() for lighting specifications.
Examples
# A solid torus: a shape whose hole a convex hull cannot represent
set.seed(1)
n <- 2000
theta <- runif(n, 0, 2 * pi) # position around the ring
phi <- runif(n, 0, 2 * pi) # position around the tube
rho <- sqrt(runif(n)) # distance from the tube center
torus <- data.frame(
x = (3 + rho * cos(phi)) * cos(theta),
y = (3 + rho * cos(phi)) * sin(theta),
z = rho * sin(phi)
)
# Convex hull: the hole is bridged over
ggplot(torus, aes(x, y, z)) +
geom_hull_3d(method = "convex", fill = "gray40") +
coord_3d(scales = "fixed")
# Alpha shape: the hole is preserved
# \donttest{
ggplot(torus, aes(x, y, z)) +
geom_hull_3d(method = "alpha", radius = 0.6, fill = "gray40") +
coord_3d(scales = "fixed")
#> Warning: RGL: unable to open X11 display
#> Warning: 'rgl.init' failed, will use the null device.
#> See '?rgl.useNULL' for ways to avoid this warning.
# }
# Use `cull_backfaces = FALSE` to render far side of hull
# \donttest{
ggplot(torus, aes(x, y, z)) +
geom_hull_3d( # default culling for comparison
method = "alpha", radius = 0.6, light = NULL,
fill = "steelblue", color = "darkred", linewidth = .5, alpha = .5) +
geom_hull_3d( # culling disabled
aes(x = x + 9), cull_backfaces = FALSE,
method = "alpha", radius = 0.6, light = NULL,
fill = "steelblue", color = "darkred", linewidth = .5, alpha = .5) +
coord_3d(scales = "fixed")
# }
# Use grouping to build separate hulls for data subsets
ggplot(iris, aes(Petal.Length, Sepal.Length, Sepal.Width,
color = Species, fill = Species)) +
geom_hull_3d() +
coord_3d(scales = "fixed")
