2
votes

I want to plot a matrix of z values with x rows and y columns as a surface similar to this graph from MATLAB.

Surface plot:

enter image description here

Code to generate matrix:

# Parameters
shape<-1.849241
scale<-38.87986
x<-seq(from = -241.440, to = 241.440, by = 0.240)# 2013 length
y<-seq(from = -241.440, to = 241.440, by = 0.240)
matrix_fun<-matrix(data = 0, nrow = length(x), ncol = length(y))

# Generate two dimensional travel distance probability density function
for (i in 1:length(x)) {
for (j in 1:length(y)){
dxy<-sqrt(x[i]^2+y[j]^2)
prob<-1/(scale^(shape)*gamma(shape))*dxy^(shape-1)*exp(-(dxy/scale))
matrix_fun[i,j]<-prob
}}

# Rescale 2-d pdf to sum to 1
a<-sum(matrix_fun)
matrix_scale<-matrix_fun/a

I am able to generate surface plots using a couple methods (persp(), persp3d(), surface3d()) but the colors aren't displaying the z values (the probabilities held within the matrix). The z values only seem to display as heights not as differentiated colors as in the MATLAB figure.

Example of graph code and graphs:

library(rgl)
persp3d(x=x, y=y, z=matrix_scale, color=rainbow(25, start=min(matrix_scale), end=max(matrix_scale)))
surface3d(x=x, y=y, z=matrix_scale, color=rainbow(25, start=min(matrix_scale), end=max(matrix_scale)))
persp(x=x, y=y, z=matrix_scale, theta=30, phi=30, col=rainbow(25, start=min(matrix_scale), end=max(matrix_scale)), border=NA)

Image of the last graph

enter image description here

Any other tips to recreate the image in R would be most appreciated (i.e. legend bar, axis tick marks, etc.)

2
Perhaps, ?filled.contour could be helpful? - alexis_laz

2 Answers

1
votes

So here's a ggplot solution which seems to come a little bit closer to the MATLAB plot

# Parameters
shape<-1.849241
scale<-38.87986
x<-seq(from = -241.440, to = 241.440, by = 2.40) 
y<-seq(from = -241.440, to = 241.440, by = 2.40)
df      <- expand.grid(x=x,y=y)
df$dxy  <- with(df,sqrt(x^2+y^2))
df$prob <- dgamma(df$dxy,shape=shape,scale=scale)
df$prob <- df$prob/sum(df$prob)

library(ggplot2)
library(colorRamps)      # for matlab.like(...)
library(scales)          # for labels=scientific
ggplot(df, aes(x,y))+
  geom_tile(aes(fill=prob))+
  scale_fill_gradientn(colours=matlab.like(10), labels=scientific)

BTW: You can generate your data frame of probabilities much more efficiently using the built-in dgamma(...) function, rather than calculating it yourself.

1
votes

In line with alexis_laz's comment, here is an example using filled.contour. You might want to increase your by to 2.40 since the finer granularity increases the time it takes to generate the plot by a lot but doesn't improve quality.

filled.contour(x = x, y = y, z = matrix_scale, color = terrain.colors)
# terrain.colors is in the base grDevices package

enter image description here

If you want something closer to your color scheme above, you can fiddle with the rainbow function:

filled.contour(x = x, y = y, z = matrix_scale,
  color = (function(n, ...) rep(rev(rainbow(n/2, ...)[1:9]), each = 3)))

enter image description here

Finer granularity:

filled.contour(x = x, y = y, z = matrix_scale, nlevels = 150,
  color = (function(n, ...)
   rev(rep(rainbow(50, start = 0, end = 0.75, ...), each = 3))[5:150]))

enter image description here