简体   繁体   English

如何将2D图像投影为三维散点图中的曲面(在R中)?

[英]How to project a 2D image as a surface in a 3D scatter plot (in R)?

I'm working with 3 dimensional coordinates data, which i'm plotting in a scatterplot, i have ~30.000 datapoints, and i've included the first 10 here so that you can reproduce it 我正在使用3维坐标数据,我正在散点图中绘图,我有~30,000个数据点,我已经包含了前10个,这样你就可以重现它

library(rgl)
library(plot3D)
library(car)

df <- data.frame(meanX = c(147.34694,
                       173.89244,
                       135.73004,
                       121.93766,
                       109.72152,
                       92.53709,
                       165.46588,
                       169.77744,
                       127.01796,
                       99.34347),
             meanY = c(140.40816,
                       110.99128,
                       134.56023,
                       164.18703,
                       166.04051,
                       155.97329,
                       105.29377,
                       104.42683,
                       130.17066,
                       155.99696),
             avgDist = c(40.788118,
                         12.957329,
                         14.24348,
                         39.10424,
                         34.694258,
                         25.532335,
                         21.491695,
                         23.528944,
                         9.309201,
                         31.916879))

I've been using the scatter3d function to plot this 我一直在使用scatter3d函数来绘制这个

scatter3d(x = df$meanX, y = df$meanY, z = df$avgDist, surface = FALSE)

Now my "problem", is that I would like to have a 2d surface with an external image file overlayed onto it at z=0, and as a bonus, if i could project a heatmap/contours from the scatterplot data (meanX and meanY used for the contours) over that image as well, that would be great. 现在我的“问题”是,我希望在z = 0时将2d表面与外部图像文件重叠在一起,如果我可以根据散点图数据投影热图/轮廓,则表示我想要加分(meanX和meanY)用于轮廓的那个图像也是如此,这将是伟大的。

This is the image i'd like to have draped at z = 0: 这是我想在z = 0时叠加的图像:

http://i.imgur.com/m6j4q3M.png http://i.imgur.com/m6j4q3M.png

That image was made with this ggplot: 那个图像是用这个ggplot制作的:

map.colors <- colorRampPalette(c("green","yellow","red"))

densityPlot <- ggplot(direData, aes(x = meanX, y = ,meanY)) + 
  stat_density2d(geom="tile", aes(fill=..density.., alpha=sqrt(sqrt(..density..))), contour=FALSE, n=100) +
  scale_alpha(range = c(0, 1.0)) + scale_fill_gradientn(colours = map.colors(5)) + 
  xlim(70,185) + ylim(70,185)

minimap <- readPNG('~/yasp/minimap.png')

densityPlot + annotation_raster(minimap, ymin = 70 ,ymax=185 ,xmin = 70,xmax = 185) + 
  stat_density2d(geom="tile", aes(fill=..density.., alpha=10*sqrt(..density..)), contour=FALSE, n=100)

Is there any way to do this? 有没有办法做到这一点? I've googled quite a bit for a solution but found no real way of doing this. 我已经搜索了相当多的解决方案,但没有找到真正的方法。 I don't mind creating the image first in ggplot2 with the heatmap, saving that, and then using that as input for the surface draping, but it would of course be quite cool if it could all be done in one call to plot. 我不介意首先在ggplot2中使用热图创建图像,保存它,然后将其用作表面覆盖的输入,但如果它可以在一次调用绘图中完成,那当然会很酷。

How about this? 这个怎么样?

I stored your lined image file in a png in the local directory, there is probably a way to do that without an intermediate file, but I would ask that as a separate question. 我将您的带衬里的图像文件存储在本地目录中的png中,可能有一种方法可以在没有中间文件的情况下执行此操作,但我会将其作为一个单独的问题。

Note that this is actually a simple case of texture mapping. 请注意,这实际上是纹理映射的一个简单情况。 The texture is saved in the gameshot.png file you specified. 纹理保存在您指定的gameshot.png文件中。 You could warp the text around a more complicated object by adding more points to the geometry and adjusting the texture map coordinates accordingly. 您可以通过向几何体添加更多点并相应地调整纹理贴图坐标来扭曲更复杂对象周围的文本。

