# How do you draw the plane on which two vectors lie?

Given two arbitrary vectors $\textbf{v}_1$ and $\textbf{v}_2$, how can I draw the plane which they span?

• To give a mathematical viewpoint: both Mark's and David S.'s approaches use the Hessian normal form of a plane. I would say that if you're trying to do anything mathematical in Mathematica, MathWorld is one of those places you should try looking for formulae in... – J. M.'s torpor Feb 7 '12 at 23:06

SeedRandom;
{v1, v2} = RandomReal[{-2, 2}, {2, 3}];
n = Cross[v1, v2];
Show[{
ContourPlot3D[n.{x, y, z} == 0, {x, -2, 2}, {y, -2, 2}, {z, -2, 2},
ContourStyle -> Opacity[0.5], Mesh -> False],
Graphics3D[{Arrow[{{0, 0, 0}, v1}], Arrow[{{0, 0, 0}, v2}]}]
}] Here's an example of how you could do it:

v1 = {1, -1/2, -1.9}; (* pick something *)
v2 = {0, 1, -1}; (* pick something *)
r0 = {-1/2, 1/2, 3/4}; (* point in the plane; pick something *)

nn = Normalize[Cross[v1-r0, v2-r0]];
r = {rx, ry, rz};
sol = Solve[Dot[nn, (r - r0)] == 0, {rz}] // Simplify
Plot3D[rz /. sol, {rx, -10, 10}, {ry, -10, 10}] • Yeah, this is definitely much better than my idea. – David Z Feb 7 '12 at 22:53
• It seems you've misapplied the formula for the Hessian normal form here. (rz - Last[v1] /. First[Solve[Dot[nn, (r - r0)] == 0, {rz}]]) /. Thread[{rx, ry} -> Take[v1, 2]] ought to be yielding 0, but it doesn't, and similarly for the version where v1 is replaced by v2. There is a simple fix: use nn = Normalize[Cross[v1 - r0, v2 - r0]]; instead for computing the normal vector. – J. M.'s torpor Feb 8 '12 at 5:28
• @J.M. You are, of course, correct--thanks for the correction! I am fixing my answer accordingly. – Cassini Feb 8 '12 at 15:30

Another option is to use Graphics3D primitives

Graphics3D[Polygon[{{0,0,0},v1,v1+v2,v2}]]


Edit

J.M. already gave one way to produce a square spanned by the two vectors as a Polygon. Another way would be to use Rotate:

{v1, v2} = RandomReal[{-1, 1}, {2, 3}]

Graphics3D[{
Rotate[Polygon[{{-1, -1, 0}, {1, -1, 0}, {1, 1, 0}, {-1, 1, 0}}],
{{0, 0, 1}, Cross[v1, v2]}],
Arrow[{{0, 0, 0}, v1}],
Arrow[{{0, 0, 0}, v2}]}] • just ahead of me again! serves me right for trying to put a nice texture on it... – acl Feb 7 '12 at 22:55
• @acl Blame David Zaslavsky. I was busy typing a ParametricPlot3D solution but had to switch tactics when his solution popped up. – Heike Feb 7 '12 at 23:02
• I think this is the most elegant – acl Feb 7 '12 at 23:04
• The problem with this method (and mine as well) is that you don't get the whole plane, only the piece of it that is directly bounded by the given vectors. So while it is elegant, I think you're answering something a little different from what the question is actually looking for. – David Z Feb 7 '12 at 23:04
• @acl at least it's the shortest. – Heike Feb 7 '12 at 23:05

I present here a modification of Heike's approach that might be attractive for some applications; it produces a square with side length c as a Polygon[] object, representing the plane spanned by v1 and v2, with origin at r0:

