Topology constructions

Topology
The constructions behind five exercises on homeomorphisms: an open interval and the line, stereographic projection, the real projective line, a segment with its ends glued, and the punctured plane.
Published

October 20, 2026

These animations go with my solutions to the problem sheets of Topological Spaces (IGCE-UNESP, 2026.2), where I am the teaching assistant. Each one follows the construction used in the written solution, with the same notation and the same exercise numbers; the solutions themselves are in Portuguese.

Exercise 2.8: an interval and the line

Show that the subset \((a,b)\) of \(\mathbb{R}\) with the induced topology is homeomorphic to \(\mathbb{R}\).

An affine map \(\varphi\) takes \((a,b)\) onto \(\left(-\frac{\pi}{2},\frac{\pi}{2}\right)\), and the tangent stretches that interval over the whole line. The video also shows where the induced topology enters the argument.

Time Section
0:07 The plan: two homeomorphisms in a row
0:22 Step 1: the affine map \(\varphi\) and its inverse \(\psi\)
0:48 Continuity, with the induced topology
1:13 Step 2: the tangent
1:37 Step 3: the composition \(\tan\circ\varphi\)

Exercise 2.11: stereographic projection

Prove that \(S^{n}\setminus\{(0,0,\dots,1)\}\) is homeomorphic to \(\mathbb{R}^{n}\) with the usual topology.

Every line through the north pole \(N\) that is not tangent to the sphere meets the sphere at one more point and the hyperplane \(H=\{x_{n+1}=0\}\) at exactly one point. Reading this in one direction gives \(\varphi\), in the other direction \(\psi\). The video derives both formulas from the lines through \(N\), then shows the cases \(n=1\) and \(n=2\).

Time Section
0:07 The setting
0:20 The construction: lines through \(N\)
1:01 The map \(\varphi\colon S^n\setminus\{N\}\to H\)
1:24 The map \(\psi\colon H\to S^n\setminus\{N\}\)
1:47 \(\varphi\) is a homeomorphism, with inverse \(\psi\)
2:10 The case \(n=1\): the circle and the line
2:47 The case \(n=2\): the sphere and the plane

Exercise 2.17: the real projective line

Prove that \(\mathbb{R}P^{1}\) and \(S^{1}\) are homeomorphic.

The map \(h(u,v)=(u^2-v^2,\,2uv)\) doubles angles, so it sends \(x\) and \(-x\) to the same point and induces \(\bar h\colon\mathbb{R}P^1\to S^1\). The video checks that \(\bar h\) is a continuous and open bijection. The short “intuition” at the start (half a circle with its ends glued) is not part of the written solution.

Time Section
0:07 The space \(\mathbb{R}P^1\): pairs of antipodal points
0:34 The map \(h(u,v)=(u^2-v^2,\ 2uv)\)
0:56 \(h(x)=h(y)\) exactly when \(y=\pm x\)
1:19 \(h\) is an open map
1:41 The induced map \(\bar h\colon\mathbb{R}P^1\to S^1\)

Exercise 2.19: gluing the ends of a segment

