.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "tutorials/xarray_tutorial.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code .. rst-class:: sphx-glr-example-title .. _sphx_glr_tutorials_xarray_tutorial.py: ========================== xarray with MetPy Tutorial ========================== `xarray `_ is a powerful Python package that provides N-dimensional labeled arrays and datasets following the Common Data Model. MetPy's suite of meteorological calculations are designed to integrate with xarray DataArrays as one of its two primary data models (the other being Pint Quantities). MetPy also provides DataArray and Dataset *accessors* (collections of methods and properties attached to the ``.metpy`` property) for coordinate/CRS and unit operations. Full information on MetPy's accessors is available in the :doc:`appropriate section of the reference guide `, otherwise, continue on in this tutorial for a demonstration of the three main components of MetPy's integration with xarray (coordinates/coordinate reference systems, units, and calculations), as well as instructive examples for both CF-compliant and non-compliant datasets. First, some general imports... .. GENERATED FROM PYTHON SOURCE LINES 24-33 .. code-block:: Python import numpy as np import xarray as xr # Any import of metpy will activate the accessors import metpy.calc as mpcalc from metpy.cbook import get_test_data from metpy.units import units .. GENERATED FROM PYTHON SOURCE LINES 34-35 ...and opening some sample data to work with. .. GENERATED FROM PYTHON SOURCE LINES 35-42 .. code-block:: Python # Open the netCDF file as a xarray Dataset data = xr.open_dataset(get_test_data('irma_gfs_example.nc', False)) # View a summary of the Dataset data .. raw:: html
<xarray.Dataset> Size: 67MB
    Dimensions:                              (time1: 9, latitude: 81,
                                              isobaric3: 31, isobaric1: 21,
                                              longitude: 131)
    Coordinates:
      * time1                                (time1) datetime64[ns] 72B 2017-09-0...
        reftime                              datetime64[ns] 8B ...
      * latitude                             (latitude) float32 324B 50.0 ... 10.0
      * isobaric3                            (isobaric3) float64 248B 100.0 ... 1...
      * isobaric1                            (isobaric1) float64 168B 1e+04 ... 1...
      * longitude                            (longitude) float32 524B 250.0 ... 3...
    Data variables:
        Vertical_velocity_pressure_isobaric  (time1, isobaric1, latitude, longitude) float32 8MB ...
        Relative_humidity_isobaric           (time1, isobaric3, latitude, longitude) float32 12MB ...
        Temperature_isobaric                 (time1, isobaric3, latitude, longitude) float32 12MB ...
        u-component_of_wind_isobaric         (time1, isobaric3, latitude, longitude) float32 12MB ...
        v-component_of_wind_isobaric         (time1, isobaric3, latitude, longitude) float32 12MB ...
        Geopotential_height_isobaric         (time1, isobaric3, latitude, longitude) float32 12MB ...
        LatLon_361X720-0p25S-180p00E         int32 4B ...
    Attributes: (12/13)
        Originating_or_generating_Center:                                        ...
        Originating_or_generating_Subcenter:                                     ...
        GRIB_table_version:                                                      ...
        Type_of_generating_process:                                              ...
        Analysis_or_forecast_generating_process_identifier_defined_by_originating...
        Conventions:                                                             ...
        ...                                                                                ...
        featureType:                                                             ...
        History:                                                                 ...
        geospatial_lat_min:                                                      ...
        geospatial_lat_max:                                                      ...
        geospatial_lon_min:                                                      ...
        geospatial_lon_max:                                                      ...


.. GENERATED FROM PYTHON SOURCE LINES 43-54 While xarray can handle a wide variety of n-dimensional data (essentially anything that can be stored in a netCDF file), a common use case is working with gridded model output. Such model data can be obtained from a THREDDS Data Server using the `siphon package `_, but here we've used an example subset of GFS data from Hurricane Irma (September 5th, 2017) included in MetPy's test suite. Generally, a local file (or remote file via OPeNDAP) can be opened with ``xr.open_dataset("path")``. Going back to the above object, this ``Dataset`` consists of *dimensions* and their associated *coordinates*, which in turn make up the axes along which the *data variables* are defined. The dataset also has a dictionary-like collection of *attributes*. What happens if we look at just a single data variable? .. GENERATED FROM PYTHON SOURCE LINES 54-58 .. code-block:: Python temperature = data['Temperature_isobaric'] temperature .. raw:: html
<xarray.DataArray 'Temperature_isobaric' (time1: 9, isobaric3: 31,
                                              latitude: 81, longitude: 131)> Size: 12MB
    [2960469 values with dtype=float32]
    Coordinates:
      * time1      (time1) datetime64[ns] 72B 2017-09-05T12:00:00 ... 2017-09-06T...
        reftime    datetime64[ns] 8B ...
      * latitude   (latitude) float32 324B 50.0 49.5 49.0 48.5 ... 11.0 10.5 10.0
      * isobaric3  (isobaric3) float64 248B 100.0 200.0 300.0 ... 9.75e+04 1e+05
      * longitude  (longitude) float32 524B 250.0 250.5 251.0 ... 314.0 314.5 315.0
    Attributes:
        long_name:                      Temperature @ Isobaric surface
        units:                          K
        Grib_Variable_Id:               VAR_0-0-0_L100
        Grib2_Parameter:                [0 0 0]
        Grib2_Parameter_Discipline:     Meteorological products
        Grib2_Parameter_Category:       Temperature
        Grib2_Parameter_Name:           Temperature
        Grib2_Level_Type:               100
        Grib2_Level_Desc:               Isobaric surface
        Grib2_Generating_Process_Type:  Forecast
        grid_mapping:                   LatLon_361X720-0p25S-180p00E


