Search code examples
rrgl

mfrow3d with contour3d erases previous plots


I'm having trouble displaying multiple 3d plots with rgl's mfrow3d and misc3d's contour3d. In particular, plotting a new subplot will result in all previous subplots being deleted. Here is a simple example:

library(rgl)
library(misc3d)

# setup rgl subplots
mfrow3d(1,2)

# step into first subplot
next3d()

# Draw a ball
f <- function(x, y, z)x^2+y^2+z^2
x <- seq(-2,2,len=20)
contour3d(f,4,x,x,x)

# advance to next subplot
next3d()

# Ball with one corner removed.
contour3d(f,4,x,x,x, 
      mask = function(x,y,z) x > 0 | y > 0 | z > 0, 
      screen = list(x = 290, y = -20),
      color = "red", color2 = "white")
# the first subplot is removed

In the first call to contour3d, the first ball draws fine on the left. However, after the second call to contour3d, the second plot is drawn on the right, but the first plot is deleted.

enter image description here

What am I missing here? My hunch is that I'm missing an argument to contour3d, as mfrow3d works fine with other *3d plotting functions, but not with with contour3d.


Solution

  • Like base graphics, rgl graphics come in two types: low level (things like drawing points, lines, etc.) and high level (like plot3d or persp3d). By default high level plots first advance to the next frame (by calling next3d()), while low level plots add to the current one.

    The misc3d::contour3d function draws everything using low-level commands, but it assumes it has control of the full window, so instead of calling next3d() to advance to the next frame, it calls clear3d() which clears the whole window.

    To work around this, you can call next3d() yourself (only after the first plot, you don't need it before the first one), and then tell contour3d() to add to the scene. That is, change your code like this:

    library(rgl)
    library(misc3d)
    
    # setup rgl subplots
    mfrow3d(1,2)
    
    # Draw a ball
    f <- function(x, y, z)x^2+y^2+z^2
    x <- seq(-2,2,len=20)
    contour3d(f,4,x,x,x)
    
    # advance to next subplot
    next3d()
    
    # Ball with one corner removed.
    contour3d(f,4,x,x,x, 
              mask = function(x,y,z) x > 0 | y > 0 | z > 0, 
              screen = list(x = 290, y = -20),
              color = "red", color2 = "white", add = TRUE)