Skip to content

Commit 8727165

Browse files
committed
Add _repr_html_ for subject too
1 parent da830d4 commit 8727165

3 files changed

Lines changed: 45 additions & 19 deletions

File tree

src/torchio/data/image.py

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from __future__ import annotations
22

3-
import base64
4-
import io
53
import warnings
64
from collections import Counter
75
from collections.abc import Callable
@@ -203,25 +201,16 @@ def __repr__(self):
203201

204202
def _repr_html_(self):
205203
try:
206-
from matplotlib import pyplot as plt
207204
from matplotlib.figure import Figure
208205
except ImportError:
209206
return self.__repr__()
210207

211-
buffer = io.BytesIO()
212-
fig = self.plot(
213-
return_fig=True,
214-
output_path=buffer,
215-
show=False,
216-
savefig_kwargs={'bbox_inches': 'tight'},
217-
)
208+
fig = self.plot(return_fig=True, show=False)
218209
assert isinstance(fig, Figure)
219-
plt.close(fig)
220-
buffer.seek(0)
221210

222-
img_str = base64.b64encode(buffer.read()).decode('utf-8')
223-
html = f'<img src="data:image/png;base64,{img_str}"/>'
224-
return html
211+
from ..visualization import _figure_to_html
212+
213+
return _figure_to_html(fig)
225214

226215
def __getitem__(self, item):
227216
if isinstance(item, (slice, int, tuple)):

src/torchio/data/subject.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from .image import Image
1515

1616
if TYPE_CHECKING:
17+
from matplotlib.figure import Figure
18+
1719
from ..transforms import Compose
1820
from ..transforms import Transform
1921

@@ -66,6 +68,19 @@ def __repr__(self):
6668
)
6769
return string
6870

71+
def _repr_html_(self):
72+
try:
73+
from matplotlib.figure import Figure
74+
except ImportError:
75+
return self.__repr__()
76+
77+
fig = self.plot(return_fig=True, show=False)
78+
assert isinstance(fig, Figure)
79+
80+
from ..visualization import _figure_to_html
81+
82+
return _figure_to_html(fig)
83+
6984
def __len__(self):
7085
return len(self.get_images(intensity_only=False))
7186

@@ -412,13 +427,16 @@ def remove_image(self, image_name: str) -> None:
412427
del self[image_name]
413428
delattr(self, image_name)
414429

415-
def plot(self, **kwargs) -> None:
430+
def plot(self, return_fig: bool = False, **kwargs) -> None | Figure:
416431
"""Plot images using matplotlib.
417432
418433
Args:
434+
return_fig: If ``True``, return the figure instead of showing it.
419435
**kwargs: Keyword arguments that will be passed on to
420436
[`plot()`][torchio.Image.plot].
421437
"""
422438
from ..visualization import plot_subject # avoid circular import
423439

424-
plot_subject(self, **kwargs)
440+
figure = plot_subject(self, **kwargs)
441+
if return_fig:
442+
return figure

src/torchio/visualization.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,21 @@ def import_mpl_plt():
3838
return mpl, plt
3939

4040

41+
def _figure_to_html(fig: Figure) -> str:
42+
"""Convert a matplotlib Figure to an HTML img tag with base64-encoded PNG."""
43+
import base64
44+
import io
45+
46+
from matplotlib import pyplot as plt
47+
48+
buffer = io.BytesIO()
49+
fig.savefig(buffer, format='png', bbox_inches='tight')
50+
plt.close(fig)
51+
buffer.seek(0)
52+
img_str = base64.b64encode(buffer.read()).decode('utf-8')
53+
return f'<img src="data:image/png;base64,{img_str}"/>'
54+
55+
4156
def rotate(image: np.ndarray, *, radiological: bool = True, n: int = -1) -> np.ndarray:
4257
# Rotate for visualization purposes
4358
image = np.rot90(image, n, axes=(0, 1))
@@ -214,8 +229,9 @@ def plot_subject(
214229
output_path=None,
215230
figsize=None,
216231
clear_axes=True,
232+
savefig_kwargs: dict[str, Any] | None = None,
217233
**plot_volume_kwargs,
218-
):
234+
) -> Figure:
219235
_, plt = import_mpl_plt()
220236
num_images = len(subject)
221237
many_images = num_images > 2
@@ -252,9 +268,12 @@ def plot_subject(
252268
axis.set_title(f'{name} ({axis_name})')
253269
plt.tight_layout()
254270
if output_path is not None:
255-
fig.savefig(output_path)
271+
if savefig_kwargs is None:
272+
savefig_kwargs = {}
273+
fig.savefig(output_path, **savefig_kwargs)
256274
if show:
257275
plt.show()
276+
return fig
258277

259278

260279
def get_num_bins(x: np.ndarray) -> int:

0 commit comments

Comments
 (0)