How to Save Cross Section Data to netCDF

771 views Asked by At

I want to save the cross section data along a transect line between two coordinates as a netCDF file.

I'm following the example code described in Metpy's Cross Section Analysis:

Here's the modified code adding the remove crs command:

import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr
import metpy.calc as mpcalc
from metpy.interpolate import cross_section

#use xarray to read the data 
data = xr.open_dataset('/home/rik/hrrr/gtgn/gtgn.t2215z.edr.f000.nc')
print(data)
<xarray.Dataset>
Dimensions:            (alt: 52, time: 1, x: 451, y: 337)
Coordinates:
  * time               (time) datetime64[ns] 2020-06-18T22:15:00
  * x                  (x) float64 0.0 1.355e+04 ... 6.082e+06 6.095e+06
  * y                  (y) float64 0.0 1.355e+04 ... 4.538e+06 4.551e+06
  * alt                (alt) float64 0.0 30.0 304.0 ... 1.494e+04 1.524e+04
Data variables:
    Lambert_Conformal  int32 ...
    param30.19.0       (time, alt, y, x) float32 ...
Attributes:
    CDI:          Climate Data Interface version 1.9.8 (https://mpimet.mpg.de...
    Conventions:  CF-1.6
    history:      Wed Oct 07 17:19:41 2020: cdo -f nc copy gtgn.t2215z.edr.f0...
    institution:  National Center for Atmospheric Research
    CDO:          Climate Data Operators version 1.9.8 (https://mpimet.mpg.de...

#parse the data and remove crs from coordinate
data = data.metpy.parse_cf().squeeze()
data.drop_vars('crs')
print(data)
<xarray.Dataset>
Dimensions:            (alt: 52, x: 451, y: 337)
Coordinates:
    time               datetime64[ns] 2020-06-18T22:15:00
  * x                  (x) float64 0.0 1.355e+04 ... 6.082e+06 6.095e+06
  * y                  (y) float64 0.0 1.355e+04 ... 4.538e+06 4.551e+06
  * alt                (alt) float64 0.0 30.0 304.0 ... 1.494e+04 1.524e+04
    crs                object Projection: lambert_conformal_conic
Data variables:
    Lambert_Conformal  int32 ...
    param30.19.0       (alt, y, x) float32 ...
Attributes:
    CDI:          Climate Data Interface version 1.9.8 (https://mpimet.mpg.de...
    Conventions:  CF-1.6
    history:      Wed Oct 07 17:19:41 2020: cdo -f nc copy gtgn.t2215z.edr.f0...
    institution:  National Center for Atmospheric Research
    CDO:          Climate Data Operators version 1.9.8 (https://mpimet.mpg.de...

#define start and end points
start = (37.0, -105.0)
end = (35.5, -90.0)

#get the cross section
cross = cross_section(data, start, end)
print(cross)
<xarray.Dataset>
Dimensions:            (alt: 52, index: 100)
Coordinates:
    time               datetime64[ns] 2020-06-18T22:15:00
    crs                object Projection: lambert_conformal_conic
  * alt                (alt) float64 0.0 30.0 304.0 ... 1.494e+04 1.524e+04
    x                  (index) float64 2.424e+06 2.438e+06 ... 3.793e+06
    y                  (index) float64 1.967e+06 1.965e+06 ... 1.772e+06
  * index              (index) int64 0 1 2 3 4 5 6 7 ... 92 93 94 95 96 97 98 99
Data variables:
    Lambert_Conformal  int32 ...
    param30.19.0       (alt, index) float64 0.3914 0.3687 ... 0.0605 0.0605
Attributes:
    CDI:          Climate Data Interface version 1.9.8 (https://mpimet.mpg.de...
    Conventions:  CF-1.6
    history:      Wed Oct 07 17:19:41 2020: cdo -f nc copy gtgn.t2215z.edr.f0...
    institution:  National Center for Atmospheric Research
    CDO:          Climate Data Operators version 1.9.8 (https://mpimet.mpg.de...

When I try to write/save the cross section xarray.dataset as a netCDF file I get the following error message:

cross.to_netcdf('/home/rik/hrrr/gtgn/xarray_cross_section_data_to_netcdf.nc')

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-12-0b4fce1219bd> in <module>
----> 1 cross.to_netcdf('/home/rik/hrrr/gtgn/xarray_cross_section_data_to_netcdf.nc')

~/miniconda3/envs/metpy/lib/python3.7/site-packages/xarray/core/dataset.py in to_netcdf(self, path, mode, format, group, engine, encoding, unlimited_dims, compute, invalid_netcdf)
   1565             unlimited_dims=unlimited_dims,
   1566             compute=compute,
-> 1567             invalid_netcdf=invalid_netcdf,
   1568         )
   1569 

~/miniconda3/envs/metpy/lib/python3.7/site-packages/xarray/backends/api.py in to_netcdf(dataset, path_or_file, mode, format, group, engine, encoding, unlimited_dims, compute, multifile, invalid_netcdf)
   1080         # to be parallelized with dask
   1081         dump_to_store(
-> 1082             dataset, store, writer, encoding=encoding, unlimited_dims=unlimited_dims
   1083         )
   1084         if autoclose:

~/miniconda3/envs/metpy/lib/python3.7/site-packages/xarray/backends/api.py in dump_to_store(dataset, store, writer, encoder, encoding, unlimited_dims)
   1126         variables, attrs = encoder(variables, attrs)
   1127 
-> 1128     store.store(variables, attrs, check_encoding, writer, unlimited_dims=unlimited_dims)
   1129 
   1130 

~/miniconda3/envs/metpy/lib/python3.7/site-packages/xarray/backends/common.py in store(self, variables, attributes, check_encoding_set, writer, unlimited_dims)
    248             writer = ArrayWriter()
    249 
--> 250         variables, attributes = self.encode(variables, attributes)
    251 
    252         self.set_attributes(attributes)

~/miniconda3/envs/metpy/lib/python3.7/site-packages/xarray/backends/common.py in encode(self, variables, attributes)
    337         # All NetCDF files get CF encoded by default, without this attempting
    338         # to write times, for example, would fail.
--> 339         variables, attributes = cf_encoder(variables, attributes)
    340         variables = {k: self.encode_variable(v) for k, v in variables.items()}
    341         attributes = {k: self.encode_attribute(v) for k, v in attributes.items()}

~/miniconda3/envs/metpy/lib/python3.7/site-packages/xarray/conventions.py in cf_encoder(variables, attributes)
    771     _update_bounds_encoding(variables)
    772 
--> 773     new_vars = {k: encode_cf_variable(v, name=k) for k, v in variables.items()}
    774 
    775     # Remove attrs from bounds variables (issue #2921)

~/miniconda3/envs/metpy/lib/python3.7/site-packages/xarray/conventions.py in <dictcomp>(.0)
    771     _update_bounds_encoding(variables)
    772 
--> 773     new_vars = {k: encode_cf_variable(v, name=k) for k, v in variables.items()}
    774 
    775     # Remove attrs from bounds variables (issue #2921)

~/miniconda3/envs/metpy/lib/python3.7/site-packages/xarray/conventions.py in encode_cf_variable(var, needs_copy, name)
    256     var = maybe_default_fill_value(var)
    257     var = maybe_encode_bools(var)
--> 258     var = ensure_dtype_not_object(var, name=name)
    259     return var
    260 

~/miniconda3/envs/metpy/lib/python3.7/site-packages/xarray/conventions.py in ensure_dtype_not_object(var, name)
    214             data[missing] = fill_value
    215         else:
--> 216             data = _copy_with_dtype(data, dtype=_infer_dtype(data, name))
    217 
    218         assert data.dtype.kind != "O" or data.dtype.metadata

~/miniconda3/envs/metpy/lib/python3.7/site-packages/xarray/conventions.py in _infer_dtype(array, name)
    150     raise ValueError(
    151         "unable to infer dtype on variable {!r}; xarray "
--> 152         "cannot serialize arbitrary Python objects".format(name)
    153     )
    154 

ValueError: unable to infer dtype on variable 'crs'; xarray cannot serialize arbitrary Python objects

What am I doing wrong?

1

There are 1 answers

0
Light_B On BEST ANSWER

As @Robert Wilson suggested in the comments, you have to remove crs from your coordinates. However, drop_vars() removes variables from a dataset. To remove a coordinate as in your case:

cross = cross.reset_coords('crs', drop=True)

Reference