Skip to content

Commit

Permalink
Merge pull request #6 from Fanchengyan/dev
Browse files Browse the repository at this point in the history
update to v0.2.2
  • Loading branch information
Fanchengyan authored Aug 19, 2024
2 parents 10b64db + d656354 commit 44e492f
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 29 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

- **Convenient to use** - You can easily generate a gallery of examples from
your Jupyter Notebooks, Markdown, or reStructuredText files. It works with `MyST` Ecosystem, including [MyST-parser](https://myst-parser.readthedocs.io/en/latest/) and [MyST-NB](https://myst-nb.readthedocs.io/en/latest/), to render markdown or jupyter notebooks in Sphinx documentation.
- **Customizable** - You can customize the gallery configuration, such as the strategy to select the thumbnail, the gallery layout, and the gallery directory.
- **Fast and robust** - It utilizes existing images to generate gallery thumbnails, eliminating code execution delays and potential accidental errors when building gallery.
- **Customizable** - You can customize the gallery, such as thumbnail selection, layout, and styling.

## Documentation

Expand Down Expand Up @@ -55,7 +56,7 @@ generate_gallery(
```

>[!NOTE]
> You can generate **multiple galleries** by proper configuration in the `conf.py` file. For more details, please refer to the [Configure multiple galleries](https://myst-sphinx-gallery.readthedocs.io/en/latest/user_guide/multi_galleries.htmll#configure-multiple-galleries).
> You can generate **multiple galleries** by proper configuration in the `conf.py` file. For more details, please refer to the [Configure multiple galleries](https://myst-sphinx-gallery.readthedocs.io/en/latest/user_guide/multi_galleries.html#configure-multiple-galleries).
## Construct the examples folder

Expand Down
1 change: 1 addition & 0 deletions docs/source/changelog/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ This is the list of changes to MyST Sphinx Gallery between each release. For ful
.. toctree::
:maxdepth: 2

v0.2.2
v0.2.1
v0.2.0
34 changes: 34 additions & 0 deletions docs/source/changelog/v0.2.2.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
==================================
What’s new in 0.2.2 (Aug 19, 2024)
==================================

Enhancements
------------

Thumbnails
^^^^^^^^^^


- :class:`~myst_sphinx_gallery.ThumbnailConfig` now supports a new option:
``max_animation_frames``, to control the maximum number of frames for the
animated thumbnail. This option is useful when the animation has too many
frames, saving storage space and building time.
- ``quality_animated`` changed from ``15`` to ``50`` to improve the quality of
the animation thumbnail. This change will not increase the animated
thumbnail file size since frames are reduced by the
``max_animation_frames`` option.


Cross-referencing
^^^^^^^^^^^^^^^^^

- the target of ``GALLERY_HEADER.rst`` now will be added a suffix ``_header``
to avoid conflict with the example files.

Runtime
^^^^^^^

Now, the runtime of building the gallery will be displayed in the console
output. This feature is useful when you want to know how long it takes to
build the gallery and optimize the building time by changing the configuration
options of thumbnails.
3 changes: 2 additions & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ Highlight Features
------------------

- **Convenient to use** - You can easily generate a gallery of examples from your Jupyter Notebooks, Markdown, or reStructuredText files. It works with ``MyST`` ecosystem, including `MyST-parser <https://myst-parser.readthedocs.io/en/latest/>`_ and `MyST-NB <https://myst-nb.readthedocs.io/en/latest/>`_, to render markdown or jupyter notebooks in Sphinx documentation.
- **Customizable** - You can customize the gallery configuration, such as the strategy to select the thumbnail, the gallery layout, and the gallery directory.
- **Fast and robust** - It utilizes existing images to generate gallery thumbnails, eliminating code execution delays and potential accidental errors when building gallery.
- **Customizable** - You can customize the gallery, such as thumbnail selection, layout, and styling.

.. toctree::
:maxdepth: 2
Expand Down
13 changes: 9 additions & 4 deletions docs/source/user_guide/cross_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ example files in the other documentation files.
Rule for generating targets
---------------------------

**For example files**:
For example files
~~~~~~~~~~~~~~~~~

- removing the number prefix ``dd-`` (if exists) and file suffix.
- converring the letters in the file name to lowercase (target must be small letters).
Expand All @@ -22,10 +23,14 @@ Rule for generating targets
The target is generated based on the file name, so you need to make sure the file name is unique.


**For GALLERY_HEADER.rst file**:
For ``GALLERY_HEADER.rst`` file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The rules are the same as the example files, except that the
**target is generated based on the folder name**.
The rules are the same as the example files, except:

- target is generated based on the folder name.
- adding a suffix ``_header`` to avoid conflict with the example files.
(need version 0.2.2 or later)

.. versionchanged:: 0.2.1

Expand Down
2 changes: 1 addition & 1 deletion myst_sphinx_gallery/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# dev versions should have "dev" in them, stable should not.
# doc/conf.py makes use of this to set the version drop-down.
# eg: "0.1.dev0", "0.1"
__version__ = "0.2.1"
__version__ = "0.2.2"


def setup(app: Sphinx):
Expand Down
14 changes: 12 additions & 2 deletions myst_sphinx_gallery/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from typing import Literal

from .grid import Grid, GridItemCard, TocTree
from .io_tools import abs_path
from .utils import abs_path


@dataclass
Expand All @@ -25,6 +25,16 @@ class ThumbnailConfig:
#: The parameters passed to the operation function.
operation_kwargs: dict[str, int] = field(default_factory=dict)

#: The maximum number of frames to extract from an animated image.
#: If the image has more frames, will sample the frames uniformly.
#:
#: .. tip::
#: If you want to make the thumbnail of animated images to be static images,
#: you can set this value to 1.
#:
#: .. versionadded:: 0.2.2
max_animation_frames: int = 100

#: The quality of the static image thumbnail.
#:
#: .. versionadded:: 0.2.1
Expand All @@ -33,7 +43,7 @@ class ThumbnailConfig:
#: The quality of the animated image thumbnail.
#:
#: .. versionadded:: 0.2.1
quality_animated: int = 15 # small quality for smaller size of animated thumbnail
quality_animated: int = 50 # small quality for smaller size of animated thumbnail

#: The parameters passed to save function for the thumbnail image.
#: See the Pillow documentation for more information:
Expand Down
11 changes: 8 additions & 3 deletions myst_sphinx_gallery/gallery.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
parse_md_images,
parse_rst_images,
)
from .io_tools import ensure_dir_exists, safe_remove_file
from .utils import ensure_dir_exists, print_run_time, safe_remove_file


@print_run_time
def generate_gallery(gallery_config: GalleryConfig | dict):
"""Generate the gallery from the examples directory."""
if isinstance(gallery_config, dict):
Expand Down Expand Up @@ -116,7 +117,9 @@ def index_file(self) -> Path:
@property
def target_str(self) -> str:
"""the target string in the gallery file used to link to the example file."""
target_ref = f"{self.config.target_prefix}{self.index_file.parent.stem}".lower()
target_ref = (
f"{self.config.target_prefix}{self.index_file.parent.stem}_header".lower()
)
return f".. _{target_ref}:"

@property
Expand Down Expand Up @@ -253,7 +256,9 @@ def index_file(self) -> Path:
@property
def target_str(self) -> str:
"""the target string in the gallery file used to link to the example file."""
target_ref = f"{self.config.target_prefix}{self.index_file.parent.stem}".lower()
target_ref = (
f"{self.config.target_prefix}{self.index_file.parent.stem}_header".lower()
)
return f".. _{target_ref}:"

@property
Expand Down
38 changes: 33 additions & 5 deletions myst_sphinx_gallery/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import nbformat
from PIL import Image, ImageOps

from .io_tools import ensure_dir_exists
from .utils import ensure_dir_exists, print_run_time

OperationMap = {
"contain": ImageOps.contain,
Expand All @@ -40,6 +40,7 @@ def __init__(
output_dir: Path | str,
ref_size: tuple[int, int] | int = (320, 224),
operation: Literal["thumbnail", "contain", "cover", "fit", "pad"] = "pad",
max_animation_frames=50,
quality_static: int = 80,
quality_animated: int = 15,
operation_kwargs: dict[str, int] | None = None,
Expand All @@ -54,7 +55,15 @@ def __init__(
ref_size : tuple[int, int]
the reference size of the thumbnail image for output.
operation : str
The operation to perform on the image. See the Pillow documentation for more information: `<https://pillow.readthedocs.io/en/stable/handbook/tutorial.html#relative-resizing>`_
The operation to perform on the image. See the Pillow documentation
for more information: `<https://pillow.readthedocs.io/en/stable/handbook/tutorial.html#relative-resizing>`_
max_animation_frames : int
The maximum number of frames to extract from an animated image.
If the image has more frames, will sample the frames uniformly.
quality_static : int
The quality of the static image thumbnail.
quality_animated : int
The quality of the animated image thumbnail.
operation_kwargs : dict
The keyword arguments for the operation.
save_kwargs : dict
Expand All @@ -79,6 +88,7 @@ def __init__(
self.operation = operation
self.operation_kwargs = operation_kwargs
self._output_dir = Path(output_dir)
self.max_animation_frames = max_animation_frames
self.quality_static = quality_static
self.quality_animated = quality_animated

Expand All @@ -101,7 +111,6 @@ def _format_save_kwargs(self, save_kwargs: dict) -> dict:
{
"quality": self.quality_animated,
"save_all": True,
"duration": self.image.info["duration"],
"loop": 0,
}
)
Expand All @@ -113,6 +122,20 @@ def _format_save_kwargs(self, save_kwargs: dict) -> dict:
kwargs.update(save_kwargs)
return kwargs

def _parse_frames(self):
"""Parse the frames and duration of the output animated image."""
n_frames = self.image.n_frames
max_frames = self.max_animation_frames
if n_frames > max_frames:
interval = n_frames // max_frames
frames = list(range(0, n_frames, interval))[:max_frames]
duration = self.image.info["duration"] * interval
else:
frames = range(n_frames)
duration = self.image.info["duration"]

return frames, duration

def _format_size(self, size: tuple[int, int] | int) -> tuple[int, int]:
"""Format the size of the thumbnail image to a tuple of length 2."""
if isinstance(size, int):
Expand Down Expand Up @@ -177,6 +200,7 @@ def generate_thumbnail(self) -> Image.Image:

return thumbnail

@print_run_time
def save_thumbnail(self, out_path: Path | None = None) -> Path:
"""Save the thumbnail image to the output directory.
Expand All @@ -193,11 +217,15 @@ def save_thumbnail(self, out_path: Path | None = None) -> Path:
"""
out_path = self.auto_output_path if out_path is None else Path(out_path)
ensure_dir_exists(out_path.parent)
print(f"Saving thumbnail to {out_path}")

if self.image.n_frames > 1:
frames_idx, duration = self._parse_frames()
self.save_kwargs.update({"duration": duration})
# extract frames
frames = []
for frame in range(self.image.n_frames):
self.image.seek(frame)
for idx in frames_idx:
self.image.seek(idx)
frames.append(self.generate_thumbnail())

frames[0].save(
Expand Down
17 changes: 17 additions & 0 deletions myst_sphinx_gallery/io_tools.py → myst_sphinx_gallery/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,20 @@ def abs_path(path: Path | str, root_dir: Path | str) -> Path:
if path.startswith("/"):
path = f".{path}"
return (Path(root_dir) / path).resolve()


def print_run_time(func):
"""Print the run time of a function."""

def wrapper(*args, **kwargs):
import time

start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()

print(f"Run time for {func.__name__}: {end_time - start_time:.2f} seconds")

return result

return wrapper
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ markers = [
"slow: marks tests as slow",
]

[tool.ruff]
line-length = 88

[tool.ruff.lint]
select = ["E", "F", "I", "SIM", "B", "UP"]
Expand All @@ -120,7 +122,7 @@ ignore = ["F401", "E501"]
[tool.ruff.format]
docstring-code-format = true


[tool.doc8]
ignore = ["D001"]
allow-long-titles = true
max-line-length=88
Loading

0 comments on commit 44e492f

Please sign in to comment.