.. GENERATED FROM PYTHON SOURCE LINES 59-85 This is a ``DataArray``, which stores just a single data variable with its associated coordinates and attributes. These individual ``DataArray``\s are the kinds of objects that MetPy's calculations take as input (more on that in `Calculations`_ section below). If you are more interested in learning about xarray's terminology and data structures, see the `terminology section `_ of xarray's documentation. Coordinates and Coordinate Reference Systems -------------------------------------------- MetPy's first set of helpers comes with identifying *coordinate types*. In a given dataset, coordinates can have a variety of different names and yet refer to the same type (such as "isobaric1" and "isobaric3" both referring to vertical isobaric coordinates). Following CF conventions, as well as using some fall-back regular expressions, MetPy can systematically identify coordinates of the following types: - time - vertical - latitude - y - longitude - x When identifying a single coordinate, it is best to use the property directly associated with that type .. GENERATED FROM PYTHON SOURCE LINES 85-88 .. code-block:: Python temperature.metpy.time .. raw:: html
<xarray.DataArray 'time1' (time1: 9)> Size: 72B
    array(['2017-09-05T12:00:00.000000000', '2017-09-05T15:00:00.000000000',
           '2017-09-05T18:00:00.000000000', '2017-09-05T21:00:00.000000000',
           '2017-09-06T00:00:00.000000000', '2017-09-06T03:00:00.000000000',
           '2017-09-06T06:00:00.000000000', '2017-09-06T09:00:00.000000000',
           '2017-09-06T12:00:00.000000000'], dtype='datetime64[ns]')
    Coordinates:
      * time1    (time1) datetime64[ns] 72B 2017-09-05T12:00:00 ... 2017-09-06T12...
        reftime  datetime64[ns] 8B ...
    Attributes:
        standard_name:  time
        long_name:      time
        udunits:        Hour since 2017-09-05T12:00:00Z
        _metpy_axis:    time


.. GENERATED FROM PYTHON SOURCE LINES 89-91 When accessing multiple coordinate types simultaneously, you can use the ``.coordinates()`` method to yield a generator for the respective coordinates .. GENERATED FROM PYTHON SOURCE LINES 91-94 .. code-block:: Python x, y = temperature.metpy.coordinates('x', 'y') .. GENERATED FROM PYTHON SOURCE LINES 95-98 These coordinate type aliases can also be used in MetPy's wrapped ``.sel`` and ``.loc`` for indexing and selecting on ``DataArray``\s. For example, to access 500 hPa heights at 1800Z, .. GENERATED FROM PYTHON SOURCE LINES 98-104 .. code-block:: Python heights = data['Geopotential_height_isobaric'].metpy.sel( time='2017-09-05 18:00', vertical=50000. ) .. GENERATED FROM PYTHON SOURCE LINES 105-126 (Notice how we specified 50000 here without units...we'll go over a better alternative in the next section on units.) One point of warning: xarray's selection and indexing only works if these coordinates are *dimension coordinates*, meaning that they are 1D and share the name of their associated dimension. In practice, this means that you can't index a dataset that has 2D latitude and longitude coordinates by latitudes and longitudes, instead, you must index by the 1D y and x dimension coordinates. (What if these coordinates are missing, you may ask? See the final subsection on ``.assign_y_x`` for more details.) Beyond just the coordinates themselves, a common need for both calculations with and plots of geospatial data is knowing the coordinate reference system (CRS) on which the horizontal spatial coordinates are defined. MetPy follows the `CF Conventions `_ for its CRS definitions, which it then caches on the ``metpy_crs`` coordinate in order for it to persist through calculations and other array operations. There are two ways to do so in MetPy: First, if your dataset is already conforming to the CF Conventions, it will have a grid mapping variable that is associated with the other data variables by the ``grid_mapping`` attribute. This is automatically parsed via the ``.parse_cf()`` method: .. GENERATED FROM PYTHON SOURCE LINES 126-140 .. code-block:: Python # Parse full dataset data_parsed = data.metpy.parse_cf() # Parse subset of dataset data_subset = data.metpy.parse_cf([ 'u-component_of_wind_isobaric', 'v-component_of_wind_isobaric', 'Vertical_velocity_pressure_isobaric' ]) # Parse single variable relative_humidity = data.metpy.parse_cf('Relative_humidity_isobaric') .. GENERATED FROM PYTHON SOURCE LINES 141-143 If your dataset doesn't have a CF-conforming grid mapping variable, you can manually specify the CRS using the ``.assign_crs()`` method: .. GENERATED FROM PYTHON SOURCE LINES 143-151 .. code-block:: Python temperature = data['Temperature_isobaric'].metpy.assign_crs( grid_mapping_name='latitude_longitude', earth_radius=6371229.0 ) temperature .. raw:: html
<xarray.DataArray 'Temperature_isobaric' (time1: 9, isobaric3: 31,
                                              latitude: 81, longitude: 131)> Size: 12MB
    [2960469 values with dtype=float32]
    Coordinates:
      * time1      (time1) datetime64[ns] 72B 2017-09-05T12:00:00 ... 2017-09-06T...
        reftime    datetime64[ns] 8B ...
      * latitude   (latitude) float32 324B 50.0 49.5 49.0 48.5 ... 11.0 10.5 10.0
      * isobaric3  (isobaric3) float64 248B 100.0 200.0 300.0 ... 9.75e+04 1e+05
      * longitude  (longitude) float32 524B 250.0 250.5 251.0 ... 314.0 314.5 315.0
        metpy_crs  object 8B Projection: latitude_longitude
    Attributes:
        long_name:                      Temperature @ Isobaric surface
        units:                          K
        Grib_Variable_Id:               VAR_0-0-0_L100
        Grib2_Parameter:                [0 0 0]
        Grib2_Parameter_Discipline:     Meteorological products
        Grib2_Parameter_Category:       Temperature
        Grib2_Parameter_Name:           Temperature
        Grib2_Level_Type:               100
        Grib2_Level_Desc:               Isobaric surface
        Grib2_Generating_Process_Type:  Forecast
        grid_mapping:                   LatLon_361X720-0p25S-180p00E