Let \(I=[0,1]\subset\mathbb{R}\) and \(\sim\) the equivalence relation on \(I\): \(x\sim x'\) if and only if \(\{x,x'\}=\{0,1\}\) or \(x=x'\). Show that \(I/\!\sim\) is homeomorphic to \(S^{1}\).

The map \(g(t)=e(2\pi t)\) induces a continuous bijection \(\bar g\colon I/\!\sim\ \to S^1\). The delicate point is openness: \(g\) itself is not open, but \(\bar g\) is, because an open set of \(I/\!\sim\) containing the class of \(0\) comes from a set containing both ends of the segment.

Time Section
0:07 The intuition: bend the segment and glue its ends
0:24 The map \(g\) and the induced map \(\bar g\)
0:45 \(g\) is not an open map
1:00 \(\bar g\) is an open map

Exercise 2.23: the punctured plane

Prove that \(\mathbb{R}^{2}\setminus\{0\}\) is homeomorphic to \(\mathbb{R}\times S^{1}\).

With \(A=(0,+\infty)\), the maps \(\varphi(r,z)=rz\) and \(\psi(v)=\bigl(\|v\|,\,v/\|v\|\bigr)\) are inverse homeomorphisms between \(A\times S^1\) and the punctured plane; in the picture, circles around the origin become horizontal circles of a cylinder and rays become its vertical lines. Then \(\exp\colon\mathbb{R}\to A\) replaces \(A\) by \(\mathbb{R}\).

Time Section
0:07 Polar coordinates, without angles
0:29 Circles and rays: the plane becomes the cylinder \(A\times S^1\)
1:04 Why \(\varphi\) and \(\psi\) are continuous
1:34 From \(A=(0,+\infty)\) to \(\mathbb{R}\): the exponential

Made with Manim Community v0.22. The excerpts below are the key parts of the code, each followed by a short explanation.

How the code works

1. Stereographic projection: one line through \(N\)

def ray_from_N(ang, color=C_MAP, width=3, length=20, box=BOX):
1    v = P(math.cos(ang), math.sin(ang))
2    seg = clip_seg(NN, NN + length * v, box)
    return Line(seg[0], seg[1], color=color, stroke_width=width)


def phi1(u, w):
    """phi for n = 1, in sphere units."""
3    return u / (1 - w)


def psi1(y):
    d = y * y + 1
4    return 2 * y / d, (y * y - 1) / d
1
The direction \(v\) of a line through \(N\), here a unit vector.
2
clip_seg keeps only the part of the line inside the box of the figure, so that no line ever runs over the text on the right.
3
For \(n=1\), \(\varphi(x)=\bar x/(1-x_{n+1})\) with \(x=(u,w)\).
4
For \(n=1\), \(\psi(y)=\bigl(2y,\ y^2-1\bigr)/(y^2+1)\).

2. Bending a segment into a circle (Exercise 2.19)

        def bend_pt(s):
            k = kap.get_value()
1            rho = L / k
            c = Mid + P(0, rho)
2            ph = k * (s - 0.5)
3            p = c + rho * P(math.sin(ph), -math.cos(ph))
            # after the bend, turn the circle so that the glued point goes to the right
            cc = Mid + P(0, L / (2 * PI))
4            return cc + rotate_vector(p - cc, rot.get_value())
1
An arc of length \(L\) that turns through the angle \(k\) has radius \(L/k\); its centre is above the midpoint of the segment.
2
The parameter \(s\in[0,1]\) becomes an angle in \([-k/2,\,k/2]\), measured from the lowest point of the arc.
3
When \(k\) is close to \(0\) this is (almost) the straight segment; animating \(k\) from \(0\) to \(2\pi\) bends it until \(s=0\) and \(s=1\) meet.
4
A last rotation moves the glued point to \((1,0)\), where \(g(0)=g(1)=e(0)\) lies.

3. From the plane to the cylinder in two moves (Exercise 2.23)

        def pos(r, a):
            # stage 1 (lam 0 -> 1): lift v to the height ||v||;  stage 2 (lam 1 -> 2): replace v by v/||v||
            k = lam.get_value()
1            k1, k2 = min(k, 1.0), max(k - 1.0, 0.0)
2            rad = (1 - k2) * r + k2 * RC
3            return P(rad * math.cos(a), rad * math.sin(a), k1 * (Z0 + 1.35 * r))
1
One number, lam, goes from \(0\) to \(2\) and drives both moves: k1 runs the first and k2 the second. Every circle and ray of the picture is redrawn from it at each frame.
2
The radius: \(r=\|v\|\) while k2 is \(0\), the radius RC of the cylinder when k2 is \(1\). This is the second move, replacing \(v\) by \(v/\|v\|\).
3
The height: \(0\) while k1 is \(0\), an increasing affine function of \(r=\|v\|\) when k1 is \(1\). This is the first move, which turns the plane into a cone.

4. Labels that never touch a line

Every label that moves with a point (\(x\), \(\varphi(x)\), \(\psi(y)\), …) is placed again at each frame by a small function:

def place(m, anchor, obstacles=(), prefs=(UR, UL, DR, DL, RIGHT, LEFT, UP, DOWN),
          buffs=(0.1, 0.17, 0.25, 0.35, 0.47, 0.6), pad=0.05, labels=(), frame=None):
    """Put label m next to the point `anchor`, at the first spot (preferred directions first, closest
    first) where its box touches no sampled point of `obstacles` and no box of `labels`."""
    pts = obstacles if isinstance(obstacles, np.ndarray) else sample_points(*obstacles)
    lbl_boxes = [bbox(l, 0.02) for l in labels]
    anchor = np.array(anchor, dtype=float)
1    for b in buffs:
        for d in prefs:
            m.next_to(anchor, d, buff=b)
            l, r, bt, t = bbox(m, pad)
            if frame is not None and (l < frame[0] or r > frame[1] or bt < frame[2] or t > frame[3]):
                continue
2            if len(pts) and ((pts[:, 0] > l) & (pts[:, 0] < r) & (pts[:, 1] > bt) & (pts[:, 1] < t)).any():
                continue
3            if any(boxes_meet((l, r, bt, t), q) for q in lbl_boxes):
                continue
4            return m
    m.next_to(anchor, prefs[0], buff=buffs[0])
    return m
1
Positions close to the point are tried first, in the preferred directions.
2
The label’s box must contain none of the points sampled densely along the curves and lines of the figure…
3
…and must not meet the labels already placed.
4
The first free position wins.

Rendering with TC_CHECK=1 runs a similar test after every animation and lists any label that touches a line, a dot or another label, or that leaves the screen.

Back to top