% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/stat-distributions-3d.R
\name{stat_distributions_3d}
\alias{stat_distributions_3d}
\alias{geom_distributions_3d}
\title{3D ridgeline distributions}
\usage{
stat_distributions_3d(
  mapping = NULL,
  data = NULL,
  geom = "ridgeline_3d",
  position = "identity",
  ...,
  direction = NULL,
  bw = "nrd0",
  adjust = 1,
  kernel = "gaussian",
  n = 512,
  trim = FALSE,
  bounds = c(-Inf, Inf),
  rel_min_height = 0,
  joint_bandwidth = FALSE,
  base = 0,
  light = NULL,
  cull_backfaces = FALSE,
  sort_method = NULL,
  scale_depth = TRUE,
  force_convex = FALSE,
  na.rm = FALSE,
  show.legend = NA,
  inherit.aes = TRUE
)

geom_distributions_3d(
  mapping = NULL,
  data = NULL,
  stat = "distributions_3d",
  position = "identity",
  ...,
  direction = NULL,
  bw = "nrd0",
  adjust = 1,
  kernel = "gaussian",
  n = 512,
  trim = FALSE,
  bounds = c(-Inf, Inf),
  rel_min_height = 0,
  joint_bandwidth = FALSE,
  base = 0,
  light = NULL,
  cull_backfaces = FALSE,
  sort_method = NULL,
  scale_depth = TRUE,
  force_convex = FALSE,
  na.rm = FALSE,
  show.legend = NA,
  inherit.aes = TRUE
)
}
\arguments{
\item{mapping}{Set of aesthetic mappings created by \code{\link[=aes]{aes()}}. This stat
requires \code{x} and \code{y} aesthetics. One of these serves as the grouping/position
variable (determined by \code{direction}), and the other provides values for
density estimation.}

\item{data}{The data to be displayed in this layer.}

\item{geom}{The geometric object to use to display the data. Defaults to
\code{\link[=geom_ridgeline_3d]{geom_ridgeline_3d()}}.}

\item{position}{Position adjustment, defaults to "identity". To collapse the result
onto one 2D surface, use \code{position_on_face()}.}

\item{...}{Other arguments passed to the layer.}

\item{direction}{Direction of ridges:
\describe{
\item{"x"}{One ridge per unique x value; ridge varies in y (default)}
\item{"y"}{One ridge per unique y value; ridge varies in x}
}}

\item{bw}{The smoothing bandwidth to be used. If numeric, the standard
deviation of the smoothing kernel. If character, a rule to choose the
bandwidth, as listed in \code{\link[stats:bandwidth]{stats::bw.nrd()}}. Options include \code{"nrd0"} (default),
\code{"nrd"}, \code{"ucv"}, \code{"bcv"}, \code{"SJ"}, \code{"SJ-ste"}, and \code{"SJ-dpi"}. Note that

automatic calculation is performed per-group unless \code{joint_bandwidth = TRUE}.}

\item{adjust}{A multiplicative bandwidth adjustment. This makes it possible
to adjust the bandwidth while still using a bandwidth estimator. For
example, \code{adjust = 1/2} means use half of the default bandwidth. Default is 1.}

\item{kernel}{Kernel function to use. One of \code{"gaussian"} (default),
\code{"rectangular"}, \code{"triangular"}, \code{"epanechnikov"}, \code{"biweight"}, \code{"cosine"},
or \code{"optcosine"}. See \code{\link[stats:density]{stats::density()}} for details.}

\item{n}{Number of equally spaced points at which the density is estimated.
Should be a power of two for efficiency. Default is 512.}

\item{trim}{If \code{FALSE} (the default), each density is computed on the full
range of the data (extended by a factor based on bandwidth). If \code{TRUE},
each density is computed over the range of that group only.}

\item{bounds}{A numeric vector of length 2 giving the lower and upper bounds
for bounded density estimation. Density values outside bounds are set to
zero. Data points outside bounds are removed with a warning.
Default is \code{c(-Inf, Inf)} (unbounded).}

\item{rel_min_height}{Lines with heights below this cutoff will be removed.
The cutoff is measured relative to the maximum height within each group.
For example, \code{rel_min_height = 0.01} removes points with density less than
1\% of the peak. Default is 0 (no removal). This is similar to the
parameter of the same name in \code{ggridges::geom_density_ridges()}.}

\item{joint_bandwidth}{If \code{TRUE}, bandwidth is computed jointly across all
groups using the specified \code{bw} method, ensuring consistent smoothing
across all density curves. This matches the behavior of
\code{\link[ggridges:stat_density_ridges]{ggridges::stat_density_ridges()}}. If \code{FALSE} (the default), bandwidth is
computed separately for each group, matching \code{\link[ggplot2:geom_density]{ggplot2::stat_density()}}.
Only applies when \code{bw} is a character string (bandwidth rule), not when
\code{bw} is provided as a numeric value.}

\item{base}{Z-value for ridge polygon bottoms. If NULL, uses min(z).}

\item{light}{A lighting specification object created by \code{\link[=light]{light()}},\code{"none"} to disable
lighting, or \code{NULL} to inherit plot-level lighting specs from the coord. Specify
plot-level lighting in \code{coord_3d()} and layer-specific lighting in \verb{geom_*3d()}
functions.}

\item{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).}