.. GENERATED FROM PYTHON SOURCE LINES 152-155 Notice the newly added ``metpy_crs`` non-dimension coordinate. Now how can we use this in practice? For individual ``DataArrays``\s, we can access the cartopy and pyproj objects corresponding to this CRS: .. GENERATED FROM PYTHON SOURCE LINES 155-159 .. code-block:: Python # Cartopy CRS, useful for plotting relative_humidity.metpy.cartopy_crs .. raw:: html
2024-04-02T16:43:18.880770 image/svg+xml Matplotlib v3.8.3, https://matplotlib.org/
<cartopy.crs.PlateCarree object at 0x7f1c5dd064d0>


.. GENERATED FROM PYTHON SOURCE LINES 160-165 .. code-block:: Python # pyproj CRS, useful for projection transformations and forward/backward azimuth and great # circle calculations temperature.metpy.pyproj_crs .. rst-class:: sphx-glr-script-out .. code-block:: none Name: undefined Axis Info [ellipsoidal]: - lon[east]: Longitude (degree) - lat[north]: Latitude (degree) Area of Use: - undefined Datum: undefined - Ellipsoid: undefined - Prime Meridian: Greenwich .. GENERATED FROM PYTHON SOURCE LINES 166-172 Finally, there are times when a certain horizontal coordinate type is missing from your dataset, and you need the other, that is, you have latitude/longitude and need y/x, or visa versa. This is where the ``.assign_y_x`` and ``.assign_latitude_longitude`` methods come in handy. Our current GFS sample won't work to demonstrate this (since, on its latitude-longitude grid, y is latitude and x is longitude), so for more information, take a look at the `Non-Compliant Dataset Example`_ below, or view the accessor documentation. .. GENERATED FROM PYTHON SOURCE LINES 174-186 Units ----- Since unit-aware calculations are a major part of the MetPy library, unit support is a major part of MetPy's xarray integration! One very important point of consideration is that xarray data variables (in both ``Dataset``\s and ``DataArray``\s) can store both unit-aware and unit-naive array types. Unit-naive array types will be used by default in xarray, so we need to convert to a unit-aware type if we want to use xarray operations while preserving unit correctness. MetPy provides the ``.quantify()`` method for this (named since we are turning the data stored inside the xarray object into a Pint ``Quantity`` object) .. GENERATED FROM PYTHON SOURCE LINES 186-190 .. code-block:: Python heights = heights.metpy.quantify() heights .. raw:: html
<xarray.DataArray 'Geopotential_height_isobaric' (latitude: 81, longitude: 131)> Size: 42kB
    <Quantity([[5883.3564 5879.3164 5875.3564 ... 5769.3965 5769.996  5770.436 ]
     [5885.476  5882.2363 5877.6763 ... 5783.916  5784.516  5785.1963]
     [5888.8765 5885.1562 5880.916  ... 5798.476  5799.076  5799.7163]
     ...
     [5892.516  5892.2363 5891.996  ... 5881.556  5881.436  5880.596 ]
     [5891.8364 5891.596  5891.7163 ... 5880.2764 5880.3564 5879.916 ]
     [5891.3564 5891.596  5891.3564 ... 5879.8765 5879.596  5878.996 ]], 'meter')>
    Coordinates:
        time1      datetime64[ns] 8B 2017-09-05T18:00:00
        reftime    datetime64[ns] 8B ...
      * latitude   (latitude) float32 324B 50.0 49.5 49.0 48.5 ... 11.0 10.5 10.0
        isobaric3  float64 8B 5e+04
      * longitude  (longitude) float32 524B 250.0 250.5 251.0 ... 314.0 314.5 315.0
    Attributes:
        long_name:                      Geopotential height @ Isobaric surface
        Grib_Variable_Id:               VAR_0-3-5_L100
        Grib2_Parameter:                [0 3 5]
        Grib2_Parameter_Discipline:     Meteorological products
        Grib2_Parameter_Category:       Mass
        Grib2_Parameter_Name:           Geopotential height
        Grib2_Level_Type:               100
        Grib2_Level_Desc:               Isobaric surface
        Grib2_Generating_Process_Type:  Forecast
        grid_mapping:                   LatLon_361X720-0p25S-180p00E


