16

I find it challenging to create aesthetically pleasing 3D surfaces in R. I am familiar with the solutions (persp, image, wireframe, lattice, rgl and several other solutions in other questions in SO), but the results are not nice.

Is it possible to create 3D surface plots in R like in MATLAB?

enter image description here

Here is the MATLAB code
    % Create a grid of x and y points
    points = linspace(-2, 0, 20);
    [X, Y] = meshgrid(points, -points);

    % Define the function Z = f(X,Y)
    Z = 2./exp((X-.5).^2+Y.^2)-2./exp((X+.5).^2+Y.^2);

    % "phong" lighting is good for curved, interpolated surfaces. "gouraud"
    % is also good for curved surfaces
    surf(X, Y, Z); view(30, 30);
    shading interp;
    light;
    lighting phong;
    title('lighting phong', 'FontName', 'Courier', 'FontSize', 14);

The plot is modern, colorful, aesthetically pleasing, the code syntax is very readable.

Is this possible in base R?

ECII
  • 10,297
  • 18
  • 80
  • 121
  • Perhaps this thread might help http://stackoverflow.com/questions/16130025/attractive-3d-plot-in-r/16131403#16131403 – Pork Chop Dec 12 '13 at 17:06
  • 6
    They are challenging because most data science people think 3D graphics far from being "modern, colourful, etc" are a useless gimmick that should have stayed in the 90s ;) Seriously though Tufte is v influential and I'm sure he would tell you the above is a waste of ink(pixels) as it would better be a flat coloured image - and you would get a truer sense of the data that way. – Stephen Henderson Dec 12 '13 at 17:13
  • 2
    I would upvote this question if you took out the complaining/opinionated part ("Why are nice 3D surface plots so challenging to do in base R?"). `library(emdbook); library(rgl)` is useful; `curve3d(2/exp((-.5)^2+y^2)-2/exp((x+.5)^2+y^2),sys3d="rgl", xlim=c(0,2),ylim=c(-2,0))` is a start, although it doesn't do the colours. (Is there a specific reason you need the solution to be in base R?). If you are "familiar with the solutions", why don't you show a starting point and tell us what is not "nice" ... ? – Ben Bolker Dec 12 '13 at 17:19
  • http://stackoverflow.com/questions/3786189/r-4d-plot-x-y-z-colours – Ben Bolker Dec 12 '13 at 17:21
  • @BenBolker This is exactly the point. There are several "attempts" (incl. emdbook, rlg) but not a real straightforward solution. Base R is a fantastic plotting tool. But when you step in the 3D area you get solutions reminding graphics of the 70's. It seems like there is no interest in aesthetically pleasing modern 3D plots in base R, and any attempts requires extra packages. Its a pity that I have to learn and use other programs just to get nice 3D plots. – ECII Dec 12 '13 at 17:24
  • @BenBolker Ben, you ask: "(Is there a specific reason you need the solution to be in base R?)". I ask myself, why shouldn't this functionality be present in base R? Why the need for additional and sometimes cumbersome packages? Check how simple the code of MATLAB is and a nice modern graph it results to. I really can't understand why is this functionality not present in base R. Maybe its just my frustration._ – ECII Dec 12 '13 at 17:33
  • But **my** point is that StackOverflow is not the right venue for the conversation. I actually agree with you that there's no single convenient solution -- I am well aware of the limitations of the various solutions (`persp()`, `lattice`, `rgl`, `scatterplot3d`) – Ben Bolker Dec 12 '13 at 17:34
  • 1
    Again, I agree that it's too bad that there's not a **package** that provides a beautiful, convenient, all-in-one solution. But I don't see why it's any problem at all that it's not in base R. (Doesn't MATLAB provide lots of functionality via add-ons too?) – Ben Bolker Dec 12 '13 at 17:35
  • 1
    It would be more productive if you gave an example and specified what "wasn't nice" about it. Then people could try to answer with improved solutions. – Ben Bolker Dec 12 '13 at 17:36
  • I removed the opinionated part of my question as per request. I hope this question stays open. The answers are very good and helpful. – ECII Dec 13 '13 at 15:15

