From 548234986df972cfa9dfea42745df6dfab6f8a71 Mon Sep 17 00:00:00 2001 From: eugenioLR Date: Fri, 12 Jul 2024 18:17:00 +0200 Subject: [PATCH 1/4] added automatic aspect ratio calculation --- src/seaborn_image/_grid.py | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/seaborn_image/_grid.py b/src/seaborn_image/_grid.py index d34346f..65f3b9c 100644 --- a/src/seaborn_image/_grid.py +++ b/src/seaborn_image/_grid.py @@ -43,8 +43,8 @@ class ImageGrid: Number of columns to display. Defaults to None. height : int or float, optional Size of the individual images. Defaults to 3. - aspect : int or float, optional - Aspect ratio of individual images. Defaults to 1. + aspect : int, float or 'auto', optional + Aspect ratio of individual images, when set to 'auto', it calculates the aspect ratio of the images passed. Defaults to 'auto'. cmap : str or `matplotlib.colors.Colormap` or list, optional Image colormap. If input data is a list of images, `cmap` can be a list of colormaps. Defaults to None. @@ -321,7 +321,7 @@ def __init__( map_func_kw=None, col_wrap=None, height=3, - aspect=1, + aspect="auto", cmap=None, robust=False, perc=(2, 98), @@ -365,6 +365,15 @@ def __init__( len(map_func) if len(map_func) >= len(data) else len(data) ) + if aspect == "auto": + aspect = 1e10 + + # Select minimum aspect ratio among all the images + for img in data: + aspect_aux = img.shape[0] / img.shape[1] + if aspect_aux < aspect: + aspect = aspect_aux + elif not isinstance(data, np.ndarray): raise ValueError("image data must be a list of images or a 3d or 4d array.") @@ -385,6 +394,9 @@ def __init__( # no of columns should now be len of map_func list col_wrap = len(map_func) if col_wrap is None else col_wrap + if aspect == "auto": + aspect = data.shape[0] / data.shape[1] + elif data.ndim in [3, 4]: if data.ndim == 4 and data.shape[-1] not in [1, 3, 4]: raise ValueError( @@ -418,6 +430,12 @@ def __init__( _nimages = len(slices) + if aspect == "auto": + # Select axis where width and height are + width_idx, height_idx = [i for i in range(data.ndim) if i != axis][:2] + + aspect = data.shape[width_idx] / data.shape[height_idx] + # ---- 3D or 4D image with an individual map_func ---- map_func_type = self._check_map_func(map_func, map_func_kw) # raise a ValueError if a list of map_func is provided for 3d image @@ -765,7 +783,7 @@ def rgbplot( *, col_wrap=3, height=3, - aspect=1, + aspect="auto", cmap=None, alpha=None, origin=None, @@ -794,8 +812,8 @@ def rgbplot( Number of columns to display. Defaults to 3. height : int or float, optional Size of the individual images. Defaults to 3. - aspect : int or float, optional - Aspect ratio of individual images. Defaults to 1. + aspect : int, float or 'auto', optional + Aspect ratio of individual images, when set to 'auto', it calculates the aspect ratio of the images passed. Defaults to 'auto'. cmap : str or `matplotlib.colors.Colormap` or list, optional Image colormap or a list of colormaps. Defaults to None. alpha : float or array-like, optional @@ -975,8 +993,8 @@ class ParamGrid(object): is not None and `row` is None. Defaults to None. height : int or float, optional Size of the individual images. Defaults to 3. - aspect : int or float, optional - Aspect ratio of individual images. Defaults to 1. + aspect : int, float or 'auto', optional + Aspect ratio of individual images, when set to 'auto', it calculates the aspect ratio of the images passed. Defaults to 'auto'. cmap : str or `matplotlib.colors.Colormap`, optional Image colormap. Defaults to None. alpha : float or array-like, optional @@ -1113,7 +1131,7 @@ def __init__( col=None, col_wrap=None, height=3, - aspect=1, + aspect="auto", cmap=None, alpha=None, origin=None, From 51e56a0d9decde424adb5213875f92909798b02e Mon Sep 17 00:00:00 2001 From: eugenioLR Date: Fri, 12 Jul 2024 18:28:04 +0200 Subject: [PATCH 2/4] aspect ratio calculation was performed backwards. Solved bug in ParamGrid with new aspect ratio argument --- src/seaborn_image/_grid.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/seaborn_image/_grid.py b/src/seaborn_image/_grid.py index 65f3b9c..45ac777 100644 --- a/src/seaborn_image/_grid.py +++ b/src/seaborn_image/_grid.py @@ -370,7 +370,7 @@ def __init__( # Select minimum aspect ratio among all the images for img in data: - aspect_aux = img.shape[0] / img.shape[1] + aspect_aux = img.shape[1] / img.shape[0] if aspect_aux < aspect: aspect = aspect_aux @@ -395,7 +395,7 @@ def __init__( col_wrap = len(map_func) if col_wrap is None else col_wrap if aspect == "auto": - aspect = data.shape[0] / data.shape[1] + aspect = data.shape[1] / data.shape[0] elif data.ndim in [3, 4]: if data.ndim == 4 and data.shape[-1] not in [1, 3, 4]: @@ -432,7 +432,7 @@ def __init__( if aspect == "auto": # Select axis where width and height are - width_idx, height_idx = [i for i in range(data.ndim) if i != axis][:2] + height_idx, width_idx = [i for i in range(data.ndim) if i != axis][:2] aspect = data.shape[width_idx] / data.shape[height_idx] @@ -1192,6 +1192,9 @@ def __init__( nrow = int(np.ceil(len(kwargs[f"{col}"]) / col_wrap)) # Calculate the base figure size + if aspect == "auto": + aspect = data.shape[1]/data.shape[0] + figsize = (ncol * height * aspect, nrow * height) fig = plt.figure(figsize=figsize) From 5ce786257b45d793a6fde25897473405c31cdaf5 Mon Sep 17 00:00:00 2001 From: eugenioLR Date: Mon, 15 Jul 2024 10:47:17 +0200 Subject: [PATCH 3/4] improved plot in ImageGrid documentation, new aspect calculation messed up the image --- src/seaborn_image/_grid.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/seaborn_image/_grid.py b/src/seaborn_image/_grid.py index 45ac777..25ad2bb 100644 --- a/src/seaborn_image/_grid.py +++ b/src/seaborn_image/_grid.py @@ -290,7 +290,8 @@ class ImageGrid: ... [pol, pl, retina], ... map_func=[gaussian, median, hessian], ... dx=[15, 100, None], - ... units="nm") + ... units="nm", + ... aspect=1) Change colorbar orientation From 201195e3f776373e866c8f3dbe8e6cd46dc5f15e Mon Sep 17 00:00:00 2001 From: eugenioLR Date: Mon, 2 Sep 2024 12:52:38 +0200 Subject: [PATCH 4/4] added tests and solved issues in pull request --- src/seaborn_image/_grid.py | 15 +++++---------- tests/test_grid.py | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/seaborn_image/_grid.py b/src/seaborn_image/_grid.py index 7e019b4..cb6b9f5 100644 --- a/src/seaborn_image/_grid.py +++ b/src/seaborn_image/_grid.py @@ -367,13 +367,8 @@ def __init__( ) if aspect == "auto": - aspect = 1e10 - - # Select minimum aspect ratio among all the images - for img in data: - aspect_aux = img.shape[1] / img.shape[0] - if aspect_aux < aspect: - aspect = aspect_aux + aspect_ratios = [img.shape[1] / img.shape[0] for img in data] + aspect = min(aspect_ratios) elif not isinstance(data, np.ndarray): raise ValueError("image data must be a list of images or a 3d or 4d array.") @@ -433,7 +428,7 @@ def __init__( if aspect == "auto": # Select axis where width and height are - height_idx, width_idx = [i for i in range(data.ndim) if i != axis][:2] + height_idx, width_idx = [i for i in range(data.ndim) if i != (axis % data.ndim)][:2] aspect = data.shape[width_idx] / data.shape[height_idx] @@ -1192,10 +1187,10 @@ def __init__( ncol = col_wrap nrow = int(np.ceil(len(kwargs[f"{col}"]) / col_wrap)) - # Calculate the base figure size if aspect == "auto": aspect = data.shape[1]/data.shape[0] - + + # Calculate the base figure size figsize = (ncol * height * aspect, nrow * height) fig = plt.figure(figsize=figsize) diff --git a/tests/test_grid.py b/tests/test_grid.py index 47ed310..156a80b 100644 --- a/tests/test_grid.py +++ b/tests/test_grid.py @@ -871,7 +871,28 @@ def test_figure_size(self): ) np.testing.assert_array_equal(g4.fig.get_size_inches(), (3 * 2 * 1.5, 2 * 2)) plt.close() + + def test_auto_aspect(self): + imgsize0 = (10, 10) + g0 = isns.ImageGrid([np.zeros(imgsize0) for i in range(10)], aspect='auto') + assert np.isclose(imgsize0[1]/imgsize0[0], g0.aspect) + plt.close() + imgsize1 = (10, 5) + g1 = isns.ImageGrid([np.zeros(imgsize1) for i in range(10)], aspect='auto') + assert np.isclose(imgsize1[1]/imgsize1[0], g1.aspect) + plt.close() + + imgsize2 = (5, 10) + g2 = isns.ImageGrid([np.zeros(imgsize2) for i in range(10)], aspect='auto') + assert np.isclose(imgsize2[1]/imgsize2[0], g2.aspect) + plt.close() + + imglist = [np.zeros(imgsize0) for i in range(4)] + [np.zeros(imgsize1) for i in range(4)] + [np.zeros(imgsize2) for i in range(4)] + g3 = isns.ImageGrid(imglist, aspect='auto') + assert np.isclose(min([imgsize0[1]/imgsize0[0], imgsize1[1]/imgsize1[0], imgsize2[1]/imgsize2[0]]), g3.aspect) + plt.close() + def test_vmin_vmax(self): g = isns.ImageGrid(cells, vmin=0.5, vmax=0.75) for ax in g.axes.ravel():