.. GENERATED FROM PYTHON SOURCE LINES 191-194 Notice how the units are now represented in the data itself, rather than as a text attribute. Now, even if we perform some kind of xarray operation (such as taking the zonal mean), the units are preserved .. GENERATED FROM PYTHON SOURCE LINES 194-198 .. code-block:: Python heights_mean = heights.mean('longitude') heights_mean .. raw:: html
<xarray.DataArray 'Geopotential_height_isobaric' (latitude: 81)> Size: 324B
    <Quantity([5636.367  5644.392  5652.7705 5661.369  5669.813  5678.5083 5687.433
     5696.517  5705.927  5715.6123 5725.702  5736.1387 5746.884  5757.718
     5768.566  5779.2812 5789.8193 5799.801  5809.502  5818.7715 5827.7744
     5836.921  5846.3857 5855.668  5864.2397 5871.804  5878.769  5885.058
     5890.129  5894.0293 5897.146  5899.633  5901.674  5903.2773 5904.41
     5905.27   5905.897  5906.592  5907.0083 5907.0806 5907.031  5906.871
     5906.777  5906.4556 5906.121  5905.798  5905.6826 5905.5986 5905.4097
     5905.1245 5904.773  5904.43   5903.954  5903.378  5902.532  5901.714
     5900.865  5900.0933 5899.336  5898.4673 5897.44   5896.233  5895.057
     5893.633  5891.532  5888.15   5883.094  5884.8022 5887.923  5889.0054
     5889.114  5888.8887 5888.685  5888.146  5887.567  5887.0317 5886.299
     5885.4214 5884.515  5883.694  5883.072 ], 'meter')>
    Coordinates:
        time1      datetime64[ns] 8B 2017-09-05T18:00:00
        reftime    datetime64[ns] 8B ...
      * latitude   (latitude) float32 324B 50.0 49.5 49.0 48.5 ... 11.0 10.5 10.0
        isobaric3  float64 8B 5e+04


.. GENERATED FROM PYTHON SOURCE LINES 199-209 However, this "quantification" is not without its consequences. By default, xarray loads its data lazily to conserve memory usage. Unless your data is chunked into a Dask array (using the ``chunks`` argument), this ``.quantify()`` method will load data into memory, which could slow your script or even cause your process to run out of memory. And so, we recommend subsetting your data before quantifying it. Also, these Pint ``Quantity`` data objects are not properly handled by xarray when writing to disk. And so, if you want to safely export your data, you will need to undo the quantification with the ``.dequantify()`` method, which converts your data back to a unit-naive array with the unit as a text attribute .. GENERATED FROM PYTHON SOURCE LINES 209-213 .. code-block:: Python heights_mean_str_units = heights_mean.metpy.dequantify() heights_mean_str_units .. raw:: html
<xarray.DataArray 'Geopotential_height_isobaric' (latitude: 81)> Size: 324B
    array([5636.367 , 5644.392 , 5652.7705, 5661.369 , 5669.813 , 5678.5083,
           5687.433 , 5696.517 , 5705.927 , 5715.6123, 5725.702 , 5736.1387,
           5746.884 , 5757.718 , 5768.566 , 5779.2812, 5789.8193, 5799.801 ,
           5809.502 , 5818.7715, 5827.7744, 5836.921 , 5846.3857, 5855.668 ,
           5864.2397, 5871.804 , 5878.769 , 5885.058 , 5890.129 , 5894.0293,
           5897.146 , 5899.633 , 5901.674 , 5903.2773, 5904.41  , 5905.27  ,
           5905.897 , 5906.592 , 5907.0083, 5907.0806, 5907.031 , 5906.871 ,
           5906.777 , 5906.4556, 5906.121 , 5905.798 , 5905.6826, 5905.5986,
           5905.4097, 5905.1245, 5904.773 , 5904.43  , 5903.954 , 5903.378 ,
           5902.532 , 5901.714 , 5900.865 , 5900.0933, 5899.336 , 5898.4673,
           5897.44  , 5896.233 , 5895.057 , 5893.633 , 5891.532 , 5888.15  ,
           5883.094 , 5884.8022, 5887.923 , 5889.0054, 5889.114 , 5888.8887,
           5888.685 , 5888.146 , 5887.567 , 5887.0317, 5886.299 , 5885.4214,
           5884.515 , 5883.694 , 5883.072 ], dtype=float32)
    Coordinates:
        time1      datetime64[ns] 8B 2017-09-05T18:00:00
        reftime    datetime64[ns] 8B ...
      * latitude   (latitude) float32 324B 50.0 49.5 49.0 48.5 ... 11.0 10.5 10.0
        isobaric3  float64 8B 5e+04
    Attributes:
        units:    meter


