Skip to content

np.roll

The np.roll() function shifts array elements along an axis with circular wrapping.

Basic Concept

1D Array Rolling

import numpy as np

arr = np.array([1, 2, 3, 4, 5])

print(np.roll(arr, 2))   # [4, 5, 1, 2, 3] - shift right by 2
print(np.roll(arr, -2))  # [3, 4, 5, 1, 2] - shift left by 2

Image Rolling

Basic Example

import matplotlib.pyplot as plt
import numpy as np
import PIL
import urllib

def main():
    url = "https://upload.wikimedia.org/wikipedia/en/4/43/Pok%C3%A9mon_Mewtwo_art.png"
    img = np.array(PIL.Image.open(urllib.request.urlopen(url)))

    fig, (ax0, ax1, ax2) = plt.subplots(1, 3, figsize=(12, 3))

    ax0.imshow(img)
    ax1.imshow(np.roll(img, 50, axis=0))  # Roll along rows (vertical)
    ax2.imshow(np.roll(img, 50, axis=1))  # Roll along columns (horizontal)

    for ax in (ax0, ax1, ax2):
        ax.axis('off')

    plt.tight_layout()
    plt.show()

if __name__ == "__main__":
    main()

Axis Reference

Roll Directions

Axis Direction Effect
0 Vertical Rows wrap top-to-bottom
1 Horizontal Columns wrap left-to-right

Positive vs Negative Shift

import matplotlib.pyplot as plt
import numpy as np
import PIL
import urllib

url = "https://upload.wikimedia.org/wikipedia/en/4/43/Pok%C3%A9mon_Mewtwo_art.png"
img = np.array(PIL.Image.open(urllib.request.urlopen(url)))

fig, axes = plt.subplots(2, 3, figsize=(12, 8))

# Row 1: Horizontal rolling (axis=1)
axes[0, 0].imshow(np.roll(img, -100, axis=1))
axes[0, 0].set_title('roll(img, -100, axis=1)')

axes[0, 1].imshow(img)
axes[0, 1].set_title('Original')

axes[0, 2].imshow(np.roll(img, 100, axis=1))
axes[0, 2].set_title('roll(img, 100, axis=1)')

# Row 2: Vertical rolling (axis=0)
axes[1, 0].imshow(np.roll(img, -100, axis=0))
axes[1, 0].set_title('roll(img, -100, axis=0)')

axes[1, 1].imshow(img)
axes[1, 1].set_title('Original')

axes[1, 2].imshow(np.roll(img, 100, axis=0))
axes[1, 2].set_title('roll(img, 100, axis=0)')

for ax in axes.flat:
    ax.axis('off')
plt.tight_layout()
plt.show()

Multi-Axis Rolling

Roll Both Axes

import matplotlib.pyplot as plt
import numpy as np

# Roll in both directions
rolled_both = np.roll(np.roll(img, 50, axis=0), 75, axis=1)

# Or use tuple for multi-axis roll
rolled_tuple = np.roll(img, (50, 75), axis=(0, 1))

fig, axes = plt.subplots(1, 3, figsize=(12, 4))

axes[0].imshow(img)
axes[0].set_title('Original')

axes[1].imshow(rolled_both)
axes[1].set_title('Sequential Roll')

axes[2].imshow(rolled_tuple)
axes[2].set_title('Tuple Roll (50, 75)')

for ax in axes:
    ax.axis('off')
plt.tight_layout()
plt.show()

Animation Effect

Creating Rolling Animation Frames

import matplotlib.pyplot as plt
import numpy as np

def create_roll_frames(img, n_frames=10, axis=1):
    """Create frames for rolling animation."""
    step = img.shape[axis] // n_frames
    frames = []
    for i in range(n_frames):
        frames.append(np.roll(img, i * step, axis=axis))
    return frames

frames = create_roll_frames(img, n_frames=5, axis=1)

fig, axes = plt.subplots(1, 5, figsize=(15, 3))
for ax, frame in zip(axes, frames):
    ax.imshow(frame)
    ax.axis('off')
plt.tight_layout()
plt.show()

Practical Applications

Seamless Texture Check

