-
Notifications
You must be signed in to change notification settings - Fork 0
/
convert.py
112 lines (82 loc) · 2.88 KB
/
convert.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
__all__ = ["coord_units", "frame", "units"]
# standard library
from typing import Optional, Sequence, TypeVar, Union
# dependencies
import numpy as np
import xarray as xr
from astropy.units import Equivalency, Quantity, Unit
# type hints
T = TypeVar("T")
Multiple = Union[Sequence[T], T]
UnitLike = Union[xr.DataArray, Unit, str]
def coord_units(
da: xr.DataArray,
coord_names: Multiple[str],
new_units: UnitLike,
/,
equivalencies: Optional[Equivalency] = None,
) -> xr.DataArray:
"""Convert the units of coordinate(s) of a DataArray.
Args:
da: Input DataArray.
coord_names: Name(s) of the coordinate(s) to be converted.
new_units: Units to be converted from the current ones.
A DataArray that has units attribute is also accepted.
equivalencies: Optional Astropy equivalencies.
Returns:
DataArray with the units of the coordinate converted.
"""
# deepcopy except for data
da = da.copy(data=da.data)
if isinstance(coord_names, str):
coord_names = [coord_names]
for coord_name in coord_names:
coord = da.coords[coord_name]
new_coord = units(coord, new_units, equivalencies)
da = da.assign_coords({coord_name: new_coord})
return da
def frame(da: xr.DataArray, new_frame: str, /) -> xr.DataArray:
"""Convert the skycoord frame of a DataArray.
Args:
da: Input DataArray.
new_frame: Frame to be converted from the current one.
Returns:
DataArray with the skycoord frame converted.
"""
# deepcopy except for data
da = da.copy(data=da.data)
if not new_frame == "relative":
raise ValueError("Relative is only available.")
lon = da.coords["lon"]
lat = da.coords["lat"]
lon_origin = da.coords["lon_origin"]
lat_origin = da.coords["lat_origin"]
# do not change the order below!
lon -= units(lon_origin, lon)
lon *= np.cos(units(lat, "rad"))
lat -= units(lat_origin, lat)
lon_origin *= 0.0
lat_origin *= 0.0
new_frame = da.frame.copy(data=new_frame)
return da.assign_coords(frame=new_frame)
def units(
da: xr.DataArray,
new_units: UnitLike,
/,
equivalencies: Optional[Equivalency] = None,
) -> xr.DataArray:
"""Convert the units of a DataArray.
Args:
da: Input DataArray.
new_units: Units to be converted from the current ones.
A DataArray that has units attribute is also accepted.
equivalencies: Optional Astropy equivalencies.
Returns:
DataArray with the units converted.
"""
if (units := da.attrs.get("units")) is None:
raise ValueError("Units must exist in DataArray attrs.")
if isinstance(new_units, xr.DataArray):
new_units = new_units.attrs["units"]
new_data = Quantity(da, units).to(new_units, equivalencies)
return da.copy(data=new_data).assign_attrs(units=new_units)