From 4c2d2b9ba3d18edb009d1077c45f469e78133236 Mon Sep 17 00:00:00 2001 From: Daniel Kohler <11864045+ddkohler@users.noreply.github.com> Date: Wed, 29 May 2024 14:28:54 -0500 Subject: [PATCH 1/3] rework artists.stitch_to_animation use pathlib use pillow new kwargs --- WrightTools/artists/_helpers.py | 57 +++++++++++++++++++++++++-------- setup.py | 10 +++--- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/WrightTools/artists/_helpers.py b/WrightTools/artists/_helpers.py index 9b2e6a5c..c28a4185 100644 --- a/WrightTools/artists/_helpers.py +++ b/WrightTools/artists/_helpers.py @@ -3,7 +3,7 @@ # --- import -------------------------------------------------------------------------------------- -import os +import pathlib import numpy as np @@ -877,7 +877,7 @@ def savefig(path, fig=None, close=True, **kwargs): if fig is None: fig = plt.gcf() - path = os.path.abspath(path) + path = pathlib.Path(path).resolve() kwargs["dpi"] = kwargs.get("dpi", 300) kwargs["transparent"] = kwargs.get("transparent", False) @@ -1085,7 +1085,9 @@ def subplots_adjust(fig=None, inches=1): fig.subplots_adjust(top=top, right=right, bottom=bottom, left=left) -def stitch_to_animation(paths, outpath=None, *, duration=0.5, palettesize=256, verbose=True): +def stitch_to_animation( + paths, outpath=None, *, duration=0.5, ignore_alpha=True, reduce=None, verbose=True, **kwargs +): """Stitch a series of images into an animation. Currently supports animated gifs, other formats coming as needed. @@ -1099,23 +1101,52 @@ def stitch_to_animation(paths, outpath=None, *, duration=0.5, palettesize=256, v of first path in `images`. Default is None. duration : number or list of numbers (optional) Duration of (each) frame in seconds. Default is 0.5. - palettesize : int (optional) - The number of colors in the resulting animation. Input is rounded to - the nearest power of 2. Default is 256. + ignore_transparency : bool (optional) + When True, transparency is excluded from the gif and color palette may be higher res. ignoring alpha takes longer and produces larger gifs + reduce : int (optional) + Reduces the resolution along both image dimensions by a factor of `reduce`. verbose : bool (optional) Toggle talkback. Default is True. + + Returns: + -------- + outpath : pathlib.Path + path to generated gif """ + import contextlib + from PIL import Image + # parse filename if outpath is None: - outpath = os.path.splitext(paths[0])[0] + ".gif" + outpath = pathlib.Path(paths[0]).with_suffix(".gif") # write t = wt_kit.Timer(verbose=False) - with t, iio.imopen(outpath, "w") as gif: - for p in paths: - frame = iio.imread(p) - gif.write( - frame, plugin="pillow", duration=duration * 1e3, loop=0, palettesize=palettesize - ) + + def process_imgs(imgs): + count = 0 + for img in imgs: + if verbose: + print(f"processing {count+1} / {len(paths)}...") + if ignore_alpha: + img = img.convert("RGB") + if reduce is not None: + img = img.reduce(reduce) + count += 1 + yield img + + with t, contextlib.ExitStack() as stack: + imgs = process_imgs(stack.enter_context(Image.open(p)) for p in paths) + img = next(imgs) + img.save( + fp=outpath, + format="GIF", + append_images=imgs, + save_all=True, + duration=duration * 1e3, + loop=0, + **kwargs, + ) + if verbose: interval = np.round(t.interval, 2) print("gif generated in {0} seconds - saved at {1}".format(interval, outpath)) diff --git a/setup.py b/setup.py index d4fe3588..16ae3faa 100755 --- a/setup.py +++ b/setup.py @@ -1,14 +1,14 @@ #! /usr/bin/env python3 -import os +import pathlib from setuptools import setup, find_packages -here = os.path.abspath(os.path.dirname(__file__)) +here = pathlib.Path(__file__).resolve().parent def read(fname): - with open(os.path.join(here, fname)) as f: + with open(here / fname) as f: return f.read() @@ -25,7 +25,7 @@ def read(fname): ] } -with open(os.path.join(here, "WrightTools", "VERSION")) as version_file: +with open(here / "WrightTools" / "VERSION") as version_file: version = version_file.read().strip() docs_require = ["sphinx", "sphinx-gallery==0.8.2", "sphinx-rtd-theme"] @@ -37,7 +37,7 @@ def read(fname): python_requires=">=3.7", install_requires=[ "h5py", - "imageio>=2.28.0", + "pillow", "matplotlib>=3.4.0", "numexpr", "numpy>=1.15.0", From 38c6d265a61a107cace01376ba9fa1e4e1bf6aec Mon Sep 17 00:00:00 2001 From: Daniel Kohler <11864045+ddkohler@users.noreply.github.com> Date: Thu, 30 May 2024 11:25:37 -0500 Subject: [PATCH 2/3] docs --- CHANGELOG.md | 2 ++ WrightTools/artists/_helpers.py | 20 +++++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd1e54d5..aedc65ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). - new artist helper function: `norm_from_channel` - new artist helper function: `ticks_from_norm` - new artist iterator `ChopHandler` +- `artists.stitch_to_animation`: new kwargs for more gif customization ### Fixed - fixed Quick2D/Quick1D issues where collapsing unused dims did not work @@ -17,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). - constants in chopped data will inherit the units of the original data ## Changed +- use `pillow` directly and remove `ImageIO` dependency - refactor of artists.quick1D and artists.quick2D - quick2D and quick1D will not force `autosave=True` if the number of figures is large. Instead, interactive plotting will be truncated if the number of figures is large. - artists now gets turbo colormap straight from matplotlib diff --git a/WrightTools/artists/_helpers.py b/WrightTools/artists/_helpers.py index c28a4185..bed113a7 100644 --- a/WrightTools/artists/_helpers.py +++ b/WrightTools/artists/_helpers.py @@ -15,6 +15,7 @@ from matplotlib.colors import Normalize, CenteredNorm, TwoSlopeNorm from mpl_toolkits.axes_grid1 import make_axes_locatable +from typing import List import imageio.v3 as iio import warnings @@ -1086,23 +1087,20 @@ def subplots_adjust(fig=None, inches=1): def stitch_to_animation( - paths, outpath=None, *, duration=0.5, ignore_alpha=True, reduce=None, verbose=True, **kwargs + paths, outpath=None, duration=0.5, ignore_alpha:bool=True, reduce:int=None, verbose=True, **kwargs ): - """Stitch a series of images into an animation. - - Currently supports animated gifs, other formats coming as needed. + """Stitch a series of images into a gif. Parameters ---------- paths : list of strings - Filepaths to the images to stitch together, in order of apperence. + Filepaths to the images to stitch together, in order of appearance. outpath : string (optional) - Path of output, including extension. If None, bases output path on path - of first path in `images`. Default is None. + Path of output, including extension. If None, bases output path on `paths[0]`. Default is None. duration : number or list of numbers (optional) Duration of (each) frame in seconds. Default is 0.5. - ignore_transparency : bool (optional) - When True, transparency is excluded from the gif and color palette may be higher res. ignoring alpha takes longer and produces larger gifs + ignore_alpha : bool (optional) + When True, transparency is excluded from the gif and color palette may be higher res. reduce : int (optional) Reduces the resolution along both image dimensions by a factor of `reduce`. verbose : bool (optional) @@ -1110,7 +1108,7 @@ def stitch_to_animation( Returns: -------- - outpath : pathlib.Path + outpath : path-like path to generated gif """ import contextlib @@ -1122,7 +1120,7 @@ def stitch_to_animation( # write t = wt_kit.Timer(verbose=False) - def process_imgs(imgs): + def process_imgs(imgs:List[Image.Image]): count = 0 for img in imgs: if verbose: From b64a93aab2144b75c8ff4e0b48d58a1836a2fbdf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 16:26:25 +0000 Subject: [PATCH 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- WrightTools/artists/_helpers.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/WrightTools/artists/_helpers.py b/WrightTools/artists/_helpers.py index bed113a7..7f72d919 100644 --- a/WrightTools/artists/_helpers.py +++ b/WrightTools/artists/_helpers.py @@ -1087,7 +1087,13 @@ def subplots_adjust(fig=None, inches=1): def stitch_to_animation( - paths, outpath=None, duration=0.5, ignore_alpha:bool=True, reduce:int=None, verbose=True, **kwargs + paths, + outpath=None, + duration=0.5, + ignore_alpha: bool = True, + reduce: int = None, + verbose=True, + **kwargs, ): """Stitch a series of images into a gif. @@ -1120,7 +1126,7 @@ def stitch_to_animation( # write t = wt_kit.Timer(verbose=False) - def process_imgs(imgs:List[Image.Image]): + def process_imgs(imgs: List[Image.Image]): count = 0 for img in imgs: if verbose: