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

UndefinedUnitError: 'dBZ' is not defined in the unit registry #3341

Closed
SpringFa opened this issue Jan 1, 2024 · 4 comments · Fixed by #3343 or #3347
Closed

UndefinedUnitError: 'dBZ' is not defined in the unit registry #3341

SpringFa opened this issue Jan 1, 2024 · 4 comments · Fixed by #3343 or #3347
Labels
Area: Units Pertains to unit information Type: Enhancement Enhancement to existing functionality
Milestone

Comments

@SpringFa
Copy link

SpringFa commented Jan 1, 2024

What went wrong?

Hello everyone!
I want to create a radar reflectivity profile, but I encountered an issue when using the cross_section function. It seems that the unit 'dBZ' for reflectivity is not defined, although the dataset used has already defined its unit. I would like to know the reason for this problem and hope that you can provide assistance.
微信截图_20240102014557

Operating System

Windows

Version

1.6.0

Python Version

3.11.4

Code to Reproduce

da = xr.open_dataset(r'E:\data\0415\20210415_090551_vdras.nc')
data = da.metpy.assign_crs(
    grid_mapping_name='lambert_conformal_conic',
    latitude_of_projection_origin=39.808887,
    longitude_of_central_meridian=116.47195,
    standard_parallel=39.808887,
    earth_radius=6371.229
).metpy.assign_latitude_longitude()
start = (116.6,39.87)
end = (117.03,39.6)
print(data)
cross = cross_section(data, start, end).set_coords(('lat', 'lon'))

Errors, Traceback, and Logs

UndefinedUnitError                        Traceback (most recent call last)
Cell In[75], line 12
     10 end = (117.03,39.6)
     11 print(data)
---> 12 cross = cross_section(data, start, end).set_coords(('lat', 'lon'))

File d:\anaconda3\Lib\site-packages\metpy\interpolate\slices.py:147, in cross_section(data, start, end, steps, interp_type)
    109 r"""Obtain an interpolated cross-sectional slice through gridded data.
    110 
    111 Utilizing the interpolation functionality in xarray, this function takes a vertical
   (...)
    143 
    144 """
    145 if isinstance(data, xr.Dataset):
    146     # Recursively apply to dataset
--> 147     return data.map(cross_section, True, (start, end), steps=steps,
    148                     interp_type=interp_type)
    149 elif data.ndim == 0:
    150     # This has no dimensions, so it is likely a projection variable. In any case, there
    151     # are no data here to take the cross section with. Therefore, do nothing.
    152     return data

File d:\anaconda3\Lib\site-packages\xarray\core\dataset.py:6037, in Dataset.map(self, func, keep_attrs, args, **kwargs)
   6035 if keep_attrs is None:
   6036     keep_attrs = _get_keep_attrs(default=False)
-> 6037 variables = {
   6038     k: maybe_wrap_array(v, func(v, *args, **kwargs))
   6039     for k, v in self.data_vars.items()
   6040 }
   6041 if keep_attrs:
   6042     for k, v in variables.items():

File d:\anaconda3\Lib\site-packages\xarray\core\dataset.py:6038, in <dictcomp>(.0)
   6035 if keep_attrs is None:
   6036     keep_attrs = _get_keep_attrs(default=False)
   6037 variables = {
-> 6038     k: maybe_wrap_array(v, func(v, *args, **kwargs))
   6039     for k, v in self.data_vars.items()
   6040 }
   6041 if keep_attrs:
   6042     for k, v in variables.items():

File d:\anaconda3\Lib\site-packages\metpy\interpolate\slices.py:173, in cross_section(data, start, end, steps, interp_type)
    170     points_cross[points_cross[:, 0] < 0, 0] += 360.
    172 # Return the interpolated data
--> 173 return interpolate_to_slice(data, points_cross, interp_type=interp_type)

File d:\anaconda3\Lib\site-packages\metpy\interpolate\slices.py:59, in interpolate_to_slice(data, points, interp_type)
     53 data_sliced = data.interp({
     54     x.name: xr.DataArray(points[:, 0], dims='index', attrs=x.attrs),
     55     y.name: xr.DataArray(points[:, 1], dims='index', attrs=y.attrs)
     56 }, method=interp_type)
     57 data_sliced.coords['index'] = range(len(points))
---> 59 return data_sliced.metpy.quantify()

File d:\anaconda3\Lib\site-packages\metpy\xarray.py:235, in MetPyDataArrayAccessor.quantify(self)
    222 """Return a new DataArray with the data converted to a `pint.Quantity`.
    223 
    224 Notes
   (...)
    228 subsetting!
    229 """
    230 if (
    231     not is_quantity(self._data_array.data)
    232     and np.issubdtype(self._data_array.data.dtype, np.number)
    233 ):
    234     # Only quantify if not already quantified and is quantifiable
--> 235     quantified_dataarray = self._data_array.copy(data=self.unit_array)
    236     if 'units' in quantified_dataarray.attrs:
    237         del quantified_dataarray.attrs['units']

File d:\anaconda3\Lib\site-packages\metpy\xarray.py:165, in MetPyDataArrayAccessor.unit_array(self)
    163     return self._data_array.data
    164 else:
--> 165     return units.Quantity(self._data_array.data, self.units)

File d:\anaconda3\Lib\site-packages\metpy\xarray.py:142, in MetPyDataArrayAccessor.units(self)
    140 else:
    141     default_unit = 'dimensionless'
