代码之家  ›  专栏  ›  技术社区  ›  skan

R: 从x,y,z绘制三维曲面

  •  30
  • skan  · 技术社区  · 15 年前


    x、 是,是 其中z是x和y的函数。

    我知道如何绘制这些点的“散点图” plot3d(x,y,z)

    但是如果我想要一个surface,我必须使用其他命令,比如surface3d 问题是它不接受与plot3d相同的输入 似乎需要一个矩阵

    (nº elements of z) = (n of elements of x) * (n of elements of x)
    

    我怎样才能得到这个矩阵? 我试过使用命令interp,就像我需要使用等高线图时那样。

    如果我有太多的点,这个矩阵就太大了。

    干杯

    5 回复  |  直到 15 年前
        1
  •  29
  •   Spacedman    15 年前

    如果x和y坐标不在网格上,则需要将x、y、z曲面插值到一个网格上。可以使用任何地质统计学软件包(geoR、gstat和其他软件包)或更简单的技术(如反距离加权)使用kriging来实现这一点。

    我猜你提到的“interp”函数来自akima包。请注意,输出矩阵与输入点的大小无关。如果需要,可以在输入中有10000个点,并将其插值到10x10网格上。默认情况下,akima::interp在40x40网格上执行此操作:

    > require(akima) ; require(rgl)
    > x=runif(1000)
    > y=runif(1000)
    > z=rnorm(1000)
    > s=interp(x,y,z)
    > dim(s$z)
    [1] 40 40
    > surface3d(s$x,s$y,s$z)
    

    因为它是随机的数据,所以看起来很糟糕。希望你的数据不是!

        2
  •  6
  •   Aaron    13 年前

    变量“b”和“s”可以是x或y。

    require(lattice)
    
    # begin generating my 3D shape
    b <- seq(from=0, to=20,by=0.5)
    s <- seq(from=0, to=20,by=0.5)
    payoff <- expand.grid(b=b,s=s)
    payoff$payoff <- payoff$b - payoff$s
    payoff$payoff[payoff$payoff < -1] <- -1
    # end generating my 3D shape
    
    
    wireframe(payoff ~ s * b, payoff, shade = TRUE, aspect = c(1, 1),
        light.source = c(10,10,10), main = "Study 1",
        scales = list(z.ticks=5,arrows=FALSE, col="black", font=10, tck=0.5),
        screen = list(z = 40, x = -75, y = 0))
    
        3
  •  6
  •   Rorschach    11 年前

    outer() 产生它。

    看看这个函数的演示 persp() ,这是绘制曲面透视图的基本图形函数。

    下面是他们的第一个例子:

    x <- seq(-10, 10, length.out = 50)  
    y <- x  
    rotsinc <- function(x,y) {
        sinc <- function(x) { y <- sin(x)/x ; y[is.na(y)] <- 1; y }  
        10 * sinc( sqrt(x^2+y^2) )  
    }
    
    z <- outer(x, y, rotsinc)  
    persp(x, y, z)
    

    surface3d() :

    require(rgl)  
    surface3d(x, y, z)
    
        4
  •  5
  •   Andrew    13 年前

    rgl 很好,但是需要一些实验来确定轴的位置。

    如果有很多点,为什么不从中随机抽取一个样本,然后绘制结果曲面。可以添加多个曲面,所有这些曲面都基于来自同一数据的采样,以查看采样过程是否对数据产生了可怕的影响。

    所以,这里有一个非常糟糕的函数,但它做了我认为你希望它做的事情(但没有采样)。给定一个矩阵(x,y,z),其中z是它将绘制点和曲面的高度。限制是每个(x,y)对只能有一个z。所以那些在自身上循环的飞机会引起问题。

    plot_points = T 将绘制生成曲面的各个点-这有助于检查曲面和点是否实际相交。这个 plot_contour = T 将在三维可视化下方绘制二维等高线图。设置颜色为 rainbow verbose = T 打印出大量的输出,用于在函数中断时调试它。

    plot_rgl_model_a <- function(fdata, plot_contour = T, plot_points = T, 
                                 verbose = F, colour = "rainbow", smoother = F){
      ## takes a model in long form, in the format
      ## 1st column x
      ## 2nd is y,
      ## 3rd is z (height)
      ## and draws an rgl model
    
      ## includes a contour plot below and plots the points in blue
      ## if these are set to TRUE
    
      # note that x has to be ascending, followed by y
      if (verbose) print(head(fdata))
    
      fdata <- fdata[order(fdata[, 1], fdata[, 2]), ]
      if (verbose) print(head(fdata))
      ##
      require(reshape2)
      require(rgl)
      orig_names <- colnames(fdata)
      colnames(fdata) <- c("x", "y", "z")
      fdata <- as.data.frame(fdata)
    
      ## work out the min and max of x,y,z
      xlimits <- c(min(fdata$x, na.rm = T), max(fdata$x, na.rm = T))
      ylimits <- c(min(fdata$y, na.rm = T), max(fdata$y, na.rm = T))
      zlimits <- c(min(fdata$z, na.rm = T), max(fdata$z, na.rm = T))
      l <- list (x = xlimits, y = ylimits, z = zlimits)
      xyz <- do.call(expand.grid, l)
      if (verbose) print(xyz)
      x_boundaries <- xyz$x
      if (verbose) print(class(xyz$x))
      y_boundaries <- xyz$y
      if (verbose) print(class(xyz$y))
      z_boundaries <- xyz$z
      if (verbose) print(class(xyz$z))
      if (verbose) print(paste(x_boundaries, y_boundaries, z_boundaries, sep = ";"))
    
      # now turn fdata into a wide format for use with the rgl.surface
      fdata[, 2] <- as.character(fdata[, 2])
      fdata[, 3] <- as.character(fdata[, 3])
      #if (verbose) print(class(fdata[, 2]))
      wide_form <- dcast(fdata, y ~ x, value_var = "z")
      if (verbose) print(head(wide_form))
      wide_form_values <- as.matrix(wide_form[, 2:ncol(wide_form)])  
      if (verbose) print(wide_form_values)
      x_values <- as.numeric(colnames(wide_form[2:ncol(wide_form)]))
      y_values <- as.numeric(wide_form[, 1])
      if (verbose) print(x_values)
      if (verbose) print(y_values)
      wide_form_values <- wide_form_values[order(y_values), order(x_values)]
      wide_form_values <- as.numeric(wide_form_values)
      x_values <- x_values[order(x_values)]
      y_values <- y_values[order(y_values)]
      if (verbose) print(x_values)
      if (verbose) print(y_values)
    
      if (verbose) print(dim(wide_form_values))
      if (verbose) print(length(x_values))
      if (verbose) print(length(y_values))
    
      zlim <- range(wide_form_values)
      if (verbose) print(zlim)
      zlen <- zlim[2] - zlim[1] + 1
      if (verbose) print(zlen)
    
      if (colour == "rainbow"){
        colourut <- rainbow(zlen, alpha = 0)
        if (verbose) print(colourut)
        col <- colourut[ wide_form_values - zlim[1] + 1]
        # if (verbose) print(col)
      } else {
        col <- "grey"
        if (verbose) print(table(col2))
      }
    
    
      open3d()
      plot3d(x_boundaries, y_boundaries, z_boundaries, 
             box = T, col = "black",  xlab = orig_names[1], 
             ylab = orig_names[2], zlab = orig_names[3])
    
      rgl.surface(z = x_values,  ## these are all different because
                  x = y_values,  ## of the confusing way that 
                  y = wide_form_values,  ## rgl.surface works! - y is the height!
                  coords = c(2,3,1),
                  color = col,
                  alpha = 1.0,
                  lit = F,
                  smooth = smoother)
    
      if (plot_points){
        # plot points in red just to be on the safe side!
        points3d(fdata, col = "blue")
      }
    
      if (plot_contour){
        # plot the plane underneath
        flat_matrix <- wide_form_values
        if (verbose) print(flat_matrix)
        y_intercept <- (zlim[2] - zlim[1]) * (-2/3) # put the flat matrix 1/2 the distance below the lower height 
        flat_matrix[which(flat_matrix != y_intercept)] <- y_intercept
        if (verbose) print(flat_matrix)
    
        rgl.surface(z = x_values,  ## these are all different because
                    x = y_values,  ## of the confusing way that 
                    y = flat_matrix,  ## rgl.surface works! - y is the height!
                    coords = c(2,3,1),
                    color = col,
                    alpha = 1.0,
                    smooth = smoother)
      }
    }
    

    这个 add_rgl_model 在没有选项的情况下执行相同的操作,但会将曲面覆盖到现有的3dplot上。

    add_rgl_model <- function(fdata){
    
      ## takes a model in long form, in the format
      ## 1st column x
      ## 2nd is y,
      ## 3rd is z (height)
      ## and draws an rgl model
    
      ##
      # note that x has to be ascending, followed by y
      print(head(fdata))
    
      fdata <- fdata[order(fdata[, 1], fdata[, 2]), ]
    
      print(head(fdata))
      ##
      require(reshape2)
      require(rgl)
      orig_names <- colnames(fdata)
    
      #print(head(fdata))
      colnames(fdata) <- c("x", "y", "z")
      fdata <- as.data.frame(fdata)
    
      ## work out the min and max of x,y,z
      xlimits <- c(min(fdata$x, na.rm = T), max(fdata$x, na.rm = T))
      ylimits <- c(min(fdata$y, na.rm = T), max(fdata$y, na.rm = T))
      zlimits <- c(min(fdata$z, na.rm = T), max(fdata$z, na.rm = T))
      l <- list (x = xlimits, y = ylimits, z = zlimits)
      xyz <- do.call(expand.grid, l)
      #print(xyz)
      x_boundaries <- xyz$x
      #print(class(xyz$x))
      y_boundaries <- xyz$y
      #print(class(xyz$y))
      z_boundaries <- xyz$z
      #print(class(xyz$z))
    
      # now turn fdata into a wide format for use with the rgl.surface
      fdata[, 2] <- as.character(fdata[, 2])
      fdata[, 3] <- as.character(fdata[, 3])
      #print(class(fdata[, 2]))
      wide_form <- dcast(fdata, y ~ x, value_var = "z")
      print(head(wide_form))
      wide_form_values <- as.matrix(wide_form[, 2:ncol(wide_form)])  
      x_values <- as.numeric(colnames(wide_form[2:ncol(wide_form)]))
      y_values <- as.numeric(wide_form[, 1])
      print(x_values)
      print(y_values)
      wide_form_values <- wide_form_values[order(y_values), order(x_values)]
      x_values <- x_values[order(x_values)]
      y_values <- y_values[order(y_values)]
      print(x_values)
      print(y_values)
    
      print(dim(wide_form_values))
      print(length(x_values))
      print(length(y_values))
    
      rgl.surface(z = x_values,  ## these are all different because
                  x = y_values,  ## of the confusing way that 
                  y = wide_form_values,  ## rgl.surface works!
                  coords = c(2,3,1),
                  alpha = .8)
      # plot points in red just to be on the safe side!
      points3d(fdata, col = "red")
    }
    

    所以我的方法是,试着用你所有的数据来做(我很容易画出从~15k点生成的曲面)。如果这样做不起作用,则取几个较小的样本,并使用这些函数一次绘制所有样本。

        5
  •  3
  •   Agustin    10 年前

    也许现在已经晚了,但是跟着Spacedman,你有没有尝试duplicate=“strip”或其他选项?

    x=runif(1000)
    y=runif(1000)
    z=rnorm(1000)
    s=interp(x,y,z,duplicate="strip")
    surface3d(s$x,s$y,s$z,color="blue")
    points3d(s)