<jupyter_start><jupyter_text>Introduction to `cf_xarray`This notebook is a brief introduction to `cf_xarray`'s current capabilities.<jupyter_code>import cf_xarray
import numpy as np
import xarray as xr

xr.set_options(display_style="text")  # work around issue 57<jupyter_output><empty_output><jupyter_text>Lets read two datasets.<jupyter_code>ds = xr.tutorial.load_dataset("air_temperature")
ds.air.attrs["standard_name"] = "air_temperature"
ds<jupyter_output><empty_output><jupyter_text>This one is inspired by POP model output and illustrates how the coordinatesattribute is interpreted<jupyter_code>pop = xr.Dataset()
pop.coords["TLONG"] = (
    ("nlat", "nlon"),
    np.ones((20, 30)),
    {"units": "degrees_east"},
)
pop.coords["TLAT"] = (
    ("nlat", "nlon"),
    2 * np.ones((20, 30)),
    {"units": "degrees_north"},
)
pop.coords["ULONG"] = (
    ("nlat", "nlon"),
    0.5 * np.ones((20, 30)),
    {"units": "degrees_east"},
)
pop.coords["ULAT"] = (
    ("nlat", "nlon"),
    2.5 * np.ones((20, 30)),
    {"units": "degrees_north"},
)

pop["UVEL"] = (
    ("nlat", "nlon"),
    np.ones((20, 30)) * 15,
    {"coordinates": "ULONG ULAT", "standard_name": "sea_water_x_velocity"},
)
pop["TEMP"] = (
    ("nlat", "nlon"),
    np.ones((20, 30)) * 15,
    {
        "coordinates": "TLONG TLAT",
        "standard_name": "sea_water_potential_temperature",
    },
)
pop<jupyter_output><empty_output><jupyter_text>This synthetic dataset has multiple `X` and `Y` coords. An example would bemodel output on a staggered grid.<jupyter_code>multiple = xr.Dataset()
multiple.coords["x1"] = ("x1", range(30), {"axis": "X"})
multiple.coords["y1"] = ("y1", range(20), {"axis": "Y"})
multiple.coords["x2"] = ("x2", range(10), {"axis": "X"})
multiple.coords["y2"] = ("y2", range(5), {"axis": "Y"})

multiple["v1"] = (("x1", "y1"), np.ones((30, 20)) * 15)
multiple["v2"] = (("x2", "y2"), np.ones((10, 5)) * 15)
multiple
# This dataset has ancillary variables