--> 142 return units.parse_units(self._data_array.attrs.get('units', default_unit))

File d:\anaconda3\Lib\site-packages\pint\facets\plain\registry.py:1189, in GenericPlainRegistry.parse_units(self, input_string, as_delta, case_sensitive)
   1161 def parse_units(
   1162     self,
   1163     input_string: str,
   1164     as_delta: Optional[bool] = None,
   1165     case_sensitive: Optional[bool] = None,
   1166 ) -> UnitT:
   1167     """Parse a units expression and returns a UnitContainer with
   1168     the canonical names.
   1169 
   (...)
   1185 
   1186     """
   1188     return self.Unit(
-> 1189         self.parse_units_as_container(input_string, as_delta, case_sensitive)
   1190     )

File d:\anaconda3\Lib\site-packages\pint\facets\nonmultiplicative\registry.py:70, in GenericNonMultiplicativeRegistry.parse_units_as_container(self, input_string, as_delta, case_sensitive)
     67 if as_delta is None:
     68     as_delta = self.default_as_delta
---> 70 return super().parse_units_as_container(input_string, as_delta, case_sensitive)

File d:\anaconda3\Lib\site-packages\pint\facets\plain\registry.py:1204, in GenericPlainRegistry.parse_units_as_container(self, input_string, as_delta, case_sensitive)
   1198 as_delta = (
   1199     as_delta if as_delta is not None else True
   1200 )  # TODO This only exists in nonmultiplicative
   1201 case_sensitive = (
   1202     case_sensitive if case_sensitive is not None else self.case_sensitive
   1203 )
-> 1204 return self._parse_units_as_container(input_string, as_delta, case_sensitive)

File d:\anaconda3\Lib\site-packages\pint\facets\plain\registry.py:1239, in GenericPlainRegistry._parse_units_as_container(self, input_string, as_delta, case_sensitive)
   1237 many = len(units) > 1
   1238 for name in units:
-> 1239     cname = self.get_name(name, case_sensitive=case_sensitive)
   1240     value = units[name]
   1241     if not cname:

File d:\anaconda3\Lib\site-packages\pint\facets\plain\registry.py:647, in GenericPlainRegistry.get_name(self, name_or_alias, case_sensitive)
    645 candidates = self.parse_unit_name(name_or_alias, case_sensitive)
    646 if not candidates:
--> 647     raise UndefinedUnitError(name_or_alias)
    649 prefix, unit_name, _ = candidates[0]
    650 if len(candidates) > 1:

UndefinedUnitError: 'dBZ' is not defined in the unit registry
@SpringFa SpringFa added the Type: Bug Something is not working like it should label Jan 1, 2024
@mgrover1
Copy link
Contributor

mgrover1 commented Jan 2, 2024

@dopplershift @dcamron - this issue also came up with Py-ART CI... any interest in a PR adding this to the registry of units in MetPy? I can submit a PR if this sounds like a reasonable path forward.

@dopplershift
Copy link
Member

For those not following the PR, happy to add dimensionally correct log units since we have accidentally expanded the code paths (interpolate_to_slice) that trigger unit parsing and thus need to be able to handle what's in unit attribute metadata.

@dopplershift dopplershift added Type: Enhancement Enhancement to existing functionality Area: Units Pertains to unit information and removed Type: Bug Something is not working like it should labels Jan 3, 2024
@dopplershift dopplershift added this to the January 2024 milestone Jan 3, 2024
@SpringFa
Copy link
Author

SpringFa commented Jan 3, 2024

@dopplershift @dcamron - this issue also came up with Py-ART CI... any interest in a PR adding this to the registry of units in MetPy? I can submit a PR if this sounds like a reasonable path forward.

Thank you for your prompt response! I changed the units of the original data, which may not be in compliance with the regulations, but it does allow me to complete the plotting. The method of adding 'dBZ' to the registry fundamentally solved the problem. Thank you for your contribution!

@SpringFa
Copy link
Author

SpringFa commented Jan 3, 2024

For those not following the PR, happy to add dimensionally correct log units since we have accidentally expanded the code paths () that trigger unit parsing and thus need to be able to handle what's in attribute metadata.interpolate_to_slice``unit

Thank you for your prompt response! I changed the units of the original data, which may not be in compliance with the regulations, but it does allow me to complete the plotting. The method of adding 'dBZ' to the registry fundamentally solved the problem. Thank you for your contribution!

@dopplershift dopplershift modified the milestones: January 2024, 1.6.1 Jan 3, 2024
dopplershift added a commit to dopplershift/MetPy that referenced this issue Jan 3, 2024
The fixup in Unidata#3255 inadvertently added unit parsing to all code paths in
interpolate_to_slice. This breaks any usages that passed in data with
unknown units. Since interpolate_to_slice has no need to do any unit
handling, avoid this unless we're actually given a quantity.
dopplershift added a commit to dopplershift/MetPy that referenced this issue Jan 3, 2024
The fixup in Unidata#3255 inadvertently added unit parsing to all code paths in
interpolate_to_slice. This breaks any usages that passed in data with
unknown units. Since interpolate_to_slice has no need to do any unit
handling, avoid this unless we're actually given a quantity.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Units Pertains to unit information Type: Enhancement Enhancement to existing functionality
Projects
None yet
3 participants