|
92 | 92 | "degreesE", |
93 | 93 | ), |
94 | 94 | }, |
95 | | - # "regular_expression": { |
96 | | - # "time": r"time[0-9]*", |
97 | | - # "vertical": ( |
98 | | - # r"(lv_|bottom_top|sigma|h(ei)?ght|altitude|depth|isobaric|pres|" |
99 | | - # r"isotherm)[a-z_]*[0-9]*" |
100 | | - # ), |
101 | | - # "y": r"y", |
102 | | - # "latitude": r"x?lat[a-z0-9]*", |
103 | | - # "x": r"x", |
104 | | - # "longitude": r"x?lon[a-z0-9]*", |
105 | | - # }, |
106 | 95 | } |
107 | 96 |
|
108 | 97 | # "vertical" is just an alias for "Z" |
|
112 | 101 | # "long_name" and "standard_name" criteria are the same. For convenience. |
113 | 102 | coordinate_criteria["long_name"] = coordinate_criteria["standard_name"] |
114 | 103 |
|
| 104 | + |
| 105 | +#: regular expressions for guess_coord_axis |
| 106 | +regex = { |
| 107 | + "time": "time[0-9]*", |
| 108 | + "vertical": ( |
| 109 | + "(lv_|bottom_top|sigma|h(ei)?ght|altitude|depth|isobaric|pres|" |
| 110 | + "isotherm)[a-z_]*[0-9]*" |
| 111 | + ), |
| 112 | + "Y": "y", |
| 113 | + "latitude": "y?lat[a-z0-9]*", |
| 114 | + "X": "x", |
| 115 | + "longitude": "x?lon[a-z0-9]*", |
| 116 | +} |
| 117 | +regex["Z"] = regex["vertical"] |
| 118 | +regex["T"] = regex["time"] |
| 119 | + |
| 120 | + |
| 121 | +attrs = { |
| 122 | + "X": {"axis": "X"}, |
| 123 | + "T": {"axis": "T", "standard_name": "time"}, |
| 124 | + "Y": {"axis": "Y"}, |
| 125 | + "Z": {"axis": "Z"}, |
| 126 | + "latitude": {"units": "degrees_north", "standard_name": "latitude"}, |
| 127 | + "longitude": {"units": "degrees_east", "standard_name": "longitude"}, |
| 128 | +} |
| 129 | +attrs["time"] = attrs["T"] |
| 130 | +attrs["vertical"] = attrs["Z"] |
| 131 | + |
| 132 | + |
| 133 | +def _is_datetime_like(da: DataArray) -> bool: |
| 134 | + import numpy as np |
| 135 | + |
| 136 | + if np.issubdtype(da.dtype, np.datetime64) or np.issubdtype( |
| 137 | + da.dtype, np.timedelta64 |
| 138 | + ): |
| 139 | + return True |
| 140 | + |
| 141 | + try: |
| 142 | + import cftime |
| 143 | + |
| 144 | + if isinstance(da.data[0], cftime.datetime): |
| 145 | + return True |
| 146 | + except ImportError: |
| 147 | + pass |
| 148 | + |
| 149 | + return False |
| 150 | + |
| 151 | + |
115 | 152 | # Type for Mapper functions |
116 | 153 | Mapper = Callable[[Union[DataArray, Dataset], str], List[str]] |
117 | 154 |
|
@@ -1090,6 +1127,45 @@ def rename_like( |
1090 | 1127 | variable.attrs["coordinates"] = coordinates |
1091 | 1128 | return self._maybe_to_dataarray(ds) |
1092 | 1129 |
|
| 1130 | + def guess_coord_axis(self, verbose: bool = False) -> Union[DataArray, Dataset]: |
| 1131 | + """ |
| 1132 | + Automagically guesses X, Y, Z, T, latitude, longitude, and adds |
| 1133 | + appropriate attributes. Uses regexes from Metpy and inspired by Iris |
| 1134 | + function of same name. |
| 1135 | +
|
| 1136 | + Existing attributes will not be modified. |
| 1137 | +
|
| 1138 | + Parameters |
| 1139 | + ---------- |
| 1140 | + verbose: bool |
| 1141 | + Print extra info to screen |
| 1142 | +
|
| 1143 | + Returns |
| 1144 | + ------- |
| 1145 | + DataArray or Dataset with appropriate attributes added |
| 1146 | + """ |
| 1147 | + import re |
| 1148 | + |
| 1149 | + obj = self._obj.copy(deep=True) |
| 1150 | + for dim in obj.dims: |
| 1151 | + if _is_datetime_like(obj[dim]): |
| 1152 | + if verbose: |
| 1153 | + print( |
| 1154 | + f"I think {dim!r} is of type 'time' since it has a datetime-like type." |
| 1155 | + ) |
| 1156 | + obj[dim].attrs = dict(ChainMap(obj[dim].attrs, attrs["time"])) |
| 1157 | + continue # prevent second detection |
| 1158 | + |
| 1159 | + for axis, pattern in regex.items(): |
| 1160 | + # match variable names |
| 1161 | + if re.match(pattern, dim.lower()): |
| 1162 | + if verbose: |
| 1163 | + print( |
| 1164 | + f"I think {dim!r} is of type {axis!r} since it matched {pattern!r}" |
| 1165 | + ) |
| 1166 | + obj[dim].attrs = dict(ChainMap(obj[dim].attrs, attrs[axis])) |
| 1167 | + return obj |
| 1168 | + |
1093 | 1169 |
|
1094 | 1170 | @xr.register_dataset_accessor("cf") |
1095 | 1171 | class CFDatasetAccessor(CFAccessor): |
|
0 commit comments