Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: fix default math font in yt plots against matplotlib >= 3.4 #3520

Merged
merged 3 commits into from Oct 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion answer-store
1 change: 0 additions & 1 deletion tests/matplotlibrc
@@ -1,4 +1,3 @@
#### MATPLOTLIBRC FORMAT

backend : Agg
mathtext.fontset : cm
4 changes: 2 additions & 2 deletions tests/tests.yaml
Expand Up @@ -92,7 +92,7 @@ answer_tests:
- yt/frontends/owls/tests/test_outputs.py:test_snapshot_033
- yt/frontends/owls/tests/test_outputs.py:test_OWLS_particlefilter

local_pw_037: # PR 3373
local_pw_038: # PR 3520
- yt/visualization/tests/test_plotwindow.py:test_attributes
- yt/visualization/tests/test_particle_plot.py:test_particle_projection_answers
- yt/visualization/tests/test_particle_plot.py:test_particle_projection_filter
Expand Down Expand Up @@ -167,7 +167,7 @@ answer_tests:
local_axialpix_007:
- yt/geometry/coordinates/tests/test_axial_pixelization.py:test_axial_pixelization

local_cylindrical_background_008: # PR 3536
local_cylindrical_background_010: # PR 3520
- yt/geometry/coordinates/tests/test_cylindrical_coordinates.py:test_noise_plots

#local_particle_trajectory_001:
Expand Down
14 changes: 14 additions & 0 deletions yt/visualization/_commons.py
@@ -1,6 +1,9 @@
import os
from typing import Optional

import matplotlib
from packaging.version import Version

from yt.utilities.logger import ytLogger as mylog

from ._mpl_imports import (
Expand All @@ -10,6 +13,17 @@
FigureCanvasSVG,
)

MPL_VERSION = Version(matplotlib.__version__)

DEFAULT_FONT_PROPERTIES = {
"family": "stixgeneral",
"size": 18,
}

if MPL_VERSION >= Version("3.4"):
DEFAULT_FONT_PROPERTIES["math_fontfamily"] = "cm"


AGG_FORMATS = [".png", ".jpg", ".jpeg", ".raw", ".rgba", ".tif", ".tiff"]
SUPPORTED_FORMATS = AGG_FORMATS + [".eps", ".ps", ".pdf", ".svg"]

Expand Down
25 changes: 14 additions & 11 deletions yt/visualization/plot_container.py
@@ -1,13 +1,14 @@
import base64
import builtins
import os
import sys
import textwrap
from collections import defaultdict
from functools import wraps

import matplotlib
import numpy as np
from matplotlib.cm import get_cmap
from matplotlib.font_manager import FontProperties
from more_itertools.more import always_iterable

from yt._maintenance.deprecation import issue_deprecation_warning
Expand All @@ -19,7 +20,7 @@
from yt.utilities.definitions import formatted_length_unit_names
from yt.utilities.exceptions import YTNotInsideNotebook

from ._commons import validate_image_name
from ._commons import DEFAULT_FONT_PROPERTIES, validate_image_name

try:
import cmocean
Expand Down Expand Up @@ -248,19 +249,20 @@ class PlotContainer:
_units_config: dict

def __init__(self, data_source, figure_size, fontsize):
from matplotlib.font_manager import FontProperties

self.data_source = data_source
self.ds = data_source.ds
self.ts = self._initialize_dataset(self.ds)
if is_sequence(figure_size):
self.figure_size = float(figure_size[0]), float(figure_size[1])
else:
self.figure_size = float(figure_size)
font_path = os.path.join(
matplotlib.get_data_path(), "fonts", "ttf", "STIXGeneral.ttf"
)
self._font_properties = FontProperties(size=fontsize, fname=font_path)

if sys.version_info >= (3, 9):
font_dict = DEFAULT_FONT_PROPERTIES | {"size": fontsize}
else:
font_dict = {**DEFAULT_FONT_PROPERTIES, "size": fontsize}
neutrinoceros marked this conversation as resolved.
Show resolved Hide resolved

self._font_properties = FontProperties(**font_dict)
self._font_color = None
self._xlabel = None
self._ylabel = None
Expand Down Expand Up @@ -508,16 +510,17 @@ def set_font(self, font_dict=None):
... )

"""
from matplotlib.font_manager import FontProperties

if font_dict is None:
font_dict = {}
if "color" in font_dict:
self._font_color = font_dict.pop("color")
# Set default values if the user does not explicitly set them.
# this prevents reverting to the matplotlib defaults.
font_dict.setdefault("family", "stixgeneral")
font_dict.setdefault("size", 18)
if sys.version_info >= (3, 9):
font_dict = DEFAULT_FONT_PROPERTIES | font_dict
else:
font_dict = {**DEFAULT_FONT_PROPERTIES, **font_dict}
neutrinoceros marked this conversation as resolved.
Show resolved Hide resolved
self._font_properties = FontProperties(**font_dict)
return self

Expand Down
82 changes: 6 additions & 76 deletions yt/visualization/profile_plotter.py
Expand Up @@ -6,6 +6,7 @@

import matplotlib
import numpy as np
from matplotlib.font_manager import FontProperties
from more_itertools.more import always_iterable, unzip
from packaging.version import parse as parse_version

Expand All @@ -17,10 +18,11 @@
from yt.utilities.logger import ytLogger as mylog

from ..data_objects.selection_objects.data_selection_objects import YTSelectionContainer
from ._commons import validate_image_name
from ._commons import DEFAULT_FONT_PROPERTIES, validate_image_name
from .base_plot_types import ImagePlotMPL, PlotMPL
from .plot_container import (
ImagePlotContainer,
PlotContainer,
get_log_minorticks,
invalidate_plot,
linear_transform,
Expand Down Expand Up @@ -113,7 +115,7 @@ def data_object_or_all_data(data_source):
return data_source


class ProfilePlot:
class ProfilePlot(PlotContainer):
r"""
Create a 1d profile plot from a data source or from a list
of profile objects.
Expand Down Expand Up @@ -374,6 +376,7 @@ def _setup_plots(self):
fontproperties=self._font_properties,
**self._text_kwargs[f],
)
self._set_font_properties()

for i, profile in enumerate(self.profiles):
for field, field_data in profile.items():
Expand Down Expand Up @@ -415,9 +418,7 @@ def _initialize_instance(cls, obj, profiles, labels, plot_specs, y_log):
obj._text_ypos = {}
obj._text_kwargs = {}

from matplotlib.font_manager import FontProperties

obj._font_properties = FontProperties(family="stixgeneral", size=18)
obj._font_properties = FontProperties(**DEFAULT_FONT_PROPERTIES)
obj._font_color = None
obj.profiles = list(always_iterable(profiles))
obj.x_log = None
Expand Down Expand Up @@ -1336,77 +1337,6 @@ def save(self, name=None, suffix=".png", mpl_kwargs=None):
self.plots[f].save(name, mpl_kwargs)
return names

@invalidate_plot
def set_font(self, font_dict=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, so can we no longer manually set the font in our plots? I don't think i ever have, but it might be something people have used in the past.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it will still be possible, thanks to inheritance. Because I'm making ProfilePlot a subclass of PlotContainer, we don't need to have this method here, which was duplicated code from PlotContainer anyway :-)

"""
Set the font and font properties.
Parameters
----------
font_dict : dict
A dict of keyword parameters to be passed to
:class:`matplotlib.font_manager.FontProperties`.
Possible keys include:
* family - The font family. Can be serif, sans-serif, cursive,
'fantasy', or 'monospace'.
* style - The font style. Either normal, italic or oblique.
* color - A valid color string like 'r', 'g', 'red', 'cobalt',
and 'orange'.
* variant - Either normal or small-caps.
* size - Either a relative value of xx-small, x-small, small,
medium, large, x-large, xx-large or an absolute font size, e.g. 12
* stretch - A numeric value in the range 0-1000 or one of
ultra-condensed, extra-condensed, condensed, semi-condensed,
normal, semi-expanded, expanded, extra-expanded or ultra-expanded
* weight - A numeric value in the range 0-1000 or one of ultralight,
light, normal, regular, book, medium, roman, semibold, demibold,
demi, bold, heavy, extra bold, or black
See the matplotlib font manager API documentation for more details.
https://matplotlib.org/stable/api/font_manager_api.html
Notes
-----
Mathtext axis labels will only obey the `size` and `color` keyword.
Examples
--------
This sets the font to be 24-pt, blue, sans-serif, italic, and
bold-face.
>>> prof = ProfilePlot(
... ds.all_data(), ("gas", "density"), ("gas", "temperature")
... )
>>> slc.set_font(
... {
... "family": "sans-serif",
... "style": "italic",
... "weight": "bold",
... "size": 24,
... "color": "blue",
... }
... )
"""
from matplotlib.font_manager import FontProperties

if font_dict is None:
font_dict = {}
if "color" in font_dict:
self._font_color = font_dict.pop("color")
# Set default values if the user does not explicitly set them.
# this prevents reverting to the matplotlib defaults.
font_dict.setdefault("family", "stixgeneral")
font_dict.setdefault("size", 18)
self._font_properties = FontProperties(**font_dict)
return self

@invalidate_plot
def set_title(self, field, title):
"""Set a title for the plot.
Expand Down