Skip to content

Commit

Permalink
ENH: determine compatible matplotlib backend semi-dynamically. Incide…
Browse files Browse the repository at this point in the history
…ntally add support for .svgz image format.
  • Loading branch information
neutrinoceros committed Oct 9, 2021
1 parent 8015b41 commit 1150fd6
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 26 deletions.
55 changes: 31 additions & 24 deletions yt/visualization/_commons.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
from typing import Optional
import sys
from typing import Optional, Type

import matplotlib
from packaging.version import Version
Expand All @@ -8,6 +9,7 @@

from ._mpl_imports import (
FigureCanvasAgg,
FigureCanvasBase,
FigureCanvasPdf,
FigureCanvasPS,
FigureCanvasSVG,
Expand All @@ -23,13 +25,33 @@
if MPL_VERSION >= Version("3.4"):
DEFAULT_FONT_PROPERTIES["math_fontfamily"] = "cm"

SUPPORTED_FORMATS = frozenset(FigureCanvasBase.get_supported_filetypes().keys())
SUPPORTED_CANVAS_CLASSES = frozenset(
(FigureCanvasAgg, FigureCanvasPdf, FigureCanvasPS, FigureCanvasSVG)
)


AGG_FORMATS = [".png", ".jpg", ".jpeg", ".raw", ".rgba", ".tif", ".tiff"]
SUPPORTED_FORMATS = AGG_FORMATS + [".eps", ".ps", ".pdf", ".svg"]
def get_canvas_class(suffix: str) -> Type[FigureCanvasBase]:
s = normalize_extension_string(suffix)
if s not in SUPPORTED_FORMATS:
raise ValueError(f"Unsupported file format '{suffix}'.")
for cls in SUPPORTED_CANVAS_CLASSES:
if s in cls.get_supported_filetypes():
return cls
raise RuntimeError(
"Something went terribly wrong. "
f"File extension '{suffix}' is supposed to be supported "
"but no compatible backend was found."
)


def normalize_extension_string(s: str) -> str:
return f".{s.lstrip('.')}"
if sys.version_info < (3, 9):
if s.startswith("."):
return s[1:]
return s
else:
return s.removeprefix(".")


def validate_image_name(filename, suffix: Optional[str] = None) -> str:
Expand All @@ -39,7 +61,7 @@ def validate_image_name(filename, suffix: Optional[str] = None) -> str:
Otherwise, suffix is appended to the filename, replacing any existing extension.
"""
name, psuffix = os.path.splitext(filename)
if psuffix in SUPPORTED_FORMATS:
if normalize_extension_string(psuffix) in SUPPORTED_FORMATS:
if suffix is not None:
suffix = normalize_extension_string(suffix)
if suffix in SUPPORTED_FORMATS and suffix != psuffix:
Expand All @@ -49,7 +71,7 @@ def validate_image_name(filename, suffix: Optional[str] = None) -> str:
psuffix,
suffix,
)
return f"{name}{suffix}"
return f"{name}.{suffix}"
return str(filename)

if suffix is None:
Expand All @@ -58,9 +80,9 @@ def validate_image_name(filename, suffix: Optional[str] = None) -> str:
suffix = normalize_extension_string(suffix)

if suffix not in SUPPORTED_FORMATS:
raise ValueError("Unsupported file format '{suffix}'.")
raise ValueError(f"Unsupported file format '{suffix}'.")

return f"{filename}{suffix}"
return f"{filename}.{suffix}"


def get_canvas(figure, filename):
Expand All @@ -72,19 +94,4 @@ def get_canvas(figure, filename):
f"Can not determine canvas class from filename '{filename}' "
f"without an extension."
)

if suffix in AGG_FORMATS:
return FigureCanvasAgg(figure)

if suffix == ".pdf":
return FigureCanvasPdf(figure)

if suffix == ".svg":
return FigureCanvasSVG(figure)

if suffix in (".eps", ".ps"):
return FigureCanvasPS(figure)

raise ValueError(
f"No matching canvas for filename '{filename}' with extension '{suffix}'."
)
return get_canvas_class(suffix)(figure)
1 change: 1 addition & 0 deletions yt/visualization/_mpl_imports.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import matplotlib
from matplotlib.backend_bases import FigureCanvasBase
from matplotlib.backends.backend_agg import FigureCanvasAgg
from matplotlib.backends.backend_pdf import FigureCanvasPdf
from matplotlib.backends.backend_ps import FigureCanvasPS
Expand Down
5 changes: 3 additions & 2 deletions yt/visualization/volume_rendering/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,9 @@ def save(
fname: string, optional
If specified, save the rendering as to the file "fname".
If unspecified, it creates a default based on the dataset filename.
The file format is inferred from the filename's suffix. Supported
formats are png, pdf, eps, and ps.
The file format is inferred from the filename's suffix.
Supported formats depend on which version of matplotlib is installed.
Default: None
sigma_clip: float, optional
Image values greater than this number times the standard deviation
Expand Down

0 comments on commit 1150fd6

Please sign in to comment.