问题描述:

I have a perspective plot of a `locfit`

model and I wish to add two things to it

- Predictor variables as points in the 3D space
- Color the surface according to the Z axis value

For the first, I have tried to use the `trans3d`

function. But I get the following error even though my variables are in vector format:

Error in cbind(x, y, z, 1) %*% pmat : requires numeric/complex matrix/vector arguments

Here is a snippet of my code

`library(locfit)`

X <- as.matrix(loc1[,1:2])

Y <- as.matrix(loc1[,3])

zz <- locfit(Y~X,kern="bisq")

pmat <- plot(zz,type="persp",zlab="Amount",xlab="",ylab="",main="Plains",

phi = 30, theta = 30, ticktype="detailed")

x1 <- as.vector(X[,1])

x2 <- as.vector(X[,2])

Y <- as.vector(Y)

points(trans3d(x1,x2,Y,pmat))

My "loc1" data can be found here - https://www.dropbox.com/s/0kdpd5hxsywnvu2/loc1_amountfreq.txt?dl=0

TL,DR: not really in `plot.locfit`

, but you can reconstruct it.

I don't think `plot.locfit`

has good support for this sort of customisation. Supposedly `get.data=T`

in your `plot`

call will plot the original data points (point 1), and it does seem to do so, *except* if `type="persp"`

. So no luck there. Alternatively you can `points(trans3d(...))`

as you have done, except you need the perspective matrix returned by `persp`

, and `plot.locfit.3d`

does not return it. So again, no luck.

For colouring, typically you make a colour scale (http://r.789695.n4.nabble.com/colour-by-z-value-persp-in-raster-package-td4428254.html) and assign each z facet the colour that goes with it. However, you need the z-values of the surface (not the z-values of your original data) for this, and `plot.locfit`

does not appear to return this either.

So to do what you want, you'll essentially be recoding `plot.locfit`

yourself (not hard, though just cludgy).

You could put this into a function so you can reuse it. We:

- make a uniform grid of x-y points
- calculate the value of the fit at each point
- use these to draw the surface (with a colour scale), saving the perspective matrix so that we can
- plot your original data

so:

```
# make a grid of x and y coords, calculate the fit at those points
n.x <- 20 # number of x points in the x-y grid
n.y <- 30 # number of y points in the x-y grid
zz <- locfit(Total ~ Mex_Freq + Cal_Freq, data=loc1, kern="bisq")
xs <- with(loc1, seq(min(Mex_Freq), max(Mex_Freq), length.out=20))
ys <- with(loc1, seq(min(Cal_Freq), max(Cal_Freq), length.out=30))
xys <- expand.grid(Mex_Freq=xs, Cal_Freq=ys)
zs <- matrix(predict(zz, xys), nrow=length(xs))
# generate a colour scale
n.cols <- 100 # number of colours
palette <- colorRampPalette(c('blue', 'green'))(n.cols) # from blue to green
# palette <- colorRampPalette(c(rgb(0,0,1,.8), rgb(0,1,0,.8)), alpha=T)(n.cols) # if you want transparency for example
# work out which colour each z-value should be in by splitting it
# up into n.cols bins
facetcol <- cut(zs, n.cols)
# draw surface, with colours (col=...)
pmat <- persp(x=xs, y=ys, zs, theta=30, phi=30, ticktype='detailed', main="plains", xlab="", ylab="", zlab="Amount", col=palette[facetcol])
# draw your original data
with(loc1, points(trans3d(Mex_Freq,Cal_Freq,Total,pmat), pch=20))
```

Note - doesn't look that pretty! might want to adjust say your colour scale colours, or the transparency of the facets, etc. Re: adding legend, there are some other questions that deal with that.

(PS: what a shame ggplot doesn't do 3D scatter plots.)