import matplotlib.pyplot as plt
import numpy as np

def check_seamless(img, shift_fraction=0.5):
    """Check if texture tiles seamlessly."""
    h, w = img.shape[:2]

    rolled_h = np.roll(img, int(h * shift_fraction), axis=0)
    rolled_w = np.roll(img, int(w * shift_fraction), axis=1)
    rolled_both = np.roll(np.roll(img, int(h * shift_fraction), axis=0),
                          int(w * shift_fraction), axis=1)

    fig, axes = plt.subplots(2, 2, figsize=(10, 10))

    axes[0, 0].imshow(img)
    axes[0, 0].set_title('Original')

    axes[0, 1].imshow(rolled_w)
    axes[0, 1].set_title('Horizontal Roll')

    axes[1, 0].imshow(rolled_h)
    axes[1, 0].set_title('Vertical Roll')

    axes[1, 1].imshow(rolled_both)
    axes[1, 1].set_title('Both Axes Roll')

    for ax in axes.flat:
        ax.axis('off')
    plt.tight_layout()
    plt.show()

check_seamless(img)

Centering Object

import matplotlib.pyplot as plt
import numpy as np

def center_object(img, current_center, target_center=None):
    """Roll image to center an object."""
    h, w = img.shape[:2]
    if target_center is None:
        target_center = (h // 2, w // 2)

    shift_y = target_center[0] - current_center[0]
    shift_x = target_center[1] - current_center[1]

    return np.roll(np.roll(img, shift_y, axis=0), shift_x, axis=1)

# Example: move object from (100, 150) to center
centered = center_object(img, current_center=(100, 150))

fig, axes = plt.subplots(1, 2, figsize=(10, 5))
axes[0].imshow(img)
axes[0].set_title('Original')
axes[1].imshow(centered)
axes[1].set_title('Centered')

for ax in axes:
    ax.axis('off')
plt.tight_layout()
plt.show()

Panorama Creation

import matplotlib.pyplot as plt
import numpy as np

def create_panorama_effect(img, repetitions=3):
    """Create a panorama by tiling and rolling."""
    # Tile horizontally
    tiled = np.tile(img, (1, repetitions, 1))

    # Show different roll positions
    fig, axes = plt.subplots(3, 1, figsize=(15, 9))

    for i, ax in enumerate(axes):
        shift = i * img.shape[1] // 2
        rolled = np.roll(tiled, shift, axis=1)
        # Crop to original width
        cropped = rolled[:, :img.shape[1]*2]
        ax.imshow(cropped)
        ax.set_title(f'Pan position {i+1}')
        ax.axis('off')

    plt.tight_layout()
    plt.show()

create_panorama_effect(img)

Comparison with Other Operations

Roll vs Slice

import matplotlib.pyplot as plt
import numpy as np

shift = 100

fig, axes = plt.subplots(1, 3, figsize=(12, 4))

# Original
axes[0].imshow(img)
axes[0].set_title('Original')

# Roll (circular - wraps around)
axes[1].imshow(np.roll(img, shift, axis=1))
axes[1].set_title('Roll (circular)')

# Slice (non-circular - loses data)
sliced = np.concatenate([img[:, shift:], np.zeros_like(img[:, :shift])], axis=1)
axes[2].imshow(sliced.astype(np.uint8))
axes[2].set_title('Slice (loses data)')

for ax in axes:
    ax.axis('off')
plt.tight_layout()
plt.show()

Grid of Roll Amounts

Various Shift Values

import matplotlib.pyplot as plt
import numpy as np

shifts = [0, 50, 100, 150, 200]

fig, axes = plt.subplots(2, 5, figsize=(15, 6))

# Horizontal rolls
for ax, shift in zip(axes[0], shifts):
    ax.imshow(np.roll(img, shift, axis=1))
    ax.set_title(f'axis=1, shift={shift}')
    ax.axis('off')

# Vertical rolls
for ax, shift in zip(axes[1], shifts):
    ax.imshow(np.roll(img, shift, axis=0))
    ax.set_title(f'axis=0, shift={shift}')
    ax.axis('off')

plt.tight_layout()
plt.show()