3b1b/manim · error · Exception

Cannot sample color from outside an image

Error message

Cannot sample color from outside an image

What it means

Raised by AbstractImageMobject.point_to_rgb (image_mobject.py:71) when the sampled point maps to an x-coordinate outside the image while the y-coordinate is inside. Note the guard reads `if not (0 <= x_alpha <= 1) and (0 <= y_alpha <= 1)` — due to precedence this only fires for out-of-range x with in-range y; a point outside in y (or both) silently clamps and returns an edge pixel instead of raising.

Source

Thrown at manimlib/mobject/types/image_mobject.py:71

    def set_opacity(self, opacity: float, recurse: bool = True):
        with self.data.being_written() as data:
            data["opacity"][:, 0] = resize_with_interpolation(
                np.array(listify(opacity)),
                self.get_num_points()
            )
        return self

    def set_color(self, color, opacity=None, recurse=None):
        return self

    def point_to_rgb(self, point: Vect3) -> Vect3:
        x0, y0 = self.get_corner(UL)[:2]
        x1, y1 = self.get_corner(DR)[:2]
        x_alpha = inverse_interpolate(x0, x1, point[0])
        y_alpha = inverse_interpolate(y0, y1, point[1])
        if not (0 <= x_alpha <= 1) and (0 <= y_alpha <= 1):
            # TODO, raise smarter exception
            raise Exception("Cannot sample color from outside an image")

        pw, ph = self.image.size
        rgb = self.image.getpixel((
            int((pw - 1) * x_alpha),
            int((ph - 1) * y_alpha),
        ))[:3]
        return np.array(rgb) / 255

View on GitHub (pinned to dee01804d4)

Solutions

  1. Before sampling, verify the point is inside the image rectangle: compare against mob.get_corner(UL) and mob.get_corner(DR)
  2. Clamp the point onto the image before calling point_to_rgb if edge-pixel behavior is acceptable
  3. If you maintain a fork/patch, fix the condition to `if not (0 <= x_alpha <= 1 and 0 <= y_alpha <= 1)` so all out-of-bounds points raise

Example fix

# before
rgb = img.point_to_rgb(np.array([5.0, 0.5, 0.0]))  # x off-image -> raises

# after
ul, dr = img.get_corner(UL)[:2], img.get_corner(DR)[:2]
if ul[0] <= p[0] <= dr[0] and dr[1] <= p[1] <= ul[1]:
    rgb = img.point_to_rgb(p)
Defensive patterns

Strategy: validation

Validate before calling

def point_on_image(img, p) -> bool:
    ul, dr = img.get_corner(UL)[:2], img.get_corner(DR)[:2]
    return ul[0] <= p[0] <= dr[0] and dr[1] <= p[1] <= ul[1]

rgb = img.point_to_rgb(p) if point_on_image(img, p) else DEFAULT_COLOR

Try / catch

try:
    rgb = img.point_to_rgb(p)
except Exception:
    rgb = np.array([0.5, 0.5, 0.5])  # fallback for off-image samples

Prevention

When it happens

Trigger: Calling image_mobject.point_to_rgb(point) where point[0] lies left/right of the image's corners but point[1] is vertically within the image; typically when probing with a point produced by an intersection or a cursor position that is off the image.

Common situations: Interactive/color-picker scenes sampling colors at arbitrary screen points; using point_to_rgb on points from line_intersections or mouse events without checking they are on the image; relying on the check to catch all out-of-image points and hitting the precedence quirk in manim versions with this source.

Related errors


AI-assisted analysis of 3b1b/manim@dee01804d4 (2026-08-14). Data as JSON: /api/errors/3554cb060f4e0c66. Report an issue: GitHub.