I would like to create randomly oriented planes. This is how I'm attempting to do that:

  1. I create a 2 random unit vectors, $\mathbf{v}_1$, and $\mathbf{v}_2$, in the $x$-$y$ plane
  2. I assume that if I rotate these two vectors around a random vector (in $x$-$y$-$z$) called $\mathbf n$, the plane on which the two vectors lie is random and uniformly distributed over the sphere.
  3. So I randomly pick $\mathbf n$, keeping in mind the issues of random point picking on spheres.
  4. I then use RotationMatrix[α, n].v1 (and same for v2) to get the new vectors on the rotated and supposedly random plane. There is some question on what to choose for the angle $\alpha$ which gives the angle of the rotation.
    • If I choose $\alpha<\pi/2$, the vectors do not encompass the entire sphere.
    • If I choose $\alpha=\pi/2$, I get a bunching of vectors at the poles.
    • If I choose $\alpha>\pi/2$, there is bunching at various latitudes. I cannot get a uniformly random distribution over the sphere!

Is there a fix to the current method I am implementing? Is there another way to do it?

My real goal here isn't creating random planes. My goal is to take two vectors with some arbitrary magnitude and direction in $x$-$y$ and then randomly orient them over the sphere while maintaining their relative positions with respect to one another. The steps I have taken above seem like the logical way to do that.

  • $\begingroup$ Isn't this the same as re-orienting $\mathbf{v}_1 \times \mathbf{v}_2$ to some arbitrary direction? $\endgroup$
    – rcollyer
    Commented Feb 2, 2012 at 19:09
  • $\begingroup$ @rcollyer I thought the same $\endgroup$
    – Rojo
    Commented Feb 2, 2012 at 19:37
  • $\begingroup$ A plane can be defined by a single normal vector, why choose two? $\endgroup$
    – Octopus
    Commented Nov 24, 2016 at 19:51

2 Answers 2


Why don't you pick a random vector on the sphere to be your first vector, instead of $\mathbf{n}$, and then pick a random uniform number between $0$ and $2 \pi$ to orient the second vector aronud the first?

Something like this, assuming you have your function randomVectorOnUnitSphere[] already (haven't tested it)

generateRandomPositioning[v1_, v2_] := 
 With[{angle = VectorAngle[v1, v2], mag1 = Norm[v1], mag2 = Norm[v2], 
   rvec = randomVectorOnUnitSphere[]},
  Module[{v1out, v2out},
   v1out = rvec mag1;
   v2out = 
    Cross[rvec, v2] //
      (* this just gives a particular vector perpendicular to v2out, 
      assuming they are not colinear *) 
      RotationTransform[angle, #][rvec] & //
      (* now I have a particular vector at the corresponding angle of v1out *) 
      RotationTransform[RandomReal[2 Pi], rvec]//(* now it's distributed uniformly *) 
      Normalize[#] mag2 &;
    {v1out, v2out}

Ok, here's my test

randomVectorOnUnitSphere[]:=With[{θ = RandomReal[2 π], φ = ArcCos[RandomReal[{-1,1}]]},
    {Cos[θ] Sin[φ],Sin[φ] Sin[φ],Cos[φ]}

ListPointPlot3D[Table[randomVectorOnUnitSphere[], {10000}], AspectRatio -> 1]

enter image description here

In[28]:= v1 = {0, 1, 1}; v2 = {0, 3, 0.4};
test = Table[generateRandomPositioning[v1, v2], {500}];

In[13]:= arrowCouple[{pt1_, pt2_}] := {Arrow[{{0, 0, 0}, pt1}], 
   Arrow[{{0, 0, 0}, pt2}]};

In[30]:= Equal @@ VectorAngle @@@ test

Out[30]= True

In[31]:= VectorAngle @@ First@test == VectorAngle[v1, v2]

Out[31]= True

   0.2], {RGBColor[RandomReal[], RandomReal[], RandomReal[]], 
     arrowCouple[#]} & /@ test}, Boxed -> False]

enter image description here

Graphics3D[{Black, arrowCouple[{v1, v2}], 
    {RGBColor[RandomReal[], RandomReal[], RandomReal[]], 
     arrowCouple[#]} & /@ test[[;; 3]]}, Boxed -> False]

enter image description here

I know, these aren't proper tests, nor am I sure this is what you want to accomplish.

If I think about it more formally, and I remember well, you need to have a clear idea of how you measure sets of "pairs of vectors of given magnitude and angle between them", so that you can talk about uniform distribution. It would mean that the probabilty of the final pair of vectors being in a certain subset is proportional to the subset's measure... But if we assume that your measure is invariant to rotations, which makes sense, then probably it's all the same

  • $\begingroup$ thanks. I will try this. The reason I was trying it my original way was that the vector magnitudes have a normal distribution and it was easiest to assign them in the x-y coordinates. I will have to worry about that later for the time being. $\endgroup$
    – BeauGeste
    Commented Feb 2, 2012 at 19:34
  • $\begingroup$ Let me see if I understand what you did: So you start with the two vectors v1 and v2. You assign v1out to a random vector on the sphere. To get v2out you take cross product of v2 and random vector. v1out and Cross[rvec, v2] form the new plane. Now you transform Cross[rvec, v2] in such a way that it reestablishes its orientation with v1out in the new plane. What is the second RotationTransform doing? $\endgroup$
    – BeauGeste
    Commented Feb 2, 2012 at 21:15
  • $\begingroup$ @BeauGeste Cross[rvec, v2], that rvec is the same I used to assign the v1out. So it gives a vector that's normal to v1out. I then use that vector to rotate v1 over a perpendicular axes to itself, the angle wanted... so as to get a vector that is at the proper angle... Finally, i rotate that vector on the v1out axes to get v2out randomly distributed, while keeping the angle $\endgroup$
    – Rojo
    Commented Feb 3, 2012 at 8:47

If all that was really wanted was to randomly orient a plane spanned by two vectors while preserving the angle between them, then the simplest way is to generate a Haar-distributed pseudorandom orthogonal matrix, and use that to perform the random orientation. The code for generating a $3\times 3$ random orthogonal matrix is surprisingly simple:

ranOrt := Orthogonalize[RandomVariate[NormalDistribution[], {3, 3}]]

(For more than three dimensions, this isn't the most efficient method, but it works nicely here and the code is nicely short.)

Try it out:

arrowCouple[{pt1_?VectorQ, pt2_?VectorQ}] := {Arrowheads[{-.04, .04}],
   Arrow[{pt1, {0, 0, 0}, pt2}]}

 Table[Prepend[With[{m = ranOrt}, arrowCouple[{m.v1, m.v2}]], 
   Hue[RandomReal[], 1, 1, 0.2]], {100}], Boxed -> False]

randomly oriented planes spanned by arrows

(I know I can use GeometricTransformation[] for this, but I prefer the explicit approach here.)


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.