Creates an interactive HTML widget that you can rotate by dragging.
Pre-renders a set of ggcube plots across a 1D or 2D grid of rotation angles
and packages them as an htmlwidgets widget. The widget displays in the
RStudio Viewer, embeds in R Markdown and Quarto documents, works in Shiny
(see orbit3dOutput()), and can be written to a self-contained HTML
file with file =. When viewing it, navigate through the views by dragging
the image or using the keyboard arrows.
Usage
orbit_3d(
plot,
pitch = NULL,
roll = NULL,
yaw = NULL,
light_azimuth = NULL,
light_elevation = NULL,
n = 36,
loop = NULL,
start = NULL,
max_frames = 500,
width = 480,
height = 480,
res = 96,
cores = 1,
device = "png",
progress = interactive(),
file = NULL,
readout = FALSE
)Arguments
- plot
A ggplot object that uses
coord_3d().- pitch, roll, yaw
Rotation angles in degrees. Each is either a single value (held fixed) or a length-2 range
c(from, to)that becomes a draggable axis. Foryaw, using a larger value forfromthantogives more natural results. Values specified here replace the ones specified incoord_3d(). See Details.- light_azimuth, light_elevation
Light direction in degrees, using the same conventions as
direction(): azimuth is a bearing clockwise from the positive y axis, and elevation is the angle above the xy plane (between -90 and 90). Each is either a single value (held fixed) or a length-2 rangec(from, to)that becomes a draggable axis. When either is given, the other is held at the plot light's current value unless also given; when both areNULL(the default), lighting is left as the plot specifies. These move the plot-level light set withlight()orcoord_3d(light = ), which must be directional (notposition-based); it is an error to use them when lighting is disabled or when any layer has its ownlight. The light'sanchoris respected: with the defaultanchor = "scene"the light moves around the data, so orbitingyawandlight_azimuthtogether partly cancels out; withanchor = "camera"it moves around the viewer.- n
Grid resolution. For a 1D orbit, a single number giving the frame count. For a 2D orbit, a length-2 vector giving the counts for the horizontal and vertical screen axes respectively (in that order, x then y). Its length must match the number of ranged parameters. Default is 36.
- loop
Controls seamless wraparound.
NULL(default) auto-detects looping independently for each axis by checking whether that axis returns to its starting view.TRUEorFALSEforce wrapping on or off for all axes.- start
Initial viewing angle(s) the orbit opens at, given in degrees as a named vector matching the variable axes, e.g.
start = c(yaw = 30),start = c(yaw = 30, roll = 45), orstart = c(light_azimuth = 90). For a 1D orbit a bare scalar (e.g.start = 30) is also accepted. The orbit opens at the frame nearest each given angle. Any variable axis not named instartopens at the midpoint of its range, as does every axis whenstart = NULL(the default). Naming an axis that is fixed rather than variable throws an error.- max_frames
Safety cap on the total number of rendered frames (
prod(n)). A 2D grid can become very large; if the requested grid exceeds this cap the function errors rather than rendering. Raise it to allow larger grids. Default is 500.- width, height
Dimensions of the animation in pixels. Defaults to 480 x 480.
- res
Resolution in ppi for the rendered frames. Default is 96. Controls the size of point-based text/lines/point elements relative to the plot. See
?grDevices::pngfor details.- cores
Number of CPU cores for parallel frame rendering. Default is 1 (sequential). Values greater than 1 use
parallel::parLapply()to render frames in parallel, which can significantly speed up animation of complex plots. Note that progress reporting is not available during parallel rendering.- device
The graphics device to use for rendering frames. Default is
"png". Other options include"ragg_png"(requires the ragg package).- progress
Whether to print a progress bar. Ignored when
cores > 1.- file
Optional path to write a self-contained HTML file (via
htmlwidgets::saveWidget()). IfNULL(default), no file is written and the widget is simply returned for display or embedding.- readout
Logical. Whether the orbit opens with a readout in its corner showing the angles of the current view, which you can copy into
coord_3d()to reproduce it. The readout always listspitch,roll, andyaw, and adds the light's azimuth and elevation (for use withdirection()) when the orbit moves the light. Angles are shown in the terms you gave them: an orbit overyaw = c(0, 360)reports values from 0 to 360. This sets only how the orbit opens: pressingrwhile the orbit has focus shows or hides the readout either way. Default isFALSE.
Value
A orbit_3d htmlwidget. Printed at the console it opens in the
RStudio Viewer or browser; in a knitr document it embeds automatically;
in Shiny use orbit3dOutput() and renderOrbit3d().
Specifying rotation and lighting
Each of pitch, roll, yaw, light_azimuth, and
light_elevation is given either as a single value (held fixed) or as
a length-2 range c(from, to) that is a variable, draggable axis. The
number of ranges determines the interaction:
One range gives a 1D orbit: horizontal drag (or left/right keyboard arrows) vary that one parameter across its range.
Two ranges give a 2D orbit: horizontal drag (or left/right keyboard arrows) vary one parameter while vertical drag/arrows vary the other.
At least one range is required. Supplying three ranges is an error.
For a 2D orbit, the horizontal (x) and vertical (y) axes are assigned
from whichever parameters are ranged, by priority. The x axis takes the
highest-priority ranged parameter in the order yaw, pitch,
roll, light_azimuth, light_elevation, and the y axis
takes the other. Camera parameters outrank light parameters, so an orbit
that ranges one of each puts the camera on horizontal drag and the light on
vertical drag. In the common case
yaw = c(0, 360), roll = c(...) this puts yaw on horizontal drag and
roll on vertical drag; yaw = c(0, 360), light_elevation = c(...)
spins the camera horizontally and raises the light vertically; and
light_azimuth = c(0, 360), light_elevation = c(...) moves only the
light, with azimuth horizontal and elevation vertical.
The range direction follows the order the values are written: for example
yaw = c(360, 0) rotates the opposite way from yaw = c(0, 360).
Looping
When a variable axis returns to its starting view (for example a full
yaw = c(0, 360) turn), that axis loops seamlessly: dragging past
either end wraps around. This is detected per axis by comparing the first
and last angle modulo 360, so a full-turn axis wraps while a partial range
(such as roll = c(-90, 90)) clamps. loop can force this on or
off for all axes at once.
Keyboard
Once the widget has focus, the arrow keys step one frame: left/right move
the horizontal axis, and (in a 2D orbit) up/down move the vertical axis.
The r key shows or hides the angle readout (see readout).
See also
animate_3d() for GIF/MP4 output.
facet_wrap_views() and facet_grid_views() for a static figure showing
several views side by side.
orbit_3d-shiny for including orbits in Shiny apps.
Examples
# \donttest{
p <- ggplot(mountain, aes(x, y, z, fill = z, color = z)) +
geom_surface_3d(linewidth = .25) +
coord_3d(light = light(anchor = "camera",direction = c(1, 1, 0)),
ratio = c(1.5, 2, 1)) +
scale_fill_viridis_c() + scale_color_viridis_c() +
theme_void()
# 1D drag-to-rotate turntable (small n to minimize runtime)
orbit_3d(p, yaw = c(360, 0), n = 12)
#> Rendering 12 frames...
#> Assembling orbit (press `r` on the orbit to toggle its angle readout)...
# 2D orbit: drag horizontally to spin (yaw), vertically to tilt (roll)
# (note you could increase `cores` to speed up compute time)
orbit_3d(p, yaw = c(360, 0), roll = c(-90, 0), n = c(20, 10),
width = 1000, height = 1000, cores = 1)
#> Rendering 200 frames...
#> Assembling orbit (press `r` on the orbit to toggle its angle readout)...