While they should not have been absolutely necessary here, I added texture map coordinates as it looked like the file and the data were not aligned by default - and in fact the gameshot.png file was displaying reversed. 虽然这里不应该是绝对必要的,但是我添加了纹理贴图坐标,因为它看起来像文件,默认情况下数据没有对齐 - 实际上gameshot.png文件显示为反转。 It looks to me like the png file you specified does not quite match the data, I think there is an inversion somewhere before you saved it. 在我看来,你指定的png文件与数据不完全匹配,我认为在你保存它之前有一个反转。

library(rgl)
library(plot3D)
library(car) 

df <- data.frame(meanX = c(147.34694, 173.89244, 135.73004, 121.93766,
                           109.72152,  92.53709, 165.46588, 169.77744,
                           127.01796,  99.34347),
                 meanY = c(140.40816, 110.99128, 134.56023, 164.18703,
                           166.04051, 155.97329, 105.29377, 104.42683,
                           130.17066, 155.99696),
                 avgDist = c(40.788118, 12.957329, 14.24348, 39.10424,
                             34.694258, 25.532335, 21.491695,23.528944,
                             9.309201,  31.916879))

car::scatter3d(x = df$meanX, y = df$meanY, z = df$avgDist, surface = FALSE)

xvek <- c(0,1)
yvek <- c(0,1)
lnx <- length(xvek)
lny <- length(yvek)
zmat <- matrix(0,lnx,lny)

# Setup the Texture coordinates - defaults seem to invert image
# tms <- matrix(c(0,0,1,1),lnx,lny) # generic case (xy-maped texture looks like png file)
# tmt <- matrix(c(0,1,0,1),lnx,lny)   

tmt <- matrix(c(1,1,0,0),lnx,lny) # "correct case" (ball density look more like picture)
tms <- matrix(c(1,0,1,0),lnx,lny) # I think the gameshot.png is in error  


# Texture file specified in question was stored locally in "gameshot.png"
surface3d(xvek,yvek,zmat,coord=c(3,1),texture_s=tms,texture_t=tmt,
          lit=F,fog=T,color="white",textype="rgb",texture="gameshot.png",add=T)

Yields this: 收益率:

在此输入图像描述

(2nd Edit) I try to write something better code and confirm two xy-coordinates are the same. (第二次编辑)我尝试编写更好的代码并确认两个xy坐标是相同的。 ggplot2 theme with no axes or grid help me to plot only the panel region. 没有轴或网格的ggplot2主题帮助我只绘制面板区域。

library(rgl); library(grid); library(gtable)

df <- data.frame(meanX = c(147.34694, 173.89244, 135.73004, 121.93766,
                           109.72152,  92.53709, 165.46588, 169.77744,
                           127.01796,  99.34347),
                 meanY = c(140.40816, 110.99128, 134.56023, 164.18703,
                           166.04051, 155.97329, 105.29377, 104.42683,
                           130.17066, 155.99696),
                 avgDist = c(40.788118, 12.957329, 14.24348, 39.10424,
                             34.694258, 25.532335, 21.491695,23.528944,
                             9.309201,  31.916879))

map.colors <- colorRampPalette(c("green","yellow","red"))

# set scale_*_continuous() to plot only the panel region. limits mean xlim (or ylim)
# change "tile" into "raster" because of making noise lines on my screen
densityPlot <- ggplot(df[,1:2], aes(x = meanX, y = ,meanY)) + 
  stat_density2d(geom="raster", aes(fill=..density.., alpha=sqrt(sqrt(..density..))), contour=FALSE, n=100) +
  scale_alpha(range = c(0, 1.0)) + scale_fill_gradientn(colours = map.colors(5)) + 
  scale_x_continuous(limits=c(70,185), expand = c(0,0)) + scale_y_continuous(limits=c(70,185), expand = c(0,0)) +
  geom_point(size=4)               # to test XY-coordinate (black points on the map)

open3d()
plot3d( df, type="s", radius=1, col="red", axes=F, 
        xlim = c(70,185), ylim = c(70,185),
        expand = 1 )
plot3d( df, type="h", col="blue", add=T )  # to test XY-coordinate (line segments from z = 0)
axes3d(c("x","y","z") )
show2d({                  # show2d uses 2D plot function's output as a texture on a box.
  grid.draw(gtable_filter(ggplotGrob(densityPlot), "panel"))
},
expand = 1 , texmipmap = F )   # texmipmap = F makes tone clear (not essential)

# I think this is clearly better than using a intermediate file,
# so I deleted related code. Thanks Mike !

情节

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM