Skip to content

Commit

Permalink
fix(plotting.annotations): expose property label generation to public…
Browse files Browse the repository at this point in the history
… api

A new `property_labels` function can be used to generate strings that are used by `label_subplot_properties` so that the labels can be used as titles easily through `eplt.set_titles`. Also, label generation now recognizes time, given as 't' with default unit seconds.
  • Loading branch information
kmnhan committed Jul 30, 2024
1 parent 01c655e commit 545781d
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 29 deletions.
110 changes: 84 additions & 26 deletions src/erlab/plotting/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"mark_points",
"mark_points_outside",
"plot_hv_text",
"property_label",
"property_labels",
"scale_units",
"set_titles",
"set_xlabels",
Expand All @@ -38,6 +38,7 @@
import pyperclip
from mpl_toolkits.axes_grid1.anchored_artists import AnchoredSizeBar

from erlab.accessors.utils import either_dict_or_kwargs
from erlab.plotting.colors import axes_textcolor

if TYPE_CHECKING:
Expand Down Expand Up @@ -94,6 +95,7 @@
PRETTY_NAMES: dict[str, tuple[str, str]] = {
"temperature": ("Temperature", "Temperature"),
"T": (r"\ensuremath{T}", r"$T$"),
"t": (r"\ensuremath{t}", r"$t$"),
"beta": (r"\ensuremath{\beta}", r"$\beta$"),
"theta": (r"\ensuremath{\theta}", r"$\theta$"),
"chi": (r"\ensuremath{\chi}", r"$\chi$"),
Expand All @@ -119,6 +121,7 @@
PRETTY_UNITS: dict[str, tuple[str, str]] = {
"temperature": (r"K", r"K"),
"T": (r"K", r"K"),
"t": (r"s", r"s"),
"theta": (r"deg", r"deg"),
"beta": (r"deg", r"deg"),
"psi": (r"deg", r"deg"),
Expand Down Expand Up @@ -321,6 +324,66 @@ def fancy_labels(ax=None, deg2rad=False) -> None:
ax.set_zlabel(label_for_dim(dim_name=ax.get_zlabel(), deg2rad=deg2rad))


def property_labels(
values: dict | None = None,
decimals: int | None = None,
si: int = 0,
name: str | None = None,
unit: str | None = None,
order: Literal["C", "F", "A", "K"] = "C",
**values_kwargs,
) -> list[str]:
"""Generate labels from a dictionary of values.
Given a dictionary of values, this function generates a list of label strings with
the key as the dimension name and the value as the dimension value. Multiple
key-value pairs will be separated by a newline character in each label. The name and
unit will be automatically determined from the key.
Parameters
----------
values
Key-value pair of annotations. The values may be a single value or an array-like
of values. If a single value, it will be converted to a list of length 1. If an
array of 2 or more dimensions is given, it will be flattened with the order
given by `order`. All values must be of the same length when flattened.
decimals
Number of decimal places to round to. If decimals is None, no rounding is
performed. If decimals is negative, it specifies the number of positions to the
left of the decimal point.
si
Powers of 10 for automatic SI prefix setting.
name
When set, overrides automatic dimension name setting.
unit
When set, overrides automatic unit setting.
order
Order in which to flatten `ax`. 'C' means to flatten in row-major (C-style)
order. 'F' means to flatten in column-major (Fortran- style) order. 'A' means to
flatten in column-major order if a is Fortran contiguous in memory, row-major
order otherwise. 'K' means to flatten a in the order the elements occur in
memory. The default is 'C'.
"""
values = either_dict_or_kwargs(values, values_kwargs, "property_labels")
strlist: Any = []
for k, v in values.items():
if not isinstance(v, tuple | list | np.ndarray):
v = [v]
else:
v = np.array(v).flatten(order=order)
strlist.append(
[
property_label(
k, val, decimals=decimals, si=si, name=name, unit=unit
).strip()
for val in v
]
)
strlist = list(zip(*strlist, strict=True))
return ["\n".join(strlist[i]) for i in range(len(strlist))]


def label_subplot_properties(
axes: matplotlib.axes.Axes | Iterable[matplotlib.axes.Axes],
values: dict,
Expand All @@ -339,24 +402,26 @@ def label_subplot_properties(
`matplotlib.axes.Axes` to label. If an array is given, the order will be
determined by the flattening method given by `order`.
values
key-value pair of annotations.
Key-value pair of annotations. The values may be a single value or an array-like
of values. If a single value, it will be converted to a list of length 1. If an
array of 2 or more dimensions is given, it will be flattened with the order
given by `order`. All values must be of the same length when flattened.
decimals
Number of decimal places to round to. If decimals is None, no
rounding is performed. If decimals is negative, it specifies the
number of positions to the left of the decimal point.
Number of decimal places to round to. If decimals is None, no rounding is
performed. If decimals is negative, it specifies the number of positions to the
left of the decimal point.
si
Powers of 10 for automatic SI prefix setting.
name
When set, overrides automatic dimension name setting.
unit
When set, overrides automatic unit setting.
order
Order in which to flatten `ax`. 'C' means to flatten in
row-major (C-style) order. 'F' means to flatten in column-major
(Fortran- style) order. 'A' means to flatten in column-major
order if a is Fortran contiguous in memory, row-major order
otherwise. 'K' means to flatten a in the order the elements
occur in memory. The default is 'C'.
Order in which to flatten `ax`. 'C' means to flatten in row-major (C-style)
order. 'F' means to flatten in column-major (Fortran- style) order. 'A' means to
flatten in column-major order if a is Fortran contiguous in memory, row-major
order otherwise. 'K' means to flatten a in the order the elements occur in
memory. The default is 'C'.
**kwargs
Extra arguments to `erlab.plotting.annotations.label_subplots`.
Expand All @@ -366,21 +431,14 @@ def label_subplot_properties(
kwargs.setdefault("suffix", "")
kwargs.setdefault("loc", "upper right")

strlist: Any = []
for k, v in values.items():
if not isinstance(v, tuple | list | np.ndarray):
v = [v]
else:
v = np.array(v).flatten(order=order)
strlist.append(
[
property_label(k, val, decimals=decimals, si=si, name=name, unit=unit)
for val in v
]
)
strlist = list(zip(*strlist, strict=True))
strlist = ["\n".join(strlist[i]) for i in range(len(strlist))]
label_subplots(axes, strlist, order=order, **kwargs)
label_subplots(
axes,
property_labels(
values, decimals=decimals, si=si, name=name, unit=unit, order=order
),
order=order,
**kwargs,
)


def label_subplots(
Expand Down
4 changes: 2 additions & 2 deletions src/erlab/plotting/erplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"plot_hex_bz",
"plot_hv_text",
"plot_slices",
"property_label",
"property_labels",
"proportional_colorbar",
"scale_units",
"set_titles",
Expand All @@ -50,7 +50,7 @@
mark_points,
mark_points_outside,
plot_hv_text,
property_label,
property_labels,
scale_units,
set_titles,
set_xlabels,
Expand Down
17 changes: 16 additions & 1 deletion tests/plotting/test_annotations.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import matplotlib.pyplot as plt
import numpy as np
import pytest
from erlab.plotting.annotations import copy_mathtext, mark_points
from erlab.plotting.annotations import copy_mathtext, mark_points, property_labels


def test_mark_points():
Expand Down Expand Up @@ -40,3 +40,18 @@ def test_copy_mathtext(outline):
assert copy_mathtext("$c_1$", svg=True, outline=outline).startswith(
'<?xml version="1.0" encoding="utf-8"'
)


def test_property_labels():
values = {
"T": [1.234, 2.345, 3.456],
"eV": [0.1, 0.2, 0.3],
"t": [0.01, 0.02, 0.03],
}
expected_labels = [
"$T = 1230$ mK\n$E-E_F = 100$ meV\n$t = 10$ ms",
"$T = 2340$ mK\n$E-E_F = 200$ meV\n$t = 20$ ms",
"$T = 3460$ mK\n$E-E_F = 300$ meV\n$t = 30$ ms",
]
labels = property_labels(values, decimals=-1, si=-3)
assert labels == expected_labels

0 comments on commit 545781d

Please sign in to comment.