This function sets user callbacks to construct axes in R or rglwidget displays.

setAxisCallbacks(axes, fns, 
                 javascript = NULL, 
                 subscene = scene$rootSubscene$id, 
                 scene = scene3d(minimal = FALSE), 
                 applyToScene = TRUE, 
                 applyToDev = missing(scene))



Which axes? Specify as number in 1:3 or letter in c("x", "y", "z").


Function or list of functions or character vector giving names of functions.


Optional block of Javascript code to be included (at the global level).


Which subscene do these callbacks apply to?


Which scene?


Should these changes apply to the scene object?


Should these changes apply to the current device?


If applyToScene is TRUE, this function adds Javascript callbacks to the scene object. If applyToDev is TRUE, it adds R callbacks to the current RGL device.

For Javascript, the callbacks are specified as strings; these will be evaluated within the browser in the global context to define the functions, which will then be called with the Javascript this object set to the current rglwidgetClass object.

For R, they may be strings or R functions.

Both options may be TRUE, in which case the callbacks must be specified as strings which are both valid Javascript and valid R. The usual way to do this is to give just a function name, with the function defined elsewhere, as in the Example below.

The functions should have a header of the form function(margin). The margin argument will be a string like "x++" indicating which margin would be chosen by R. If RGL would not choose to draw any axis annotations (which happens with rglwidget, though not currently in R itself), only the letter will be passed, e.g. "x".


Invisibly returns an rglScene object. This object will record the changes if applyToScene

is TRUE.

If applyToDev is TRUE, it will also have the side effect of attempting to install the callbacks.

See also

setUserCallbacks for mouse callbacks.


Duncan Murdoch


# Draw arrows instead of tick marks on axes

arrowAxis <- local({
  ids <- c(NA, NA, NA)
  bbox <- c(NA, NA, NA, NA, NA, NA)
  function(margin) {
    dim <- if (grepl("x", margin)) 1 else
           if (grepl("y", margin)) 2 else
    inds <- 2*dim + (-1):0
    range <- par3d("bbox")[inds]
    if (!identical(bbox[inds], range)) {
      if (![dim]))
        pop3d(id = ids[dim])
      bbox[inds] <<- range 
      center <- mean(range)
      from <- mean(c(range[1], center))
      to <- mean(c(center, range[2]))
      # margin should agree with suggestion, so use "x++" etc.
      margin <- gsub("-", "+", margin)
      ids[dim] <- arrow3d(p0 = c(from, 1, 1), 
                         p1 = c(to, 1, 1),
                         n = 4,
                         type = "lines",
                         margin = margin,
                         floating = TRUE)

# Define the Javascript function with the same name to use in WebGL
# Since Javascript won't change the bounding box, this function
# doesn't need to do anything.
js <- "
window.arrowAxis = function(margin) {} ;

xyz <- matrix(rnorm(60), ncol = 3)
plot3d(xyz, xlab = "x", ylab = "y", zlab = "z")

setAxisCallbacks(1:3, "arrowAxis", javascript = js) rglwidget()