Skip to content

Commit 4460449

Browse files
committed
Replaces cf-units with pint
1 parent 7320a9e commit 4460449

File tree

4 files changed

+32
-60
lines changed

4 files changed

+32
-60
lines changed

pyproject.toml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ dependencies = [
2626
"earthkit-data",
2727
"earthkit-plots-default-styles",
2828
"cartopy>=0.22.0",
29-
"cf-units",
29+
"pint",
3030
"matplotlib",
3131
"pyyaml",
3232
"numpy",
@@ -40,9 +40,6 @@ license = {text = "Apache License Version 2.0"}
4040
name = "earthkit-plots"
4141
readme = "README.md"
4242
requires-python = ">=3.8"
43-
optional-dependencies.all = [
44-
"cf_units"
45-
]
4643
optional-dependencies.test = [
4744
"nbconvert",
4845
"nbformat",

src/earthkit/plots/metadata/units.py

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,30 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import re
16+
17+
from pint import UnitRegistry
18+
19+
ureg = UnitRegistry()
20+
Q_ = ureg.Quantity
21+
22+
23+
def _pintify(unit_str):
24+
# Replace spaces with dots
25+
unit_str = unit_str.replace(" ", ".")
26+
27+
# Insert ^ between characters and numbers (including negative numbers)
28+
unit_str = re.sub(r"([a-zA-Z])(-?\d+)", r"\1^\2", unit_str)
29+
30+
return ureg(unit_str).units
1531

16-
_NO_CF_UNITS = False
17-
try:
18-
import cf_units
19-
except ImportError:
20-
_NO_CF_UNITS = True
2132

2233
#: Units for temperature anomalies.
2334
TEMPERATURE_ANOM_UNITS = [
2435
"kelvin",
2536
"celsius",
2637
]
2738

28-
#: Pretty units for temperature.
29-
PRETTY_UNITS = {
30-
"celsius": "°C",
31-
"fahrenheit": "°F",
32-
}
3339

3440
#: Unit equivalences.
3541
UNIT_EQUIVALENCE = {
@@ -48,9 +54,7 @@ def are_equal(unit_1, unit_2):
4854
unit_2 : str
4955
The second unit.
5056
"""
51-
if _NO_CF_UNITS:
52-
raise ImportError("cf-units is required for checking unit equivalence")
53-
return cf_units.Unit(unit_1) == cf_units.Unit(unit_2)
57+
return _pintify(unit_1) == _pintify(unit_2)
5458

5559

5660
def anomaly_equivalence(units):
@@ -81,24 +85,24 @@ def convert(data, source_units, target_units):
8185
target_units : str
8286
The units to convert to.
8387
"""
84-
if _NO_CF_UNITS:
85-
raise ImportError("cf-units is required for unit conversion")
88+
source_units = _pintify(source_units)
89+
target_units = _pintify(target_units)
8690
try:
87-
result = cf_units.Unit(source_units).convert(data, target_units)
91+
result = (data * source_units).to(target_units).magnitude
8892
except ValueError as err:
8993
for units in UNIT_EQUIVALENCE:
90-
if cf_units.Unit(source_units) == cf_units.Unit(units):
94+
if source_units == _pintify(units):
9195
try:
92-
equal_units = UNIT_EQUIVALENCE[units]
93-
result = cf_units.Unit(equal_units).convert(data, target_units)
96+
equal_units = _pintify(UNIT_EQUIVALENCE[units])
97+
result = (data * equal_units).to(target_units)
9498
except ValueError:
9599
raise err
96100
else:
97101
break
98102
return result
99103

100104

101-
def format_units(units):
105+
def format_units(units, exponential_notation=False):
102106
"""
103107
Format units for display in LaTeX.
104108
@@ -112,27 +116,7 @@ def format_units(units):
112116
>>> format_units("kg m-2")
113117
"$kg m^{-2}$"
114118
"""
115-
if _NO_CF_UNITS:
116-
return f"${PRETTY_UNITS.get(units, units)}$"
117-
118-
from cf_units.tex import tex
119-
120-
for name, formatted_units in PRETTY_UNITS.items():
121-
try:
122-
if are_equal(units, name):
123-
units = formatted_units
124-
break
125-
except ValueError:
126-
continue
127-
else:
128-
try:
129-
units = str(cf_units.Unit(units))
130-
except ValueError:
131-
pass
132-
133-
try:
134-
formatted_units = f"${tex(units)}$"
135-
except SyntaxError:
136-
formatted_units = units
137-
138-
return formatted_units
119+
latex_str = f"{_pintify(units):~L}"
120+
if exponential_notation:
121+
raise NotImplementedError("Exponential notation is not yet supported.")
122+
return f"${latex_str}$"

src/earthkit/plots/styles/__init__.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
# limitations under the License.
1414

1515
import inspect
16-
import warnings
1716

1817
import matplotlib as mpl
1918
import matplotlib.pyplot as plt
@@ -82,7 +81,6 @@ class Style:
8281
any data incompatible with these units will not be able to use this
8382
`Style`. If `units` are not provided, then data plotted using this
8483
`Style` will remain in their original units.
85-
Note that passing `units` requires `cf_units` to be installed.
8684
units_label : str, optional
8785
The label to use in titles and legends to represent the units of the
8886
data.
@@ -128,13 +126,6 @@ def __init__(
128126
self.normalize = normalize
129127
self.gradients = gradients
130128

131-
if units is not None and metadata.units._NO_CF_UNITS:
132-
warnings.warn(
133-
"You must have cf-units installed to use unit conversion "
134-
"features; since no cf-units installation was found, no units "
135-
"will be applied to this style"
136-
)
137-
units = None
138129
self._units = units
139130
self._units_label = units_label
140131
self.scale_factor = scale_factor
@@ -219,7 +210,7 @@ def convert_units(self, values, source_units, short_name=""):
219210
values : numpy.ndarray
220211
The values to convert from their source units to this `Style`'s
221212
units.
222-
source_units : str or cf_units.Unit
213+
source_units : str
223214
The source units of the given values.
224215
short_name : str, optional
225216
The short name of the variable, which is used to make extra

src/earthkit/plots/styles/auto.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
from earthkit.plots import styles
2222
from earthkit.plots._plugins import PLUGINS
23-
from earthkit.plots.metadata.units import _NO_CF_UNITS, are_equal
23+
from earthkit.plots.metadata.units import are_equal
2424
from earthkit.plots.schemas import schema
2525

2626

@@ -42,7 +42,7 @@ def guess_style(data, units=None, **kwargs):
4242
data, the data will be converted to the target units and the style
4343
will be adjusted accordingly.
4444
"""
45-
if not schema.automatic_styles or schema.style_library is None or _NO_CF_UNITS:
45+
if not schema.automatic_styles or schema.style_library is None:
4646
return styles.DEFAULT_STYLE
4747

4848
if schema.style_library not in PLUGINS:

0 commit comments

Comments
 (0)