We now have the foundation we needed to introduce the concept of a vector. Everything we do for the remainder of the course will build upon this section.
import numpy as np
import plotly.graph_objects as go
from pathlib import Path as _PlotPath
import sys as _plot_sys
_notes_root = next(path for path in [_PlotPath.cwd(), *_PlotPath.cwd().parents] if (path / "myst.yml").exists())
if str(_notes_root) not in _plot_sys.path:
_plot_sys.path.insert(0, str(_notes_root))
from plot_style import style_plotly as _style_plotly
def _vector_figure(vectors, vdeltax=0.3, vdeltay=0.3, vdeltaz=0.3):
dimension = len(vectors[0][0][0])
fig = go.Figure()
for (start, end), color, label in vectors:
start = np.asarray(start, dtype=float)
end = np.asarray(end, dtype=float)
delta = end - start
if dimension == 2:
fig.add_trace(go.Scatter(
x=[start[0], end[0]], y=[start[1], end[1]], mode="lines",
line=dict(color=color, width=4), showlegend=False,
hovertemplate="(%{x}, %{y})<extra></extra>",
))
fig.add_annotation(
x=end[0], y=end[1], ax=start[0], ay=start[1],
xref="x", yref="y", axref="x", ayref="y",
showarrow=True, arrowhead=3, arrowsize=1.2, arrowwidth=3,
arrowcolor=color,
)
if label:
midpoint = (start + end) / 2
fig.add_annotation(
x=midpoint[0] + vdeltax, y=midpoint[1] + vdeltay,
text=label, showarrow=False, font=dict(color=color, size=16),
)
else:
fig.add_trace(go.Scatter3d(
x=[start[0], end[0]], y=[start[1], end[1]], z=[start[2], end[2]],
mode="lines", line=dict(color=color, width=8),
showlegend=False, hoverinfo="skip",
))
length = np.linalg.norm(delta)
if length:
unit = delta / length
fig.add_trace(go.Cone(
x=[end[0]], y=[end[1]], z=[end[2]],
u=[unit[0]], v=[unit[1]], w=[unit[2]],
anchor="tip", sizemode="absolute", sizeref=0.28,
colorscale=[[0, color], [1, color]], showscale=False,
hoverinfo="skip",
))
if label:
midpoint = (start + end) / 2
fig.add_trace(go.Scatter3d(
x=[midpoint[0] + vdeltax], y=[midpoint[1] + vdeltay],
z=[midpoint[2] + vdeltaz], mode="text", text=[label],
textfont=dict(color=color, size=16), hoverinfo="skip",
showlegend=False,
))
return fig
def plot_vectors_non_origin(vectors, **kwargs):
return _vector_figure(vectors, **kwargs)
def plot_vectors(vectors, **kwargs):
converted = []
for endpoint, color, label in vectors:
converted.append(((tuple(0 for _ in endpoint), endpoint), color, label))
return _vector_figure(converted, **kwargs)
def _set_vector_colors(fig, vectors, overrides):
if np.asarray(vectors[0][0]).ndim == 1:
vectors = [((tuple(0 for _ in endpoint), endpoint), color, label) for endpoint, color, label in vectors]
dimension = len(vectors[0][0][0])
trace_index = 0
annotation_index = 0
for vector_index, ((start, end), _, label) in enumerate(vectors):
color = overrides.get(vector_index)
if dimension == 2:
if color:
fig.data[trace_index].line.color = color
fig.layout.annotations[annotation_index].arrowcolor = color
if label:
fig.layout.annotations[annotation_index + 1].font.color = color
trace_index += 1
annotation_index += 1 + bool(label)
else:
if color:
fig.data[trace_index].line.color = color
trace_index += 1
if np.linalg.norm(np.asarray(end) - np.asarray(start)):
if color:
fig.data[trace_index].colorscale = [[0, color], [1, color]]
trace_index += 1
if label:
if color:
fig.data[trace_index].textfont.color = color
trace_index += 1
return fig
A common way to visualize a vector is as an arrow. Let’s start with some examples of vectors with two components:
u=[−42],v=[23],w=[50].
The default way to visualize a vector with two components is as an arrow from the origin, (0,0), to the point at the vector’s coordinates. For example, v can be visualized as the arrow from (0,0) to (2,3).
vectors = [
((-4, 2), "orange", r"$\vec u$"),
((2, 3), "#3d81f6", r"$\vec v$"),
((5, 0), "#d81a60", r"$\vec w$"),
]
fig = plot_vectors(vectors, vdeltax=0.2, vdeltay=0.35)
fig.update_layout(
width=800, height=500,
xaxis_title="$x$", yaxis_title="$y$", showlegend=False,
)
fig.update_xaxes(range=[-5, 6], dtick=1, scaleanchor="y")
fig.update_yaxes(range=[-1, 5], dtick=1)
_style_plotly(fig, renderer="png")
_set_vector_colors(fig, vectors, {0: "orange", 1: "#3d81f6", 2: "#d81a60"})
fig.layout.annotations[3].x += 0.7 # Move the v label to the right of its arrow.
fig.show(scale=2)
We often think of a vector as an object with a magnitude and direction:
The magnitude of a vector is the length of the corresponding arrow; we will define this formally in Chapter 1.5.
The direction of a vector has a formal definition that we will cover in due time. To get you thinking about what the definition of a vector’s direction might be, consider the fact that [12], [24], and [100200] all point in the same direction, so the formal definitions of their directions must all be the same.
But, a vector doesn’t inherently have a fixed position! The arrow from (0,0) to (2,3) is the same as the arrow from (3,1) to (5,4). In both cases, to travel from the first point to the second, one moves 2 units to the right and 3 units up.
import numpy as np
import plotly.graph_objects as go
# The vector v = (2,3)
v = np.array([2, 3])
# Different initial points
starts = np.array([
[0, 0],
[3, 1],
[-2, 2],
[1, -3],
[-3, -2],
])
fig = go.Figure()
for start in starts:
end = start + v
fig.add_trace(go.Scatter(
x=[start[0], end[0]], y=[start[1], end[1]], mode="lines",
line=dict(color="#3d81f6", width=4), showlegend=False,
hovertemplate="(%{x}, %{y})<extra></extra>",
))
fig.add_annotation(
x=end[0], y=end[1], ax=start[0], ay=start[1],
xref="x", yref="y", axref="x", ayref="y",
showarrow=True, arrowhead=3, arrowsize=1.2, arrowwidth=3,
arrowcolor="#3d81f6",
)
fig.add_trace(go.Scatter(
x=[start[0]], y=[start[1]], mode="markers",
marker=dict(size=7, color="#3d81f6"), showlegend=False,
hovertemplate="start: (%{x}, %{y})<extra></extra>",
))
fig.update_layout(
title=r"$$\text{These are all the same vector, } \vec v = \begin{bmatrix} 2 \\ 3 \end{bmatrix}$$", width=700, height=700,
xaxis_title="$x$", yaxis_title="$y$",
)
fig.update_xaxes(range=[-5, 7], dtick=1, scaleanchor="y")
fig.update_yaxes(range=[-5, 7], dtick=1)
_style_plotly(fig, renderer="png")
fig.show(scale=2)
So, we can think of a vector as representing the displacement between points.
Vectors have both a magnitude and direction. Real numbers, on the other hand, only have a numerical value, with no direction. To emphasize this difference, we will often call real numbers scalars. A scalar is just a single number.
You might have noticed that all of the example visualizations above involved vectors with exactly two components.
Indeed:
Vectors with two components can be visualized in two-dimensional space.
Vectors with three components can be visualized in three-dimensional space.
We can’t directly visualize vectors with more than three components in three-dimensional space. But that doesn’t mean they don’t exist! Vectors are often used to store real-world data, for use in building models for making predictions. Using an example from Chapter 1.3, if we collected a student’s age, height in inches, shoe size, number of siblings, and number of followers on Instagram, we could represent that student’s data as a vector with five components.
x=⎣⎡1968102450⎦⎤
In this setting, the components of x represent the student’s age, height, shoe size, number of siblings, and number of Instagram followers, in that order. We aren’t thinking of the student data vector as measuring any sort of displacement; it is being used to represent data.
It is useful to have a name to refer to the set of all vectors with a fixed number of components. In general, the set of vectors with n components is called Rn. We also referred to this set as the n-dimensional Euclidean space in Chapter 1.3. Think of n as the general placeholder for the number of components in a vector.
For instance, if w=⎣⎡352⎦⎤ and x=⎣⎡2.1e1.23.5⎦⎤, then it is valid to write
w∈R3
and
x∈R4.
These statements are pronounced “w is in R three” and “x is in R four”, respectively.
Vectors are new mathematical objects, and as such, we need to carefully define the operations that they support. Our focus for now is primarily vectors in R2 and R3 – that is, vectors with two or three components – since we can more easily visualize these vectors, and we want to build your geometric intuition. That said, we will still provide general formulas for vectors with any number of components, since it’s important to have a concrete sense of how these operations work.
Let’s start with vector addition. First, to be able to add two vectors, it is necessary that they have the same number of components. Given that is the case, the sum of two vectors is a new vector whose components are the sums of the components of the original two.
For example, if u=[12] and v=[3−1], then
u+v=[1+32+(−1)]=[41].
u and v are both vectors in R2, and so is their sum. If v had, say, three components, we couldn’t add it to u.
Let’s visualize the sum of these two vectors geometrically.
from IPython.display import display, HTML
import plotly.io as pio
import numpy as np
# Set default renderer to high-DPI static image
pio.renderers.default = "png"
display(HTML(
'<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG"></script>'
))
# ---
# Define vectors in the format: (((start_x, start_y), (end_x, end_y)), color, label)
vectors = [
(((0, 0), (1, 2)), 'orange', r'$\vec u$'), # u starts at origin
(((1, 2), (4, 1)), '#3d81f6', r'$\vec v$'), # v starts at tip of u
(((0, 0), (4, 1)), 'green', r'$\vec u + \vec v$') # u+v starts at origin, ends at tip of v
]
fig = plot_vectors_non_origin(vectors, vdeltax=0.4, vdeltay=0.4)
fig.update_layout(width=500, height=400, yaxis_scaleanchor="x")
fig.update_xaxes(range=[-1, 5], tickvals=np.arange(-2, 7))
fig.update_yaxes(range=[-1, 3], tickvals=np.arange(-2, 5))
_style_plotly(fig, renderer="png")
_set_vector_colors(fig, vectors, {0: "orange", 1: "#3d81f6"})
fig.show(scale=3)
Loading...
To compute u+v, we started by drawing u at the origin, and placed v’s tail at the tip of u. Remember that vectors have no fixed position, so this is legal – v can be placed at (1,2) just as well as it can be placed at (0,0).
After placing v’s tail at the tip of u, the vector from the origin to the tip of v is the sum, u+v. This is sometimes called the tip-to-tail method.
Does it matter that we “started” with u at the origin? No! We could have placed v at the origin and u at its tip, and we would have ended up with the same sum.
from IPython.display import display, HTML
import plotly.io as pio
import numpy as np
# Set default renderer to high-DPI static image
pio.renderers.default = "png"
display(HTML(
'<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG"></script>'
))
# ---
# Define vectors in the format: (((start_x, start_y), (end_x, end_y)), color, label)
vectors = [
(((0, 0), (3, -1)), '#3d81f6', r'$\vec v$'), # v starts at origin
(((3, -1), (4, 1)), 'orange', r'$\vec u$'), # u starts at tip of v
(((0, 0), (4, 1)), 'green', r'$\vec v + \vec u$') # v+u starts at origin, ends at tip of u
]
fig = plot_vectors_non_origin(vectors, vdeltax=0.4, vdeltay=0.4)
fig.update_layout(width=500, height=400, yaxis_scaleanchor="x")
fig.update_xaxes(range=[-1, 5], tickvals=np.arange(-2, 7))
fig.update_yaxes(range=[-1, 3], tickvals=np.arange(-2, 5))
_style_plotly(fig, renderer="png")
_set_vector_colors(fig, vectors, {0: "#3d81f6", 1: "orange"})
fig.show(scale=3)
Loading...
What this is showing us is that vector addition is commutative: the order in which we add vectors does not matter.
Another viewpoint – one that will be especially important when we subtract two vectors – is to place both vectors u and v at the origin, and interpret u+v as the diagonal of the parallelogram formed by the two vectors. (For more on parallelograms, see Activity 1 from above.)
import plotly.io as pio
import plotly.graph_objects as go
import numpy as np
# Set default renderer to high-DPI static image
pio.renderers.default = "png"
# ---
# Define the primary vectors and their resultant sum starting from the origin
vectors = [
(((0, 0), (1, 2)), 'orange', '<i>u</i>\u20D7'),
(((0, 0), (3, -1)), '#3d81f6', '<i>v</i>\u20D7'),
(((0, 0), (4, 1)), 'green', '<i>u</i>\u20D7 + <i>v</i>\u20D7')
]
# Generate the figure using the custom utility
fig = plot_vectors_non_origin(vectors, vdeltax=0.4, vdeltay=0.4)
# Add dashed lines to explicitly show the parallelogram
# 1. Edge parallel to v, starting at the tip of u (1, 2) and ending at the sum (4, 1)
fig.add_trace(go.Scatter(
x=[1, 4], y=[2, 1], mode='lines',
line=dict(color='gray', width=2, dash='dash'),
showlegend=False, hoverinfo='skip'
))
# 2. Edge parallel to u, starting at the tip of v (3, -1) and ending at the sum (4, 1)
fig.add_trace(go.Scatter(
x=[3, 4], y=[-1, 1], mode='lines',
line=dict(color='gray', width=2, dash='dash'),
showlegend=False, hoverinfo='skip'
))
# Format the layout to keep the grid perfectly square
fig.update_layout(width=600, height=600, yaxis_scaleanchor="x")
# Set the grid to comfortably frame the entire parallelogram
fig.update_layout(width=500, height=400, yaxis_scaleanchor="x")
fig.update_xaxes(range=[-1, 5], tickvals=np.arange(-2, 7))
fig.update_yaxes(range=[-1, 3], tickvals=np.arange(-2, 5))
# Export statically
_style_plotly(fig, renderer="png")
_set_vector_colors(fig, vectors, {0: "orange", 1: "#3d81f6"})
fig.show(scale=3)
Vector addition works the same way in R3. For example, let
u=⎣⎡221⎦⎤,v=⎣⎡−122⎦⎤.
Drawing v from the tip of u gives the sum u+v=⎣⎡143⎦⎤.
# Draw u, then v from the tip of u, and connect the origin to their sum.
vectors = [
(((0, 0, 0), (2, 2, 1)), "orange", "<i>u</i>\u20D7"),
(((2, 2, 1), (1, 4, 3)), "#3d81f6", "<i>v</i>\u20D7"),
(((0, 0, 0), (1, 4, 3)), "#d81a60", "<i>u</i>\u20D7 + <i>v</i>\u20D7"),
]
fig = plot_vectors_non_origin(vectors, vdeltax=0.2, vdeltay=0.2, vdeltaz=0.2)
fig.update_layout(
width=600, height=500,
scene=dict(
xaxis=dict(range=[-1, 3], dtick=1),
yaxis=dict(range=[0, 5], dtick=1),
zaxis=dict(range=[0, 4], dtick=1),
aspectratio=dict(x=1, y=1, z=1),
),
)
_style_plotly(fig, renderer="plotly_mimetype")
_set_vector_colors(fig, vectors, {0: "orange", 1: "#3d81f6", 2: "#d81a60"})
fig.show()
Loading...
How do we add three or more vectors? Associativity says that the placement of parentheses does not matter:
(u+v)+w=u+(v+w).
Let’s illustrate using the following three vectors in R2:
Now that we have a solid understanding by way of examples, let us state a formal definition of vector addition. If v is a vector in Rn, it’s common to use the scalars v1,v2,...,vn to represent the components of v:
Note that we have deliberately defined this operation as scalar multiplication, not just “multiplication” in general: this operation involves multiplying a vector by a scalar, not two vectors together. We will define one way of multiplying vectors in Chapter 1.5, when we study the dot product.
Similar to vector addition, scalar multiplication can also be viewed geometrically. Consider v=[3−1] along with two of its scalar multiples:
from IPython.display import display, HTML
import plotly.io as pio
import numpy as np
# Set default renderer to high-DPI static image
pio.renderers.default = "png"
display(HTML(
'<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG"></script>'
))
# ---
# Draw 3v first so that v remains visible on top of it.
vectors = [
((9, -3), "black", r"$3\vec{v}$"),
((3, -1), "#3d81f6", r"$\vec{v}$"),
((-1.5, 0.5), "gray", r"$-\frac{1}{2}\vec{v}$"),
]
# Adjust vdeltax and vdeltay to position the labels
fig = plot_vectors(vectors, vdeltax=0.4, vdeltay=-0.4)
# Lock the aspect ratio so the scaling is visually accurate
fig.update_layout(width=800, height=450, yaxis_scaleanchor="x")
fig.update_xaxes(range=[-2, 10], tickvals=np.arange(-2, 11))
fig.update_yaxes(range=[-4, 2], tickvals=np.arange(-4, 3))
_style_plotly(fig, renderer="png")
_set_vector_colors(fig, vectors, {0: "black", 1: "#3d81f6", 2: "gray"})
fig.layout.annotations[5].x -= 0.25
fig.layout.annotations[5].y += 0.75
fig.show(scale=3)
Loading...
The vector 3v points in the same direction as v and is three times as long. The vector −21v points in the opposite direction and is half as long. In general, the absolute value of the scalar determines the change in length, while a negative sign reverses the direction.
It is worth questioning: what happens if we multiply a vector by the scalar 0? The result is the zero vector, which we will discuss momentarily.
Addition and scalar multiplication are the core building blocks of vectors. We can perform both operations in a single expression, e.g.
3u−4v.
A vector that results from scaling and adding one or more vectors is called a linear combination of the original vectors. As with vector addition, we will build an understanding through examples, before concluding with a formal definition.
What does it mean to subtract one vector from another? To subtract v from u, all we need to do is multiply v by the scalar -1, and add the resulting vector to u.
u−(v)=u+(−v).
Remember that −v is a vector with the same magnitude (length) as v, just pointing in the opposite direction.
vectors = [
(((0, 0), (1, 2)), 'orange', '<i>u</i>\u20D7'),
(((0, 0), (3, -1)), '#3d81f6', '<i>v</i>\u20D7'),
(((0, 0), (1 - 3, 2 - (-1))), '#d81a60', '<i>u</i>\u20D7 - <i>v</i>\u20D7'),
(((1, 2), (1 - 3, 2 - (-1))), 'gray', '-<i>v</i>\u20D7'), # -v from tip of u to u - v
(((3, -1), (1, 2)), '#d81a60', None), # u-v from the tip of v to the tip of u
]
fig = plot_vectors_non_origin(vectors, vdeltax=0.4, vdeltay=0.2)
fig.update_layout(width=600, height=600, yaxis_scaleanchor="x")
fig.update_xaxes(range=[-3, 3], tickvals=np.arange(-3, 4))
fig.update_yaxes(range=[-2, 4], tickvals=np.arange(-2, 5))
_style_plotly(fig, renderer="png")
_set_vector_colors(
fig,
vectors,
{
0: "orange",
1: "#3d81f6",
2: "#d81a60",
3: "gray",
4: "#d81a60",
}
)
# Show the translated copy of u-v as a dotted arrow from v to u.
fig.data[4].line.dash = "dot"
dotted_direction = np.array([1, 2]) - np.array([3, -1])
dotted_direction = dotted_direction / np.linalg.norm(dotted_direction)
fig.layout.annotations[-1].ax = 1 - 0.25 * dotted_direction[0]
fig.layout.annotations[-1].ay = 2 - 0.25 * dotted_direction[1]
fig.add_annotation(
x=2.35, y=0.75, text='<i>u</i>\u20D7 - <i>v</i>\u20D7',
showarrow=False, font=dict(color="#d81a60", size=16),
)
fig.show(scale=3)
Notice that u−v is also the vector that results from drawing an arrow from the tip of v to the tip of u, when bothu and v are drawn at the origin! This is why we earlier described u−v as being one of the diagonals of the parallelogram formed by u and v.
The previous example raises an important point: what happens when you subtract a vector from itself? Again, suppose v=[3−1]. Then,
v−v=[3−1]−[3−1]=[00]=0.
A vector in which all components are equal to 0 is called a zero vector, 0. When we say “the” zero vector, the number of components in that zero vector is usually clear from the context. The zero vector has a length of 0, and its direction is undefined: it looks like a point at the origin.
# Draw u, then v, then w so that the three displacements close the path.
vectors = [
(((0, 0), (-2, 3)), "orange", "<i>u</i>\u20D7"),
(((-2, 3), (2, 4)), "#3d81f6", "<i>v</i>\u20D7"),
(((2, 4), (0, 0)), "#d81a60", "<i>w</i>\u20D7"),
]
fig = plot_vectors_non_origin(vectors, vdeltax=0.3, vdeltay=0.25)
fig.update_layout(
width=600, height=600,
xaxis_title="$x$", yaxis_title="$y$", showlegend=False,
)
fig.update_xaxes(range=[-3, 3], dtick=1, scaleanchor="y")
fig.update_yaxes(range=[-1, 5], dtick=1)
_style_plotly(fig, renderer="png")
_set_vector_colors(fig, vectors, {0: "orange", 1: "#3d81f6", 2: "#d81a60"})
fig.write_image(_notes_root / "ch01" / "imgs" / "activity2-close-loop.png", scale=2)
Observe: every vector in R2 can be written as a sum of scalar multiples of two specific vectors: [10] and [01]. For example,
v=[3−1]=3[10]+(−1)[01].
The vectors [10] and [01] have a special name: they are the standard basis vectors for R2. Think of them as the default building blocks that we use to express all other vectors with two components.
“Basis” has a formal definition that we will see later; the main idea for now is that the standard basis vectors in Rn can be used to express every single vector in Rn, and furthermore, the way to express every vector is unique.
Let’s focus on vectors in R2. For example, observe that
[23]=[20]+[03]=2[10]+3[01]=2e1+3e2.
This decomposition is unique, meaning that there is no other way to construct [23] using e1 and e2 as building blocks.
from IPython.display import display, HTML
import plotly.io as pio
import numpy as np
# Set default renderer to high-DPI static image
pio.renderers.default = "png"
display(HTML(
'<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG"></script>'
))
# ---
# Decompose [2, 3] into scaled copies of the standard basis vectors.
vectors = [
(((0, 0), (2, 0)), "#3d81f6", r"$2\vec e_1$"),
(((2, 0), (2, 3)), "#3d81f6", r"$3\vec e_2$"),
(((0, 0), (1, 0)), "black", r"$\vec e_1$"),
(((0, 0), (0, 1)), "black", r"$\vec e_2$"),
(((0, 0), (2, 3)), "orange", r"$\begin{bmatrix}2 \\ 3\end{bmatrix}$"),
]
fig = plot_vectors_non_origin(vectors, vdeltax=0.3, vdeltay=0.3)
fig.update_layout(width=600, height=600, yaxis_scaleanchor="x")
fig.update_xaxes(range=[-1, 4], dtick=1)
fig.update_yaxes(range=[-1, 4], dtick=1)
_style_plotly(fig, renderer="png")
_set_vector_colors(
fig, vectors,
{0: "#3d81f6", 1: "#3d81f6", 2: "black", 3: "black", 4: "orange"},
)
fig.layout.annotations[5].x = 0.5
fig.layout.annotations[5].y = -0.35
fig.layout.annotations[7].x = -0.35
fig.layout.annotations[7].y = 0.5
# Move the [2, 3] annotation up by 1 unit on the y-axis
fig.layout.annotations[9].y += 1
fig.show(scale=3)
Loading...
In effect, we are decomposing [23] as a sum of a vector parallel to the x-axis (a “horizontal” vector) and one parallel to the y-axis (a “vertical” vector).
The same principle holds in R3: any vector with three components can be decomposed as a sum of three vectors, one parallel to each of the x-, y-, and z-axes. For example,
# Decompose [2, 3, -1] into scaled copies of the standard basis vectors, showing only e's and the final vector.
vectors = [
(((0, 0, 0), (1, 0, 0)), "black", "e<sub>1</sub>"),
(((0, 0, 0), (0, 1, 0)), "black", "e<sub>2</sub>"),
(((0, 0, 0), (0, 0, 1)), "black", "e<sub>3</sub>"),
(((0, 0, 0), (2, 3, -1)), "orange", "[2, 3, -1]"),
]
fig = plot_vectors_non_origin(vectors, vdeltax=0.18, vdeltay=0.18, vdeltaz=0.18)
_style_plotly(fig, renderer="plotly_mimetype")
fig.update_layout(
width=700, height=600,
scene=dict(
xaxis=dict(range=[-2, 4], dtick=1, gridcolor="#f0f0f0", linecolor="#f0f0f0"),
yaxis=dict(range=[-2, 5], dtick=1, gridcolor="#f0f0f0", linecolor="#f0f0f0"),
zaxis=dict(range=[-2, 2], dtick=1, gridcolor="#f0f0f0", linecolor="#f0f0f0"),
aspectmode="cube",
),
)
_set_vector_colors(
fig, vectors,
{
0: "black", 1: "black", 2: "black", 3: "orange"
},
)
# Draw faint coordinate axes through the origin.
axis_segments = [
([-2, 4], [0, 0], [0, 0]),
([0, 0], [-2, 5], [0, 0]),
([0, 0], [0, 0], [-2, 2]),
]
for x, y, z in axis_segments:
fig.add_trace(go.Scatter3d(
x=x, y=y, z=z, mode="lines",
line=dict(color="#f0f0f0", width=3), opacity=0.85,
hoverinfo="skip", showlegend=False,
))
# Keep the vectors visually on top of the coordinate axes.
fig.data = fig.data[-3:] + fig.data[:-3]
fig.show()
Loading...
Note: the plot above shows the vector ⎣⎡23−1⎦⎤ written horizontally; this is just due to a limitation in the plotting system, and it is not meant to be written horizontally.
Why would we ever need to break a vector into its components this way? The decomposition tells us how much of the vector lies in each coordinate direction, which lets us analyze or change those directions separately.
In physics, for example, we can split a force into horizontal and vertical components and apply Newton’s laws along each axis.
In data analysis, each basis direction can represent a different measured feature, allowing us to study the contribution of each feature separately.
In general, a vector v∈Rn can be expressed as
⎣⎡v1⋮vn⎦⎤=v1e1+⋯+vnen,
where e1 is the first standard basis vector in Rn – a vector with a 1 at position 1 and 0’s in all other positions – e2 is the second standard basis vector, and so on.
All of these expressions are examples of linear combinations: each expression involves scaling and adding vectors together to create another vector. Think of the original vectors, such as u and v in the expression 3u−4v, as “building blocks.” The scalars 3 and -4 tell us how much of each building block to use. Adding the scaled vectors creates the new vector 3u−4v.
We have used v1,v2,…,vk as placeholders to give a general formula for cases where we have an arbitrary number of vectors, not just two or three. Here, k is the placeholder for the number of vectors we have. In concrete examples, we may label our vectors v1,v2,… or simply u,v. These are all just symbols. The important thing to look for is whether v has the vector arrow on top: v1 is a vector, but v1 is a scalar.
The type of question we will start asking is, “Can this vector be made out of a linear combination of these other vectors?” The answer is not always yes!
For example, suppose
u=⎣⎡100⎦⎤andv=⎣⎡010⎦⎤.
Every linear combination of u and v has the form
au+bv=⎣⎡ab0⎦⎤.
No matter how hard we try, the last component will always be zero. Therefore, no linear combination of u and v can reach ⎣⎡−121⎦⎤, or any other vector in R3 whose last component is nonzero.
# Compare u and v with a vector they cannot reach.
vectors = [
(((0, 0, 0), (1, 0, 0)), "orange", "u"),
(((0, 0, 0), (0, 1, 0)), "#3d81f6", "v"),
(((0, 0, 0), (-1, 2, 1)), "#d81a60", "[-1, 2, 1]"),
]
fig = plot_vectors_non_origin(vectors, vdeltax=0.18, vdeltay=0.18, vdeltaz=0.18)
_style_plotly(fig, renderer="plotly_mimetype")
_set_vector_colors(fig, vectors, {0: "orange", 1: "#3d81f6", 2: "#d81a60"})
# Draw the coordinate axes through the origin.
axis_segments = [
([-1.5, 1.5], [0, 0], [0, 0]),
([0, 0], [-0.5, 2.5], [0, 0]),
([0, 0], [0, 0], [-0.5, 2.5]),
]
for x, y, z in axis_segments:
fig.add_trace(go.Scatter3d(
x=x, y=y, z=z, mode="lines",
line=dict(color="#f0f0f0", width=3), opacity=0.55,
hoverinfo="skip", showlegend=False,
))
# Keep the vectors visually on top of the coordinate axes.
fig.data = fig.data[-3:] + fig.data[:-3]
fig.update_layout(
width=700, height=600,
scene=dict(
xaxis=dict(range=[-1.5, 1.5], dtick=1, gridcolor="#f0f0f0", linecolor="#f0f0f0"),
yaxis=dict(range=[-0.5, 2.5], dtick=1, gridcolor="#f0f0f0", linecolor="#f0f0f0"),
zaxis=dict(range=[-0.5, 2.5], dtick=1, gridcolor="#f0f0f0", linecolor="#f0f0f0"),
aspectmode="cube",
camera=dict(eye=dict(x=1.45, y=1.45, z=1.15)),
),
)
fig.show()
Loading...
In Chapter 1.5, we will formally define the magnitude, or length, or a vector.