在R中创建3个数字变量的Surface 3D图

时间:2018-07-19 05:09:32

标签: r plot ggplot2 scatter-plot r-plotly

> plot_data
      cs    w          u
1     0  0.0 1.00000000
2   125  0.5 1.23818786
3   250  1.0 4.15500984
4   375  1.5 1.41931096
5   500  2.0 0.51660657
6   625  2.5 0.29800493
7   750  3.0 0.20846944
8   875  3.5 0.16441816
9  1000  4.0 0.14116564
10 1125  4.5 0.12890978

#Scatter PLot 
 p <- plot_ly(x=plot_data$cs,y=plot_data$w,z=plot_data$u)
 p

plot_data是具有三个变量的数据框..使用plot_ly函数可以获得3d散点图..如何对与表面图查找矩阵相同的变量进行表面图绘制以及如何创建该矩阵。

enter image description here

2 个答案:

答案 0 :(得分:2)

TL; DR 有很多选项。下面说明了三个,其中一个根据OP的要求带有plotlyplotly可能不是最好的。可能需要一些数据准备,就像OP和answer by @rar给出的示例数据一样。

免责声明::不幸的是,R中3d曲面图有点麻烦。与R中的所有许多选项相比,我发现python-matplotlibextremely easy, straightforward, and intuitive

数据准备1:您实际上应该拥有3d数据

将2d数据绘制为3d是一个常见错误。例如,OP中的数据在3d中形成几乎线性的曲线。尽管可以将这些点视为在xy平原中特定位置的z轴值的独立观测值,并据此对3d曲面进行插值,但我怀疑得出的曲面图是否非常有用或有用。 / p>

在任何情况下,要绘制3d曲面,您几乎总是需要在x-y-plain上形成观察网格。要对R中的此类网格进行必要的插值,可以像这样使用akima::interp

library(akima)
df <- data.frame(matrix(rnorm(60), nrow=20))
plot_data <- interp(df$X1,df$X2,df$X3)

但是,akima::interp相当脆弱,在某些情况下(例如,下面的data_grid变量的示例)将使您的R解释程序外壳崩溃。

从正面看,它为您创建了一个包含两个向量和一个矩阵的数据结构,这是R中所有(?)3d曲面绘制函数所期望的数据。

数据准备2:您不能使用长格式的数据

说,您在3x3网格中有9个点的数据(为使此示例简单起见):

data_grid <- data.frame(data_col = c(45.62151, 60.30996, 66.01667, 45.48701, 
                                     60.39519, 65.42441, 45.48208, 60.39041, 65.52165), 
               axis_one=c(10000, 10000, 10000, 1000000, 1000000, 1000000, 100000000, 
                          100000000, 100000000), 
               axis_two=c(1, 100, 10000,1, 100, 10000,1, 100, 10000))
data_grid
#  data_col axis_one axis_two
#1 45.62151    1e+04        1
#2 60.30996    1e+04      100
#3 66.01667    1e+04    10000
#4 45.48701    1e+06        1
#5 60.39519    1e+06      100
#6 65.42441    1e+06    10000
#7 45.48208    1e+08        1
#8 60.39041    1e+08      100
#9 65.52165    1e+08    10000

我无法在R中找到任何3d绘图程序包或函数来接受这样的数据结构。关于R在stackoverflow上进行3d绘制的大多数答复都假定了这一点,这可能是因为在大多数情况下,这不是经验数据,而是从3d函数提取的值。示例hereherehere或基数R中包含的(对于3d绘图示例)经常使用的volcano数据集。

那么这些软件包会带来什么?他们需要两个向量(用于基本平面中的网格坐标)和一个矩阵,该矩阵的条目对应于由这两个向量为z轴创建的网格。换句话说,您需要将所有长格式的数据重新排列为宽格式,即以x和y坐标为行和列索引/标签的矩阵。

这可以通过reshape2::acast完成:

library(reshape2)
plot_matrix <- t(acast(data_grid, axis_one~axis_two, value.var="data_col"))
plot_matrix
#         10000    1e+06    1e+08
#1     45.62151 45.48701 45.48208
#100   60.30996 60.39519 60.39041
#10000 66.01667 65.42441 65.52165

如果您已经具有宽格式的数据:太棒了,则不必这样做。

请注意,另一个answer by @rar似乎使用的是长格式结构的示例数据,但以错误的方式绘制,因此R不会将列csw解释为基本坐标,而是作为其他意见。很难确定这是否确实是一个错误,或者答案是否是这种意图。不幸的是,它只包含很少的文本。

绘图选项1:使用persp进行绘图

绘图非常简单。不幸的是,我们现在也修改了x和y数据。因此,我们必须将它们从矩阵的列和行名称中拉出。在将数据转换为宽格式矩阵之前,可能还有其他方法可以保存这些信息,但是如果不同轴的数据来自不同的对象,这可能是错误的来源。

persp(x = as.numeric(colnames(plot_matrix)), 
  y = as.numeric(rownames(plot_matrix)), 
  z = plot_matrix,
  xlab = "Axis one",
  ylab = "Axis two",
  zlab = "Data",
  ticktype ='detailed',
  theta = 310, 
  phi = 20,
  col = "green", shade = 0.5)