.. GENERATED FROM PYTHON SOURCE LINES 214-217 Other useful unit integration features include: Unit-based selection/indexing: .. GENERATED FROM PYTHON SOURCE LINES 217-224 .. code-block:: Python heights_at_45_north = data['Geopotential_height_isobaric'].metpy.sel( latitude=45 * units.degrees_north, vertical=300 * units.hPa ) heights_at_45_north .. raw:: html
<xarray.DataArray 'Geopotential_height_isobaric' (time1: 9, longitude: 131)> Size: 5kB
    [1179 values with dtype=float32]
    Coordinates:
      * time1      (time1) datetime64[ns] 72B 2017-09-05T12:00:00 ... 2017-09-06T...
        reftime    datetime64[ns] 8B ...
        latitude   float32 4B 45.0
        isobaric3  float64 8B 3e+04
      * longitude  (longitude) float32 524B 250.0 250.5 251.0 ... 314.0 314.5 315.0
    Attributes:
        long_name:                      Geopotential height @ Isobaric surface
        units:                          gpm
        Grib_Variable_Id:               VAR_0-3-5_L100
        Grib2_Parameter:                [0 3 5]
        Grib2_Parameter_Discipline:     Meteorological products
        Grib2_Parameter_Category:       Mass
        Grib2_Parameter_Name:           Geopotential height
        Grib2_Level_Type:               100
        Grib2_Level_Desc:               Isobaric surface
        Grib2_Generating_Process_Type:  Forecast
        grid_mapping:                   LatLon_361X720-0p25S-180p00E


.. GENERATED FROM PYTHON SOURCE LINES 225-226 Unit conversion: .. GENERATED FROM PYTHON SOURCE LINES 226-230 .. code-block:: Python temperature_degc = temperature[0].metpy.convert_units('degC') temperature_degc .. raw:: html
<xarray.DataArray 'Temperature_isobaric' (isobaric3: 31, latitude: 81,
                                              longitude: 131)> Size: 1MB
    <Quantity([[[-15.149994 -15.149994 -15.25     ... -14.949982 -14.949982 -14.850006]
      [-15.25     -15.25     -15.350006 ... -14.949982 -14.949982 -14.949982]
      [-15.350006 -15.350006 -15.350006 ... -15.049988 -15.049988 -15.049988]
      ...
      [-12.350006 -12.350006 -12.350006 ... -15.149994 -15.049988 -14.949982]
      [-12.149994 -12.149994 -12.149994 ... -15.049988 -15.049988 -14.949982]
      [-11.949982 -11.949982 -11.949982 ... -15.049988 -14.949982 -14.850006]]

     [[-16.649994 -16.649994 -16.649994 ... -17.549988 -17.549988 -17.649994]
      [-16.75     -16.75     -16.850006 ... -17.649994 -17.649994 -17.649994]
      [-16.949982 -16.949982 -16.949982 ... -17.75     -17.75     -17.75    ]
      ...
      [-14.049988 -14.049988 -14.049988 ... -12.049988 -11.75     -11.549988]
      [-13.949982 -13.949982 -13.949982 ... -12.049988 -11.75     -11.549988]
      [-13.75     -13.850006 -13.850006 ... -12.049988 -11.75     -11.549988]]

     [[-21.75     -21.75     -21.75     ... -22.649994 -22.649994 -22.649994]
      [-21.949997 -21.84999  -21.84999  ... -22.75     -22.75     -22.75    ]
      [-22.049988 -22.049988 -22.049988 ... -22.84999  -22.84999  -22.949997]
      ...
    ...
      ...
      [ 22.149994  22.149994  22.149994 ...  22.550018  22.649994  22.75    ]
      [ 22.050018  22.050018  21.950012 ...  22.550018  22.149994  22.350006]
      [ 21.950012  21.75      22.149994 ...  22.550018  22.450012  22.050018]]

     [[ 15.649994  15.149994  14.649994 ...  11.950012  11.850006  11.75    ]
      [ 15.149994  15.149994  15.050018 ...  11.950012  11.649994  11.450012]
      [ 15.050018  14.850006  15.050018 ...  11.850006  11.75      11.649994]
      ...
      [ 24.149994  24.25      24.149994 ...  24.649994  24.649994  24.850006]
      [ 23.950012  23.950012  23.850006 ...  24.649994  24.25      24.450012]
      [ 23.850006  23.649994  23.75     ...  24.649994  24.25      24.050018]]

     [[ 17.050018  16.550018  16.050018 ...  13.450012  13.450012  13.550018]
      [ 16.550018  16.550018  16.450012 ...  13.350006  13.050018  12.950012]
      [ 16.450012  16.25      16.450012 ...  13.050018  12.850006  12.850006]
      ...
      [ 26.350006  26.350006  26.25     ...  26.75      26.850006  26.950012]
      [ 26.050018  26.050018  25.950012 ...  26.75      26.350006  26.550018]
      [ 26.050018  25.75      25.649994 ...  26.75      26.350006  26.149994]]], 'degree_Celsius')>
    Coordinates:
        time1      datetime64[ns] 8B 2017-09-05T12:00:00
        reftime    datetime64[ns] 8B ...
      * latitude   (latitude) float32 324B 50.0 49.5 49.0 48.5 ... 11.0 10.5 10.0
      * isobaric3  (isobaric3) float64 248B 100.0 200.0 300.0 ... 9.75e+04 1e+05
      * longitude  (longitude) float32 524B 250.0 250.5 251.0 ... 314.0 314.5 315.0
        metpy_crs  object 8B Projection: latitude_longitude
    Attributes:
        long_name:                      Temperature @ Isobaric surface
        Grib_Variable_Id:               VAR_0-0-0_L100
        Grib2_Parameter:                [0 0 0]
        Grib2_Parameter_Discipline:     Meteorological products
        Grib2_Parameter_Category:       Temperature
        Grib2_Parameter_Name:           Temperature
        Grib2_Level_Type:               100
        Grib2_Level_Desc:               Isobaric surface
        Grib2_Generating_Process_Type:  Forecast
        grid_mapping:                   LatLon_361X720-0p25S-180p00E


