diff --git a/_config.yml b/_config.yml
index aa23ce0e..4a93c7d9 100644
--- a/_config.yml
+++ b/_config.yml
@@ -22,31 +22,58 @@ exclude_patterns:
   # string_formatting.Rmd.
   # https://github.com/executablebooks/meta/discussions/105
   # https://myst-nb.readthedocs.io/en/latest/use/orphaned_nb.html#orphaned-nb
-  - README.md
-  - todo.md
-  - _scripts
+  # OE: I have sorted the pages with a tentative sectioning
+  #
+  # Python and Numpy
   - pages/allclose.Rmd
-  - pages/anterior_cingulate.md
   - pages/arange.Rmd
-  - pages/array_reductions.md
-  - pages/bibliography.md
   - pages/boolean_indexing.Rmd
-  - pages/choosing_editor.md
-  - pages/classes.md
-  - pages/classes_and_labs.md
-  - pages/coding_style.md
+  - pages/array_reductions.md
   - pages/comparing_arrays.Rmd
   - pages/comparing_floats.md
   - pages/diag_inverse.md
-  - pages/diagnostics_project.md
-  - pages/dipy_registration.Rmd
   - pages/docstrings.md
   - pages/dot_and_outer.md
   - pages/dot_outer.Rmd
-  - pages/ds114_sub009_highres.nii
-  - pages/example_data.md
-  - pages/exercises.md
   - pages/floating_in_text.md
+  - pages/index_reshape.Rmd
+  - pages/keyword_arguments.Rmd
+  - pages/list_comprehensions.Rmd
+  - pages/methods_vs_functions.Rmd
+  - pages/nans.md
+  - pages/newaxis.Rmd
+  - pages/numpy_diag.Rmd
+  - pages/numpy_meshgrid.Rmd
+  - pages/numpy_random.Rmd
+  - pages/numpy_squeeze.Rmd
+  - pages/numpy_transpose.Rmd
+  - pages/on_loops.Rmd
+  - pages/packages_namespaces.Rmd
+  - pages/printing_floating.Rmd
+  - pages/string_literals.md
+  - pages/subtract_mean_math.md
+  - pages/subtract_means.Rmd
+  - pages/two_dunders.md
+  # Images and code and images
+  - pages/saving_images.Rmd
+  - pages/plot_lines.Rmd
+  - pages/subplots.Rmd
+  # Coordinate systems and spatial transforms
+  # [all transferred already]
+  # Into the fourth dimension
+  - pages/reshape_and_4d.Rmd
+  - pages/tr_and_headers.Rmd
+  # Statistics
+  - pages/whole_image_statistics.Rmd
+  - pages/pearson_functions.md
+  - pages/validate_against_scipy.Rmd
+  # Hemodynamic response modeling
+  - pages/anterior_cingulate.md
+  - pages/otsu_threshold.Rmd
+  - pages/introducing_nipype.Rmd
+  # Code organization and collaboration
+  - pages/choosing_editor.md
+  - pages/coding_style.md
   - pages/full_scripting.md
   - pages/git_videos.md
   - pages/git_walk_through.Rmd
@@ -54,54 +81,34 @@ exclude_patterns:
   - pages/github_dummies_homework.md
   - pages/github_glm_homework.md
   - pages/github_pca_homework.md
-  - pages/glossary.md
-  - pages/image_header_and_affine.Rmd
-  - pages/images_and_affines.Rmd
-  - pages/index.md
-  - pages/index_reshape.Rmd
   - pages/installation_on_linux.md
   - pages/installation_on_mac.md
   - pages/installation_on_windows.md
-  - pages/introducing_nipype.Rmd
-  - pages/keyword_arguments.Rmd
-  - pages/list_comprehensions.Rmd
+  # Meta-course
+  - README.md
+  - todo.md
+  - _scripts
+  - pages/bibliography.md
+  - pages/classes.md
+  - pages/classes_and_labs.md
+  - pages/diagnostics_project.md
+  - pages/ds114_sub009_highres.nii
+  - pages/example_data.md
+  - pages/exercises.md
+  - pages/glossary.md
+  - pages/index.md
   - pages/logistics.md
   - pages/markdown.md
   - pages/mentors.md