anc = xr.Dataset()
anc["q"] = (
    ("x", "y"),
    np.random.randn(10, 20),
    dict(
        standard_name="specific_humidity",
        units="g/g",
        ancillary_variables="q_error_limit q_detection_limit",
    ),
)
anc["q_error_limit"] = (
    ("x", "y"),
    np.random.randn(10, 20),
    dict(standard_name="specific_humidity standard_error", units="g/g"),
)
anc["q_detection_limit"] = xr.DataArray(
    1e-3,
    attrs=dict(
        standard_name="specific_humidity detection_minimum", units="g/g"
    ),
)
anc<jupyter_output><empty_output><jupyter_text>What attributes have been discovered?<jupyter_code>ds.lon<jupyter_output><empty_output><jupyter_text>`ds.lon` has attributes `axis: X`. This means that `cf_xarray` can identify the`'X'` axis as being represented by the `lon` variable.It can also use the `standard_name` and `units` attributes to infer that `lon`is "Longitude". To see variable names that `cf_xarray` can infer, use`.cf.describe()`<jupyter_code>ds.cf.describe()<jupyter_output><empty_output><jupyter_text>For `pop`, only `latitude` and `longitude` are detected, not `X` or `Y`. Pleasecomment here: https://github.com/xarray-contrib/cf-xarray/issues/23 if you haveopinions about this behaviour.<jupyter_code>pop.cf.describe()<jupyter_output><empty_output><jupyter_text>For `multiple`, multiple `X` and `Y` coordinates are detected<jupyter_code>multiple.cf.describe()<jupyter_output><empty_output><jupyter_text>Feature: Accessing coordinate variables`.cf` implements `__getitem__` to allow easy access to coordinate and axisvariables.<jupyter_code>ds.cf["X"]<jupyter_output><empty_output><jupyter_text>Indexing with a scalar key raises an error if the key maps to multiple variablesnames<jupyter_code>multiple.cf["X"]
pop.cf["longitude"]<jupyter_output><empty_output><jupyter_text>To get back all variables associated with that key, pass a single element listinstead.<jupyter_code>multiple.cf[["X"]]
pop.cf[["longitude"]]<jupyter_output><empty_output><jupyter_text>DataArrays return DataArrays<jupyter_code>pop.UVEL.cf["longitude"]<jupyter_output><empty_output><jupyter_text>`Dataset.cf[...]` returns a single `DataArray`, parsing the `coordinates`attribute if present, so we correctly get the `TLONG` variable and not the`ULONG` variable<jupyter_code>pop.cf["TEMP"]<jupyter_output><empty_output><jupyter_text>`Dataset.cf[...]` also interprets the `ancillary_variables` attribute. Theancillary variables are returned as coordinates of a DataArray<jupyter_code>anc.cf["q"]<jupyter_output><empty_output><jupyter_text>Feature: Accessing variables by standard names<jupyter_code>pop.cf[["sea_water_potential_temperature", "UVEL"]]
anc.cf["specific_humidity"]<jupyter_output><empty_output><jupyter_text>Feature: Utility functionsThere are some utility functions to allow use by downstream libraries<jupyter_code>pop.cf.get_valid_keys()<jupyter_output><empty_output><jupyter_text>You can test for presence of these keys<jupyter_code>"sea_water_x_velocity" in pop.cf<jupyter_output><empty_output><jupyter_text>Feature: Rewriting property dictionaries`cf_xarray` will rewrite the `.sizes` and `.chunks` dictionaries so that one canindex by a special CF axis or coordinate name<jupyter_code>ds.cf.sizes<jupyter_output><empty_output><jupyter_text>Note the duplicate entries above:1. One for `X`, `Y`, `T`2. and one for `longitude`, `latitude` and `time`.An error is raised if there are multiple `'X'` variables (for example)<jupyter_code>multiple.cf.sizes
multiple.v1.cf.sizes<jupyter_output><empty_output><jupyter_text>Feature: Renaming coordinate variables`cf_xarray` lets you rewrite coordinate variables in one dataset to likevariables in another dataset. This can only be done when a one-to-one mapping ispossibleIn this example, `TLONG` and `TLAT` are renamed to `lon` and `lat` i.e. theircounterparts in `ds`. Note the the `coordinates` attribute is appropriatelychanged.<jupyter_code>pop.cf["TEMP"].cf.rename_like(ds)<jupyter_output><empty_output><jupyter_text>Feature: Rewriting arguments`cf_xarray` can rewrite arguments for a large number of xarray functions. Bythis I mean that instead of specifing say `dim="lon"`, you can pass `dim="X"` or`dim="longitude"` and `cf_xarray` will rewrite that to `dim="lon"` based on theattributes present in the dataset.Here are a few examples  Slicing<jupyter_code>ds.air.cf.isel(T=1)<jupyter_output><empty_output><jupyter_text>Slicing works will expand a single key like `X` to multiple dimensions if thosedimensions are tagged with `axis: X`<jupyter_code>multiple.cf.isel(X=1, Y=1)<jupyter_output><empty_output><jupyter_text>Reductions<jupyter_code>ds.air.cf.mean("X")<jupyter_output><empty_output><jupyter_text>Expanding to multiple dimensions is also supported<jupyter_code># takes the mean along ["x1", "x2"]
multiple.cf.mean("X")<jupyter_output><empty_output><jupyter_text>Plotting<jupyter_code>ds.air.cf.isel(time=1).cf.plot(x="X", y="Y")
ds.air.cf.isel(T=1, Y=[0, 1, 2]).cf.plot(x="longitude", hue="latitude")<jupyter_output><empty_output><jupyter_text>`cf_xarray` can facet<jupyter_code>seasonal = (
    ds.air.groupby("time.season")
    .mean()
    .reindex(season=["DJF", "MAM", "JJA", "SON"])
)
seasonal.cf.plot(x="longitude", y="latitude", col="season")<jupyter_output><empty_output><jupyter_text>Resample & groupby<jupyter_code>ds.cf.resample(T="D").mean()<jupyter_output><empty_output><jupyter_text>`cf_xarray` also understands the "datetime accessor" syntax for groupby<jupyter_code>ds.cf.groupby("T.month").mean("longitude")<jupyter_output><empty_output><jupyter_text>Rolling & coarsen<jupyter_code>ds.cf.rolling(X=5).mean()<jupyter_output><empty_output><jupyter_text>`coarsen` works but everything later will break because of xarray bughttps://github.com/pydata/xarray/issues/4120`ds.isel(lon=slice(50)).cf.coarsen(Y=5, X=10).mean()`  Feature: mix "special names" and variable names<jupyter_code>ds.cf.groupby("T.month").mean(["lat", "X"])<jupyter_output><empty_output><jupyter_text>Feature: Weight by Cell Measures`cf_xarray` can weight by cell measure variables `"area"` and `"volume"` if theappropriate attribute is set<jupyter_code># Lets make some weights (not sure if this is right)
ds.coords["cell_area"] = (
    np.cos(ds.air.cf["latitude"] * np.pi / 180)
    * xr.ones_like(ds.air.cf["longitude"])
    * 105e3
    * 110e3
)
# and set proper attributes
ds.air.attrs["cell_measures"] = "area: cell_area"
ds.air.cf.weighted("area").mean(["latitude", "time"]).cf.plot(x="longitude")
ds.air.mean(["lat", "time"]).cf.plot(x="longitude")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15513996706657257, 'fraction_numerical': 0.013290990355210539, 'mean_word_length': 6.858595194085027, 'pattern_counts': {'":': 12, '<': 125, '<?xml version=': 0, '>': 125, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '31', 'dir': 'jupyter-structured-clean-dedup', 'id': '14693', 'license': 'Apache-2.0', 'n_tokens_mistral': 3154, 'n_tokens_neox': 3033, 'n_words': 632, 'path': 'doc/examples/introduction.ipynb', 'repo_name': 'Ouranosinc/cf-xarray', 'size': '8502'}