\item{sort_method}{Depth sorting algorithm. See \link{sorting_methods} for details.}

\item{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.}

\item{force_convex}{Logical indicating whether to remove polygon vertices that are not part of the
convex hull. Default value varies by geom. Specifying TRUE can help reduce artifacts in surfaces
that have polygon tiles that wrap over a visible horizon. For prism-type geoms like columns and
voxels, FALSE is safe because polygons fill always be convex.}

\item{na.rm}{If \code{FALSE}, missing values are removed.}

\item{show.legend}{Logical indicating whether this layer should be included in legends.}

\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics.}

\item{stat}{Statistical transformation to use on the data. Defaults to
\code{\link[=stat_distributions_3d]{stat_distributions_3d()}}.}
}
\value{
A \code{Layer} object that can be added to a ggplot.
}
\description{
Computes 1D kernel density estimates for each group and arranges them as
ridgeline polygons in 3D space. Similar to \code{ggridges::geom_density_ridges()},
but rendered as 3D surfaces using \code{\link[=geom_ridgeline_3d]{geom_ridgeline_3d()}}.
}
\details{
This stat is modeled after \code{\link[ggplot2:geom_density]{ggplot2::stat_density()}}, with similar
parametrization for bandwidth selection, kernel choice, and boundary handling.
}
\section{Aesthetics}{

\code{stat_distributions_3d()} understands the following aesthetics (required
aesthetics are in bold):
\describe{
\item{\strong{x}}{X coordinate - either density variable or position variable
depending on \code{direction}}
\item{\strong{y}}{Y coordinate - either position variable or density variable
depending on \code{direction}}
\item{group}{Grouping variable (typically derived from the position aesthetic)}
\item{fill, colour, alpha, linewidth, linetype}{Passed to \code{\link[=geom_ridgeline_3d]{geom_ridgeline_3d()}}}
}
}

\section{Direction}{

The \code{direction} parameter determines how the data is interpreted:
\describe{
\item{\code{direction = NULL} (default)}{Automatically detects direction based
on whether \code{x} or \code{y} is discrete (factor/character). If \code{x} is discrete
and \code{y} is continuous, uses \code{"x"}; if \code{y} is discrete and \code{x} is
continuous, uses \code{"y"}. Falls back to \code{"x"} if ambiguous.}
\item{\code{direction = "x"}}{Ridges march along the x-axis. Each unique
x value defines a group, and density is computed from the y values within
that group. The resulting density curves lie in the y-z plane.}
\item{\code{direction = "y"}}{Ridges march along the y-axis. Each unique y value
defines a group, and density is computed from the x values. The resulting
density curves lie in the x-z plane.}
}
}

\section{Computed variables}{

The following variables are computed and available via \code{after_stat()}:
\describe{
\item{density}{The kernel density estimate at each point}
\item{ndensity}{Density normalized to a maximum of 1 within each group}
\item{count}{Density multiplied by number of observations (expected count)}
\item{n}{Number of observations in the group}
\item{bw}{Bandwidth actually used for this group}
}
}

\examples{
library(ggplot2)

# Basic usage with iris data
p <- ggplot(iris, aes(y = Sepal.Length, x = Species, fill = Species)) +
  coord_3d() +
  scale_z_continuous(expand = expansion(mult = c(0, NA))) + # remove gap beneath ridges
  theme(legend.position = "none")
p + stat_distributions_3d()

# Normalize max ridge heights
p + stat_distributions_3d(aes(z = after_stat(ndensity)))

# Adjust smoothing bandwidth
p + stat_distributions_3d(adjust = 0.5)

# Use joint bandwidth for consistent smoothing across groups
p + stat_distributions_3d(joint_bandwidth = TRUE)

# Different bandwidth selection rules
p + stat_distributions_3d(bw = "SJ")

# Remove tails with rel_min_height
p + stat_distributions_3d(rel_min_height = 0.05)

# Trim to data range
p + stat_distributions_3d(trim = TRUE)

# Rotated to reduce perspective distortion
p + stat_distributions_3d(alpha = .7) +
   coord_3d(pitch = 0, roll = -90, yaw = 90, dist = 5,
      panels = c("zmin", "xmin"))

}
\seealso{
\code{\link[=geom_ridgeline_3d]{geom_ridgeline_3d()}} for rendering pre-computed ridgeline data,
\code{\link[=stat_density_3d]{stat_density_3d()}} for 2D kernel density surfaces,
\code{\link[ggplot2:geom_density]{ggplot2::stat_density()}} for the parametrization this stat follows,
\code{ggridges::geom_density_ridges()} for the 2D ridgeline equivalent.
}