-  - pages/methods_vs_functions.Rmd
   - pages/multi_model_homework.md
-  - pages/nans.md
-  - pages/newaxis.Rmd
-  - pages/numpy_diag.Rmd
-  - pages/numpy_meshgrid.Rmd
-  - pages/numpy_random.Rmd
-  - pages/numpy_squeeze.Rmd
-  - pages/numpy_transpose.Rmd
-  - pages/on_loops.Rmd
-  - pages/otsu_threshold.Rmd
-  - pages/packages_namespaces.Rmd
   - pages/participate.md
   - pages/participate_grading.md
-  - pages/pearson_functions.md
-  - pages/plot_lines.Rmd
   - pages/preparation.md
-  - pages/printing_floating.Rmd
   - pages/project_grading.md
   - pages/projects.md
-  - pages/resampling_with_ndimage.Rmd
-  - pages/reshape_and_4d.Rmd
-  - pages/rotation_2d_3d.md
-  - pages/saving_images.Rmd
-  - pages/string_literals.md
-  - pages/subplots.Rmd
-  - pages/subtract_mean_math.md
-  - pages/subtract_means.Rmd
   - pages/topics.md
-  - pages/tr_and_headers.Rmd
-  - pages/two_dunders.md
+  # Drop?
   - pages/using_pythonpath.Rmd
-  - pages/validate_against_scipy.Rmd
-  - pages/whole_image_statistics.Rmd
 
 # Define the name of the latex output file for PDF builds
 latex:
diff --git a/_toc.yml b/_toc.yml
index c379e9eb..61d5d4b7 100644
--- a/_toc.yml
+++ b/_toc.yml
@@ -26,6 +26,11 @@ parts:
   - file: pages/nibabel_affines
   - file: pages/nibabel_apply_affine
   - file: pages/map_coordinates
+  - file: pages/image_header_and_affine
+  - file: pages/images_and_affines
+  - file: pages/rotation_2d_3d
+  - file: pages/resampling_with_ndimage
+  - file: pages/dipy_registration
 - caption: Statistics
   chapters:
   - file: pages/mean_test_example
diff --git a/code/rotations.py b/code/rotations.py
new file mode 100644
index 00000000..891908e7
--- /dev/null
+++ b/code/rotations.py
@@ -0,0 +1,66 @@
+""" Rotation matrices for rotations around x, y, z axes
+
+See: https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
+"""
+
+import numpy as np
+
+
+def x_rotmat(theta):
+    """ Rotation matrix for rotation of `theta` radians around x axis
+
+    Parameters
+    ----------
+    theta : scalar
+        Rotation angle in radians
+
+    Returns
+    -------
+    M : shape (3, 3) array
+        Rotation matrix
+    """
+    cos_t = np.cos(theta)
+    sin_t = np.sin(theta)
+    return np.array([[1, 0, 0],
+                     [0, cos_t, -sin_t],
+                     [0, sin_t, cos_t]])
+
+
+def y_rotmat(theta):
+    """ Rotation matrix for rotation of `theta` radians around y axis
+
+    Parameters
+    ----------
+    theta : scalar
+        Rotation angle in radians
+
+    Returns
+    -------
+    M : shape (3, 3) array
+        Rotation matrix
+    """
+    cos_t = np.cos(theta)
+    sin_t = np.sin(theta)
+    return np.array([[cos_t, 0, sin_t],
+                     [0, 1, 0],
+                     [-sin_t, 0, cos_t]])
+
+
+def z_rotmat(theta):
+    """ Rotation matrix for rotation of `theta` radians around z axis
+
+    Parameters
+    ----------
+    theta : scalar
+        Rotation angle in radians
+
+    Returns
+    -------
+    M : shape (3, 3) array
+        Rotation matrix
+    """
+    cos_t = np.cos(theta)
+    sin_t = np.sin(theta)
+    return np.array([[cos_t, -sin_t, 0],
+                     [sin_t, cos_t, 0],
+                     [0, 0, 1]])
diff --git a/pages/dipy_registration.Rmd b/pages/dipy_registration.Rmd
index 8b61b436..dc0778c3 100644
--- a/pages/dipy_registration.Rmd
+++ b/pages/dipy_registration.Rmd
@@ -6,11 +6,13 @@ jupyter:
       format_name: rmarkdown
       format_version: '1.2'
       jupytext_version: 1.11.5
