Re: [R] Adding points to wireframe

From: Deepayan Sarkar <deepayan.sarkar_at_gmail.com>
Date: Tue 22 Nov 2005 - 07:24:56 EST

On 11/18/05, Pierre-Luc Brunelle <pierre-luc.brunelle@polymtl.ca> wrote:
> Hi,
>
> I am using function wireframe from package lattice to draw a 3D surface.
> I would like to add a few points on the surface. I read in a post from
> Deepayan Sarkar that "To do this in a wireframe plot you would probably
> use the panel function panel.3dscatter". Does someone have an example?

Here goes. Let's say the surface you want is:

surf <-

    expand.grid(x = seq(-pi, pi, length = 50),

                y = seq(-pi, pi, length = 50))

surf$z <-

    with(surf, {

        d <- 3 * sqrt(x^2 + y^2)
        exp(-0.02 * d^2) * sin(d)

    })

To draw just the surface, you can of course do

library(lattice)
wireframe(z ~ x * y, g, aspect = c(1, .5),

          scales = list(arrows = FALSE))

To modify the display, you will want to write your own panel.3d.wireframe function (as suggested in ?panel.cloud), which defaults to 'panel.3dwire'. The first thing to realise is that lots of funny things go on inside panel functions that you don't really want to know about. The trick is to make liberal use of the ... argument, only naming arguments that you need to work with or override. So our first try might be to write an explicit but minimal panel.3d.wireframe function that does nothing new:

wireframe(z ~ x * y, g, aspect = c(1, .5),

          scales = list(arrows = FALSE),
          panel.3d.wireframe = function(...) {
              panel.3dwire(...)
          })

Now, you want to add points using 3dscatter, and that's obviously going to use different data. However, most of the rest of the arguments will be the same for the panel.3dwire and panel.3dscatter calls (giving details of the 3-D to 2-D projection, mostly), so you need to capture the data passed in to panel.3d.wireframe, without worrying about the exact form of the rest of the arguments. This can be done by:

wireframe(z ~ x * y, g, aspect = c(1, .5),

          scales = list(arrows = FALSE),
          panel.3d.wireframe = function(x, y, z, ...) {
              panel.3dwire(x = x, y = y, z = z, ...)
          })

which is of course the same as before. Now let's add a few points using panel.3dscatter:

wireframe(z ~ x * y, g, aspect = c(1, .5),

          scales = list(arrows = FALSE),
          panel.3d.wireframe = function(x, y, z, ...) {
              panel.3dwire(x = x, y = y, z = z, ...)
              panel.3dscatter(x = runif(10, -0.5, 0.5),
                              y = runif(10, -0.5, 0.5),
                              z = runif(10, -0.25, 0.25),
                              ...)
          })

Note that the ... arguments have been passed on to panel.3dscatter. Without it, you would have the error that you reported.

Now, presumably the points that you want to add are in the original data scale, whereas panel.3dwire wants data in a different (linearly shifted and scaled) scale suitable for 3-D transformations. I happened to know what that transformed scale is (usually [-0.5, 0.5]), and the call above makes use of that knowledge. In practice, you would have to make the conversion from data scale to transformed scale yourself, and that's where the *lim and *lim.scaled arguments come in. They contain the range of the data cube in the original and transformed scales respectively. So let's say the points you want to add (in the original scale) are:

pts <-

    data.frame(x = runif(10, -pi, pi),
               y = runif(10, -pi, pi),
               z = runif(10, -1, 1))


Then the suitable transformation can be done as follows:

wireframe(z ~ x * y, g, aspect = c(1, .5),

          scales = list(arrows = FALSE),
          pts = pts,
          panel.3d.wireframe =
          function(x, y, z,
                   xlim, ylim, zlim,
                   xlim.scaled, ylim.scaled, zlim.scaled,
                   pts,
                   ...) {
              panel.3dwire(x = x, y = y, z = z,
                           xlim = xlim,
                           ylim = ylim,
                           zlim = zlim,
                           xlim.scaled = xlim.scaled,
                           ylim.scaled = ylim.scaled,
                           zlim.scaled = zlim.scaled,
                           ...)
              xx <-
                  xlim.scaled[1] + diff(xlim.scaled) *
                      (pts$x - xlim[1]) / diff(xlim)
              yy <-
                  ylim.scaled[1] + diff(ylim.scaled) *
                      (pts$y - ylim[1]) / diff(ylim)
              zz <-
                  zlim.scaled[1] + diff(zlim.scaled) *
                      (pts$z - zlim[1]) / diff(zlim)
              panel.3dscatter(x = xx,
                              y = yy,
                              z = zz,
                              xlim = xlim,
                              ylim = ylim,
                              zlim = zlim,
                              xlim.scaled = xlim.scaled,
                              ylim.scaled = ylim.scaled,
                              zlim.scaled = zlim.scaled,
                              ...)
          })

Hope this helps,

-Deepayan



R-help@stat.math.ethz.ch mailing list
https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide! http://www.R-project.org/posting-guide.html Received on Tue Nov 22 07:32:21 2005

This archive was generated by hypermail 2.1.8 : Fri 03 Mar 2006 - 03:41:15 EST