Build the matrix of any linear motion of the plane by asking where the two basis vectors land: scaling, rotation by any angle, shear, reflection and projection. Derive the rotation matrix from the unit circle, and see which maps keep lengths and which keep areas.
Write down the matrix of a scaling, a rotation, a shear, a reflection and a projection by asking where the two basis vectors land.
Derive the rotation matrix for an angle from the unit circle, and explain where its minus sign sits and why.
Apply a rotation and a shear to a vector by hand and check the result by measuring lengths.
State which of these maps keep lengths, which keep areas, and which cannot be undone.
In review. The maths and code on this page are checked by automated tests on every change, but an independent reader has not signed it off yet. Spot a mistake or a confusing step? Tell us.
The question
A phone turns a photo upright. A vision model is trained on copies of each picture that have been turned and slanted a little, so that it learns to know a cat at any tilt. Each of those motions is a matrix of four numbers. Which four numbers turn the whole plane by 30 degrees, and can you work them out rather than memorise them?
From the last lesson
1. What do the two columns of a \(2 \times 2\) matrix record?
Show answer
Where the basis vectors land. The first column is \(T(\ihat)\) and the second is \(T(\jhat)\).
2. State the definition of \(\mat{A}\vect{v}\) for \(\vect{v} = (x, y)\) in words.
Show answer
Take \(x\) times the first column of \(\mat{A}\) plus \(y\) times the second column.
Intuition
The last lesson read a matrix by asking two questions: where does \(\ihat\) land, and where does \(\jhat\) land? This lesson runs the idea backwards. To build the matrix of a motion you can picture, ask the same two questions and write the answers down as columns.
M02.4.3-F1
A rotation and a shear. In each panel the two vermillion arrows are where \(\ihat\) and \(\jhat\) land, and they are the two columns of the matrix printed below.
Check the shear panel. \(\ihat\) has not moved, so the first column is \((1, 0)\). The tip of \(\jhat\) has slid one unit to the right, to \((1, 1)\), so that is the second column. The picture and the matrix say the same thing.
Build it up
One motion at a time. Each step asks the two questions and nothing else.
Step 1. Scaling. Stretch the plane by a factor \(a\) sideways and a factor \(d\) upwards. Then \(\ihat\) lands on \((a, 0)\) and \(\jhat\) on \((0, d)\):
\[
\begin{bmatrix} a & 0 \\ 0 & d \end{bmatrix}.
\]
With \(a = d = 1\) nothing moves, and the matrix is the identity.
Step 2. A quarter turn. Turn the plane by \(90°\) anticlockwise. The arrow \(\ihat\), which pointed right, now points up: it lands on \((0, 1)\). The arrow \(\jhat\), which pointed up, now points left: it lands on \((-1, 0)\). So a quarter turn has matrix \(\begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix}\), and it sends any vector \((a, b)\) to \(a\,(0, 1) + b\,(-1, 0) = (-b, a)\).
Step 3. A turn by any angle \(\theta\). First, is a rotation linear at all? Yes. It moves every shape rigidly. Turn the parallelogram that builds \(\vect{u} + \vect{v}\) and you get the parallelogram that builds the turned \(\vect{u}\) plus the turned \(\vect{v}\): that is additivity. Turn an arrow that was stretched by \(c\) and you get the turned arrow stretched by \(c\): that is homogeneity. So a rotation has a matrix, and we only need two landing spots.
M02.4.3-F2
The two columns of the rotation matrix, read off the unit circle. Left:\(\ihat\) is turned to the point at angle \(\theta\). Right:\(\jhat\) starts a quarter turn ahead of \(\ihat\), so its triangle is the same triangle, a quarter turn on.
Where \(\ihat\) lands. The tip of \(\ihat\) sits on the unit circle at angle \(0\). Turning by \(\theta\) carries it along the circle to angle \(\theta\). The point of the unit circle at angle \(\theta\) is \((\cos\theta, \sin\theta)\): that is how cosine and sine are defined. In the left panel the right-angled triangle has a long side of length 1, so its horizontal side is \(\cos\theta\) and its vertical side is \(\sin\theta\).
Where \(\jhat\) lands. The tip of \(\jhat\) starts at angle \(90°\), a quarter turn ahead of \(\ihat\). After the rotation it is still a quarter turn ahead of where \(\ihat\) landed. So take the landing spot of \(\ihat\), which is \((\cos\theta, \sin\theta)\), and give it a quarter turn. Step 2 says a quarter turn sends \((a, b)\) to \((-b, a)\), so \(\jhat\) lands on \((-\sin\theta, \cos\theta)\). The right panel shows the same thing: the triangle has been turned, so the side \(\cos\theta\) now runs up and the side \(\sin\theta\) now runs to the left, which is where the minus sign comes from.
Two checks. At \(\theta = 90°\), \(\cos\theta = 0\) and \(\sin\theta = 1\), and the matrix becomes the quarter turn of Step 2. At \(\theta = 0\) it is the identity.
Step 4. Shear. Hold the horizontal axis still and slide everything above it sideways, in proportion to its height. Then \(\ihat\) does not move, and \(\jhat\), at height 1, slides \(k\) units to land on \((k, 1)\):
It sends \((x, y)\) to \(x\,(1, 0) + y\,(k, 1) = (x + ky,\; y)\). Heights do not change. A point at height \(y\) moves sideways by \(ky\). Slanted (oblique) type is upright type after a shear.
Step 5. Reflection. Mirror the plane in the vertical axis. \(\ihat\) flips to \((-1, 0)\) and \(\jhat\), which lies on the mirror, stays at \((0, 1)\): the matrix is \(\begin{bmatrix} -1 & 0 \\ 0 & 1 \end{bmatrix}\). Mirroring in the horizontal axis instead gives \(\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}\).
Step 6. Projection onto an axis. Drop every point straight down onto the horizontal axis. \(\ihat\) is already on the axis and stays at \((1, 0)\). \(\jhat\) drops to the origin, \((0, 0)\). The matrix is \(\begin{bmatrix} 1 & 0 \\ 0 & 0 \end{bmatrix}\), and it sends \((x, y)\) to \((x, 0)\).
M02.4.3-F5
The gallery: all six maps side by side. Each matrix is its two vermillion arrows, written as columns.
The formal statement
NoteThe five families
For any numbers \(a\), \(d\), \(k\) and any angle \(\theta\):
The reflection shown is in the vertical axis and the projection is onto the horizontal axis. A positive angle means an anticlockwise turn, the direction in which angles are measured on the unit circle. A turn by \(\theta\) clockwise is a turn by \(-\theta\).
Rotation keeps every length. Take any \(\vect{v} = (x, y)\) and write \(c = \cos\theta\), \(s = \sin\theta\). By the column view, \(\mat{R}(\theta)\vect{v} = x\,(c, s) + y\,(-s, c) = (xc - ys,\; xs + yc)\). Its squared length is
The first step expands both squares. In the second the two middle terms cancel and the rest is grouped. The third uses \(\cos^2\theta + \sin^2\theta = 1\), which is Pythagoras in the triangle of the figure. So \(\norm{\mat{R}(\theta)\vect{v}} = \norm{\vect{v}}\) for every vector.
What each family keeps. Two questions can be asked of any map. Does it keep the length of every vector? And by what factor does it change area? For area, watch the unit square: it has area 1, so the area of its image is the factor.
Map
Keeps lengths?
Area factor
Scale (\(a, d > 0\))
Only if \(a = d = 1\)
\(a \times d\)
Rotate
Yes
1
Shear (\(k \neq 0\))
No
1
Reflect
Yes
1, turned over
Project
No
0
Scaling turns the unit square into a rectangle \(a\) wide and \(d\) tall. A rotation turns the square without resizing it. A shear sends \(\jhat\) to \((k, 1)\), of length \(\sqrt{1 + k^2}\), so lengths change. Yet the square becomes a parallelogram with base 1 and height 1, so its area is still 1. A reflection sends \((x, y)\) to \((-x, y)\), and \((-x)^2 + y^2 = x^2 + y^2\), so lengths are kept. The area is kept too, but the plane is turned over: the letter F in the gallery comes out back to front, which no turning could do. A projection sends \(\jhat\) to \((0, 0)\) and flattens the square to a segment, of area 0. Its height is gone, so the map cannot be undone.
This factor is the same for every shape, not only the unit square, and it has a name: the determinant. It is negative when the plane is turned over. M02.8 develops it.
Go deeper: the angle-addition formulas, for free
The matrix was built from just two landing spots. Does it really turn every vector by \(\theta\)? Take the unit vector at angle \(\alpha\), which is \((\cos\alpha, \sin\alpha)\). The matrix sends it to
Turning by \(\theta\) should give the unit vector at angle \(\alpha + \theta\), which is \((\cos(\alpha + \theta), \sin(\alpha + \theta))\). The two agree exactly when
These are the angle-addition formulas of trigonometry. If you already trust the formulas, they confirm that the matrix turns every unit vector by \(\theta\), and by homogeneity every other vector too. If you trust the argument in Step 3 that a rotation is linear, then you have just proved the formulas.
The \(2 \times 2\) rotation matrix is at work inside current language models. Rotary position embedding, introduced in the RoFormer paper (2021), tells a transformer where a word sits in a sentence by rotating pairs of coordinates of its vector. For the word at position \(m\), a pair is turned by the angle \(m\theta\), using exactly the matrix of this lesson with \(m\theta\) in place of \(\theta\). Because rotations keep lengths, the position is written into the vector’s direction without changing its size.
Worked example
Take \(\vect{v} = (2, 1)\). Rotate it by \(90°\), rotate it by \(30°\), and shear it with \(k = 1\). Its length is \(\norm{\vect{v}} = \sqrt{2^2 + 1^2} = \sqrt{5} \approx 2.236\).
M02.4.3-F3
The three results. A rotation carries the tip of \(\vect{v}\) along a circle, so the length cannot change. The shear slides it along a horizontal line, and it leaves the circle.
Rotate by \(90°\). The matrix is \(\begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix}\). By columns,
Its length is \(\sqrt{(-1)^2 + 2^2} = \sqrt{5}\), the same as before.
Rotate by \(30°\). Here \(\cos {30°} = \tfrac{\sqrt{3}}{2} \approx 0.866\) and \(\sin {30°} = \tfrac12\), so the matrix is \(\begin{bmatrix} 0.866 & -0.5 \\ 0.5 & 0.866 \end{bmatrix}\) and
Its length is \(\sqrt{3^2 + 1^2} = \sqrt{10} \approx 3.162\). The height is still 1. The tip has slid sideways by its height, and the vector is longer.
Code
A rotation matrix from scratch, using only the standard library. The one line that matters is the conversion from degrees to radians.
import mathdef rotation(degrees):"""The matrix that turns the plane anticlockwise by an angle given in degrees.""" theta = math.radians(degrees) # cos and sin expect radians c, s = math.cos(theta), math.sin(theta)return [[c, -s], # first column (c, s): where i-hat lands [s, c]] # second column (-s, c): where j-hat landsdef matvec(A, v):"""Matrix times vector: v[0] of the first column plus v[1] of the second."""return [v[0] * A[0][0] + v[1] * A[0][1], v[0] * A[1][0] + v[1] * A[1][1]]def length(v):return math.sqrt(v[0] **2+ v[1] **2)v = [2, 1]shear = [[1, 1], [0, 1]]print(f"v itself length = {length(v):.3f}")for name, M in [("rotate 90", rotation(90)), ("rotate 30", rotation(30)), ("shear", shear)]: w = matvec(M, v)print(f"{name:10} image = ({w[0]:.3f}, {w[1]:.3f}) length = {length(w):.3f}")
The numbers match the worked example. Now NumPy: first a check on the from-scratch matrix, then a test of the table above on a thousand random vectors.
import numpy as npdef rotation_np(degrees): theta = np.deg2rad(degrees)return np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]])print(np.round(rotation_np(30), 3))print("same as the from-scratch matrix:", np.allclose(rotation_np(30), rotation(30)))gallery = {"scale": np.array([[2.0, 0.0], [0.0, 1.5]]),"rotate": rotation_np(30),"shear": np.array([[1.0, 1.0], [0.0, 1.0]]),"reflect": np.array([[-1.0, 0.0], [0.0, 1.0]]),"project": np.array([[1.0, 0.0], [0.0, 0.0]]),}rng = np.random.default_rng(0)tests = rng.normal(size=(1000, 2)) # a thousand random vectorsfor name, M in gallery.items(): keeps =all(np.isclose(np.linalg.norm(M @ x), np.linalg.norm(x)) for x in tests)print(f"{name:8} keeps lengths: {str(keeps):5} area factor: {np.linalg.det(M):+.2f}")
[[ 0.866 -0.5 ]
[ 0.5 0.866]]
same as the from-scratch matrix: True
scale keeps lengths: False area factor: +3.00
rotate keeps lengths: True area factor: +1.00
shear keeps lengths: False area factor: +1.00
reflect keeps lengths: True area factor: -1.00
project keeps lengths: False area factor: +0.00
np.linalg.det is NumPy’s name for the area factor of the last column of the table, with a minus sign when the plane is turned over. M02.8 explains how it is computed. Last, the mistake that catches everyone once:
wrong = math.cos(30) # 30 is taken as radiansright = math.cos(math.radians(30)) # 30 degrees, converted firstprint("cosine of 30 radians:", round(wrong, 4))print("cosine of 30 degrees:", round(right, 4))
cosine of 30 radians: 0.1543
cosine of 30 degrees: 0.866
Explore
The matrix playground of this module is in the previous lesson. Try the presets Rotate 90°, Shear and Reflect. For each, read the two columns off the arrows before you look at the matrix, and watch the area factor: 1 for the rotation and the shear, \(-1\) for the reflection. Then build a rotation by \(30°\) by setting the columns to \((0.9, 0.5)\) and \((-0.5, 0.9)\), the nearest the sliders allow. The area factor reads 1.06, not 1, because 0.9 is only a rounding of 0.866.
Pitfalls
M02.4.3-F4
Wrong beside right. The dotted green outline is the result that was wanted: a turn by \(30°\) anticlockwise. Putting the minus sign on the other sine turns the plane the wrong way. Passing degrees to a function that expects radians turns it by an unrelated angle.
“The minus sign goes on the bottom-left sine.”
That matrix, \(\begin{bmatrix} \cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \end{bmatrix}\), is a rotation, but a clockwise one: it is \(\mat{R}(-\theta)\), because \(\cos(-\theta) = \cos\theta\) and \(\sin(-\theta) = -\sin\theta\). Do not memorise where the sign goes. Ask where \(\ihat\) lands. For a small positive angle it must tip upwards, so the first column is \((\cos\theta, +\sin\theta)\). The minus sign is left for the top right.
“np.cos(30) is the cosine of 30 degrees.”
NumPy and Python’s math module measure angles in radians. cos(30) is the cosine of 30 radians, which is four full turns and another \(279°\). It equals about \(0.154\), not \(0.866\). Convert first, with np.deg2rad(30) or math.radians(30). Code that rotates training images by “15” without converting turns them by about \(859°\).
“A shear is just a kind of rotation: both of them tilt things.”
They differ in what they keep. A rotation keeps every length and every angle, and unless it turns by a multiple of \(360°\) it leaves only the origin where it was. A shear keeps a whole line of points fixed (the horizontal axis), changes lengths and angles, and keeps only heights and areas. Image-augmentation libraries offer the two as separate settings for this reason.
Check yourself
Recall
1. Which two questions give you the matrix of a linear motion of the plane?
Show answer
Where does \(\ihat\) land (first column), and where does \(\jhat\) land (second column)?
2. Write the matrix of a rotation by the angle \(\theta\).
Show answer
\(\begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix}\). Its columns are \((\cos\theta, \sin\theta)\) and \((-\sin\theta, \cos\theta)\).
3. In which direction does a positive angle turn the plane?
Show answer
Anticlockwise, the direction in which angles are measured on the unit circle.
4. What is the matrix of a shear, and which of length and area does it keep?
Show answer
\(\begin{bmatrix} 1 & k \\ 0 & 1 \end{bmatrix}\). It keeps areas and heights. It does not keep lengths.
5. Which map in the gallery cannot be undone, and what is its area factor?
Show answer
The projection. Its area factor is 0: the unit square is flattened to a segment.
Exercises
1.★ By asking where \(\ihat\) and \(\jhat\) land, write the matrix of (a) a rotation by \(180°\), (b) the reflection in the horizontal axis, (c) the map that makes everything three times as large.
Show solution
(a) A half turn sends \(\ihat\) to \((-1, 0)\) and \(\jhat\) to \((0, -1)\): \(\begin{bmatrix} -1 & 0 \\ 0 & -1 \end{bmatrix}\). The formula agrees, since \(\cos {180°} = -1\) and \(\sin {180°} = 0\).
(b) \(\ihat\) lies on the mirror and stays at \((1, 0)\). \(\jhat\) flips to \((0, -1)\): \(\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}\).
(c) \(\ihat\) lands on \((3, 0)\) and \(\jhat\) on \((0, 3)\): \(\begin{bmatrix} 3 & 0 \\ 0 & 3 \end{bmatrix}\).
2.★★ Let \(\vect{v} = (1, 1)\). (a) Rotate it by \(45°\) and check that its length has not changed. (b) Apply the shear with \(k = 2\). Has its length changed?
Show solution
(a) \(\cos {45°} = \sin {45°} = \tfrac{\sqrt{2}}{2}\), so the columns are \(\big(\tfrac{\sqrt2}{2}, \tfrac{\sqrt2}{2}\big)\) and \(\big(-\tfrac{\sqrt2}{2}, \tfrac{\sqrt2}{2}\big)\). Then
Its length is \(\sqrt{2}\), and \(\norm{\vect{v}} = \sqrt{1^2 + 1^2} = \sqrt{2}\) too. The vector started at \(45°\) and now points straight up, at \(90°\).
(b) The matrix is \(\begin{bmatrix} 1 & 2 \\ 0 & 1 \end{bmatrix}\), so the image is \(1\,(1, 0) + 1\,(2, 1) = (3, 1)\), of length \(\sqrt{10} \approx 3.162\). The length has changed.
3.★★★ Show that a turn by \(-\theta\) undoes a turn by \(\theta\): for every vector \(\vect{v}\), applying \(\mat{R}(\theta)\) and then \(\mat{R}(-\theta)\) returns \(\vect{v}\).
Show solution
Write \(c = \cos\theta\) and \(s = \sin\theta\), and let \(\vect{v} = (x, y)\). From the formal section, \(\vect{w} = \mat{R}(\theta)\vect{v} = (xc - ys,\; xs + yc)\).
Since \(\cos(-\theta) = c\) and \(\sin(-\theta) = -s\), the matrix \(\mat{R}(-\theta)\) is \(\begin{bmatrix} c & s \\ -s & c \end{bmatrix}\). Apply it to \(\vect{w}\) by the row view:
So \(\mat{R}(-\theta)\vect{w} = (x, y) = \vect{v}\). Doing one map after another is the subject of M02.5, and undoing a map is the subject of M02.7.
Summary card
To build a matrix, ask where the basis vectors land.
M02.4.3-F1
Each matrix is its two arrows.
Rotate by \(\theta\) (anticlockwise).\(\begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix}\). Keeps lengths and areas.
Shear.\(\begin{bmatrix} 1 & k \\ 0 & 1 \end{bmatrix}\) sends \((x, y)\) to \((x + ky, y)\). Keeps areas, not lengths.
Scale.\(\begin{bmatrix} a & 0 \\ 0 & d \end{bmatrix}\). Area factor \(ad\).
Reflect.\(\begin{bmatrix} -1 & 0 \\ 0 & 1 \end{bmatrix}\). Keeps lengths and areas, turns the plane over.
Project.\(\begin{bmatrix} 1 & 0 \\ 0 & 0 \end{bmatrix}\). Area factor 0: it cannot be undone.
In code. Convert degrees to radians before calling cos and sin.
Sources and next steps
Sources. Each was opened and checked against this lesson on 12 November 2026.
Marc Deisenroth, Aldo Faisal and Cheng Soon Ong, Mathematics for Machine Learning, Cambridge University Press, 2020 (free PDF). Section 3.9 derives the rotation matrix from the images of the two basis vectors (equations 3.75 and 3.76), states the convention that a positive angle turns anticlockwise, and lists the properties that rotations preserve distances and angles.
Grant Sanderson, Linear transformations and matrices, 3Blue1Brown, Linear Algebra, chapter 3. Builds the matrices of the \(90°\) anticlockwise rotation and of the shear by recording where \(\ihat\) and \(\jhat\) land.
Grant Sanderson, The determinant, 3Blue1Brown, Linear Algebra, chapter 6. The factor by which a linear map scales areas is its determinant; it is negative when orientation is inverted and zero when the plane is squashed onto a line.
NumPy manual, numpy.cos. The input is an angle in radians.
torchvision documentation, RandomAffine. An image-augmentation transform with separate settings for rotation (degrees) and shear.
Jianlin Su and others, RoFormer: Enhanced Transformer with Rotary Position Embedding (2021). Section 3.2 multiplies a vector at position \(m\) by the \(2 \times 2\) rotation matrix for the angle \(m\theta\) (equation 13) and extends it to pairs of coordinates (equation 15).