Skip to content

Commit d481870

Browse files
committed
refactor(inset): normalise inset image input to a PIL Image
1 parent d7b9533 commit d481870

2 files changed

Lines changed: 15 additions & 10 deletions

File tree

plotnine/composition/_inset_image.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing import TYPE_CHECKING, Literal
55

66
import numpy as np
7+
from PIL import Image
78
from PIL.Image import Image as PILImage
89

910
from ..themes.theme import theme
@@ -70,8 +71,8 @@ def __init__(
7071
):
7172
from matplotlib.transforms import Bbox
7273

73-
self._image = image
74-
self._image_size = _image_size(image) # (W, H) px
74+
self._image = _to_pil_image(image)
75+
self._image_size = self._image.size # (W, H) px
7576
self._frac_bbox = Bbox.unit()
7677
self._anchor = _resolve_anchor(anchor)
7778
self.theme = theme()
@@ -150,16 +151,22 @@ def _draw_plot_background(self):
150151
self.theme.targets.plot_background = self.patch
151152

152153

153-
def _image_size(obj: PILImage | np.ndarray) -> tuple[int, int]:
154+
def _to_pil_image(obj: PILImage | np.ndarray) -> PILImage:
154155
"""
155-
Return the (width, height) of a PIL image or ndarray in pixels
156+
Normalise an image input to a PIL Image for resampling
157+
158+
A `PIL.Image` is returned unchanged. A uint8 ndarray (L / RGB /
159+
RGBA) is wrapped directly. A float ndarray follows matplotlib's
160+
`[0, 1]` convention and is clipped then scaled to uint8; the final
161+
inset output is an 8-bit raster regardless, so nothing visible is
162+
lost.
156163
"""
157164
if isinstance(obj, PILImage):
158-
return obj.size # PIL exposes (W, H)
159-
165+
return obj
160166
arr = np.asarray(obj)
161-
h, w = arr.shape[:2] # ndarray is HWC or HW
162-
return w, h
167+
if arr.dtype != np.uint8:
168+
arr = (np.clip(arr, 0, 1) * 255).round().astype(np.uint8)
169+
return Image.fromarray(arr)
163170

164171

165172
# Named anchors → (h, v) fractions in [0, 1]², where `h = 0`

tests/test_inset_element.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,6 @@ def test_themed_background_wraps_envelope(self):
304304
def test_ndarray_and_pil_render_identically(self):
305305
# Same image content as ndarray and PIL.Image must produce
306306
# identical baselines — pins the input contract through
307-
# `_image_size` and `np.asarray(self._image)` in
308-
# `_InsetImage`.
309307
pil = Image.fromarray(self.image)
310308
p_arr = self.host + inset_element(self.image, *self.area)
311309
p_pil = self.host + inset_element(pil, *self.area)

0 commit comments

Comments
 (0)