Given two arbitrary vectors $\textbf{v}_1$ and $\textbf{v}_2$, how can I draw the plane which they span?
-
3To 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 missing motivation Feb 07 '12 at 23:06
9 Answers
SeedRandom[3];
{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}]}]
}]

- 271,378
- 34
- 587
- 1,371
- 32,469
- 3
- 103
- 161
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}]

- 5,556
- 5
- 28
- 38
-
-
1It 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 yielding0, but it doesn't, and similarly for the version wherev1is replaced byv2. There is a simple fix: usenn = Normalize[Cross[v1 - r0, v2 - r0]];instead for computing the normal vector. – J. M.'s missing motivation Feb 08 '12 at 05:28 -
@J.M. You are, of course, correct--thanks for the correction! I am fixing my answer accordingly. – Cassini Feb 08 '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}]}]

- 35,858
- 3
- 108
- 157
-
just ahead of me again! serves me right for trying to put a nice texture on it... – acl Feb 07 '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 07 '12 at 23:02
-
1
-
1The 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 07 '12 at 23:04
-
-
@David on the other hand, you can't actually draw the whole plane spanned by them, as the question asks :) – acl Feb 07 '12 at 23:06
-
@acl: heh, true :-) Naturally, I meant that with this solution and mine, the bounds of the region of the plane which is rendered need to be set separately from the bounds of the plot region, as opposed to Mark's and (other) David's solutions which automatically plot as much of the plane as will fit in the specified axes. – David Z Feb 07 '12 at 23:09
-
Of course, one could modify Heike's approach (which is important since you effectively use just one
Polygon[]for your plane) by orthogonalizing and then multiplying your now-orthogonal vectors with a scale factor. – J. M.'s missing motivation Feb 07 '12 at 23:16 -
@J.M. The number of Polygons used in for example David Skulsky's solution can be reduced quite a bit by setting
PlotPoints->2, MaxRecursion->1. – Heike Feb 07 '12 at 23:23
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.
- 4,921
- 4
- 25
- 35
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}
- 124,525
- 11
- 401
- 574
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]

- 73,078
- 9
- 204
- 355
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]}]}}]]
![plane spanned by vectors, ContourPlot3D[] version.](../../images/8b193f9130068a43b24bdb7577beae32.webp)
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]}]}}]]
![plane spanned by vectors, Plot3D[] version.](../../images/f6a4a5e2ce5a9e9ef8c30efd37c139f7.webp)
- 124,525
- 11
- 401
- 574
SeedRandom[1]
{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}}]

- 394,356
- 18
- 477
- 896
If vectors are no parallel, you can get a nice orthonormal basis for the plane so you can control the plane sides.
v1 = {1, -1/2, -19/10}; v2 = {0, 1, -1};(*spanning vectors*)
{u, v} = Orthogonalize[{v1, v2}];
Graphics3D[{(Plane)
First@ParametricPlot3D[t u + s v, {t, -1, 2}, {s, -3, 2.5},
Mesh -> None, PlotStyle -> {Opacity[0.4], Gray}],
(First@ParametricPlot3D[t v1 + s v2, {t, -1, 2}, {s, -3, 2.5},
Mesh -> None, PlotStyle -> {Opacity[0.4], Gray}],)
(Vectors)
Arrowheads[{0.06}], AbsoluteThickness[3.5],
Arrow[{{0, 0, 0}, v1}], Orange, Arrow[{{0, 0, 0}, v2}]
}, Boxed -> False, ViewPoint -> {3, 0.09, 1.3}]
Or simply you can draw an paralelogram
v1 = {1, -1/2, -19/10}; v2 = {0, 1, -1}; or3 = {0, 0, 0};
Graphics3D[{(*Plane*)
EdgeForm[Thin],
FaceForm[{Gray, Opacity[0.1]}], Polygon[{v1, or3, v2, v1 + v2}],
(*Vectors*)
Arrowheads[{0.06}], AbsoluteThickness[3.5],
Arrow[{{0, 0, 0}, v1}], Orange, Arrow[{{0, 0, 0}, v2}]
}, Boxed -> False, ViewPoint -> {3, 0.09, 1.3}]
- 589
- 2
- 9

