← Python
ex04June 21, 2026 · 8 min read

Transpose by Hand: Rotating an Image Without a Library

The transpose swaps the axes of an array. Learn what it does geometrically, why the subject bans np.transpose here, and how to implement it yourself with nested loops.

pythonnumpytransposeimages

Exercise 04, "rotate me", carries a red warning: you must do the transpose yourself — no library is allowed for it. That constraint is the whole point. It forces you to understand what a transpose actually is, instead of calling a one-liner.

What a transpose does

The transpose swaps the axes of an array. For a 2D array, element (i, j) moves to position (j, i) — rows become columns and columns become rows. A shape of (3, 5) becomes (5, 3).

1 2 3            1 4
4 5 6     ->     2 5
                 3 6
(2 x 3)          (3 x 2)

Geometrically, transposing reflects the image across its main diagonal. For the square raccoon crop in the subject, that diagonal flip is the visible "rotation".

First, cut a square

A transpose of a non-square image changes its shape (H×W becomes W×H), so the subject has you cut a square region first — reusing the slicing skill from exercise 03:

from load_image import ft_load

image = ft_load("animal.jpeg")
square = image[0:400, 0:400]        # a 400x400 region
print("The shape of image is:", square.shape)

Implementing transpose yourself

No .T, no np.transpose, no np.swapaxes. Build the output by hand. The rule is simply out[j][i] = in[i][j]:

def ft_transpose(matrix):
    """Return the transpose of a 2D matrix (out[j][i] = in[i][j])."""
    rows = len(matrix)
    cols = len(matrix[0])
    result = [[0] * rows for _ in range(cols)]
    for i in range(rows):
        for j in range(cols):
            result[j][i] = matrix[i][j]
    return result

Read it carefully: the output has cols rows and rows columns — the dimensions are swapped — and each value is copied to its mirrored position. This is the literal definition of a transpose, written out as code.

A NumPy-friendly version

If you are working with a NumPy array but still must avoid the built-in transpose, you can use fancy indexing with explicit index grids — you are still doing the index swap yourself:

import numpy as np

def ft_transpose(a):
    """Transpose a 2D NumPy array without np.transpose / .T."""
    h, w = a.shape
    out = np.empty((w, h), dtype=a.dtype)
    for i in range(h):
        for j in range(w):
            out[j, i] = a[i, j]
    return out

The double loop is O(H×W). For a 400×400 image that is 160,000 assignments — instant. The point is comprehension, not micro-optimization.

Print the result and display it

The subject wants the new shape and the transposed data printed, then the image shown:

import matplotlib.pyplot as plt

result = ft_transpose(square[:, :, 0])   # one channel -> clean 2D
print("New shape after Transpose:", result.shape)
print(result)

plt.imshow(result, cmap="gray")
plt.show()

On screen the raccoon appears mirrored across the diagonal — the visual proof your transpose is correct.

Transpose vs rotation (the nuance)

Strictly, a transpose is a diagonal reflection, not a true rotation. A real 90° rotation is a transpose plus a flip of one axis (rotated = transpose(image)[:, ::-1]). The exercise calls it "rotate" loosely; knowing the precise difference is exactly the kind of detail a good defense will probe.

Takeaways

  • Transpose swaps axes: (i, j) -> (j, i), shape (H, W) -> (W, H).
  • Implement it with a double loop — the banned library call is the learning objective.
  • Cut a square first so the shape stays manageable.
  • A pure transpose is a diagonal mirror; a true rotation also flips an axis.