2 Answers2

21

jet.colors is the R-answer to one of hte Matlab color palettes:

points = seq(-2, 0, length=20)
#create a grid
XY = expand.grid(X=points,Y=-points)
# A z-function 
Zf <- function(X,Y){
     2./exp((X-.5)^2+Y^2)-2./exp((X+.5)^2+Y^2);
     }
# populate a surface
Z <- Zf(XY$X, XY$Y)
zlim <- range(Z)
zlen <- zlim[2] - zlim[1] + 1

jet.colors <-   # function from grDevices package
      colorRampPalette(c("#00007F", "blue", "#007FFF", "cyan",
                      "#7FFF7F", "yellow", "#FF7F00", "red", "#7F0000"))
colorzjet <- jet.colors(100)  # 100 separate color 
require(rgl)
open3d()
rgl.surface(x=points, y=matrix(Z,20), 
            coords=c(1,3,2),z=-points, 
            color=colorzjet[ findInterval(Z, seq(min(Z), max(Z), length=100))] )
axes3d()
rgl.snapshot("copyMatlabstyle.png")

CopyMatlab.style.png"

I will admit that getting the colors to line up with the "Z-axis" (which is actually the rgl y-axis) seemed very unintuitive. If you want the shiny, specular effect that Matlab delivers you can play with the angle of illumination.

enter image description here

You can also add or remove lighting:

clear3d(type = "lights")
light3d(theta=0, phi=0)
light3d(theta=0, phi=0)  # twice as much light.

After:

 grid3d("x")
 grid3d("y")
 grid3d("z")

 rgl.snapshot("copyMatlabstyle3.png")

enter image description here

You could have put the y-grid "behind" the surface with:

grid3d("y+")

Similar tweaks to the axes3d or axis3d calls could move the location of the scales.

For further examples, look at http://rgm3.lab.nig.ac.jp/RGM/R_image_list and search for 'plot3d' which brings up examples of the R2BayesX::plot3d function, Look at Karline Soetaert's plot3D package vignette, "50 ways to plot a volcano"

IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • Very nice. You could use `grid3d()` to add surface grids as in the MATLAB plot. I must admit I find the specular lighting a distraction in these cases. (For what it's worth, there is actually a bit of discussion of 3D perspective plots in one of Bill Cleveland's books -- so they have at least some statistical-graphics-purist credentials. Also, I agree with commenter above that Tufte would think 3D was a waste in this example, but he certainly doesn't disapprove of it in general -- one of his headings is "escaping flatland" ...) – Ben Bolker Dec 12 '13 at 21:28
  • 1
    I find 3d graphics particularly useful when placed side-by-side with contour plots. The contour plots allow sensible extraction of numeric values, while the 3d plots let one appreciate the "shape" and locations of the most abrupt changes. – IRTFM Dec 12 '13 at 21:34
  • Thanks DWin not only for the beautiful answer but also for the web links to read on. In this example color is not useful (but it was an easy example). I feel that color+3D is useful when one would like to simultaneously map another dimension to the plot. I find such plots very useful, not necessarily in the publication/reporting stage but also in the data analysis stage, to able to visualize more than 2 dimensions simultaneously. Cheers and thanks. – ECII Dec 13 '13 at 15:24
5

This may well not do everything you want, but I'm posting it in hopes of attracting better answers.

X <- Y <-  seq(-2, 0, length.out= 20)
Z <- outer(X,Y,
           function(X,Y) 2/exp((X-.5)^2+Y^2)-2/exp((X+.5)^2+Y^2))
cc <- colorRamp(rev(rainbow(10)))
Zsc <- (Z-min(Z))/diff(range(Z))
rgbvec2col <- function(x) do.call(rgb,c(as.list(x),list(max=255)))
colvec <- apply(cc(Zsc),1,rgbvec2col)

library(rgl)
surface3d(X,Y,Z,col=colvec)
bbox3d(color=c("white","black"))
Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
  • Took me at least 3 hours to come up with a "better answer". I learned a lot in the effort. – IRTFM Aug 14 '21 at 17:39