If we were able to generate uniformly distributed variables on [0 ; 1], we could easily generate variables on other spaces such as [0 ; 1] x [0 ; 1], which is a square of side 1. It can be simply done by using two independant variables X1 and X2, uniformly distributed on [0 ; 1], and by considering X = (X1 , X2). Then X is a random variable evenly distributed on the square [0 ; 1] x [0 ; 1]
![]() |
The first method I thought of, is wrong. I was tempted to generate two variables Y1 and Y2 where Y1 follows a uniform on [0 ; Pi] and Y2 follows a uniform on [-Pi ; Pi]. In other words :
- Y1 = Pi * X1
- Y2 = 2Pi * (X2 - 0.5).
Then I wanted to consider (Y1, Y2) as the spherical coordinated of the sphere.
However, this method does NOT generate a uniform on the sphere. Indeed, it has a tendency to over generate north and south poles. The reason is simple, this method generates, in average the same amount of variable in each latitude. North and South poles are of smaller area than Equator. Therefore, the closer we are from the Equator latitude the less variables there are.
On the following graph, we observe a high density of point in the "middle" of the sphere, this is the North Pole. It shows that this method does not offer a uniform distribution. By the way, the graph is computed with the library rgl, which provides a display device for 3 dimensions objects. And then a little code provided in the rgl help allows to move automatically the device and take a snapshot for each view. You can eventually generate a GIF on gifmake (like for the map in Spatial segregation in cities - An explanation by a neural network model).
![]() |
A wrong method to generate evenly distributed variables on the sphere. The North Pole and the South Pole are over represented. |
Many methods have been proposed to generate evenly distributed random variables on a sphere. We propose one of them here. We consider the couple z = (u,v) defined as :
- u = 2 * Pi * X1
- v = arc-cos(2 * (X2 - 0.5))
In this case, a theorem shows that z = (u , v) generates evenly distributed variables. It can be observed on the next graph. There is no irregularity in the distribution of the random variables.
![]() |
A correct simulation of a uniform distribution on a sphere. There is no over represented area. |
Other methods exist. I like this one since it is really simple and uses a uniform distribution at the beginning. The idea of this post is to show that generating a uniform distribution can be adapted to many shapes and cases. However, to do so, a previous analytical study has to be done to find the correct transformation.
So this method would help you to avoid being too many times in the chilly places such as North Pole and South Pole since it does not overrepresent the extreme latitudes.
The program (R) :
# import package to plot in 3D
install.packages("rgl", dependencies = TRUE)
library(rgl)
################################################################
# Uniform distribution in a square
################################################################
size = 10000
x1 = runif(size)
x2 = runif(size)
# the option pch = '.' change the symbol for the graph into dot.
# cex = 2 doubles the size of the dots
plot(x1,x2, col = 'blue', pch = '.', cex = 2)
################################################################
# Wrong solution for the sphere
################################################################
y1 = pi * x1
y2 = 2* pi * (x2-0.5)
y = matrix(0, nrow = 2, ncol = size)
y[1,] = y1
y[2,] = y2
plot(y1, y2)
# This function transform the spherical coordinates into cartesian coordinates
sphereToCartesian = function(matrice){
x= matrix(0,nrow = 3, ncol = length(matrice[1,]))
x[1,] = sin(matrice[2,]) * cos(matrice[1,])
x[2,] = sin(matrice[2,]) * sin(matrice[1,])
x[3,] = cos(matrice[2,])
return(x)
}
a = sphereToCartesian(y)
plot3d(x = a[1,], y = a[2,], z = a[3,])
#you should enlarge the device window, before running this, if you want to have a meaningful graph
rgl.bringtotop()
rgl.viewpoint(0,20)
for (i in 1:45) {
rgl.viewpoint(i,20)
filename <- paste("pic",i,".png",sep="")
rgl.snapshot(filename, fmt="png")
}
################################################################
# Correct solution for the sphere
################################################################
uniformSphere = function(length){
x1 = runif(length, 0,1)
x2 = runif(length, 0,1)
u = 2*pi*x1
v = acos(2*x2- 1)
z =matrix(0, ncol = length, nrow = 2)
z[1,] = u
z[2,] = v
return(z)
}
z = uniformSphere(size)
b = sphereToCartesian(z)
plot3d(x = b[1,], y = b[2,], z = b[3,])
Hello Edwin,
ReplyDeleteI just discovered your blog via the R-bloggers mailing list, it seems very interesting.
As for this post, the "spherical coordinate method" is nice but it becomes tough to implement in higher dimensions. Another method begins by sampling a 3-dimensional vector X with a spherical distribution (e.g. standard Gaussian, using Box-Muller) and then sets Y = X/||X|| which is uniformly distributed on the unit sphere.
This method is arguably a little less economical since it takes N+1 random numbers to sample from an N-dimensional, but it straightforward to implement in any dimension. Moreover, similar ideas can be applied to sample e.g. random orthogonal matrices, etc.
Peldv,
DeleteThank you for your comment (the first comment on this blog by the way!). You are absolutely right, there are many other methods to generate a uniform distribution on a sphere. Each of them with benefits and disadvantages.
The method you are talking about has been mentioned by Muller in this paper : A Note on a Uniformly Method for Generating Points on N-Dimensional Spheres, Muller, 1959. This method is based on a marvelous property of the Normal distribution :
“the N-dimensional canonical Normal Density Function has constant probability on the surfaces of N-dimensional spheres with common centers.”. This method needs Normal generation, but as you said, we can start from a uniform distribution since we can generate a Normal from a Uniform with the Box and Muller method. You can find the code of this method in one of my previous post : http://probaperception.blogspot.co.uk/2012/11/generation-of-normal-distribution-from.html.
The advantage of this method is its “user friendly” code. Besides, its complexity in term of random generation for a N-dimension sphere is N+1 (not exactly if N is even, but we can code it so that it is close from N+1).
The code is really simple :
################################################################
# Muller Method
################################################################
uniformMullerSphere = function(sample, dimension = 3){
a = matrix(rnorm(sample*dimension), nrow = dimension, ncol = sample)
b = a
for(i in 1:sample){
b[,i] = a[,i]/sqrt(sum(a[,i]**2))
}
return(b)
}
z = uniformMullerSphere(1000,3)
plot3d(x = z[1,], y = z[2,], z = z[3,])
Thanks Peldv for your comment.
This comment has been removed by the author.
ReplyDeleteLove your blog! We've just booked one of our favourite luxury holiday cottages in the UK for this summer. I can't wait, just hope the weather is fine!
ReplyDelete