persp的主要缺点在于它似乎无法具有对数刻度轴。这很不方便;所以我们必须手动进行。

persp(x = log(as.numeric(colnames(plot_matrix))), 
  y = log(as.numeric(rownames(plot_matrix))), 
  z = plot_matrix,
  xlab = "log Axis one",
  ylab = "log Axis two",
  zlab = "Data",
  ticktype ='detailed',
  theta = 310, 
  phi = 20,
  col = "green", shade = 0.5)

我们照常保存该图(尽管与Python相比是直觉的)

pdf(file="out.pdf", width=5, height=5)
persp(x = log(as.numeric(colnames(plot_matrix))), 
  y = log(as.numeric(rownames(plot_matrix))), 
  z = plot_matrix,
  xlab = "log Axis one",
  ylab = "log Axis two",
  zlab = "Data",
  ticktype ='detailed',
  theta = 310, 
  phi = 20,
  col = "green", shade = 0.5)
dev.off()

...或等同于png等。 persp

绘图选项2:使用plotly绘图

OP询问了有关情节。所以我们开始:

Plotly具有更多功能并且看上去更好,但是保留了一些相同的缺点(需要宽格式)。

library(plotly)
plot_ly(
      x = as.numeric(colnames(plot_matrix)), 
      y = as.numeric(rownames(plot_matrix)), 
      z = plot_matrix
    ) %>% 
  add_surface() %>%
  layout(
    title = "",
    scene = list(
      xaxis = list(type = "log", title = "Total observations"),
      yaxis = list(type = "log", title = "Firm size"),
      zaxis = list(title = "Median"),
      camera = list(eye = list(x = 1.95, y = -1.25, z = 1.25))
    ))

然而,用图谋可能几乎是不可能的。过去,plotly似乎需要订阅付费服务才能使用plotly::export在其服务器上在线创建图形。今天,它建议使用必须安装的名为orca的软件包。安装选项在orca's github repository中进行了描述,并且总是需要您通过安装不受信任的第三方程序包或第二个程序包管理器conda来入侵您的系统,这些程序可能也需要root用户访问权限或整个Python的第二个发行版。 / p>

如果您已经在使用他们的工具栈,例如,如果您有用于Python的Anaconda发行版,则可以安装orca而不会影响系统的完整性。否则,不要打扰。在这种情况下,您可以通过执行以下操作来保存该图(显然;我无法对其进行测试)

plotly_figure <- plot_ly(
      x = as.numeric(colnames(plot_matrix)), 
      y = as.numeric(rownames(plot_matrix)), 
      z = plot_matrix
    ) %>% 
  add_surface() %>%
  layout(
    title = "",
    scene = list(
      xaxis = list(type = "log", title = "Total observations"),
      yaxis = list(type = "log", title = "Firm size"),
      zaxis = list(title = "Median"),
      camera = list(eye = list(x = 1.95, y = -1.25, z = 1.25))
    ))
orca(plotly_figure, file="out.pdf")

请注意,他们的网站使用了第三方脚本,这些脚本会破坏浏览器的附件(尤其是增强隐私的附件),这也是一个危险信号。 plotly::plot_ly plot; this is more like a screenshot 该图当然更像是屏幕截图,因为它不允许我保存任何内容。 绘图选项3+:其他软件包

还有更多软件包。例如。 plot3D,它具有一些功能,其中包括plot3D::persp3D,此处适当。与persp相比,它看起来更花哨,并添加了突出表面高度的颜色。

plot3D::persp3D(x = log(as.numeric(colnames(plot_matrix))), 
  y = log(as.numeric(rownames(plot_matrix))), 
  z = plot_matrix,
  xlab = "log Axis one",
  ylab = "log Axis two",
  zlab = "Data",
  ticktype ='detailed',
  theta = 310, 
  phi = 20)

对于更密集的数据(例如上面用akima::interp创建的数据)来说,它看起来更有趣:

plot3D::persp3D(x = plot_data$x, 
  y = plot_data$y, 
  z = plot_data$z,
  xlab = "log Axis one",
  ylab = "log Axis two",
  zlab = "Data",
  ticktype ='detailed',
  theta = 310, 
  phi = 20)

保存这些数字应该像上面的persp中那样工作。 plot3D::persp3D plot

还有一个rgl:plot3d;如果我理解正确,则需要非常密集的数据和otherwise falls back to a 3d scatter plot

答案 1 :(得分:0)

library(plotly)    
# df_sample could be your plot_data    
> df_sample 
         cs w     u
    1  21.0 6 160.0
    2  21.0 6 160.0
    3  22.8 4 108.0
    4  21.4 6 258.0
    5  18.7 8 360.0
    6  18.1 6 225.0
    7  14.3 8 360.0
    8  24.4 4 146.7
    9  22.8 4 140.8
    10 19.2 6 167.6
> df<-as.matrix(df_sample, rownames.force = NA)
> plot_ly(z=~df) %>% add_surface()

enter image description here

如果要更改x,y和z轴。然后在绘制时按如下方式重新排列列。

plot_ly(z=~df[,c(3,1,2)])%>%add_surface()

enter image description here