.. GENERATED FROM PYTHON SOURCE LINES 231-232 To base unit conversion: .. GENERATED FROM PYTHON SOURCE LINES 232-236 .. code-block:: Python temperature_degk = temperature_degc.metpy.convert_to_base_units() temperature_degk .. raw:: html
<xarray.DataArray 'Temperature_isobaric' (isobaric3: 31, latitude: 81,
                                              longitude: 131)> Size: 1MB
    <Quantity([[[258.  258.  257.9 ... 258.2 258.2 258.3]
      [257.9 257.9 257.8 ... 258.2 258.2 258.2]
      [257.8 257.8 257.8 ... 258.1 258.1 258.1]
      ...
      [260.8 260.8 260.8 ... 258.  258.1 258.2]
      [261.  261.  261.  ... 258.1 258.1 258.2]
      [261.2 261.2 261.2 ... 258.1 258.2 258.3]]

     [[256.5 256.5 256.5 ... 255.6 255.6 255.5]
      [256.4 256.4 256.3 ... 255.5 255.5 255.5]
      [256.2 256.2 256.2 ... 255.4 255.4 255.4]
      ...
      [259.1 259.1 259.1 ... 261.1 261.4 261.6]
      [259.2 259.2 259.2 ... 261.1 261.4 261.6]
      [259.4 259.3 259.3 ... 261.1 261.4 261.6]]

     [[251.4 251.4 251.4 ... 250.5 250.5 250.5]
      [251.2 251.3 251.3 ... 250.4 250.4 250.4]
      [251.1 251.1 251.1 ... 250.3 250.3 250.2]
      ...
    ...
      ...
      [295.3 295.3 295.3 ... 295.7 295.8 295.9]
      [295.2 295.2 295.1 ... 295.7 295.3 295.5]
      [295.1 294.9 295.3 ... 295.7 295.6 295.2]]

     [[288.8 288.3 287.8 ... 285.1 285.  284.9]
      [288.3 288.3 288.2 ... 285.1 284.8 284.6]
      [288.2 288.  288.2 ... 285.  284.9 284.8]
      ...
      [297.3 297.4 297.3 ... 297.8 297.8 298. ]
      [297.1 297.1 297.  ... 297.8 297.4 297.6]
      [297.  296.8 296.9 ... 297.8 297.4 297.2]]

     [[290.2 289.7 289.2 ... 286.6 286.6 286.7]
      [289.7 289.7 289.6 ... 286.5 286.2 286.1]
      [289.6 289.4 289.6 ... 286.2 286.  286. ]
      ...
      [299.5 299.5 299.4 ... 299.9 300.  300.1]
      [299.2 299.2 299.1 ... 299.9 299.5 299.7]
      [299.2 298.9 298.8 ... 299.9 299.5 299.3]]], 'kelvin')>
    Coordinates:
        time1      datetime64[ns] 8B 2017-09-05T12:00:00
        reftime    datetime64[ns] 8B ...
      * latitude   (latitude) float32 324B 50.0 49.5 49.0 48.5 ... 11.0 10.5 10.0
      * isobaric3  (isobaric3) float64 248B 100.0 200.0 300.0 ... 9.75e+04 1e+05
      * longitude  (longitude) float32 524B 250.0 250.5 251.0 ... 314.0 314.5 315.0
        metpy_crs  object 8B Projection: latitude_longitude
    Attributes:
        long_name:                      Temperature @ Isobaric surface
        Grib_Variable_Id:               VAR_0-0-0_L100
        Grib2_Parameter:                [0 0 0]
        Grib2_Parameter_Discipline:     Meteorological products
        Grib2_Parameter_Category:       Temperature
        Grib2_Parameter_Name:           Temperature
        Grib2_Level_Type:               100
        Grib2_Level_Desc:               Isobaric surface
        Grib2_Generating_Process_Type:  Forecast
        grid_mapping:                   LatLon_361X720-0p25S-180p00E


.. GENERATED FROM PYTHON SOURCE LINES 237-238 Unit conversion for coordinates: .. GENERATED FROM PYTHON SOURCE LINES 238-241 .. code-block:: Python heights_on_hpa_levels = heights.metpy.convert_coordinate_units('isobaric3', 'hPa') heights_on_hpa_levels['isobaric3'] .. raw:: html
<xarray.DataArray 'isobaric3' ()> Size: 8B
    array(500.)
    Coordinates:
        time1      datetime64[ns] 8B 2017-09-05T18:00:00
        reftime    datetime64[ns] 8B ...
        isobaric3  float64 8B 500.0
    Attributes:
        units:        hPa
        positive:     down
        _metpy_axis:  vertical