+  kernelspec:
+    display_name: Python 3 (ipykernel)
+    language: python
+    name: python3
 ---
 
-$\newcommand{L}[1]{\| #1 \|}\newcommand{VL}[1]{\L{ \vec{#1} }}\newcommand{R}[1]{\operatorname{Re}\,(#1)}\newcommand{I}[1]{\operatorname{Im}\, (#1)}$
-
-## Registration with dipy
+# Registration with dipy
 
 [Dipy](http://nipy.org/dipy) is a Python package for diffusion imaging.
 
@@ -86,9 +88,9 @@ Dipy works on the image data arrays. It also needs the affine arrays of each
 of the images:
 
 ```{python}
-moving_data = moving_img.get_data()
+moving_data = moving_img.get_fdata()
 moving_affine = moving_img.affine
-template_data = template_img.get_data()
+template_data = template_img.get_fdata()
 template_affine = template_img.affine
 ```
 
@@ -262,31 +264,3 @@ regtools.overlay_slices(template_data, warped_moving, None, 1,
 regtools.overlay_slices(template_data, warped_moving, None, 2,
                         "Template", "Transformed")
 ```
-
-<!-- vim:ft=rst -->
-<!-- Course -->
-<!-- BIC -->
-<!-- Python distributions -->
-<!-- Version control -->
-<!-- Editors -->
-<!-- Python and common libraries -->
-<!-- IPython -->
-<!-- Virtualenv and helpers -->
-<!-- Pypi and packaging -->
-<!-- Mac development -->
-<!-- Windows development -->
-<!-- Nipy and friends -->
-<!-- FMRI datasets -->
-<!-- Languages -->
-<!-- Imaging software -->
-<!-- Installation -->
-<!-- Tutorials -->
-<!-- MB tutorials -->
-<!-- Ideas -->
-<!-- Psych-214 -->
-<!-- People -->
-<!-- Licenses -->
-<!-- Neuroimaging stuff -->
-<!-- OpenFMRI projects -->
-<!-- Unix -->
-<!-- Substitutions -->
diff --git a/pages/ds107_sub012_highres.nii b/pages/ds107_sub012_highres.nii
new file mode 120000
index 00000000..07e2c060
--- /dev/null
+++ b/pages/ds107_sub012_highres.nii
@@ -0,0 +1 @@
+../data/ds107_sub012_highres.nii
\ No newline at end of file
diff --git a/pages/ds114_sub009_highres_brain_222.nii b/pages/ds114_sub009_highres_brain_222.nii
new file mode 120000
index 00000000..056bf8be
--- /dev/null
+++ b/pages/ds114_sub009_highres_brain_222.nii
@@ -0,0 +1 @@
+../data/ds114_sub009_highres_brain_222.nii
\ No newline at end of file
diff --git a/pages/ds114_sub009_highres_moved.hdr b/pages/ds114_sub009_highres_moved.hdr
new file mode 120000
index 00000000..ccf244f7
--- /dev/null
+++ b/pages/ds114_sub009_highres_moved.hdr
@@ -0,0 +1 @@
+../data/ds114_sub009_highres_moved.hdr
\ No newline at end of file
diff --git a/pages/ds114_sub009_highres_moved.img b/pages/ds114_sub009_highres_moved.img
new file mode 120000
index 00000000..9c8ad1e9
--- /dev/null
+++ b/pages/ds114_sub009_highres_moved.img
@@ -0,0 +1 @@
+../data/ds114_sub009_highres_moved.img
\ No newline at end of file
diff --git a/pages/image_header_and_affine.Rmd b/pages/image_header_and_affine.Rmd
index 85245b56..02531b8e 100644
--- a/pages/image_header_and_affine.Rmd
+++ b/pages/image_header_and_affine.Rmd
@@ -6,11 +6,13 @@ jupyter:
       format_name: rmarkdown
       format_version: '1.2'
       jupytext_version: 1.11.5
+  kernelspec:
+    display_name: Python 3 (ipykernel)
+    language: python
+    name: python3
 ---
 
-$\newcommand{L}[1]{\| #1 \|}\newcommand{VL}[1]{\L{ \vec{#1} }}\newcommand{R}[1]{\operatorname{Re}\,(#1)}\newcommand{I}[1]{\operatorname{Im}\, (#1)}$
-
-## The image header and affine
+# The image header and affine
 
 See: [coordinate systems and affine transforms](http://nipy.org/nibabel/coordinate_systems.html) for an introduction.
 
@@ -18,13 +20,6 @@ See: [coordinate systems and affine transforms](http://nipy.org/nibabel/coordina
 # import common modules
 import numpy as np
 np.set_printoptions(precision=4, suppress=True)  # print arrays to 4DP
-import matplotlib.pyplot as plt
-```
-
-```{python}
-#: gray colormap and nearest neighbor interpolation by default
-plt.rcParams['image.cmap'] = 'gray'
-plt.rcParams['image.interpolation'] = 'nearest'
 ```
 
 ## The image affine
@@ -87,31 +82,3 @@ may still find them used. They have only one advantage, which is that, if some
 software wants to change only the header information, it only has to rewrite a
 small `.hdr` file, rather than the whole `.nii` file containing the image
 data and the header.
-
-<!-- vim:ft=rst -->
-<!-- Course -->
-<!-- BIC -->
-<!-- Python distributions -->
-<!-- Version control -->
-<!-- Editors -->
-<!-- Python and common libraries -->
-<!-- IPython -->
-<!-- Virtualenv and helpers -->
-<!-- Pypi and packaging -->
-<!-- Mac development -->
-<!-- Windows development -->
-<!-- Nipy and friends -->
-<!-- FMRI datasets -->
-<!-- Languages -->
-<!-- Imaging software -->
-<!-- Installation -->
-<!-- Tutorials -->
-<!-- MB tutorials -->
-<!-- Ideas -->
-<!-- Psych-214 -->
-<!-- People -->
-<!-- Licenses -->
-<!-- Neuroimaging stuff -->
-<!-- OpenFMRI projects -->
-<!-- Unix -->
-<!-- Substitutions -->
diff --git a/pages/images_and_affines.Rmd b/pages/images_and_affines.Rmd
index 1b5ba5e1..d7bdd5ac 100644
--- a/pages/images_and_affines.Rmd
+++ b/pages/images_and_affines.Rmd
@@ -6,11 +6,13 @@ jupyter:
       format_name: rmarkdown
       format_version: '1.2'
       jupytext_version: 1.11.5
+  kernelspec:
+    display_name: Python 3 (ipykernel)
+    language: python
+    name: python3
 ---
 
-$\newcommand{L}[1]{\| #1 \|}\newcommand{VL}[1]{\L{ \vec{#1} }}\newcommand{R}[1]{\operatorname{Re}\,(#1)}\newcommand{I}[1]{\operatorname{Im}\, (#1)}$
-
-## Images and affines
+# Images and affines
 
 See: [coordinate systems and affine transforms](http://nipy.org/nibabel/coordinate_systems.html) for background.
 
@@ -25,20 +27,40 @@ import nibabel as nib
 
 ## Affines, inverses
 
-We often have the situation where we compose an affine of several
-transformations. We do the composing using matrix multiplication. For example,
-the following code composes two rotations and a translation.  We are using the
-`rotations.py` module to make the 3D rotation matrices.  Remember – matrix multiplication works right to left.
+We often have the situation where we compose an affine of several transformations.
+We do the composing using matrix multiplication.
+For example, the following code composes two rotations and a translation.
 
-```{python}
-# get functions to make 3D rotation matrices
-from rotations import x_rotmat, y_rotmat, z_rotmat
-```
+<div class="alert alert-info">
+
+**Remember:**
+Matrix multiplication works right to left.
+
+</div>
 
 Here is a rotation matrix (3 x 3) for a rotation of -0.2 radians around the x
 axis:
 
 ```{python}
+def x_rotmat(theta):
+    """ Rotation matrix for rotation of `theta` radians around x axis
+
+    Parameters
+    ----------
+    theta : scalar
+        Rotation angle in radians
+
+    Returns
+    -------
+    M : shape (3, 3) array
+        Rotation matrix
+    """
+    cos_t = np.cos(theta)
+    sin_t = np.sin(theta)
+    return np.array([[1, 0, 0],
+                     [0, cos_t, -sin_t],
+                     [0, sin_t, cos_t]])
+
 first_rotation = x_rotmat(-0.2)
 first_rotation
 ```
@@ -55,6 +77,25 @@ first_affine
 Now we made a second affine matrix for a rotation around y of 0.4 radians:
 
 ```{python}
+def y_rotmat(theta):
+    """ Rotation matrix for rotation of `theta` radians around y axis
+
+    Parameters
+    ----------
+    theta : scalar
+        Rotation angle in radians
+
+    Returns
+    -------
+    M : shape (3, 3) array
+        Rotation matrix
+    """
+    cos_t = np.cos(theta)
+    sin_t = np.sin(theta)
+    return np.array([[cos_t, 0, sin_t],
+                     [0, 1, 0],
+                     [-sin_t, 0, cos_t]])
+
 second_affine = np.eye(4)
 second_affine[:3, :3] = y_rotmat(0.4)
 second_affine
@@ -198,31 +239,3 @@ F = third_affine.dot(second_affine)
 F  
 np.allclose(third_with_second, F)
 ```
-
-<!-- vim:ft=rst -->
-<!-- Course -->
-<!-- BIC -->
-<!-- Python distributions -->
-<!-- Version control -->
-<!-- Editors -->
-<!-- Python and common libraries -->
-<!-- IPython -->
-<!-- Virtualenv and helpers -->
-<!-- Pypi and packaging -->
-<!-- Mac development -->
-<!-- Windows development -->
-<!-- Nipy and friends -->
-<!-- FMRI datasets -->
-<!-- Languages -->
-<!-- Imaging software -->
-<!-- Installation -->
-<!-- Tutorials -->
-<!-- MB tutorials -->
-<!-- Ideas -->
-<!-- Psych-214 -->
-<!-- People -->
-<!-- Licenses -->
-<!-- Neuroimaging stuff -->
-<!-- OpenFMRI projects -->
-<!-- Unix -->
-<!-- Substitutions -->
diff --git a/pages/mni_icbm152_t1_tal_nlin_asym_09a_masked_222.nii b/pages/mni_icbm152_t1_tal_nlin_asym_09a_masked_222.nii
new file mode 120000
index 00000000..416ff5ef
--- /dev/null
+++ b/pages/mni_icbm152_t1_tal_nlin_asym_09a_masked_222.nii
@@ -0,0 +1 @@
+../data/mni_icbm152_t1_tal_nlin_asym_09a_masked_222.nii
\ No newline at end of file
diff --git a/pages/resampling_with_ndimage.Rmd b/pages/resampling_with_ndimage.Rmd
index 1c5ab994..9b559175 100644
--- a/pages/resampling_with_ndimage.Rmd
+++ b/pages/resampling_with_ndimage.Rmd
@@ -6,11 +6,13 @@ jupyter:
       format_name: rmarkdown
       format_version: '1.2'
       jupytext_version: 1.11.5
+  kernelspec:
+    display_name: Python 3 (ipykernel)
+    language: python
+    name: python3
 ---
 
-$\newcommand{L}[1]{\| #1 \|}\newcommand{VL}[1]{\L{ \vec{#1} }}\newcommand{R}[1]{\operatorname{Re}\,(#1)}\newcommand{I}[1]{\operatorname{Im}\, (#1)}$
-
-## Resampling with scipy.ndimage
+# Resampling with `scipy.ndimage`
 
 ```{python}
 # import common modules
@@ -210,31 +212,3 @@ K.shape
 
 Remember that the `M` matrix and `translation` vector apply to the
 coordinates implied by the output shape.
-
-<!-- vim:ft=rst -->
-<!-- Course -->
-<!-- BIC -->
-<!-- Python distributions -->
-<!-- Version control -->
-<!-- Editors -->
-<!-- Python and common libraries -->
-<!-- IPython -->
-<!-- Virtualenv and helpers -->
-<!-- Pypi and packaging -->
-<!-- Mac development -->
-<!-- Windows development -->
-<!-- Nipy and friends -->
-<!-- FMRI datasets -->
-<!-- Languages -->
-<!-- Imaging software -->
-<!-- Installation -->
-<!-- Tutorials -->
-<!-- MB tutorials -->
-<!-- Ideas -->
-<!-- Psych-214 -->
-<!-- People -->
-<!-- Licenses -->
-<!-- Neuroimaging stuff -->
-<!-- OpenFMRI projects -->
-<!-- Unix -->
-<!-- Substitutions -->
diff --git a/pages/rotation_2d_3d.md b/pages/rotation_2d_3d.md
index 001cfe88..bbdafab6 100644
--- a/pages/rotation_2d_3d.md
+++ b/pages/rotation_2d_3d.md
@@ -1,3 +1,17 @@
+---
+jupyter:
+  jupytext:
+    text_representation:
+      extension: .md
+      format_name: markdown
+      format_version: '1.3'
+      jupytext_version: 1.11.5
+  kernelspec:
+    display_name: Python 3 (ipykernel)
+    language: python
+    name: python3
+---
+
 # Rotations and rotation matrices
 
 ## Rotations in two dimensions
@@ -40,19 +54,19 @@ See [rotation in 2D] for a visual proof.
 
 ## Rotations in three dimensions
 
-Rotations in three dimensions extend simply from two dimensions.  Consider a
-[right-handed] set of x, y, z axes, maybe forming the x axis with your right
-thumb, the y axis with your index finger, and the z axis with your middle
-finger.  Now look down the z axis, from positive z toward negative z.  You see
-the x and y axes pointing right and up respectively, on a plane in front of
-you.  A rotation around z leaves z unchanged, but changes x and y according to
-the 2D rotation formula above:
+Rotations in three dimensions extend simply from two dimensions.  
+Consider a [right-handed] set of x, y, z axes, maybe forming the x axis with your right thumb, the y axis with your index finger, and the z axis with your middle
+finger.
+Now look down the z axis, from positive z toward negative z.
+You see the x and y axes pointing right and up respectively, on a plane in front of you.
+A rotation around z leaves z unchanged, but changes x and y according to the 2D rotation formula above:
 
 $$
-R_z(\theta) &= \begin{bmatrix}
-\cos \theta &  -\sin \theta & 0 \\[3pt]
-\sin \theta & \cos \theta & 0\\[3pt]
-0 & 0 & 1\\
+R_z(\theta) =
+\begin{bmatrix}
+\cos \theta &  -\sin \theta & 0 \\
+\sin \theta & \cos \theta & 0 \\
+0 & 0 & 1 \\
 \end{bmatrix}
 $$
 
@@ -66,7 +80,7 @@ z' = y \sin \theta + z \cos \theta
 $$
 
 $$
-R_x(\theta) &= \begin{bmatrix}
+R_x(\theta) = \begin{bmatrix}
 1 & 0 & 0 \\
 0 & \cos \theta &  -\sin \theta \\[3pt]
 0 & \sin \theta  &  \cos \theta \\[3pt]
@@ -83,7 +97,7 @@ x' = z \sin \theta + x \cos \theta
 $$
 
 $$
-R_y(\theta) &= \begin{bmatrix}
+R_y(\theta) = \begin{bmatrix}
 \cos \theta & 0 & \sin \theta \\[3pt]
 0 & 1 & 0 \\[3pt]
 -\sin \theta & 0 & \cos \theta \\
diff --git a/pages/rotations.py b/pages/rotations.py
new file mode 120000
index 00000000..4c2effff
--- /dev/null
+++ b/pages/rotations.py
@@ -0,0 +1 @@
+../code/rotations.py
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index bff56cf0..019b98c2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,3 +5,5 @@ nibabel
 ipython
 jupytext[myst]
 okpy
+dipy
+fury<0.8  # pacify dipy imports