v1 = {1, -1/2, -19/10}; v2 = {0, 1, -1}; (* spanning vectors *)
r0 = {-1/2, 1/2, 3/4}; (* origin *)
{o1, o2, o3} = Orthogonalize[Append[#, Cross @@ #]] &[{v1 - r0, v2 - r0}];
With[{c = 6}, (* generate a c×c square *)
Graphics3D[{{Directive[EdgeForm[], Gray],
Polygon[{r0 + c (o1 + o2)/2, r0 - c (o1 - o2)/2,
r0 - c (o1 + o2)/2, r0 + c (o1 - o2)/2}]},
{Red, Arrow[{r0, v1}], Arrow[{r0, v2}]},
{Blue, Arrow[{r0, r0 + Cross[v1 - r0, v2 - r0]}]}},
Boxed -> False, Lighting -> "Neutral", PlotRange -> All]] As can be seen from the code, the trick is in producing mutually orthogonal unit vectors via Orthogonalize[] (for older versions, use QRDecomposition[] instead and take the $\mathbf Q$ factor) that can be nicely scaled/combined afterwards.

Here's how to verify that a square is indeed produced as claimed:

FullSimplify[Map[Norm, Differences[Append[#, First[#]]]]&[{r0 + c (o1 + o2)/2,
r0 - c (o1 - o2)/2, r0 - c (o1 + o2)/2, r0 + c (o1 - o2)/2}], c > 0]
{c, c, c, c}


If your vectors are three-element lists, here's one way (though I really feel like a hack for suggesting this):

ParametricPlot3D[u v1 + v v2, {u,-1,1},{v,-1,1},
PlotRange->{{-1,1},{-1,1},Automatic}]


You may have to adjust the limits of -1 and 1 depending on how much of the plane you want to plot.

Using

v1 = {1, -1/2, -19/10}; v2 = {0, 1, -1}; (* spanning vectors *)
r0 = {-1/2, 1/2, 3/4}; (* origin *)


as a concrete example, I present here, for giggles, variations of Mark's and David Skulsky's answers, based on formula 18 here.

Mark:

Show[ContourPlot3D[
Det[PadRight[{{x, y, z}, r0, v1, v2}, {4, 4}, 1]] == 0, {x, -3,
3}, {y, -3, 3}, {z, -3, 3}, BoxRatios -> Automatic,
ContourStyle -> Opacity[0.5], Mesh -> False],
Graphics3D[{{Red, Arrow[{r0, v1}], Arrow[{r0, v2}]}, {Blue,
Arrow[{r0, r0 + Cross[v1 - r0, v2 - r0]}]}}]] David (plus Heike's suggestion):

Show[Plot3D[
Evaluate[z /.
First[Solve[
Det[PadRight[{{x, y, z}, r0, v1, v2}, {4, 4}, 1]] == 0,
z]]], {x, -2, 2}, {y, -2, 2}, BoxRatios -> Automatic,
MaxRecursion -> 1, Mesh -> 0, PlotPoints -> 2],
Graphics3D[{{Red, Arrow[{r0, v1}], Arrow[{r0, v2}]}, {Blue,
Arrow[{r0, r0 + Cross[v1 - r0, v2 - r0]}]}}]] Interactive - drag orange dots around.

Manipulate[ Graphics3D[{{Blue, Opacity[.5], Polygon[{{-1, -1, 0}, {1, -1, 0},
{1, 1, 0}, {-1, 1, 0}}]}, {Red, Thick, Arrow[{{0, 0, 0}, Flatten@{p, 0}}]},
{Black, Thick, Arrow[{{0, 0, 0}, Flatten@{q, 0}}]}}, SphericalRegion -> True,
Boxed -> False, ViewAngle -> .37],{{p, {1, 0}}, {-1, -1},{1, 1}},{{q, {0, 1}},
{-1, -1}, {1, 1}}, ControlPlacement -> Left] SeedRandom
{v1, v2} = RandomReal[{-5, 5}, {2, 3}];

Graphics3D[{Arrow[{{0, 0, 0}, v1}], Arrow[{{0, 0, 0}, v2}]},
ClipPlanes -> InfinitePlane[{{0, 0, 0}, v1, v2}],
ClipPlanesStyle -> Opacity[0.3, Green],
PlotRange -> {{-5, 5}, {-5, 5}, {-5, 5}}] 