.. GENERATED FROM PYTHON SOURCE LINES 242-243 Accessing just the underlying unit array: .. GENERATED FROM PYTHON SOURCE LINES 243-246 .. code-block:: Python heights_unit_array = heights.metpy.unit_array heights_unit_array .. raw:: html
Magnitude
[[5883.3564453125 5879.31640625 5875.3564453125 ... 5769.396484375
5769.99609375 5770.43603515625]
[5885.47607421875 5882.236328125 5877.67626953125 ... 5783.916015625
5784.51611328125 5785.1962890625]
[5888.87646484375 5885.15625 5880.916015625 ... 5798.47607421875
5799.076171875 5799.71630859375]
...
[5892.51611328125 5892.236328125 5891.99609375 ... 5881.55615234375
5881.43603515625 5880.59619140625]
[5891.83642578125 5891.59619140625 5891.71630859375 ... 5880.2763671875
5880.3564453125 5879.916015625]
[5891.3564453125 5891.59619140625 5891.3564453125 ... 5879.87646484375
5879.59619140625 5878.99609375]]
Unitsmeter


.. GENERATED FROM PYTHON SOURCE LINES 247-248 Accessing just the underlying units: .. GENERATED FROM PYTHON SOURCE LINES 248-251 .. code-block:: Python height_units = heights.metpy.units height_units .. raw:: html
meter


.. GENERATED FROM PYTHON SOURCE LINES 252-259 Calculations ------------ MetPy's xarray integration extends to its calculation suite as well. Most grid-capable calculations (such as thermodynamics, kinematics, and smoothers) fully support xarray ``DataArray``\s by accepting them as inputs, returning them as outputs, and automatically using the attached coordinate data/metadata to determine grid arguments .. GENERATED FROM PYTHON SOURCE LINES 259-267 .. code-block:: Python heights = data_parsed.metpy.parse_cf('Geopotential_height_isobaric').metpy.sel( time='2017-09-05 18:00', vertical=500 * units.hPa ) u_g, v_g = mpcalc.geostrophic_wind(heights) u_g .. raw:: html
<xarray.DataArray (latitude: 81, longitude: 131)> Size: 85kB
    <Quantity([[ 2.33535886  4.60981877  2.93625413 ... 22.89067952 22.89183583
      23.49234567]
     [ 4.38966801  4.64400083  4.42111986 ... 23.12487204 23.12526033
      23.28446103]
     [ 5.54483395  4.9994661   5.35235118 ... 22.97939121 22.94731075
      22.75482798]
     ...
     [-3.42134235 -3.29600145 -3.16911313 ... -7.60556204 -6.84423212
      -4.56488464]
     [-3.84801887 -2.12410641 -2.1224862  ... -5.57355154 -6.1049832
      -5.30945593]
     [-2.64743317  2.22914893 -2.78516091 ...  0.27885616 -4.18284239
      -7.24175843]], 'meter / second')>
    Coordinates:
        time1      datetime64[ns] 8B 2017-09-05T18:00:00
        reftime    datetime64[ns] 8B 2017-09-05T12:00:00
      * latitude   (latitude) float32 324B 50.0 49.5 49.0 48.5 ... 11.0 10.5 10.0
      * longitude  (longitude) float32 524B 250.0 250.5 251.0 ... 314.0 314.5 315.0
        metpy_crs  object 8B Projection: latitude_longitude
        isobaric3  float64 8B 5e+04


.. GENERATED FROM PYTHON SOURCE LINES 268-274 For profile-based calculations (and most remaining calculations in the ``metpy.calc`` module), xarray ``DataArray``\s are accepted as inputs, but the outputs remain Pint Quantities (typically scalars). Note that MetPy's profile calculations (such as CAPE and CIN) require the sounding to be ordered from highest to lowest pressure. As seen earlier in this tutorial, this data is ordered the other way, so we need to reverse the inputs to ``mpcalc.surface_based_cape_cin``. .. GENERATED FROM PYTHON SOURCE LINES 274-291 .. code-block:: Python data_at_point = data.metpy.sel( time1='2017-09-05 12:00', latitude=30 * units.degrees_north, longitude=260 * units.degrees_east ) dewpoint = mpcalc.dewpoint_from_relative_humidity( data_at_point['Temperature_isobaric'], data_at_point['Relative_humidity_isobaric'] ) cape, cin = mpcalc.surface_based_cape_cin( data_at_point['isobaric3'][::-1], data_at_point['Temperature_isobaric'][::-1], dewpoint[::-1] ) cape .. raw:: html
2106.334802261844 joule/kilogram


