Search code examples
r3dsurfacepolynomials

How to plot a 3D surface out of columns data frames if I do not know the polynomial function


I have some data of longitudes and latitudes. My third variable is the penetration of the electric Vehicle in an municipality. Hence, I have sparse datas and I do not know the mapping from f(long,lat) -> MS_Year. I have the following datas

long              lat              MS_Year
<dbl>             <dbl>              <dbl>
 1 -66.0436169857389 50.3417726256247  0.0122
 2 -66.1704063635085 48.168838536499   0.0115
 3 -67.1376617834163 48.9202603958534  0.0136
 4 -67.474931686395  48.8025438021711  0.0108
 5 -67.5756670981796 48.5194066352801  0.0111
 6 -67.6273066949175 48.429540936994   0.0167

I have been able to do the 3D scatter plot without any problems.

scatterplot3d(Plot_Me_Tot_2019_grouped)

[enter image description here][1]

However, I've spent the whole day trying to understand how to do a surface. To my understanding, it is particularly hard, because I need to use a nonparametric estimator to show how complex the topology is. (The idea is to justify a nonparametric regression, which I've just learned about and never used; it might explain my total struggle).

Hence, I need to create a polynomial function f(long,lat) that has output MS_Year.

I Tried to applied it as follow :

library(predict3d)
library(rgl)

fit5=lm(MS_Year ~polym(long, lat,degree=5, raw=T),data=Plot_Me_Tot_2019_grouped)
predict3d(fit5,radius=0.05)

I did that, caused It combines this [polynomial regression][2], to this [3D plotting][3]. It's a total failure.

Did someone ever faced similar issues ?

I feel my problem is to create the linked function AKA the f(long,lat) and then with this, use expand.grid(long,lang) to create a surface and plot it.

One should understand that I do not posses a good understanding of the translation from the DF to the matrix format required for the 3D surface.

Thanks a lot for your time [1]: https://i.sstatic.net/6ceJj.png [2]: Polynomial regression with two variables with R [3]: https://cran.r-project.org/web/packages/predict3d/vignettes/predict3d.html


Solution

  • I think you don't want a polynomial for the whole surface: that's likely to be very unstable, with huge amounts of variation between the points.

    However, you might want a low degree local polynomial fit, or some low degree interpolation.

    You haven't posted your real data, so I'll demonstrate with fake data. First, we do interpolation between the points:

    set.seed(123)
    df <- data.frame(long = rnorm(100, -66, 1),
                     lat = rnorm(100, 49, 1))
    df$MS_Year <- 0.015 + df$long/1000 + df$lat/1000 + rnorm(100, 0.01, 0.0005)
    head(df)
    #>        long      lat     MS_Year
    #> 1 -66.56048 48.28959 0.007828523
    #> 2 -66.23018 49.25688 0.008682913
    #> 3 -64.44129 48.75331 0.009179444
    #> 4 -65.92949 48.65246 0.007994563
    #> 5 -65.87071 48.04838 0.006970499
    #> 6 -64.28494 48.95497 0.009431914
    
    library(interp)
    surf <- interp(df$long, df$lat, df$MS_Year,
                   xo = sort(df$long), yo = sort(df$lat))
    
    library(rgl)
    plot3d(df, type = "s", size = 0.5)
    persp3d(surf, col = "gray", add = TRUE)
    
    

    screenshot

    This did bilinear interpolation between the points; it ends up very rough. You'll probably prefer to fit some sort of surface to the points rather than interpolate them. This fits a local smooth:

    library(mgcv)
    #> Loading required package: nlme
    #> This is mgcv 1.8-38. For overview type 'help("mgcv-package")'.
    fit <- gam(MS_Year ~ s(long, lat), data = df)
    xo <- sort(df$long)
    yo <- sort(df$lat)
    grid <- expand.grid(long = xo, lat = yo)
    pred <- predict(fit, newdata = grid)
    plot3d(df, type = "s", size = 0.5)
    persp3d(xo, yo, matrix(pred, 100,100), col = "gray", add = TRUE)
    

    Created on 2022-01-23 by the reprex package (v2.0.1)

    screenshot

    That's the same dataset, but the smoother managed to see that it's more or less linear in both long and lat. Your data probably won't end up with such a simple shape.