.. GENERATED FROM PYTHON SOURCE LINES 292-304 A few remaining portions of MetPy's calculations (mainly the interpolation module and a few other functions) do not fully support xarray, and so, use of ``.values`` may be needed to convert to a bare NumPy array. For full information on xarray support for your function of interest, see the :doc:`/api/index`. CF-Compliant Dataset Example ---------------------------- The GFS sample used throughout this tutorial so far has been an example of a CF-compliant dataset. These kinds of datasets are easiest to work with it MetPy, since most of the "xarray magic" uses CF metadata. For this kind of dataset, a typical workflow looks like the following .. GENERATED FROM PYTHON SOURCE LINES 304-323 .. code-block:: Python # Load data, parse it for a CF grid mapping, and promote lat/lon data variables to coordinates data = xr.open_dataset( get_test_data('narr_example.nc', False) ).metpy.parse_cf().set_coords(['lat', 'lon']) # Subset to only the data you need to save on memory usage subset = data.metpy.sel(isobaric=500 * units.hPa) # Quantify if you plan on performing xarray operations that need to maintain unit correctness subset = subset.metpy.quantify() # Perform calculations heights = mpcalc.smooth_gaussian(subset['Geopotential_height'], 5) subset['u_geo'], subset['v_geo'] = mpcalc.geostrophic_wind(heights) # Plot heights.plot() .. image-sg:: /tutorials/images/sphx_glr_xarray_tutorial_001.png :alt: time = 1987-04-04T18:00:00, isobaric = 500.0 [h... :srcset: /tutorials/images/sphx_glr_xarray_tutorial_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 324-328 .. code-block:: Python # Save output subset.metpy.dequantify().drop_vars('metpy_crs').to_netcdf('500hPa_analysis.nc') .. GENERATED FROM PYTHON SOURCE LINES 329-334 Non-Compliant Dataset Example ----------------------------- When CF metadata (such as grid mapping, coordinate attributes, etc.) are missing, a bit more work is required to manually supply the required information, for example, .. GENERATED FROM PYTHON SOURCE LINES 334-353 .. code-block:: Python nonstandard = xr.Dataset({ 'temperature': (('y', 'x'), np.arange(0, 9).reshape(3, 3) * units.degC), 'y': ('y', np.arange(0, 3) * 1e5, {'units': 'km'}), 'x': ('x', np.arange(0, 3) * 1e5, {'units': 'km'}) }) # Add both CRS and then lat/lon coords using chained methods data = nonstandard.metpy.assign_crs( grid_mapping_name='lambert_conformal_conic', latitude_of_projection_origin=38.5, longitude_of_central_meridian=262.5, standard_parallel=38.5, earth_radius=6371229.0 ).metpy.assign_latitude_longitude() # Preview the changes data .. raw:: html
<xarray.Dataset> Size: 272B
    Dimensions:      (y: 3, x: 3)
    Coordinates:
      * y            (y) float64 24B 0.0 1e+05 2e+05
      * x            (x) float64 24B 0.0 1e+05 2e+05
        metpy_crs    object 8B Projection: lambert_conformal_conic
        latitude     (y, x) float64 72B 38.5 38.49 38.48 39.4 ... 40.3 40.29 40.28
        longitude    (y, x) float64 72B -97.5 -96.35 -95.2 ... -97.5 -96.32 -95.14
    Data variables:
        temperature  (y, x) int64 72B <Quantity([[0 1 2]  [3 4 5]  [6 7 8]], 'deg...


.. GENERATED FROM PYTHON SOURCE LINES 354-452 Once the CRS and additional coordinates are assigned, you can generally proceed as you would for a CF-compliant dataset. What Could Go Wrong? -------------------- Depending on your dataset and what you are trying to do, you might run into problems with xarray and MetPy. Below are examples of some of the most common issues - Multiple coordinate conflict - An axis not being available - An axis not being interpretable - ``UndefinedUnitError`` **Coordinate Conflict** Code: :: x = data['Temperature'].metpy.x Error Message: :: /home/user/env/MetPy/metpy/xarray.py:305: UserWarning: More than one x coordinate present for variable "Temperature". Fix: Manually assign the coordinates using the ``assign_coordinates()`` method on your DataArray, or by specifying the ``coordinates`` argument to the ``parse_cf()`` method on your Dataset, to map the ``time``, ``vertical``, ``y``, ``latitude``, ``x``, and ``longitude`` axes (as applicable to your data) to the corresponding coordinates. :: data['Temperature'].assign_coordinates({'time': 'time', 'vertical': 'isobaric', 'y': 'y', 'x': 'x'}) x = data['Temperature'].metpy.x or :: temperature = data.metpy.parse_cf('Temperature', coordinates={'time': 'time', 'vertical': 'isobaric', 'y': 'y', 'x': 'x'}) x = temperature.metpy.x **Axis Unavailable** Code: :: data['Temperature'].metpy.vertical Error Message: :: AttributeError: vertical attribute is not available. This means that your data variable does not have the coordinate that was requested, at least as far as the parser can recognize. Verify that you are requesting a coordinate that your data actually has, and if it still is not available, you will need to manually specify the coordinates as discussed above. **Axis Not Interpretable** Code: :: x, y, ensemble = data['Temperature'].metpy.coordinates('x', 'y', 'ensemble') Error Message: :: AttributeError: 'ensemble' is not an interpretable axis This means that you are requesting a coordinate that MetPy is (currently) unable to parse. While this means it cannot be recognized automatically, you can still obtain your desired coordinate directly by accessing it by name. If you have a need for systematic identification of a new coordinate type, we welcome pull requests for such new functionality on GitHub! **Undefined Unit Error** If the units attribute on your xarray data is not recognizable by Pint, you will likely receive an ``UndefinedUnitError``. In this case, you will likely have to update the units attribute to one that can be parsed properly by Pint. It is our aim to have all valid CF/UDUNITS unit strings be parseable, but this work is ongoing. If many variables in your dataset are not parseable, the ``.update_attribute`` method on the MetPy accessor may come in handy. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 2.996 seconds) .. _sphx_glr_download_tutorials_xarray_tutorial.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: xarray_tutorial.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: xarray_tutorial.py ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_