# index.html.md # Xarray documentation Xarray makes working with labelled multi-dimensional arrays in Python simple, efficient, and fun! **Version**: 2026.7.0 - [What’s New](whats-new.md#whats-new) **Useful links**: [Home](https://xarray.dev) | [Code Repository](https://github.com/pydata/xarray) | [Issues](https://github.com/pydata/xarray/issues) | [Discussions](https://github.com/pydata/xarray/discussions) | [Releases](https://github.com/pydata/xarray/releases) | [Tutorial](https://tutorial.xarray.dev) | [Stack Overflow](https://stackoverflow.com/questions/tagged/python-xarray) | [Blog](https://xarray.dev/blog) | ![](_static/index_getting_started.svg) *New to Xarray?* Start here with our installation instructions and a brief overview of Xarray. ![](_static/index_user_guide.svg) *Ready to deepen your understanding of Xarray?* Visit the user guide for detailed explanations of the data model, common computational patterns, and more. ![](_static/index_api.svg) *Need to learn more about a specific Xarray function?* Go here to review the documentation of all public functions and classes in Xarray. ![](_static/index_contribute.svg) *Saw a typo in the documentation? Want to improve existing functionalities?* Please review our guide on improving Xarray. # index.html.md # Getting Started The getting started guide aims to get you using Xarray productively as quickly as possible. It is designed as an entry point for new users, and it provided an introduction to Xarray’s main concepts. * [Overview: Why xarray?](why-xarray.md) * [What labels enable](why-xarray.md#what-labels-enable) * [Core data structures](why-xarray.md#core-data-structures) * [Goals and aspirations](why-xarray.md#goals-and-aspirations) * [Installation](installing.md) * [Required dependencies](installing.md#required-dependencies) * [Optional dependencies](installing.md#optional-dependencies) * [Minimum dependency versions](installing.md#minimum-dependency-versions) * [Instructions](installing.md#instructions) * [Development versions](installing.md#development-versions) * [Testing](installing.md#testing) * [Quick overview](quick-overview.md) * [Create a DataArray](quick-overview.md#create-a-dataarray) * [Indexing](quick-overview.md#indexing) * [Attributes](quick-overview.md#attributes) * [Computation](quick-overview.md#computation) * [GroupBy](quick-overview.md#groupby) * [Plotting](quick-overview.md#plotting) * [pandas](quick-overview.md#pandas) * [Datasets](quick-overview.md#datasets) * [Read & write netCDF files](quick-overview.md#read-write-netcdf-files) * [DataTrees](quick-overview.md#datatrees) * [Tutorials and Videos](tutorials-and-videos.md) * [Tutorials](tutorials-and-videos.md#tutorials) * [Videos](tutorials-and-videos.md#videos) * [Books, Chapters and Articles](tutorials-and-videos.md#books-chapters-and-articles) # index.html.md # Xarray Developer’s Guide We welcome your skills and enthusiasm at the Xarray project! There are numerous opportunities to contribute beyond just writing code. All contributions, including bug reports, bug fixes, documentation improvements, enhancement suggestions, and other ideas are welcome. Please review our Contributor’s guide for more guidance. In this section you will also find documentation on the internal organization of Xarray’s source code, the roadmap for current development priorities, as well as how to engage with core maintainers of the Xarray codebase. # index.html.md # User Guide In this user guide, you will find detailed descriptions and examples that describe many common tasks that you can accomplish with Xarray. # Data model * [Terminology](terminology.md) * [Data Structures](data-structures.md) * [DataArray](data-structures.md#dataarray) * [Dataset](data-structures.md#dataset) * [DataTree](data-structures.md#datatree) * [Coordinates](data-structures.md#coordinates) * [Hierarchical data](hierarchical-data.md) * [Why Hierarchical Data?](hierarchical-data.md#why-hierarchical-data) * [Node Relationships](hierarchical-data.md#node-relationships) * [Navigating Trees](hierarchical-data.md#navigating-trees) * [Manipulating Trees](hierarchical-data.md#manipulating-trees) * [Tree Contents](hierarchical-data.md#tree-contents) * [Computation](hierarchical-data.md#computation) * [Operating on Multiple Trees](hierarchical-data.md#operating-on-multiple-trees) * [Alignment and Coordinate Inheritance](hierarchical-data.md#alignment-and-coordinate-inheritance) * [Parallel Computing with Dask](dask.md) * [Examples](dask.md#examples) * [Using Dask with Xarray](dask.md#using-dask-with-xarray) * [Deploying Dask](dask.md#deploying-dask) * [Best Practices](dask.md#best-practices) # Core operations * [Indexing and selecting data](indexing.md) * [Quick overview](indexing.md#quick-overview) * [Positional indexing](indexing.md#positional-indexing) * [Indexing with dimension names](indexing.md#indexing-with-dimension-names) * [Nearest neighbor lookups](indexing.md#nearest-neighbor-lookups) * [Dataset indexing](indexing.md#dataset-indexing) * [Dropping labels and dimensions](indexing.md#dropping-labels-and-dimensions) * [Masking with `where`](indexing.md#masking-with-where) * [Selecting values with `isin`](indexing.md#selecting-values-with-isin) * [Vectorized Indexing](indexing.md#vectorized-indexing) * [Assigning values with indexing](indexing.md#assigning-values-with-indexing) * [More advanced indexing](indexing.md#more-advanced-indexing) * [Align and reindex](indexing.md#align-and-reindex) * [Missing coordinate labels](indexing.md#missing-coordinate-labels) * [Underlying Indexes](indexing.md#underlying-indexes) * [Copies vs. Views](indexing.md#copies-vs-views) * [Multi-level indexing](indexing.md#multi-level-indexing) * [Indexing rules](indexing.md#indexing-rules) * [Combining data](combining.md) * [Concatenate](combining.md#concatenate) * [Merge](combining.md#merge) * [Combine](combining.md#combine) * [Update](combining.md#update) * [Equals and identical](combining.md#equals-and-identical) * [Merging with ‘no_conflicts’](combining.md#merging-with-no-conflicts) * [Combining along multiple dimensions](combining.md#combining-along-multiple-dimensions) * [Reshaping and reorganizing data](reshaping.md) * [Importing the library](reshaping.md#importing-the-library) * [Reordering dimensions](reshaping.md#reordering-dimensions) * [Expand and squeeze dimensions](reshaping.md#expand-and-squeeze-dimensions) * [Converting between datasets and arrays](reshaping.md#converting-between-datasets-and-arrays) * [Stack and unstack](reshaping.md#stack-and-unstack) * [Set and reset index](reshaping.md#set-and-reset-index) * [Shift and roll](reshaping.md#shift-and-roll) * [Sort](reshaping.md#sort) * [Reshaping via coarsen](reshaping.md#reshaping-via-coarsen) * [Computation](computation.md) * [Basic array math](computation.md#basic-array-math) * [Missing values](computation.md#missing-values) * [Aggregation](computation.md#aggregation) * [Rolling window operations](computation.md#rolling-window-operations) * [Weighted array reductions](computation.md#weighted-array-reductions) * [Coarsen large arrays](computation.md#coarsen-large-arrays) * [Computation using Coordinates](computation.md#computation-using-coordinates) * [Fitting polynomials](computation.md#fitting-polynomials) * [Fitting arbitrary functions](computation.md#fitting-arbitrary-functions) * [Broadcasting by dimension name](computation.md#broadcasting-by-dimension-name) * [Automatic alignment](computation.md#automatic-alignment) * [Coordinates](computation.md#coordinates) * [Math with datasets](computation.md#math-with-datasets) * [Wrapping custom computation](computation.md#wrapping-custom-computation) * [GroupBy: Group and Bin Data](groupby.md) * [Split](groupby.md#split) * [Binning](groupby.md#binning) * [Apply](groupby.md#apply) * [First and last](groupby.md#first-and-last) * [Grouped arithmetic](groupby.md#grouped-arithmetic) * [Multidimensional Grouping](groupby.md#multidimensional-grouping) * [Grouper Objects](groupby.md#grouper-objects) * [Grouping by multiple variables](groupby.md#grouping-by-multiple-variables) * [Time Grouping and Resampling](groupby.md#time-grouping-and-resampling) * [Shuffling](groupby.md#shuffling) * [Interpolating data](interpolation.md) * [Scalar and 1-dimensional interpolation](interpolation.md#scalar-and-1-dimensional-interpolation) * [Multi-dimensional Interpolation](interpolation.md#multi-dimensional-interpolation) * [Interpolation methods](interpolation.md#interpolation-methods) * [Advanced Interpolation](interpolation.md#advanced-interpolation) * [Interpolating arrays with NaN](interpolation.md#interpolating-arrays-with-nan) * [Example](interpolation.md#example) # I/O * [Reading and writing files](io.md) * [Backend Selection](io.md#backend-selection) * [netCDF](io.md#netcdf) * [HDF5](io.md#hdf5) * [Zarr](io.md#zarr) * [Kerchunk](io.md#kerchunk) * [Iris](io.md#iris) * [OPeNDAP](io.md#opendap) * [Pickle](io.md#pickle) * [Dictionary](io.md#dictionary) * [Rasterio](io.md#rasterio) * [GRIB format via cfgrib](io.md#grib-format-via-cfgrib) * [CSV and other formats supported by pandas](io.md#csv-and-other-formats-supported-by-pandas) * [Third party libraries](io.md#third-party-libraries) * [Complex Numbers](complex-numbers.md) * [Operations on Complex Data](complex-numbers.md#operations-on-complex-data) * [Reading and Writing Complex Data](complex-numbers.md#reading-and-writing-complex-data) * [See also](complex-numbers.md#see-also) # Visualization * [Plotting](plotting.md) * [Introduction](plotting.md#introduction) * [DataArrays](plotting.md#dataarrays) * [Datasets](plotting.md#datasets) * [Maps](plotting.md#maps) * [Details](plotting.md#details) # Interoperability * [Working with pandas](pandas.md) * [Hierarchical and tidy data](pandas.md#hierarchical-and-tidy-data) * [Lossless and reversible conversion](pandas.md#lossless-and-reversible-conversion) * [Multi-dimensional data](pandas.md#multi-dimensional-data) * [Transitioning from pandas.Panel to xarray](pandas.md#transitioning-from-pandas-panel-to-xarray) * [Working with numpy-like arrays](duckarrays.md) * [Why “duck”?](duckarrays.md#why-duck) * [What is a numpy-like array?](duckarrays.md#what-is-a-numpy-like-array) * [Wrapping numpy-like arrays in xarray](duckarrays.md#wrapping-numpy-like-arrays-in-xarray) * [Extensions using duck arrays](duckarrays.md#extensions-using-duck-arrays) * [Xarray related projects](ecosystem.md) * [Geosciences](ecosystem.md#geosciences) * [Machine Learning](ecosystem.md#machine-learning) * [Other domains](ecosystem.md#other-domains) * [Extend xarray capabilities](ecosystem.md#extend-xarray-capabilities) * [Visualization](ecosystem.md#visualization) * [Non-Python projects](ecosystem.md#non-python-projects) # Domain-specific workflows * [Time series data](time-series.md) * [Creating datetime64 data](time-series.md#creating-datetime64-data) * [Datetime indexing](time-series.md#datetime-indexing) * [Datetime components](time-series.md#datetime-components) * [Resampling and grouped operations](time-series.md#resampling-and-grouped-operations) * [Weather and climate data](weather-climate.md) * [Related Variables](weather-climate.md#related-variables) * [CF-compliant coordinate variables](weather-climate.md#cf-compliant-coordinate-variables) * [Non-standard calendars and dates outside the precision range](weather-climate.md#non-standard-calendars-and-dates-outside-the-precision-range) * [Arithmetic limitations with `cftime` objects](weather-climate.md#arithmetic-limitations-with-cftime-objects) # Options and Testing * [Configuration](options.md) * [Testing your code](testing.md) * [Hypothesis testing](testing.md#hypothesis-testing) # index.html.md # Xarray Internals Xarray builds upon two of the foundational libraries of the scientific Python stack, NumPy and pandas. It is written in pure Python (no C or Cython extensions), which makes it easy to develop and extend. Instead, we push compiled code to [optional dependencies](../getting-started-guide/installing.md#installing). The pages in this section are intended for: * Contributors to xarray who wish to better understand some of the internals, * Developers from other fields who wish to extend xarray with domain-specific logic, perhaps to support a new scientific community of users, * Developers of other packages who wish to interface xarray with their existing tools, e.g. by creating a backend for reading a new file format, or wrapping a custom array type. # ERA5-GRIB-example.html.md You can run this notebook in a [live session](https://mybinder.org/v2/gh/pydata/xarray/doc/examples/main?urlpath=lab/tree/doc/examples/ERA5-GRIB-example.ipynb) [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/pydata/xarray/main?urlpath=lab/tree/doc/examples/ERA5-GRIB-example.ipynb) or view it [on Github](https://github.com/pydata/xarray/blob/main/doc/examples/ERA5-GRIB-example.ipynb). # GRIB Data Example GRIB format is commonly used to disseminate atmospheric model data. With xarray and the cfgrib engine, GRIB data can easily be analyzed and visualized. To read GRIB data, you can use `xarray.load_dataset`. The only extra code you need is to specify the engine as `cfgrib`. Let’s create a simple plot of 2-m air temperature in degrees Celsius: With CartoPy, we can create a more detailed plot, using built-in shapefiles to help provide geographic context: Finally, we can also pull out a time series for a given location easily: # README.html.md # xarray You can find information about building the docs at our [Contributing page](http:/docs.xarray.dev/en/latest/contributing.html#contributing-to-the-documentation). # ROMS_ocean_model.html.md You can run this notebook in a [live session](https://mybinder.org/v2/gh/pydata/xarray/doc/examples/main?urlpath=lab/tree/doc/examples/ROMS_ocean_model.ipynb) [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/pydata/xarray/main?urlpath=lab/tree/doc/examples/ROMS_ocean_model.ipynb) or view it [on Github](https://github.com/pydata/xarray/blob/main/doc/examples/ROMS_ocean_model.ipynb). # ROMS Ocean Model Example The Regional Ocean Modeling System ([ROMS](https://www.myroms.org/)) is an open source hydrodynamic model that is used for simulating currents and water properties in coastal and estuarine regions. ROMS is one of a few standard ocean models, and it has an active user community. ROMS uses a regular C-Grid in the horizontal, similar to other structured grid ocean and atmospheric models, and a stretched vertical coordinate (see [the ROMS documentation](https://www.myroms.org/wiki/Vertical_S-coordinate) for more details). Both of these require special treatment when using `xarray` to analyze ROMS ocean model output. This example notebook shows how to create a lazily evaluated vertical coordinate, and make some basic plots. The `xgcm` package is required to do analysis that is aware of the horizontal C-Grid. Load a sample ROMS file. This is a subset of a full model available at ```none http://barataria.tamu.edu/thredds/catalog.html?dataset=txla_hindcast_agg ``` The subsetting was done using the following command on one of the output files: ```none #open dataset ds = xr.open_dataset('/d2/shared/TXLA_ROMS/output_20yr_obc/2001/ocean_his_0015.nc') # Turn on chunking to activate dask and parallelize read/write. ds = ds.chunk({'ocean_time': 1}) # Pick out some of the variables that will be included as coordinates ds = ds.set_coords(['Cs_r', 'Cs_w', 'hc', 'h', 'Vtransform']) # Select a subset of variables. Salt will be visualized, zeta is used to # calculate the vertical coordinate variables = ['salt', 'zeta'] ds[variables].isel(ocean_time=slice(47, None, 7*24), xi_rho=slice(300, None)).to_netcdf('ROMS_example.nc', mode='w') ``` So, the `ROMS_example.nc` file contains a subset of the grid, one 3D variable, and two time steps. ## Load in ROMS dataset as an xarray object ## Add a lazilly calculated vertical coordinates Write equations to calculate the vertical coordinate. These will be only evaluated when data is requested. Information about the ROMS vertical coordinate can be found [here](https://www.myroms.org/wiki/Vertical_S-coordinate). In short, for `Vtransform==2` as used in this example, $Z_0 = (h_c \, S + h \,C) / (h_c + h)$ $z = Z_0 (\zeta + h) + \zeta$ where the variables are defined as in the link above. ## A naive vertical slice Creating a slice using the s-coordinate as the vertical dimension is typically not very informative. We can feed coordinate information to the plot method to give a more informative cross-section that uses the depths. Note that we did not need to slice the depth or longitude information separately, this was done automatically as the variable was sliced. ## A plan view Now make a naive plan view, without any projection information, just using lon/lat as x/y. This looks OK, but will appear compressed because lon and lat do not have an aspect constrained by the projection. And let’s use a projection to make it nicer, and add a coast. # accessors.html.md # Accessors | [`accessor_dt.DatetimeAccessor`](../generated/xarray.core.accessor_dt.DatetimeAccessor.md#xarray.core.accessor_dt.DatetimeAccessor)(obj) | Access datetime fields for DataArrays with datetime-like dtypes. | |---------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------| | [`accessor_dt.TimedeltaAccessor`](../generated/xarray.core.accessor_dt.TimedeltaAccessor.md#xarray.core.accessor_dt.TimedeltaAccessor)(obj) | Access Timedelta fields for DataArrays with Timedelta-like dtypes. | | [`accessor_str.StringAccessor`](../generated/xarray.core.accessor_str.StringAccessor.md#xarray.core.accessor_str.StringAccessor)(obj) | Vectorized string functions for string-like arrays. | # advanced.html.md # Advanced API The methods and properties here are advanced API and not recommended for use unless you know what you are doing. | [`Dataset.variables`](../generated/xarray.Dataset.variables.md#xarray.Dataset.variables) | Low level interface to Dataset contents as dict of Variable objects. | |------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------| | [`DataArray.variable`](../generated/xarray.DataArray.variable.md#xarray.DataArray.variable) | Low level interface to the Variable object for this DataArray. | | [`DataTree.variables`](../generated/xarray.DataTree.variables.md#xarray.DataTree.variables) | Low level interface to node contents as dict of Variable objects. | | [`Variable`](../generated/xarray.Variable.md#xarray.Variable)(dims, data[, attrs, encoding, fastpath]) | A netcdf-like variable consisting of dimensions, data and attributes which describe a single Array. | | [`IndexVariable`](../generated/xarray.IndexVariable.md#xarray.IndexVariable)(dims, data[, attrs, encoding, ...]) | Wrapper for accommodating a pandas.Index in an xarray.Variable. | | [`as_variable`](../generated/xarray.as_variable.md#xarray.as_variable)(obj[, name, auto_convert]) | Convert an object into a Variable. | | [`Context`](../generated/xarray.Context.md#xarray.Context)(func) | object carrying the information of a call | | [`register_dataset_accessor`](../generated/xarray.register_dataset_accessor.md#xarray.register_dataset_accessor)(name) | Register a custom property on xarray.Dataset objects. | | [`register_dataarray_accessor`](../generated/xarray.register_dataarray_accessor.md#xarray.register_dataarray_accessor)(name) | Register a custom accessor on xarray.DataArray objects. | | [`register_datatree_accessor`](../generated/xarray.register_datatree_accessor.md#xarray.register_datatree_accessor)(name) | Register a custom accessor on DataTree objects. | | [`Dataset.set_close`](../generated/xarray.Dataset.set_close.md#xarray.Dataset.set_close)(close) | Register the function that releases any resources linked to this object. | # ai-policy.html.md # AI Usage Policy **Note:** Some Xarray developers use AI tools as part of our development workflow. We assume this is now common. Tools, patterns, and norms are evolving fast — this policy aims to avoid restricting contributors’ choice of tooling while ensuring that: - Reviewers are not overburdened - Contributions can be maintained - The submitter can vouch for and explain all changes - Developers can acquire new skills[1](#id2) To that end this policy applies regardless of whether the code was written by hand, with AI assistance, or generated entirely by an AI tool. ## Core Principle: Changes If you submit a pull request, you are responsible for understanding and having fully reviewed the changes. You must be able to explain why each change is correct[2](#id4) and how it fits into the project. Strive to minimize changes to ease the burden on reviewers — avoid including unnecessary or loosely related changes. ## Core Principle: Communication PR descriptions, issue comments, and review responses must be your own words. The substance and reasoning must come from you. Do not paste AI-generated text as comments or review responses. Please attempt to be concise. PR descriptions should follow the provided template. Using AI to improve the language of your writing (grammar, phrasing, spelling, etc.) is acceptable. Be careful that it does not introduce inaccurate details in the process. Maintainers reserve the right to delete or hide comments that violate our AI policy or code of conduct. ## Code and Tests ### Review Every Line You must have personally reviewed and understood all changes before submitting. If you used AI to generate code, you are expected to have read it critically and tested it. As with a hand-written PR, the description should explain the approach and reasoning behind the changes. Do not leave it to reviewers to figure out what the code does and why. #### Not Acceptable > I pointed an agent at the issue and here are the changes > This is what Claude came up with. 🤷 #### Acceptable > I iterated multiple times with an agent to produce this. The agent wrote the code at my direction, > and I have fully read and validated the changes. > I pointed an agent at the issue and it generated a first draft. I reviewed the changes thoroughly and understand the implementation well. ### Large AI-Assisted Contributions Generating code with agents is fast and easy. Reviewing it is not. Making a PR with a large diff shifts the burden from the contributor to the reviewer. To guard against this asymmetry: If you are planning a large AI-assisted contribution (e.g., a significant refactor, a framework migration, or a new subsystem), **open an issue first** to discuss the scope and approach with maintainers. This helps us decide if the change is worthwhile, how it should be structured, and any other important decisions. Maintainers reserve the right to close PRs where the scope makes meaningful review impractical, or when they suspect this policy has been violated. Similarly they may request that large changes be broken into smaller, reviewable pieces. ## Documentation The same core principles apply to both code and documentation. You must review the result for accuracy and are ultimately responsible for all changes made. Xarray has domain-specific semantics that AI tools frequently get wrong. Do not submit documentation that you haven’t carefully read and verified. --- * **[1]** Over-reliance on AI tools has been shown to [hinder skill formation amongst software developers](https://arxiv.org/abs/2601.20245). * **[2]** You may also open a draft PR with changes in order to discuss and receive feedback on the best approach if you are not sure what the best way forward is. # api-hidden.html.md | [`core.coordinates.DatasetCoordinates.get`](generated/xarray.core.coordinates.DatasetCoordinates.get.md#xarray.core.coordinates.DatasetCoordinates.get)(k[,d]) | | |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [`core.coordinates.DatasetCoordinates.items`](generated/xarray.core.coordinates.DatasetCoordinates.items.md#xarray.core.coordinates.DatasetCoordinates.items)() | | | [`core.coordinates.DatasetCoordinates.keys`](generated/xarray.core.coordinates.DatasetCoordinates.keys.md#xarray.core.coordinates.DatasetCoordinates.keys)() | | | [`core.coordinates.DatasetCoordinates.values`](generated/xarray.core.coordinates.DatasetCoordinates.values.md#xarray.core.coordinates.DatasetCoordinates.values)() | | | [`core.coordinates.DatasetCoordinates.dims`](generated/xarray.core.coordinates.DatasetCoordinates.dims.md#xarray.core.coordinates.DatasetCoordinates.dims) | Mapping from dimension names to lengths or tuple of dimension names. | | [`core.coordinates.DatasetCoordinates.sizes`](generated/xarray.core.coordinates.DatasetCoordinates.sizes.md#xarray.core.coordinates.DatasetCoordinates.sizes) | Mapping from dimension names to lengths. | | [`core.coordinates.DatasetCoordinates.dtypes`](generated/xarray.core.coordinates.DatasetCoordinates.dtypes.md#xarray.core.coordinates.DatasetCoordinates.dtypes) | Mapping from coordinate names to dtypes. | | [`core.coordinates.DatasetCoordinates.variables`](generated/xarray.core.coordinates.DatasetCoordinates.variables.md#xarray.core.coordinates.DatasetCoordinates.variables) | Low level interface to Coordinates contents as dict of Variable objects. | | [`core.coordinates.DatasetCoordinates.xindexes`](generated/xarray.core.coordinates.DatasetCoordinates.xindexes.md#xarray.core.coordinates.DatasetCoordinates.xindexes) | Mapping of `Index` objects used for label based indexing. | | [`core.coordinates.DatasetCoordinates.indexes`](generated/xarray.core.coordinates.DatasetCoordinates.indexes.md#xarray.core.coordinates.DatasetCoordinates.indexes) | Mapping of pandas.Index objects used for label based indexing. | | [`core.coordinates.DatasetCoordinates.to_dataset`](generated/xarray.core.coordinates.DatasetCoordinates.to_dataset.md#xarray.core.coordinates.DatasetCoordinates.to_dataset)() | Convert these coordinates into a new Dataset | | [`core.coordinates.DatasetCoordinates.to_index`](generated/xarray.core.coordinates.DatasetCoordinates.to_index.md#xarray.core.coordinates.DatasetCoordinates.to_index)([...]) | Convert all index coordinates into a [`pandas.Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index). | | [`core.coordinates.DatasetCoordinates.update`](generated/xarray.core.coordinates.DatasetCoordinates.update.md#xarray.core.coordinates.DatasetCoordinates.update)(other) | Update this Coordinates variables with other coordinate variables. | | [`core.coordinates.DatasetCoordinates.assign`](generated/xarray.core.coordinates.DatasetCoordinates.assign.md#xarray.core.coordinates.DatasetCoordinates.assign)([...]) | Assign new coordinates (and indexes) to a Coordinates object, returning a new object with all the original coordinates in addition to the new ones. | | [`core.coordinates.DatasetCoordinates.merge`](generated/xarray.core.coordinates.DatasetCoordinates.merge.md#xarray.core.coordinates.DatasetCoordinates.merge)(...) | Merge two sets of coordinates to create a new Dataset | | [`core.coordinates.DatasetCoordinates.copy`](generated/xarray.core.coordinates.DatasetCoordinates.copy.md#xarray.core.coordinates.DatasetCoordinates.copy)([...]) | Return a copy of this Coordinates object. | | [`core.coordinates.DatasetCoordinates.equals`](generated/xarray.core.coordinates.DatasetCoordinates.equals.md#xarray.core.coordinates.DatasetCoordinates.equals)(other) | Two Coordinates objects are equal if they have matching variables, all of which are equal. | | [`core.coordinates.DatasetCoordinates.identical`](generated/xarray.core.coordinates.DatasetCoordinates.identical.md#xarray.core.coordinates.DatasetCoordinates.identical)(other) | Like equals, but also checks all variable attributes. | | [`computation.rolling.DatasetCoarsen.boundary`](generated/xarray.computation.rolling.DatasetCoarsen.boundary.md#xarray.computation.rolling.DatasetCoarsen.boundary) | | | [`computation.rolling.DatasetCoarsen.coord_func`](generated/xarray.computation.rolling.DatasetCoarsen.coord_func.md#xarray.computation.rolling.DatasetCoarsen.coord_func) | | | [`computation.rolling.DatasetCoarsen.obj`](generated/xarray.computation.rolling.DatasetCoarsen.obj.md#xarray.computation.rolling.DatasetCoarsen.obj) | | | [`computation.rolling.DatasetCoarsen.side`](generated/xarray.computation.rolling.DatasetCoarsen.side.md#xarray.computation.rolling.DatasetCoarsen.side) | | | [`computation.rolling.DatasetCoarsen.trim_excess`](generated/xarray.computation.rolling.DatasetCoarsen.trim_excess.md#xarray.computation.rolling.DatasetCoarsen.trim_excess) | | | [`computation.rolling.DatasetCoarsen.windows`](generated/xarray.computation.rolling.DatasetCoarsen.windows.md#xarray.computation.rolling.DatasetCoarsen.windows) | | | [`computation.rolling.DatasetRolling.center`](generated/xarray.computation.rolling.DatasetRolling.center.md#xarray.computation.rolling.DatasetRolling.center) | | | [`computation.rolling.DatasetRolling.dim`](generated/xarray.computation.rolling.DatasetRolling.dim.md#xarray.computation.rolling.DatasetRolling.dim) | | | [`computation.rolling.DatasetRolling.min_periods`](generated/xarray.computation.rolling.DatasetRolling.min_periods.md#xarray.computation.rolling.DatasetRolling.min_periods) | | | [`computation.rolling.DatasetRolling.obj`](generated/xarray.computation.rolling.DatasetRolling.obj.md#xarray.computation.rolling.DatasetRolling.obj) | | | [`computation.rolling.DatasetRolling.rollings`](generated/xarray.computation.rolling.DatasetRolling.rollings.md#xarray.computation.rolling.DatasetRolling.rollings) | | | [`computation.rolling.DatasetRolling.window`](generated/xarray.computation.rolling.DatasetRolling.window.md#xarray.computation.rolling.DatasetRolling.window) | | | [`computation.weighted.DatasetWeighted.obj`](generated/xarray.computation.weighted.DatasetWeighted.obj.md#xarray.computation.weighted.DatasetWeighted.obj) | | | [`computation.weighted.DatasetWeighted.weights`](generated/xarray.computation.weighted.DatasetWeighted.weights.md#xarray.computation.weighted.DatasetWeighted.weights) | | | [`Dataset.load_store`](generated/xarray.Dataset.load_store.md#xarray.Dataset.load_store)(store[, decoder]) | Create a new dataset from the contents of a backends.\*DataStore object | | [`Dataset.dump_to_store`](generated/xarray.Dataset.dump_to_store.md#xarray.Dataset.dump_to_store)(store, \*\*kwargs) | Store dataset contents to a backends.\*DataStore object. | | [`DataArray.astype`](generated/xarray.DataArray.astype.md#xarray.DataArray.astype)(dtype, \*[, order, casting, ...]) | Copy of the xarray object, with data cast to a specified type. | | [`DataArray.item`](generated/xarray.DataArray.item.md#xarray.DataArray.item)(\*args) | Copy an element of an array to a standard Python scalar and return it. | | [`core.coordinates.DataArrayCoordinates.get`](generated/xarray.core.coordinates.DataArrayCoordinates.get.md#xarray.core.coordinates.DataArrayCoordinates.get)(k[,d]) | | | [`core.coordinates.DataArrayCoordinates.items`](generated/xarray.core.coordinates.DataArrayCoordinates.items.md#xarray.core.coordinates.DataArrayCoordinates.items)() | | | [`core.coordinates.DataArrayCoordinates.keys`](generated/xarray.core.coordinates.DataArrayCoordinates.keys.md#xarray.core.coordinates.DataArrayCoordinates.keys)() | | | [`core.coordinates.DataArrayCoordinates.values`](generated/xarray.core.coordinates.DataArrayCoordinates.values.md#xarray.core.coordinates.DataArrayCoordinates.values)() | | | [`core.coordinates.DataArrayCoordinates.dims`](generated/xarray.core.coordinates.DataArrayCoordinates.dims.md#xarray.core.coordinates.DataArrayCoordinates.dims) | Mapping from dimension names to lengths or tuple of dimension names. | | [`core.coordinates.DataArrayCoordinates.sizes`](generated/xarray.core.coordinates.DataArrayCoordinates.sizes.md#xarray.core.coordinates.DataArrayCoordinates.sizes) | Mapping from dimension names to lengths. | | [`core.coordinates.DataArrayCoordinates.dtypes`](generated/xarray.core.coordinates.DataArrayCoordinates.dtypes.md#xarray.core.coordinates.DataArrayCoordinates.dtypes) | Mapping from coordinate names to dtypes. | | [`core.coordinates.DataArrayCoordinates.variables`](generated/xarray.core.coordinates.DataArrayCoordinates.variables.md#xarray.core.coordinates.DataArrayCoordinates.variables) | Low level interface to Coordinates contents as dict of Variable objects. | | [`core.coordinates.DataArrayCoordinates.xindexes`](generated/xarray.core.coordinates.DataArrayCoordinates.xindexes.md#xarray.core.coordinates.DataArrayCoordinates.xindexes) | Mapping of `Index` objects used for label based indexing. | | [`core.coordinates.DataArrayCoordinates.indexes`](generated/xarray.core.coordinates.DataArrayCoordinates.indexes.md#xarray.core.coordinates.DataArrayCoordinates.indexes) | Mapping of pandas.Index objects used for label based indexing. | | [`core.coordinates.DataArrayCoordinates.to_dataset`](generated/xarray.core.coordinates.DataArrayCoordinates.to_dataset.md#xarray.core.coordinates.DataArrayCoordinates.to_dataset)() | Convert these coordinates into a new Dataset. | | [`core.coordinates.DataArrayCoordinates.to_index`](generated/xarray.core.coordinates.DataArrayCoordinates.to_index.md#xarray.core.coordinates.DataArrayCoordinates.to_index)([...]) | Convert all index coordinates into a [`pandas.Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index). | | [`core.coordinates.DataArrayCoordinates.update`](generated/xarray.core.coordinates.DataArrayCoordinates.update.md#xarray.core.coordinates.DataArrayCoordinates.update)(other) | Update this Coordinates variables with other coordinate variables. | | [`core.coordinates.DataArrayCoordinates.assign`](generated/xarray.core.coordinates.DataArrayCoordinates.assign.md#xarray.core.coordinates.DataArrayCoordinates.assign)([...]) | Assign new coordinates (and indexes) to a Coordinates object, returning a new object with all the original coordinates in addition to the new ones. | | [`core.coordinates.DataArrayCoordinates.merge`](generated/xarray.core.coordinates.DataArrayCoordinates.merge.md#xarray.core.coordinates.DataArrayCoordinates.merge)(...) | Merge two sets of coordinates to create a new Dataset | | [`core.coordinates.DataArrayCoordinates.copy`](generated/xarray.core.coordinates.DataArrayCoordinates.copy.md#xarray.core.coordinates.DataArrayCoordinates.copy)([...]) | Return a copy of this Coordinates object. | | [`core.coordinates.DataArrayCoordinates.equals`](generated/xarray.core.coordinates.DataArrayCoordinates.equals.md#xarray.core.coordinates.DataArrayCoordinates.equals)(other) | Two Coordinates objects are equal if they have matching variables, all of which are equal. | | [`core.coordinates.DataArrayCoordinates.identical`](generated/xarray.core.coordinates.DataArrayCoordinates.identical.md#xarray.core.coordinates.DataArrayCoordinates.identical)(other) | Like equals, but also checks all variable attributes. | | [`computation.rolling.DataArrayCoarsen.boundary`](generated/xarray.computation.rolling.DataArrayCoarsen.boundary.md#xarray.computation.rolling.DataArrayCoarsen.boundary) | | | [`computation.rolling.DataArrayCoarsen.coord_func`](generated/xarray.computation.rolling.DataArrayCoarsen.coord_func.md#xarray.computation.rolling.DataArrayCoarsen.coord_func) | | | [`computation.rolling.DataArrayCoarsen.obj`](generated/xarray.computation.rolling.DataArrayCoarsen.obj.md#xarray.computation.rolling.DataArrayCoarsen.obj) | | | [`computation.rolling.DataArrayCoarsen.side`](generated/xarray.computation.rolling.DataArrayCoarsen.side.md#xarray.computation.rolling.DataArrayCoarsen.side) | | | [`computation.rolling.DataArrayCoarsen.trim_excess`](generated/xarray.computation.rolling.DataArrayCoarsen.trim_excess.md#xarray.computation.rolling.DataArrayCoarsen.trim_excess) | | | [`computation.rolling.DataArrayCoarsen.windows`](generated/xarray.computation.rolling.DataArrayCoarsen.windows.md#xarray.computation.rolling.DataArrayCoarsen.windows) | | | [`computation.rolling.DataArrayRolling.center`](generated/xarray.computation.rolling.DataArrayRolling.center.md#xarray.computation.rolling.DataArrayRolling.center) | | | [`computation.rolling.DataArrayRolling.dim`](generated/xarray.computation.rolling.DataArrayRolling.dim.md#xarray.computation.rolling.DataArrayRolling.dim) | | | [`computation.rolling.DataArrayRolling.min_periods`](generated/xarray.computation.rolling.DataArrayRolling.min_periods.md#xarray.computation.rolling.DataArrayRolling.min_periods) | | | [`computation.rolling.DataArrayRolling.obj`](generated/xarray.computation.rolling.DataArrayRolling.obj.md#xarray.computation.rolling.DataArrayRolling.obj) | | | [`computation.rolling.DataArrayRolling.window`](generated/xarray.computation.rolling.DataArrayRolling.window.md#xarray.computation.rolling.DataArrayRolling.window) | | | [`computation.rolling.DataArrayRolling.window_labels`](generated/xarray.computation.rolling.DataArrayRolling.window_labels.md#xarray.computation.rolling.DataArrayRolling.window_labels) | | | [`computation.weighted.DataArrayWeighted.obj`](generated/xarray.computation.weighted.DataArrayWeighted.obj.md#xarray.computation.weighted.DataArrayWeighted.obj) | | | [`computation.weighted.DataArrayWeighted.weights`](generated/xarray.computation.weighted.DataArrayWeighted.weights.md#xarray.computation.weighted.DataArrayWeighted.weights) | | | [`core.coordinates.DataTreeCoordinates.get`](generated/xarray.core.coordinates.DataTreeCoordinates.get.md#xarray.core.coordinates.DataTreeCoordinates.get)(k[,d]) | | | [`core.coordinates.DataTreeCoordinates.items`](generated/xarray.core.coordinates.DataTreeCoordinates.items.md#xarray.core.coordinates.DataTreeCoordinates.items)() | | | [`core.coordinates.DataTreeCoordinates.keys`](generated/xarray.core.coordinates.DataTreeCoordinates.keys.md#xarray.core.coordinates.DataTreeCoordinates.keys)() | | | [`core.coordinates.DataTreeCoordinates.values`](generated/xarray.core.coordinates.DataTreeCoordinates.values.md#xarray.core.coordinates.DataTreeCoordinates.values)() | | | [`core.coordinates.DataTreeCoordinates.dims`](generated/xarray.core.coordinates.DataTreeCoordinates.dims.md#xarray.core.coordinates.DataTreeCoordinates.dims) | Mapping from dimension names to lengths or tuple of dimension names. | | [`core.coordinates.DataTreeCoordinates.sizes`](generated/xarray.core.coordinates.DataTreeCoordinates.sizes.md#xarray.core.coordinates.DataTreeCoordinates.sizes) | Mapping from dimension names to lengths. | | [`core.coordinates.DataTreeCoordinates.dtypes`](generated/xarray.core.coordinates.DataTreeCoordinates.dtypes.md#xarray.core.coordinates.DataTreeCoordinates.dtypes) | Mapping from coordinate names to dtypes. | | [`core.coordinates.DataTreeCoordinates.variables`](generated/xarray.core.coordinates.DataTreeCoordinates.variables.md#xarray.core.coordinates.DataTreeCoordinates.variables) | Low level interface to Coordinates contents as dict of Variable objects. | | [`core.coordinates.DataTreeCoordinates.xindexes`](generated/xarray.core.coordinates.DataTreeCoordinates.xindexes.md#xarray.core.coordinates.DataTreeCoordinates.xindexes) | Mapping of `Index` objects used for label based indexing. | | [`core.coordinates.DataTreeCoordinates.indexes`](generated/xarray.core.coordinates.DataTreeCoordinates.indexes.md#xarray.core.coordinates.DataTreeCoordinates.indexes) | Mapping of pandas.Index objects used for label based indexing. | | [`core.coordinates.DataTreeCoordinates.to_dataset`](generated/xarray.core.coordinates.DataTreeCoordinates.to_dataset.md#xarray.core.coordinates.DataTreeCoordinates.to_dataset)() | Convert these coordinates into a new Dataset | | [`core.coordinates.DataTreeCoordinates.to_index`](generated/xarray.core.coordinates.DataTreeCoordinates.to_index.md#xarray.core.coordinates.DataTreeCoordinates.to_index)([...]) | Convert all index coordinates into a [`pandas.Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index). | | [`core.coordinates.DataTreeCoordinates.update`](generated/xarray.core.coordinates.DataTreeCoordinates.update.md#xarray.core.coordinates.DataTreeCoordinates.update)(other) | Update this Coordinates variables with other coordinate variables. | | [`core.coordinates.DataTreeCoordinates.assign`](generated/xarray.core.coordinates.DataTreeCoordinates.assign.md#xarray.core.coordinates.DataTreeCoordinates.assign)([...]) | Assign new coordinates (and indexes) to a Coordinates object, returning a new object with all the original coordinates in addition to the new ones. | | [`core.coordinates.DataTreeCoordinates.merge`](generated/xarray.core.coordinates.DataTreeCoordinates.merge.md#xarray.core.coordinates.DataTreeCoordinates.merge)(...) | Merge two sets of coordinates to create a new Dataset | | [`core.coordinates.DataTreeCoordinates.copy`](generated/xarray.core.coordinates.DataTreeCoordinates.copy.md#xarray.core.coordinates.DataTreeCoordinates.copy)([...]) | Return a copy of this Coordinates object. | | [`core.coordinates.DataTreeCoordinates.equals`](generated/xarray.core.coordinates.DataTreeCoordinates.equals.md#xarray.core.coordinates.DataTreeCoordinates.equals)(other) | Two Coordinates objects are equal if they have matching variables, all of which are equal. | | [`core.coordinates.DataTreeCoordinates.identical`](generated/xarray.core.coordinates.DataTreeCoordinates.identical.md#xarray.core.coordinates.DataTreeCoordinates.identical)(other) | Like equals, but also checks all variable attributes. | | [`core.accessor_dt.DatetimeAccessor.ceil`](generated/xarray.core.accessor_dt.DatetimeAccessor.ceil.md#xarray.core.accessor_dt.DatetimeAccessor.ceil)(freq) | Round timestamps upward to specified frequency resolution. | | [`core.accessor_dt.DatetimeAccessor.floor`](generated/xarray.core.accessor_dt.DatetimeAccessor.floor.md#xarray.core.accessor_dt.DatetimeAccessor.floor)(freq) | Round timestamps downward to specified frequency resolution. | | [`core.accessor_dt.DatetimeAccessor.round`](generated/xarray.core.accessor_dt.DatetimeAccessor.round.md#xarray.core.accessor_dt.DatetimeAccessor.round)(freq) | Round timestamps to specified frequency resolution. | | [`core.accessor_dt.DatetimeAccessor.strftime`](generated/xarray.core.accessor_dt.DatetimeAccessor.strftime.md#xarray.core.accessor_dt.DatetimeAccessor.strftime)(...) | Return an array of formatted strings specified by date_format, which supports the same string format as the python standard library. | | [`core.accessor_dt.DatetimeAccessor.calendar`](generated/xarray.core.accessor_dt.DatetimeAccessor.calendar.md#xarray.core.accessor_dt.DatetimeAccessor.calendar) | The name of the calendar of the dates. | | [`core.accessor_dt.DatetimeAccessor.date`](generated/xarray.core.accessor_dt.DatetimeAccessor.date.md#xarray.core.accessor_dt.DatetimeAccessor.date) | Date corresponding to datetimes | | [`core.accessor_dt.DatetimeAccessor.day`](generated/xarray.core.accessor_dt.DatetimeAccessor.day.md#xarray.core.accessor_dt.DatetimeAccessor.day) | The days of the datetime | | [`core.accessor_dt.DatetimeAccessor.dayofweek`](generated/xarray.core.accessor_dt.DatetimeAccessor.dayofweek.md#xarray.core.accessor_dt.DatetimeAccessor.dayofweek) | The day of the week with Monday=0, Sunday=6 | | [`core.accessor_dt.DatetimeAccessor.day_of_week`](generated/xarray.core.accessor_dt.DatetimeAccessor.day_of_week.md#xarray.core.accessor_dt.DatetimeAccessor.day_of_week) | The day of the week with Monday=0, Sunday=6 | | [`core.accessor_dt.DatetimeAccessor.dayofyear`](generated/xarray.core.accessor_dt.DatetimeAccessor.dayofyear.md#xarray.core.accessor_dt.DatetimeAccessor.dayofyear) | The ordinal day of the year | | [`core.accessor_dt.DatetimeAccessor.day_of_year`](generated/xarray.core.accessor_dt.DatetimeAccessor.day_of_year.md#xarray.core.accessor_dt.DatetimeAccessor.day_of_year) | The ordinal day of the year | | [`core.accessor_dt.DatetimeAccessor.days_in_month`](generated/xarray.core.accessor_dt.DatetimeAccessor.days_in_month.md#xarray.core.accessor_dt.DatetimeAccessor.days_in_month) | The number of days in the month | | [`core.accessor_dt.DatetimeAccessor.daysinmonth`](generated/xarray.core.accessor_dt.DatetimeAccessor.daysinmonth.md#xarray.core.accessor_dt.DatetimeAccessor.daysinmonth) | The number of days in the month | | [`core.accessor_dt.DatetimeAccessor.hour`](generated/xarray.core.accessor_dt.DatetimeAccessor.hour.md#xarray.core.accessor_dt.DatetimeAccessor.hour) | The hours of the datetime | | [`core.accessor_dt.DatetimeAccessor.is_leap_year`](generated/xarray.core.accessor_dt.DatetimeAccessor.is_leap_year.md#xarray.core.accessor_dt.DatetimeAccessor.is_leap_year) | Indicate if the date belongs to a leap year | | [`core.accessor_dt.DatetimeAccessor.is_month_end`](generated/xarray.core.accessor_dt.DatetimeAccessor.is_month_end.md#xarray.core.accessor_dt.DatetimeAccessor.is_month_end) | Indicate whether the date is the last day of the month | | [`core.accessor_dt.DatetimeAccessor.is_month_start`](generated/xarray.core.accessor_dt.DatetimeAccessor.is_month_start.md#xarray.core.accessor_dt.DatetimeAccessor.is_month_start) | Indicate whether the date is the first day of the month | | [`core.accessor_dt.DatetimeAccessor.is_quarter_end`](generated/xarray.core.accessor_dt.DatetimeAccessor.is_quarter_end.md#xarray.core.accessor_dt.DatetimeAccessor.is_quarter_end) | Indicate whether the date is the last day of a quarter | | [`core.accessor_dt.DatetimeAccessor.is_quarter_start`](generated/xarray.core.accessor_dt.DatetimeAccessor.is_quarter_start.md#xarray.core.accessor_dt.DatetimeAccessor.is_quarter_start) | Indicate whether the date is the first day of a quarter | | [`core.accessor_dt.DatetimeAccessor.is_year_end`](generated/xarray.core.accessor_dt.DatetimeAccessor.is_year_end.md#xarray.core.accessor_dt.DatetimeAccessor.is_year_end) | Indicate whether the date is the last day of the year | | [`core.accessor_dt.DatetimeAccessor.is_year_start`](generated/xarray.core.accessor_dt.DatetimeAccessor.is_year_start.md#xarray.core.accessor_dt.DatetimeAccessor.is_year_start) | Indicate whether the date is the first day of a year | | [`core.accessor_dt.DatetimeAccessor.isocalendar`](generated/xarray.core.accessor_dt.DatetimeAccessor.isocalendar.md#xarray.core.accessor_dt.DatetimeAccessor.isocalendar)() | Dataset containing ISO year, week number, and weekday. | | [`core.accessor_dt.DatetimeAccessor.microsecond`](generated/xarray.core.accessor_dt.DatetimeAccessor.microsecond.md#xarray.core.accessor_dt.DatetimeAccessor.microsecond) | The microseconds of the datetime | | [`core.accessor_dt.DatetimeAccessor.minute`](generated/xarray.core.accessor_dt.DatetimeAccessor.minute.md#xarray.core.accessor_dt.DatetimeAccessor.minute) | The minutes of the datetime | | [`core.accessor_dt.DatetimeAccessor.month`](generated/xarray.core.accessor_dt.DatetimeAccessor.month.md#xarray.core.accessor_dt.DatetimeAccessor.month) | The month as January=1, December=12 | | [`core.accessor_dt.DatetimeAccessor.nanosecond`](generated/xarray.core.accessor_dt.DatetimeAccessor.nanosecond.md#xarray.core.accessor_dt.DatetimeAccessor.nanosecond) | The nanoseconds of the datetime | | [`core.accessor_dt.DatetimeAccessor.quarter`](generated/xarray.core.accessor_dt.DatetimeAccessor.quarter.md#xarray.core.accessor_dt.DatetimeAccessor.quarter) | The quarter of the date | | [`core.accessor_dt.DatetimeAccessor.season`](generated/xarray.core.accessor_dt.DatetimeAccessor.season.md#xarray.core.accessor_dt.DatetimeAccessor.season) | Season of the year | | [`core.accessor_dt.DatetimeAccessor.second`](generated/xarray.core.accessor_dt.DatetimeAccessor.second.md#xarray.core.accessor_dt.DatetimeAccessor.second) | The seconds of the datetime | | [`core.accessor_dt.DatetimeAccessor.time`](generated/xarray.core.accessor_dt.DatetimeAccessor.time.md#xarray.core.accessor_dt.DatetimeAccessor.time) | Timestamps corresponding to datetimes | | [`core.accessor_dt.DatetimeAccessor.week`](generated/xarray.core.accessor_dt.DatetimeAccessor.week.md#xarray.core.accessor_dt.DatetimeAccessor.week) | The week ordinal of the year | | [`core.accessor_dt.DatetimeAccessor.weekday`](generated/xarray.core.accessor_dt.DatetimeAccessor.weekday.md#xarray.core.accessor_dt.DatetimeAccessor.weekday) | The day of the week with Monday=0, Sunday=6 | | [`core.accessor_dt.DatetimeAccessor.weekofyear`](generated/xarray.core.accessor_dt.DatetimeAccessor.weekofyear.md#xarray.core.accessor_dt.DatetimeAccessor.weekofyear) | The week ordinal of the year | | [`core.accessor_dt.DatetimeAccessor.year`](generated/xarray.core.accessor_dt.DatetimeAccessor.year.md#xarray.core.accessor_dt.DatetimeAccessor.year) | The year of the datetime | | [`core.accessor_dt.TimedeltaAccessor.ceil`](generated/xarray.core.accessor_dt.TimedeltaAccessor.ceil.md#xarray.core.accessor_dt.TimedeltaAccessor.ceil)(freq) | Round timestamps upward to specified frequency resolution. | | [`core.accessor_dt.TimedeltaAccessor.floor`](generated/xarray.core.accessor_dt.TimedeltaAccessor.floor.md#xarray.core.accessor_dt.TimedeltaAccessor.floor)(freq) | Round timestamps downward to specified frequency resolution. | | [`core.accessor_dt.TimedeltaAccessor.round`](generated/xarray.core.accessor_dt.TimedeltaAccessor.round.md#xarray.core.accessor_dt.TimedeltaAccessor.round)(freq) | Round timestamps to specified frequency resolution. | | [`core.accessor_dt.TimedeltaAccessor.days`](generated/xarray.core.accessor_dt.TimedeltaAccessor.days.md#xarray.core.accessor_dt.TimedeltaAccessor.days) | Number of days for each element | | [`core.accessor_dt.TimedeltaAccessor.microseconds`](generated/xarray.core.accessor_dt.TimedeltaAccessor.microseconds.md#xarray.core.accessor_dt.TimedeltaAccessor.microseconds) | Number of microseconds (>= 0 and less than 1 second) for each element | | [`core.accessor_dt.TimedeltaAccessor.nanoseconds`](generated/xarray.core.accessor_dt.TimedeltaAccessor.nanoseconds.md#xarray.core.accessor_dt.TimedeltaAccessor.nanoseconds) | Number of nanoseconds (>= 0 and less than 1 microsecond) for each element | | [`core.accessor_dt.TimedeltaAccessor.seconds`](generated/xarray.core.accessor_dt.TimedeltaAccessor.seconds.md#xarray.core.accessor_dt.TimedeltaAccessor.seconds) | Number of seconds (>= 0 and less than 1 day) for each element | | [`core.accessor_str.StringAccessor.capitalize`](generated/xarray.core.accessor_str.StringAccessor.capitalize.md#xarray.core.accessor_str.StringAccessor.capitalize)() | Convert strings in the array to be capitalized. | | [`core.accessor_str.StringAccessor.casefold`](generated/xarray.core.accessor_str.StringAccessor.casefold.md#xarray.core.accessor_str.StringAccessor.casefold)() | Convert strings in the array to be casefolded. | | [`core.accessor_str.StringAccessor.cat`](generated/xarray.core.accessor_str.StringAccessor.cat.md#xarray.core.accessor_str.StringAccessor.cat)(\*others) | Concatenate strings elementwise in the DataArray with other strings. | | [`core.accessor_str.StringAccessor.center`](generated/xarray.core.accessor_str.StringAccessor.center.md#xarray.core.accessor_str.StringAccessor.center)(width) | Pad left and right side of each string in the array. | | [`core.accessor_str.StringAccessor.contains`](generated/xarray.core.accessor_str.StringAccessor.contains.md#xarray.core.accessor_str.StringAccessor.contains)(pat) | Test if pattern or regex is contained within each string of the array. | | [`core.accessor_str.StringAccessor.count`](generated/xarray.core.accessor_str.StringAccessor.count.md#xarray.core.accessor_str.StringAccessor.count)(pat) | Count occurrences of pattern in each string of the array. | | [`core.accessor_str.StringAccessor.decode`](generated/xarray.core.accessor_str.StringAccessor.decode.md#xarray.core.accessor_str.StringAccessor.decode)(encoding) | Decode character string in the array using indicated encoding. | | [`core.accessor_str.StringAccessor.encode`](generated/xarray.core.accessor_str.StringAccessor.encode.md#xarray.core.accessor_str.StringAccessor.encode)(encoding) | Encode character string in the array using indicated encoding. | | [`core.accessor_str.StringAccessor.endswith`](generated/xarray.core.accessor_str.StringAccessor.endswith.md#xarray.core.accessor_str.StringAccessor.endswith)(pat) | Test if the end of each string in the array matches a pattern. | | [`core.accessor_str.StringAccessor.extract`](generated/xarray.core.accessor_str.StringAccessor.extract.md#xarray.core.accessor_str.StringAccessor.extract)(...) | Extract the first match of capture groups in the regex pat as a new dimension in a DataArray. | | [`core.accessor_str.StringAccessor.extractall`](generated/xarray.core.accessor_str.StringAccessor.extractall.md#xarray.core.accessor_str.StringAccessor.extractall)(...) | Extract all matches of capture groups in the regex pat as new dimensions in a DataArray. | | [`core.accessor_str.StringAccessor.find`](generated/xarray.core.accessor_str.StringAccessor.find.md#xarray.core.accessor_str.StringAccessor.find)(sub[, ...]) | Return lowest or highest indexes in each strings in the array where the substring is fully contained between [start:end]. | | [`core.accessor_str.StringAccessor.findall`](generated/xarray.core.accessor_str.StringAccessor.findall.md#xarray.core.accessor_str.StringAccessor.findall)(pat) | Find all occurrences of pattern or regular expression in the DataArray. | | [`core.accessor_str.StringAccessor.format`](generated/xarray.core.accessor_str.StringAccessor.format.md#xarray.core.accessor_str.StringAccessor.format)(...) | Perform python string formatting on each element of the DataArray. | | [`core.accessor_str.StringAccessor.get`](generated/xarray.core.accessor_str.StringAccessor.get.md#xarray.core.accessor_str.StringAccessor.get)(i[, ...]) | Extract character number i from each string in the array. | | [`core.accessor_str.StringAccessor.get_dummies`](generated/xarray.core.accessor_str.StringAccessor.get_dummies.md#xarray.core.accessor_str.StringAccessor.get_dummies)(dim) | Return DataArray of dummy/indicator variables. | | [`core.accessor_str.StringAccessor.index`](generated/xarray.core.accessor_str.StringAccessor.index.md#xarray.core.accessor_str.StringAccessor.index)(sub) | Return lowest or highest indexes in each strings where the substring is fully contained between [start:end]. | | [`core.accessor_str.StringAccessor.isalnum`](generated/xarray.core.accessor_str.StringAccessor.isalnum.md#xarray.core.accessor_str.StringAccessor.isalnum)() | Check whether all characters in each string are alphanumeric. | | [`core.accessor_str.StringAccessor.isalpha`](generated/xarray.core.accessor_str.StringAccessor.isalpha.md#xarray.core.accessor_str.StringAccessor.isalpha)() | Check whether all characters in each string are alphabetic. | | [`core.accessor_str.StringAccessor.isdecimal`](generated/xarray.core.accessor_str.StringAccessor.isdecimal.md#xarray.core.accessor_str.StringAccessor.isdecimal)() | Check whether all characters in each string are decimal. | | [`core.accessor_str.StringAccessor.isdigit`](generated/xarray.core.accessor_str.StringAccessor.isdigit.md#xarray.core.accessor_str.StringAccessor.isdigit)() | Check whether all characters in each string are digits. | | [`core.accessor_str.StringAccessor.islower`](generated/xarray.core.accessor_str.StringAccessor.islower.md#xarray.core.accessor_str.StringAccessor.islower)() | Check whether all characters in each string are lowercase. | | [`core.accessor_str.StringAccessor.isnumeric`](generated/xarray.core.accessor_str.StringAccessor.isnumeric.md#xarray.core.accessor_str.StringAccessor.isnumeric)() | Check whether all characters in each string are numeric. | | [`core.accessor_str.StringAccessor.isspace`](generated/xarray.core.accessor_str.StringAccessor.isspace.md#xarray.core.accessor_str.StringAccessor.isspace)() | Check whether all characters in each string are spaces. | | [`core.accessor_str.StringAccessor.istitle`](generated/xarray.core.accessor_str.StringAccessor.istitle.md#xarray.core.accessor_str.StringAccessor.istitle)() | Check whether all characters in each string are titlecase. | | [`core.accessor_str.StringAccessor.isupper`](generated/xarray.core.accessor_str.StringAccessor.isupper.md#xarray.core.accessor_str.StringAccessor.isupper)() | Check whether all characters in each string are uppercase. | | [`core.accessor_str.StringAccessor.join`](generated/xarray.core.accessor_str.StringAccessor.join.md#xarray.core.accessor_str.StringAccessor.join)([dim, sep]) | Concatenate strings in a DataArray along a particular dimension. | | [`core.accessor_str.StringAccessor.len`](generated/xarray.core.accessor_str.StringAccessor.len.md#xarray.core.accessor_str.StringAccessor.len)() | Compute the length of each string in the array. | | [`core.accessor_str.StringAccessor.ljust`](generated/xarray.core.accessor_str.StringAccessor.ljust.md#xarray.core.accessor_str.StringAccessor.ljust)(width) | Pad right side of each string in the array. | | [`core.accessor_str.StringAccessor.lower`](generated/xarray.core.accessor_str.StringAccessor.lower.md#xarray.core.accessor_str.StringAccessor.lower)() | Convert strings in the array to lowercase. | | [`core.accessor_str.StringAccessor.lstrip`](generated/xarray.core.accessor_str.StringAccessor.lstrip.md#xarray.core.accessor_str.StringAccessor.lstrip)([...]) | Remove leading characters. | | [`core.accessor_str.StringAccessor.match`](generated/xarray.core.accessor_str.StringAccessor.match.md#xarray.core.accessor_str.StringAccessor.match)(pat) | Determine if each string in the array matches a regular expression. | | [`core.accessor_str.StringAccessor.normalize`](generated/xarray.core.accessor_str.StringAccessor.normalize.md#xarray.core.accessor_str.StringAccessor.normalize)(form) | Return the Unicode normal form for the strings in the datarray. | | [`core.accessor_str.StringAccessor.pad`](generated/xarray.core.accessor_str.StringAccessor.pad.md#xarray.core.accessor_str.StringAccessor.pad)(width) | Pad strings in the array up to width. | | [`core.accessor_str.StringAccessor.partition`](generated/xarray.core.accessor_str.StringAccessor.partition.md#xarray.core.accessor_str.StringAccessor.partition)(dim) | Split the strings in the DataArray at the first occurrence of separator sep. | | [`core.accessor_str.StringAccessor.repeat`](generated/xarray.core.accessor_str.StringAccessor.repeat.md#xarray.core.accessor_str.StringAccessor.repeat)(repeats) | Repeat each string in the array. | | [`core.accessor_str.StringAccessor.replace`](generated/xarray.core.accessor_str.StringAccessor.replace.md#xarray.core.accessor_str.StringAccessor.replace)(...) | Replace occurrences of pattern/regex in the array with some string. | | [`core.accessor_str.StringAccessor.rfind`](generated/xarray.core.accessor_str.StringAccessor.rfind.md#xarray.core.accessor_str.StringAccessor.rfind)(sub) | Return highest indexes in each strings in the array where the substring is fully contained between [start:end]. | | [`core.accessor_str.StringAccessor.rindex`](generated/xarray.core.accessor_str.StringAccessor.rindex.md#xarray.core.accessor_str.StringAccessor.rindex)(sub) | Return highest indexes in each strings where the substring is fully contained between [start:end]. | | [`core.accessor_str.StringAccessor.rjust`](generated/xarray.core.accessor_str.StringAccessor.rjust.md#xarray.core.accessor_str.StringAccessor.rjust)(width) | Pad left side of each string in the array. | | [`core.accessor_str.StringAccessor.rpartition`](generated/xarray.core.accessor_str.StringAccessor.rpartition.md#xarray.core.accessor_str.StringAccessor.rpartition)(dim) | Split the strings in the DataArray at the last occurrence of separator sep. | | [`core.accessor_str.StringAccessor.rsplit`](generated/xarray.core.accessor_str.StringAccessor.rsplit.md#xarray.core.accessor_str.StringAccessor.rsplit)(dim) | Split strings in a DataArray around the given separator/delimiter sep. | | [`core.accessor_str.StringAccessor.rstrip`](generated/xarray.core.accessor_str.StringAccessor.rstrip.md#xarray.core.accessor_str.StringAccessor.rstrip)([...]) | Remove trailing characters. | | [`core.accessor_str.StringAccessor.slice`](generated/xarray.core.accessor_str.StringAccessor.slice.md#xarray.core.accessor_str.StringAccessor.slice)([...]) | Slice substrings from each string in the array. | | [`core.accessor_str.StringAccessor.slice_replace`](generated/xarray.core.accessor_str.StringAccessor.slice_replace.md#xarray.core.accessor_str.StringAccessor.slice_replace)([...]) | Replace a positional slice of a string with another value. | | [`core.accessor_str.StringAccessor.split`](generated/xarray.core.accessor_str.StringAccessor.split.md#xarray.core.accessor_str.StringAccessor.split)(dim) | Split strings in a DataArray around the given separator/delimiter sep. | | [`core.accessor_str.StringAccessor.startswith`](generated/xarray.core.accessor_str.StringAccessor.startswith.md#xarray.core.accessor_str.StringAccessor.startswith)(pat) | Test if the start of each string in the array matches a pattern. | | [`core.accessor_str.StringAccessor.strip`](generated/xarray.core.accessor_str.StringAccessor.strip.md#xarray.core.accessor_str.StringAccessor.strip)([...]) | Remove leading and trailing characters. | | [`core.accessor_str.StringAccessor.swapcase`](generated/xarray.core.accessor_str.StringAccessor.swapcase.md#xarray.core.accessor_str.StringAccessor.swapcase)() | Convert strings in the array to be swapcased. | | [`core.accessor_str.StringAccessor.title`](generated/xarray.core.accessor_str.StringAccessor.title.md#xarray.core.accessor_str.StringAccessor.title)() | Convert strings in the array to titlecase. | | [`core.accessor_str.StringAccessor.translate`](generated/xarray.core.accessor_str.StringAccessor.translate.md#xarray.core.accessor_str.StringAccessor.translate)(table) | Map characters of each string through the given mapping table. | | [`core.accessor_str.StringAccessor.upper`](generated/xarray.core.accessor_str.StringAccessor.upper.md#xarray.core.accessor_str.StringAccessor.upper)() | Convert strings in the array to uppercase. | | [`core.accessor_str.StringAccessor.wrap`](generated/xarray.core.accessor_str.StringAccessor.wrap.md#xarray.core.accessor_str.StringAccessor.wrap)(width, ...) | Wrap long strings in the array in paragraphs with length less than width. | | [`core.accessor_str.StringAccessor.zfill`](generated/xarray.core.accessor_str.StringAccessor.zfill.md#xarray.core.accessor_str.StringAccessor.zfill)(width) | Pad each string in the array by prepending '0' characters. | | [`Variable.all`](generated/xarray.Variable.all.md#xarray.Variable.all)([dim]) | Reduce this NamedArray's data by applying `all` along some dimension(s). | | [`Variable.any`](generated/xarray.Variable.any.md#xarray.Variable.any)([dim]) | Reduce this NamedArray's data by applying `any` along some dimension(s). | | [`Variable.argmax`](generated/xarray.Variable.argmax.md#xarray.Variable.argmax)([dim, axis, keep_attrs, skipna]) | Index or indices of the maximum of the Variable over one or more dimensions. | | [`Variable.argmin`](generated/xarray.Variable.argmin.md#xarray.Variable.argmin)([dim, axis, keep_attrs, skipna]) | Index or indices of the minimum of the Variable over one or more dimensions. | | [`Variable.argsort`](generated/xarray.Variable.argsort.md#xarray.Variable.argsort)([axis, kind, order, stable]) | Returns the indices that would sort this array. | | [`Variable.astype`](generated/xarray.Variable.astype.md#xarray.Variable.astype)(dtype, \*[, order, casting, ...]) | Copy of the Variable object, with data cast to a specified type. | | [`Variable.broadcast_equals`](generated/xarray.Variable.broadcast_equals.md#xarray.Variable.broadcast_equals)(other[, equiv]) | True if two Variables have the values after being broadcast against each other; otherwise False. | | [`Variable.chunk`](generated/xarray.Variable.chunk.md#xarray.Variable.chunk)([chunks, name, lock, ...]) | Coerce this array's data into a dask array with the given chunks. | | [`Variable.clip`](generated/xarray.Variable.clip.md#xarray.Variable.clip)([min, max]) | Return an array whose values are limited to `[min, max]`. | | [`Variable.coarsen`](generated/xarray.Variable.coarsen.md#xarray.Variable.coarsen)(windows, func[, boundary, ...]) | Apply reduction function. | | [`Variable.compute`](generated/xarray.Variable.compute.md#xarray.Variable.compute)(\*\*kwargs) | Trigger loading data into memory and return a new variable. | | [`Variable.concat`](generated/xarray.Variable.concat.md#xarray.Variable.concat)(variables[, dim, positions, ...]) | Concatenate variables along a new or existing dimension. | | [`Variable.conj`](generated/xarray.Variable.conj.md#xarray.Variable.conj)() | Complex-conjugate all elements. | | [`Variable.conjugate`](generated/xarray.Variable.conjugate.md#xarray.Variable.conjugate)(\*args, \*\*kwargs) | a.conj() | | [`Variable.copy`](generated/xarray.Variable.copy.md#xarray.Variable.copy)([deep, data]) | Returns a copy of this object. | | [`Variable.count`](generated/xarray.Variable.count.md#xarray.Variable.count)([dim]) | Reduce this NamedArray's data by applying `count` along some dimension(s). | | [`Variable.cumprod`](generated/xarray.Variable.cumprod.md#xarray.Variable.cumprod)([dim, skipna]) | Reduce this NamedArray's data by applying `cumprod` along some dimension(s). | | [`Variable.cumsum`](generated/xarray.Variable.cumsum.md#xarray.Variable.cumsum)([dim, skipna]) | Reduce this NamedArray's data by applying `cumsum` along some dimension(s). | | [`Variable.equals`](generated/xarray.Variable.equals.md#xarray.Variable.equals)(other[, equiv]) | True if two Variables have the same dimensions and values; otherwise False. | | [`Variable.fillna`](generated/xarray.Variable.fillna.md#xarray.Variable.fillna)(value) | | | [`Variable.get_axis_num`](generated/xarray.Variable.get_axis_num.md#xarray.Variable.get_axis_num)(dim) | Return axis number(s) corresponding to dimension(s) in this array. | | [`Variable.identical`](generated/xarray.Variable.identical.md#xarray.Variable.identical)(other[, equiv]) | Like equals, but also checks attributes. | | [`Variable.isel`](generated/xarray.Variable.isel.md#xarray.Variable.isel)([indexers, missing_dims]) | Return a new array indexed along the specified dimension(s). | | [`Variable.isnull`](generated/xarray.Variable.isnull.md#xarray.Variable.isnull)([keep_attrs]) | Test each value in the array for whether it is a missing value. | | [`Variable.item`](generated/xarray.Variable.item.md#xarray.Variable.item)(\*args) | Copy an element of an array to a standard Python scalar and return it. | | [`Variable.load`](generated/xarray.Variable.load.md#xarray.Variable.load)(\*\*kwargs) | Trigger loading data into memory and return this variable. | | [`Variable.load_async`](generated/xarray.Variable.load_async.md#xarray.Variable.load_async)(\*\*kwargs) | Trigger and await asynchronous loading of data into memory and return this variable. | | [`Variable.max`](generated/xarray.Variable.max.md#xarray.Variable.max)([dim, skipna]) | Reduce this NamedArray's data by applying `max` along some dimension(s). | | [`Variable.mean`](generated/xarray.Variable.mean.md#xarray.Variable.mean)([dim, skipna]) | Reduce this NamedArray's data by applying `mean` along some dimension(s). | | [`Variable.median`](generated/xarray.Variable.median.md#xarray.Variable.median)([dim, skipna]) | Reduce this NamedArray's data by applying `median` along some dimension(s). | | [`Variable.min`](generated/xarray.Variable.min.md#xarray.Variable.min)([dim, skipna]) | Reduce this NamedArray's data by applying `min` along some dimension(s). | | [`Variable.no_conflicts`](generated/xarray.Variable.no_conflicts.md#xarray.Variable.no_conflicts)(other[, equiv]) | True if the intersection of two Variable's non-null data is equal; otherwise false. | | [`Variable.notnull`](generated/xarray.Variable.notnull.md#xarray.Variable.notnull)([keep_attrs]) | Test each value in the array for whether it is not a missing value. | | [`Variable.pad`](generated/xarray.Variable.pad.md#xarray.Variable.pad)([pad_width, mode, stat_length, ...]) | Return a new Variable with padded data. | | [`Variable.prod`](generated/xarray.Variable.prod.md#xarray.Variable.prod)([dim, skipna, min_count]) | Reduce this NamedArray's data by applying `prod` along some dimension(s). | | [`Variable.quantile`](generated/xarray.Variable.quantile.md#xarray.Variable.quantile)(q[, dim, method, ...]) | Compute the qth quantile of the data along the specified dimension. | | [`Variable.rank`](generated/xarray.Variable.rank.md#xarray.Variable.rank)(dim[, pct]) | Ranks the data. | | [`Variable.reduce`](generated/xarray.Variable.reduce.md#xarray.Variable.reduce)(func[, dim, axis, ...]) | Reduce this array by applying func along some dimension(s). | | [`Variable.roll`](generated/xarray.Variable.roll.md#xarray.Variable.roll)([shifts]) | Return a new Variable with rolled data. | | [`Variable.rolling_window`](generated/xarray.Variable.rolling_window.md#xarray.Variable.rolling_window)(dim, window, ...[, ...]) | Make a rolling_window along dim and add a new_dim to the last place. | | [`Variable.round`](generated/xarray.Variable.round.md#xarray.Variable.round)(\*args, \*\*kwargs) | | | [`Variable.searchsorted`](generated/xarray.Variable.searchsorted.md#xarray.Variable.searchsorted)(v[, side, sorter]) | Find indices where elements of v should be inserted in a to maintain order. | | [`Variable.set_dims`](generated/xarray.Variable.set_dims.md#xarray.Variable.set_dims)(dim[, shape]) | Return a new variable with given set of dimensions. | | [`Variable.shift`](generated/xarray.Variable.shift.md#xarray.Variable.shift)([shifts, fill_value]) | Return a new Variable with shifted data. | | [`Variable.squeeze`](generated/xarray.Variable.squeeze.md#xarray.Variable.squeeze)([dim]) | Return a new object with squeezed data. | | [`Variable.stack`](generated/xarray.Variable.stack.md#xarray.Variable.stack)([dim]) | Stack any number of existing dim into a single new dimension. | | [`Variable.std`](generated/xarray.Variable.std.md#xarray.Variable.std)([dim, skipna, ddof]) | Reduce this NamedArray's data by applying `std` along some dimension(s). | | [`Variable.sum`](generated/xarray.Variable.sum.md#xarray.Variable.sum)([dim, skipna, min_count]) | Reduce this NamedArray's data by applying `sum` along some dimension(s). | | [`Variable.to_base_variable`](generated/xarray.Variable.to_base_variable.md#xarray.Variable.to_base_variable)() | Return this variable as a base xarray.Variable | | [`Variable.to_coord`](generated/xarray.Variable.to_coord.md#xarray.Variable.to_coord)() | to_coord has been deprecated. | | [`Variable.to_dict`](generated/xarray.Variable.to_dict.md#xarray.Variable.to_dict)([data, encoding]) | Dictionary representation of variable. | | [`Variable.to_index`](generated/xarray.Variable.to_index.md#xarray.Variable.to_index)() | Convert this variable to a pandas.Index | | [`Variable.to_index_variable`](generated/xarray.Variable.to_index_variable.md#xarray.Variable.to_index_variable)() | Return this variable as an xarray.IndexVariable | | [`Variable.to_variable`](generated/xarray.Variable.to_variable.md#xarray.Variable.to_variable)() | to_variable has been deprecated. | | [`Variable.transpose`](generated/xarray.Variable.transpose.md#xarray.Variable.transpose)(\*dim[, missing_dims]) | Return a new Variable object with transposed dimensions. | | [`Variable.unstack`](generated/xarray.Variable.unstack.md#xarray.Variable.unstack)([dim]) | Unstack an existing dimension into multiple new dimensions. | | [`Variable.var`](generated/xarray.Variable.var.md#xarray.Variable.var)([dim, skipna, ddof]) | Reduce this NamedArray's data by applying `var` along some dimension(s). | | [`Variable.where`](generated/xarray.Variable.where.md#xarray.Variable.where)(cond[, other]) | | | [`Variable.T`](generated/xarray.Variable.T.md#xarray.Variable.T) | Return a new object with transposed dimensions. | | [`Variable.attrs`](generated/xarray.Variable.attrs.md#xarray.Variable.attrs) | Dictionary of local attributes on this NamedArray. | | [`Variable.chunks`](generated/xarray.Variable.chunks.md#xarray.Variable.chunks) | Tuple of block lengths for this NamedArray's data, in order of dimensions, or None if the underlying data is not a dask array. | | [`Variable.data`](generated/xarray.Variable.data.md#xarray.Variable.data) | The Variable's data as an array. | | [`Variable.dims`](generated/xarray.Variable.dims.md#xarray.Variable.dims) | Tuple of dimension names with which this NamedArray is associated. | | [`Variable.dtype`](generated/xarray.Variable.dtype.md#xarray.Variable.dtype) | Data-type of the array’s elements. | | [`Variable.encoding`](generated/xarray.Variable.encoding.md#xarray.Variable.encoding) | Dictionary of encodings on this variable. | | [`Variable.drop_encoding`](generated/xarray.Variable.drop_encoding.md#xarray.Variable.drop_encoding)() | Return a new Variable without encoding. | | [`Variable.imag`](generated/xarray.Variable.imag.md#xarray.Variable.imag) | The imaginary part of the variable. | | [`Variable.nbytes`](generated/xarray.Variable.nbytes.md#xarray.Variable.nbytes) | Total bytes consumed by the elements of the data array. | | [`Variable.ndim`](generated/xarray.Variable.ndim.md#xarray.Variable.ndim) | Number of array dimensions. | | [`Variable.real`](generated/xarray.Variable.real.md#xarray.Variable.real) | The real part of the variable. | | [`Variable.shape`](generated/xarray.Variable.shape.md#xarray.Variable.shape) | Get the shape of the array. | | [`Variable.size`](generated/xarray.Variable.size.md#xarray.Variable.size) | Number of elements in the array. | | [`Variable.sizes`](generated/xarray.Variable.sizes.md#xarray.Variable.sizes) | Ordered mapping from dimension names to lengths. | | [`Variable.values`](generated/xarray.Variable.values.md#xarray.Variable.values) | The variable's data as a numpy.ndarray | | [`IndexVariable.all`](generated/xarray.IndexVariable.all.md#xarray.IndexVariable.all)([dim]) | Reduce this NamedArray's data by applying `all` along some dimension(s). | | [`IndexVariable.any`](generated/xarray.IndexVariable.any.md#xarray.IndexVariable.any)([dim]) | Reduce this NamedArray's data by applying `any` along some dimension(s). | | [`IndexVariable.argmax`](generated/xarray.IndexVariable.argmax.md#xarray.IndexVariable.argmax)([dim, axis, ...]) | Index or indices of the maximum of the Variable over one or more dimensions. | | [`IndexVariable.argmin`](generated/xarray.IndexVariable.argmin.md#xarray.IndexVariable.argmin)([dim, axis, ...]) | Index or indices of the minimum of the Variable over one or more dimensions. | | [`IndexVariable.argsort`](generated/xarray.IndexVariable.argsort.md#xarray.IndexVariable.argsort)([axis, kind, order, ...]) | Returns the indices that would sort this array. | | [`IndexVariable.astype`](generated/xarray.IndexVariable.astype.md#xarray.IndexVariable.astype)(dtype, \*[, order, ...]) | Copy of the Variable object, with data cast to a specified type. | | [`IndexVariable.broadcast_equals`](generated/xarray.IndexVariable.broadcast_equals.md#xarray.IndexVariable.broadcast_equals)(other[, equiv]) | True if two Variables have the values after being broadcast against each other; otherwise False. | | [`IndexVariable.chunk`](generated/xarray.IndexVariable.chunk.md#xarray.IndexVariable.chunk)([chunks, name, lock, ...]) | Coerce this array's data into a dask array with the given chunks. | | [`IndexVariable.clip`](generated/xarray.IndexVariable.clip.md#xarray.IndexVariable.clip)([min, max]) | Return an array whose values are limited to `[min, max]`. | | [`IndexVariable.coarsen`](generated/xarray.IndexVariable.coarsen.md#xarray.IndexVariable.coarsen)(windows, func[, ...]) | Apply reduction function. | | [`IndexVariable.compute`](generated/xarray.IndexVariable.compute.md#xarray.IndexVariable.compute)(\*\*kwargs) | Trigger loading data into memory and return a new variable. | | [`IndexVariable.concat`](generated/xarray.IndexVariable.concat.md#xarray.IndexVariable.concat)(variables[, dim, ...]) | Specialized version of Variable.concat for IndexVariable objects. | | [`IndexVariable.conj`](generated/xarray.IndexVariable.conj.md#xarray.IndexVariable.conj)() | Complex-conjugate all elements. | | [`IndexVariable.conjugate`](generated/xarray.IndexVariable.conjugate.md#xarray.IndexVariable.conjugate)(\*args, \*\*kwargs) | a.conj() | | [`IndexVariable.copy`](generated/xarray.IndexVariable.copy.md#xarray.IndexVariable.copy)([deep, data]) | Returns a copy of this object. | | [`IndexVariable.count`](generated/xarray.IndexVariable.count.md#xarray.IndexVariable.count)([dim]) | Reduce this NamedArray's data by applying `count` along some dimension(s). | | [`IndexVariable.cumprod`](generated/xarray.IndexVariable.cumprod.md#xarray.IndexVariable.cumprod)([dim, skipna]) | Reduce this NamedArray's data by applying `cumprod` along some dimension(s). | | [`IndexVariable.cumsum`](generated/xarray.IndexVariable.cumsum.md#xarray.IndexVariable.cumsum)([dim, skipna]) | Reduce this NamedArray's data by applying `cumsum` along some dimension(s). | | [`IndexVariable.equals`](generated/xarray.IndexVariable.equals.md#xarray.IndexVariable.equals)(other[, equiv]) | True if two Variables have the same dimensions and values; otherwise False. | | [`IndexVariable.fillna`](generated/xarray.IndexVariable.fillna.md#xarray.IndexVariable.fillna)(value) | | | [`IndexVariable.get_axis_num`](generated/xarray.IndexVariable.get_axis_num.md#xarray.IndexVariable.get_axis_num)(dim) | Return axis number(s) corresponding to dimension(s) in this array. | | [`IndexVariable.get_level_variable`](generated/xarray.IndexVariable.get_level_variable.md#xarray.IndexVariable.get_level_variable)(level) | Return a new IndexVariable from a given MultiIndex level. | | [`IndexVariable.identical`](generated/xarray.IndexVariable.identical.md#xarray.IndexVariable.identical)(other[, equiv]) | Like equals, but also checks attributes. | | [`IndexVariable.isel`](generated/xarray.IndexVariable.isel.md#xarray.IndexVariable.isel)([indexers, missing_dims]) | Return a new array indexed along the specified dimension(s). | | [`IndexVariable.isnull`](generated/xarray.IndexVariable.isnull.md#xarray.IndexVariable.isnull)([keep_attrs]) | Test each value in the array for whether it is a missing value. | | [`IndexVariable.item`](generated/xarray.IndexVariable.item.md#xarray.IndexVariable.item)(\*args) | Copy an element of an array to a standard Python scalar and return it. | | [`IndexVariable.load`](generated/xarray.IndexVariable.load.md#xarray.IndexVariable.load)() | Trigger loading data into memory and return this variable. | | [`IndexVariable.max`](generated/xarray.IndexVariable.max.md#xarray.IndexVariable.max)([dim, skipna]) | Reduce this NamedArray's data by applying `max` along some dimension(s). | | [`IndexVariable.mean`](generated/xarray.IndexVariable.mean.md#xarray.IndexVariable.mean)([dim, skipna]) | Reduce this NamedArray's data by applying `mean` along some dimension(s). | | [`IndexVariable.median`](generated/xarray.IndexVariable.median.md#xarray.IndexVariable.median)([dim, skipna]) | Reduce this NamedArray's data by applying `median` along some dimension(s). | | [`IndexVariable.min`](generated/xarray.IndexVariable.min.md#xarray.IndexVariable.min)([dim, skipna]) | Reduce this NamedArray's data by applying `min` along some dimension(s). | | [`IndexVariable.no_conflicts`](generated/xarray.IndexVariable.no_conflicts.md#xarray.IndexVariable.no_conflicts)(other[, equiv]) | True if the intersection of two Variable's non-null data is equal; otherwise false. | | [`IndexVariable.notnull`](generated/xarray.IndexVariable.notnull.md#xarray.IndexVariable.notnull)([keep_attrs]) | Test each value in the array for whether it is not a missing value. | | [`IndexVariable.pad`](generated/xarray.IndexVariable.pad.md#xarray.IndexVariable.pad)([pad_width, mode, ...]) | Return a new Variable with padded data. | | [`IndexVariable.prod`](generated/xarray.IndexVariable.prod.md#xarray.IndexVariable.prod)([dim, skipna, min_count]) | Reduce this NamedArray's data by applying `prod` along some dimension(s). | | [`IndexVariable.quantile`](generated/xarray.IndexVariable.quantile.md#xarray.IndexVariable.quantile)(q[, dim, method, ...]) | Compute the qth quantile of the data along the specified dimension. | | [`IndexVariable.rank`](generated/xarray.IndexVariable.rank.md#xarray.IndexVariable.rank)(dim[, pct]) | Ranks the data. | | [`IndexVariable.reduce`](generated/xarray.IndexVariable.reduce.md#xarray.IndexVariable.reduce)(func[, dim, axis, ...]) | Reduce this array by applying func along some dimension(s). | | [`IndexVariable.roll`](generated/xarray.IndexVariable.roll.md#xarray.IndexVariable.roll)([shifts]) | Return a new Variable with rolled data. | | [`IndexVariable.rolling_window`](generated/xarray.IndexVariable.rolling_window.md#xarray.IndexVariable.rolling_window)(dim, window, ...) | Make a rolling_window along dim and add a new_dim to the last place. | | [`IndexVariable.round`](generated/xarray.IndexVariable.round.md#xarray.IndexVariable.round)(\*args, \*\*kwargs) | | | [`IndexVariable.searchsorted`](generated/xarray.IndexVariable.searchsorted.md#xarray.IndexVariable.searchsorted)(v[, side, sorter]) | Find indices where elements of v should be inserted in a to maintain order. | | [`IndexVariable.set_dims`](generated/xarray.IndexVariable.set_dims.md#xarray.IndexVariable.set_dims)(dim[, shape]) | Return a new variable with given set of dimensions. | | [`IndexVariable.shift`](generated/xarray.IndexVariable.shift.md#xarray.IndexVariable.shift)([shifts, fill_value]) | Return a new Variable with shifted data. | | [`IndexVariable.squeeze`](generated/xarray.IndexVariable.squeeze.md#xarray.IndexVariable.squeeze)([dim]) | Return a new object with squeezed data. | | [`IndexVariable.stack`](generated/xarray.IndexVariable.stack.md#xarray.IndexVariable.stack)([dim]) | Stack any number of existing dim into a single new dimension. | | [`IndexVariable.std`](generated/xarray.IndexVariable.std.md#xarray.IndexVariable.std)([dim, skipna, ddof]) | Reduce this NamedArray's data by applying `std` along some dimension(s). | | [`IndexVariable.sum`](generated/xarray.IndexVariable.sum.md#xarray.IndexVariable.sum)([dim, skipna, min_count]) | Reduce this NamedArray's data by applying `sum` along some dimension(s). | | [`IndexVariable.to_base_variable`](generated/xarray.IndexVariable.to_base_variable.md#xarray.IndexVariable.to_base_variable)() | Return this variable as a base xarray.Variable | | [`IndexVariable.to_coord`](generated/xarray.IndexVariable.to_coord.md#xarray.IndexVariable.to_coord)() | to_coord has been deprecated. | | [`IndexVariable.to_dict`](generated/xarray.IndexVariable.to_dict.md#xarray.IndexVariable.to_dict)([data, encoding]) | Dictionary representation of variable. | | [`IndexVariable.to_index`](generated/xarray.IndexVariable.to_index.md#xarray.IndexVariable.to_index)() | Convert this variable to a pandas.Index | | [`IndexVariable.to_index_variable`](generated/xarray.IndexVariable.to_index_variable.md#xarray.IndexVariable.to_index_variable)() | Return this variable as an xarray.IndexVariable | | [`IndexVariable.to_variable`](generated/xarray.IndexVariable.to_variable.md#xarray.IndexVariable.to_variable)() | to_variable has been deprecated. | | [`IndexVariable.transpose`](generated/xarray.IndexVariable.transpose.md#xarray.IndexVariable.transpose)(\*dim[, missing_dims]) | Return a new Variable object with transposed dimensions. | | [`IndexVariable.unstack`](generated/xarray.IndexVariable.unstack.md#xarray.IndexVariable.unstack)([dim]) | Unstack an existing dimension into multiple new dimensions. | | [`IndexVariable.var`](generated/xarray.IndexVariable.var.md#xarray.IndexVariable.var)([dim, skipna, ddof]) | Reduce this NamedArray's data by applying `var` along some dimension(s). | | [`IndexVariable.where`](generated/xarray.IndexVariable.where.md#xarray.IndexVariable.where)(cond[, other]) | | | [`IndexVariable.T`](generated/xarray.IndexVariable.T.md#xarray.IndexVariable.T) | Return a new object with transposed dimensions. | | [`IndexVariable.attrs`](generated/xarray.IndexVariable.attrs.md#xarray.IndexVariable.attrs) | Dictionary of local attributes on this NamedArray. | | [`IndexVariable.chunks`](generated/xarray.IndexVariable.chunks.md#xarray.IndexVariable.chunks) | Tuple of block lengths for this NamedArray's data, in order of dimensions, or None if the underlying data is not a dask array. | | [`IndexVariable.data`](generated/xarray.IndexVariable.data.md#xarray.IndexVariable.data) | The Variable's data as an array. | | [`IndexVariable.dims`](generated/xarray.IndexVariable.dims.md#xarray.IndexVariable.dims) | Tuple of dimension names with which this NamedArray is associated. | | [`IndexVariable.dtype`](generated/xarray.IndexVariable.dtype.md#xarray.IndexVariable.dtype) | Data-type of the array’s elements. | | [`IndexVariable.encoding`](generated/xarray.IndexVariable.encoding.md#xarray.IndexVariable.encoding) | Dictionary of encodings on this variable. | | [`IndexVariable.imag`](generated/xarray.IndexVariable.imag.md#xarray.IndexVariable.imag) | The imaginary part of the variable. | | [`IndexVariable.level_names`](generated/xarray.IndexVariable.level_names.md#xarray.IndexVariable.level_names) | Return MultiIndex level names or None if this IndexVariable has no MultiIndex. | | [`IndexVariable.name`](generated/xarray.IndexVariable.name.md#xarray.IndexVariable.name) | | | [`IndexVariable.nbytes`](generated/xarray.IndexVariable.nbytes.md#xarray.IndexVariable.nbytes) | Total bytes consumed by the elements of the data array. | | [`IndexVariable.ndim`](generated/xarray.IndexVariable.ndim.md#xarray.IndexVariable.ndim) | Number of array dimensions. | | [`IndexVariable.real`](generated/xarray.IndexVariable.real.md#xarray.IndexVariable.real) | The real part of the variable. | | [`IndexVariable.shape`](generated/xarray.IndexVariable.shape.md#xarray.IndexVariable.shape) | Get the shape of the array. | | [`IndexVariable.size`](generated/xarray.IndexVariable.size.md#xarray.IndexVariable.size) | Number of elements in the array. | | [`IndexVariable.sizes`](generated/xarray.IndexVariable.sizes.md#xarray.IndexVariable.sizes) | Ordered mapping from dimension names to lengths. | | [`IndexVariable.values`](generated/xarray.IndexVariable.values.md#xarray.IndexVariable.values) | The variable's data as a numpy.ndarray | | [`NamedArray.all`](generated/xarray.NamedArray.all.md#xarray.NamedArray.all)([dim]) | Reduce this NamedArray's data by applying `all` along some dimension(s). | | [`NamedArray.any`](generated/xarray.NamedArray.any.md#xarray.NamedArray.any)([dim]) | Reduce this NamedArray's data by applying `any` along some dimension(s). | | [`NamedArray.attrs`](generated/xarray.NamedArray.attrs.md#xarray.NamedArray.attrs) | Dictionary of local attributes on this NamedArray. | | [`NamedArray.broadcast_to`](generated/xarray.NamedArray.broadcast_to.md#xarray.NamedArray.broadcast_to)([dim]) | Broadcast the NamedArray to a new shape. | | [`NamedArray.chunks`](generated/xarray.NamedArray.chunks.md#xarray.NamedArray.chunks) | Tuple of block lengths for this NamedArray's data, in order of dimensions, or None if the underlying data is not a dask array. | | [`NamedArray.chunksizes`](generated/xarray.NamedArray.chunksizes.md#xarray.NamedArray.chunksizes) | Mapping from dimension names to block lengths for this NamedArray's data. | | [`NamedArray.copy`](generated/xarray.NamedArray.copy.md#xarray.NamedArray.copy)([deep, data]) | Returns a copy of this object. | | [`NamedArray.count`](generated/xarray.NamedArray.count.md#xarray.NamedArray.count)([dim]) | Reduce this NamedArray's data by applying `count` along some dimension(s). | | [`NamedArray.cumprod`](generated/xarray.NamedArray.cumprod.md#xarray.NamedArray.cumprod)([dim, skipna]) | Reduce this NamedArray's data by applying `cumprod` along some dimension(s). | | [`NamedArray.cumsum`](generated/xarray.NamedArray.cumsum.md#xarray.NamedArray.cumsum)([dim, skipna]) | Reduce this NamedArray's data by applying `cumsum` along some dimension(s). | | [`NamedArray.data`](generated/xarray.NamedArray.data.md#xarray.NamedArray.data) | The NamedArray's data as an array. | | [`NamedArray.dims`](generated/xarray.NamedArray.dims.md#xarray.NamedArray.dims) | Tuple of dimension names with which this NamedArray is associated. | | [`NamedArray.dtype`](generated/xarray.NamedArray.dtype.md#xarray.NamedArray.dtype) | Data-type of the array’s elements. | | [`NamedArray.expand_dims`](generated/xarray.NamedArray.expand_dims.md#xarray.NamedArray.expand_dims)([dim]) | Expand the dimensions of the NamedArray. | | [`NamedArray.get_axis_num`](generated/xarray.NamedArray.get_axis_num.md#xarray.NamedArray.get_axis_num)(dim) | Return axis number(s) corresponding to dimension(s) in this array. | | [`NamedArray.max`](generated/xarray.NamedArray.max.md#xarray.NamedArray.max)([dim, skipna]) | Reduce this NamedArray's data by applying `max` along some dimension(s). | | [`NamedArray.mean`](generated/xarray.NamedArray.mean.md#xarray.NamedArray.mean)([dim, skipna]) | Reduce this NamedArray's data by applying `mean` along some dimension(s). | | [`NamedArray.median`](generated/xarray.NamedArray.median.md#xarray.NamedArray.median)([dim, skipna]) | Reduce this NamedArray's data by applying `median` along some dimension(s). | | [`NamedArray.min`](generated/xarray.NamedArray.min.md#xarray.NamedArray.min)([dim, skipna]) | Reduce this NamedArray's data by applying `min` along some dimension(s). | | [`NamedArray.nbytes`](generated/xarray.NamedArray.nbytes.md#xarray.NamedArray.nbytes) | Total bytes consumed by the elements of the data array. | | [`NamedArray.ndim`](generated/xarray.NamedArray.ndim.md#xarray.NamedArray.ndim) | Number of array dimensions. | | [`NamedArray.prod`](generated/xarray.NamedArray.prod.md#xarray.NamedArray.prod)([dim, skipna, min_count]) | Reduce this NamedArray's data by applying `prod` along some dimension(s). | | [`NamedArray.reduce`](generated/xarray.NamedArray.reduce.md#xarray.NamedArray.reduce)(func[, dim, axis, keepdims]) | Reduce this array by applying func along some dimension(s). | | [`NamedArray.shape`](generated/xarray.NamedArray.shape.md#xarray.NamedArray.shape) | Get the shape of the array. | | [`NamedArray.size`](generated/xarray.NamedArray.size.md#xarray.NamedArray.size) | Number of elements in the array. | | [`NamedArray.sizes`](generated/xarray.NamedArray.sizes.md#xarray.NamedArray.sizes) | Ordered mapping from dimension names to lengths. | | [`NamedArray.std`](generated/xarray.NamedArray.std.md#xarray.NamedArray.std)([dim, skipna, ddof]) | Reduce this NamedArray's data by applying `std` along some dimension(s). | | [`NamedArray.sum`](generated/xarray.NamedArray.sum.md#xarray.NamedArray.sum)([dim, skipna, min_count]) | Reduce this NamedArray's data by applying `sum` along some dimension(s). | | [`NamedArray.var`](generated/xarray.NamedArray.var.md#xarray.NamedArray.var)([dim, skipna, ddof]) | Reduce this NamedArray's data by applying `var` along some dimension(s). | | [`plot.plot`](generated/xarray.plot.plot.md#xarray.plot.plot)(darray, \*[, row, col, col_wrap, ...]) | Default plot of DataArray using [`matplotlib.pyplot`](https://matplotlib.org/stable/api/pyplot_summary.html#module-matplotlib.pyplot). | | [`plot.line`](generated/xarray.plot.line.md#xarray.plot.line)(darray, \*args[, row, col, ...]) | Line plot of DataArray values. | | [`plot.step`](generated/xarray.plot.step.md#xarray.plot.step)(darray, \*args[, where, drawstyle, ...]) | Step plot of DataArray values. | | [`plot.hist`](generated/xarray.plot.hist.md#xarray.plot.hist)(darray, \*[, figsize, size, ...]) | Histogram of DataArray. | | [`plot.contour`](generated/xarray.plot.contour.md#xarray.plot.contour)(darray, \*args[, x, y, figsize, ...]) | Contour plot of 2D DataArray. | | [`plot.contourf`](generated/xarray.plot.contourf.md#xarray.plot.contourf)(darray, \*args[, x, y, ...]) | Filled contour plot of 2D DataArray. | | [`plot.imshow`](generated/xarray.plot.imshow.md#xarray.plot.imshow)(darray, \*args[, x, y, figsize, ...]) | Image plot of 2D DataArray. | | [`plot.pcolormesh`](generated/xarray.plot.pcolormesh.md#xarray.plot.pcolormesh)(darray, \*args[, x, y, ...]) | Pseudocolor plot of 2D DataArray. | | [`plot.scatter`](generated/xarray.plot.scatter.md#xarray.plot.scatter)(ds, \*[, x, y, z, hue, ...]) | Scatter variables against each other. | | [`plot.surface`](generated/xarray.plot.surface.md#xarray.plot.surface)(darray, \*args[, x, y, figsize, ...]) | Surface plot of 2D DataArray. | | [`CFTimeIndex.all`](generated/xarray.CFTimeIndex.all.md#xarray.CFTimeIndex.all)(\*args, \*\*kwargs) | Return whether all elements are Truthy. | | [`CFTimeIndex.any`](generated/xarray.CFTimeIndex.any.md#xarray.CFTimeIndex.any)(\*args, \*\*kwargs) | Return whether any element is Truthy. | | [`CFTimeIndex.append`](generated/xarray.CFTimeIndex.append.md#xarray.CFTimeIndex.append)(other) | Append a collection of Index options together. | | [`CFTimeIndex.argsort`](generated/xarray.CFTimeIndex.argsort.md#xarray.CFTimeIndex.argsort)(\*args, \*\*kwargs) | Return the integer indices that would sort the index. | | [`CFTimeIndex.argmax`](generated/xarray.CFTimeIndex.argmax.md#xarray.CFTimeIndex.argmax)([axis, skipna]) | Return int position of the largest value in the Index. | | [`CFTimeIndex.argmin`](generated/xarray.CFTimeIndex.argmin.md#xarray.CFTimeIndex.argmin)([axis, skipna]) | Return int position of the smallest value in the Index. | | [`CFTimeIndex.asof`](generated/xarray.CFTimeIndex.asof.md#xarray.CFTimeIndex.asof)(label) | Return the label from the index, or, if not present, the previous one. | | [`CFTimeIndex.asof_locs`](generated/xarray.CFTimeIndex.asof_locs.md#xarray.CFTimeIndex.asof_locs)(where, mask) | Return the locations (indices) of labels in the index. | | [`CFTimeIndex.astype`](generated/xarray.CFTimeIndex.astype.md#xarray.CFTimeIndex.astype)(dtype[, copy]) | Create an Index with values cast to dtypes. | | [`CFTimeIndex.calendar`](generated/xarray.CFTimeIndex.calendar.md#xarray.CFTimeIndex.calendar) | The calendar used by the datetimes in the index. | | [`CFTimeIndex.ceil`](generated/xarray.CFTimeIndex.ceil.md#xarray.CFTimeIndex.ceil)(freq) | Round dates up to fixed frequency. | | [`CFTimeIndex.contains`](generated/xarray.CFTimeIndex.contains.md#xarray.CFTimeIndex.contains)(key) | Needed for .loc based partial-string indexing | | [`CFTimeIndex.copy`](generated/xarray.CFTimeIndex.copy.md#xarray.CFTimeIndex.copy)([name, deep]) | Make a copy of this object. | | [`CFTimeIndex.day_of_week`](generated/xarray.CFTimeIndex.day_of_week.md#xarray.CFTimeIndex.day_of_week) | The day of week of the datetime | | [`CFTimeIndex.day_of_year`](generated/xarray.CFTimeIndex.day_of_year.md#xarray.CFTimeIndex.day_of_year) | The ordinal day of year of the datetime | | [`CFTimeIndex.days_in_month`](generated/xarray.CFTimeIndex.days_in_month.md#xarray.CFTimeIndex.days_in_month) | The number of days in the month of the datetime | | [`CFTimeIndex.delete`](generated/xarray.CFTimeIndex.delete.md#xarray.CFTimeIndex.delete)(loc) | Make new Index with passed location(-s) deleted. | | [`CFTimeIndex.difference`](generated/xarray.CFTimeIndex.difference.md#xarray.CFTimeIndex.difference)(other[, sort]) | Return a new Index with elements of index not in other. | | [`CFTimeIndex.drop`](generated/xarray.CFTimeIndex.drop.md#xarray.CFTimeIndex.drop)(labels[, errors]) | Make new Index with passed list of labels deleted. | | [`CFTimeIndex.drop_duplicates`](generated/xarray.CFTimeIndex.drop_duplicates.md#xarray.CFTimeIndex.drop_duplicates)(\*[, keep]) | Return Index with duplicate values removed. | | [`CFTimeIndex.droplevel`](generated/xarray.CFTimeIndex.droplevel.md#xarray.CFTimeIndex.droplevel)([level]) | Return index with requested level(s) removed. | | [`CFTimeIndex.dropna`](generated/xarray.CFTimeIndex.dropna.md#xarray.CFTimeIndex.dropna)([how]) | Return Index without NA/NaN values. | | [`CFTimeIndex.duplicated`](generated/xarray.CFTimeIndex.duplicated.md#xarray.CFTimeIndex.duplicated)([keep]) | Indicate duplicate index values. | | [`CFTimeIndex.equals`](generated/xarray.CFTimeIndex.equals.md#xarray.CFTimeIndex.equals)(other) | Determine if two Index object are equal. | | [`CFTimeIndex.factorize`](generated/xarray.CFTimeIndex.factorize.md#xarray.CFTimeIndex.factorize)([sort, use_na_sentinel]) | Encode the object as an enumerated type or categorical variable. | | [`CFTimeIndex.fillna`](generated/xarray.CFTimeIndex.fillna.md#xarray.CFTimeIndex.fillna)(value) | Fill NA/NaN values with the specified value. | | [`CFTimeIndex.floor`](generated/xarray.CFTimeIndex.floor.md#xarray.CFTimeIndex.floor)(freq) | Round dates down to fixed frequency. | | [`CFTimeIndex.get_indexer`](generated/xarray.CFTimeIndex.get_indexer.md#xarray.CFTimeIndex.get_indexer)(target[, method, ...]) | Compute indexer and mask for new index given the current index. | | [`CFTimeIndex.get_indexer_for`](generated/xarray.CFTimeIndex.get_indexer_for.md#xarray.CFTimeIndex.get_indexer_for)(target) | Guaranteed return of an indexer even when non-unique. | | [`CFTimeIndex.get_indexer_non_unique`](generated/xarray.CFTimeIndex.get_indexer_non_unique.md#xarray.CFTimeIndex.get_indexer_non_unique)(target) | Compute indexer and mask for new index given the current index. | | [`CFTimeIndex.get_level_values`](generated/xarray.CFTimeIndex.get_level_values.md#xarray.CFTimeIndex.get_level_values)(level) | Return an Index of values for requested level. | | [`CFTimeIndex.get_loc`](generated/xarray.CFTimeIndex.get_loc.md#xarray.CFTimeIndex.get_loc)(key) | Adapted from pandas.tseries.index.DatetimeIndex.get_loc | | [`CFTimeIndex.get_slice_bound`](generated/xarray.CFTimeIndex.get_slice_bound.md#xarray.CFTimeIndex.get_slice_bound)(label, side) | Calculate slice bound that corresponds to given label. | | [`CFTimeIndex.get_value`](generated/xarray.CFTimeIndex.get_value.md#xarray.CFTimeIndex.get_value)(series, key) | Adapted from pandas.tseries.index.DatetimeIndex.get_value | | [`CFTimeIndex.groupby`](generated/xarray.CFTimeIndex.groupby.md#xarray.CFTimeIndex.groupby)(values) | Group the index labels by a given array of values. | | [`CFTimeIndex.identical`](generated/xarray.CFTimeIndex.identical.md#xarray.CFTimeIndex.identical)(other) | Similar to equals, but checks that object attributes and types are also equal. | | [`CFTimeIndex.insert`](generated/xarray.CFTimeIndex.insert.md#xarray.CFTimeIndex.insert)(loc, item) | Make new Index inserting new item at location. | | [`CFTimeIndex.intersection`](generated/xarray.CFTimeIndex.intersection.md#xarray.CFTimeIndex.intersection)(other[, sort]) | Form the intersection of two Index objects. | | [`CFTimeIndex.is_`](generated/xarray.CFTimeIndex.is_.md#xarray.CFTimeIndex.is_)(other) | More flexible, faster check like `is` but that works through views. | | [`CFTimeIndex.isin`](generated/xarray.CFTimeIndex.isin.md#xarray.CFTimeIndex.isin)(values[, level]) | Return a boolean array where the index values are in values. | | [`CFTimeIndex.isna`](generated/xarray.CFTimeIndex.isna.md#xarray.CFTimeIndex.isna)() | Detect missing values. | | [`CFTimeIndex.isnull`](generated/xarray.CFTimeIndex.isnull.md#xarray.CFTimeIndex.isnull)() | Detect missing values. | | [`CFTimeIndex.item`](generated/xarray.CFTimeIndex.item.md#xarray.CFTimeIndex.item)() | Return the first element of the underlying data as a Python scalar. | | [`CFTimeIndex.join`](generated/xarray.CFTimeIndex.join.md#xarray.CFTimeIndex.join)(other, \*[, how, level, ...]) | Compute join_index and indexers to conform data structures to the new index. | | [`CFTimeIndex.map`](generated/xarray.CFTimeIndex.map.md#xarray.CFTimeIndex.map)(mapper[, na_action]) | Map values using an input mapping or function. | | [`CFTimeIndex.max`](generated/xarray.CFTimeIndex.max.md#xarray.CFTimeIndex.max)([axis, skipna]) | Return the maximum value of the Index. | | [`CFTimeIndex.memory_usage`](generated/xarray.CFTimeIndex.memory_usage.md#xarray.CFTimeIndex.memory_usage)([deep]) | Memory usage of the values. | | [`CFTimeIndex.min`](generated/xarray.CFTimeIndex.min.md#xarray.CFTimeIndex.min)([axis, skipna]) | Return the minimum value of the Index. | | [`CFTimeIndex.notna`](generated/xarray.CFTimeIndex.notna.md#xarray.CFTimeIndex.notna)() | Detect existing (non-missing) values. | | [`CFTimeIndex.notnull`](generated/xarray.CFTimeIndex.notnull.md#xarray.CFTimeIndex.notnull)() | Detect existing (non-missing) values. | | [`CFTimeIndex.nunique`](generated/xarray.CFTimeIndex.nunique.md#xarray.CFTimeIndex.nunique)([dropna]) | Return number of unique elements in the object. | | [`CFTimeIndex.putmask`](generated/xarray.CFTimeIndex.putmask.md#xarray.CFTimeIndex.putmask)(mask, value) | Return a new Index of the values set with the mask. | | [`CFTimeIndex.ravel`](generated/xarray.CFTimeIndex.ravel.md#xarray.CFTimeIndex.ravel)([order]) | Return a view on self. | | [`CFTimeIndex.reindex`](generated/xarray.CFTimeIndex.reindex.md#xarray.CFTimeIndex.reindex)(target[, method, level, ...]) | Create index with target's values. | | [`CFTimeIndex.rename`](generated/xarray.CFTimeIndex.rename.md#xarray.CFTimeIndex.rename)(name, \*[, inplace]) | Alter Index or MultiIndex name. | | [`CFTimeIndex.repeat`](generated/xarray.CFTimeIndex.repeat.md#xarray.CFTimeIndex.repeat)(repeats[, axis]) | Repeat elements of an Index. | | [`CFTimeIndex.round`](generated/xarray.CFTimeIndex.round.md#xarray.CFTimeIndex.round)(freq) | Round dates to a fixed frequency. | | [`CFTimeIndex.searchsorted`](generated/xarray.CFTimeIndex.searchsorted.md#xarray.CFTimeIndex.searchsorted)(value[, side, sorter]) | Find indices where elements should be inserted to maintain order. | | [`CFTimeIndex.set_names`](generated/xarray.CFTimeIndex.set_names.md#xarray.CFTimeIndex.set_names)(names, \*[, level, inplace]) | Set Index or MultiIndex name. | | [`CFTimeIndex.shift`](generated/xarray.CFTimeIndex.shift.md#xarray.CFTimeIndex.shift)(periods[, freq]) | Shift the CFTimeIndex a multiple of the given frequency. | | [`CFTimeIndex.slice_indexer`](generated/xarray.CFTimeIndex.slice_indexer.md#xarray.CFTimeIndex.slice_indexer)([start, end, step]) | Compute the slice indexer for input labels and step. | | [`CFTimeIndex.slice_locs`](generated/xarray.CFTimeIndex.slice_locs.md#xarray.CFTimeIndex.slice_locs)([start, end, step]) | Compute slice locations for input labels. | | [`CFTimeIndex.sort_values`](generated/xarray.CFTimeIndex.sort_values.md#xarray.CFTimeIndex.sort_values)(\*[, return_indexer, ...]) | Return a sorted copy of the index. | | [`CFTimeIndex.sortlevel`](generated/xarray.CFTimeIndex.sortlevel.md#xarray.CFTimeIndex.sortlevel)([level, ascending, ...]) | For internal compatibility with the Index API. | | [`CFTimeIndex.strftime`](generated/xarray.CFTimeIndex.strftime.md#xarray.CFTimeIndex.strftime)(date_format) | Return an Index of formatted strings specified by date_format, which supports the same string format as the python standard library. | | [`CFTimeIndex.symmetric_difference`](generated/xarray.CFTimeIndex.symmetric_difference.md#xarray.CFTimeIndex.symmetric_difference)(other[, ...]) | Compute the symmetric difference of two Index objects. | | [`CFTimeIndex.take`](generated/xarray.CFTimeIndex.take.md#xarray.CFTimeIndex.take)(indices[, axis, ...]) | Return a new Index of the values selected by the indices. | | [`CFTimeIndex.to_datetimeindex`](generated/xarray.CFTimeIndex.to_datetimeindex.md#xarray.CFTimeIndex.to_datetimeindex)([unsafe, time_unit]) | If possible, convert this index to a pandas.DatetimeIndex. | | [`CFTimeIndex.to_flat_index`](generated/xarray.CFTimeIndex.to_flat_index.md#xarray.CFTimeIndex.to_flat_index)() | Identity method. | | [`CFTimeIndex.to_frame`](generated/xarray.CFTimeIndex.to_frame.md#xarray.CFTimeIndex.to_frame)([index, name]) | Create a DataFrame with a column containing the Index. | | [`CFTimeIndex.to_list`](generated/xarray.CFTimeIndex.to_list.md#xarray.CFTimeIndex.to_list)() | Return a list of the values. | | [`CFTimeIndex.to_numpy`](generated/xarray.CFTimeIndex.to_numpy.md#xarray.CFTimeIndex.to_numpy)([dtype, copy, na_value]) | A NumPy ndarray representing the values in this Series or Index. | | [`CFTimeIndex.to_series`](generated/xarray.CFTimeIndex.to_series.md#xarray.CFTimeIndex.to_series)([index, name]) | Create a Series with both index and values equal to the index keys. | | [`CFTimeIndex.tolist`](generated/xarray.CFTimeIndex.tolist.md#xarray.CFTimeIndex.tolist)() | Return a list of the values. | | [`CFTimeIndex.transpose`](generated/xarray.CFTimeIndex.transpose.md#xarray.CFTimeIndex.transpose)(\*args, \*\*kwargs) | Return the transpose, which is by definition self. | | [`CFTimeIndex.union`](generated/xarray.CFTimeIndex.union.md#xarray.CFTimeIndex.union)(other[, sort]) | Form the union of two Index objects. | | [`CFTimeIndex.unique`](generated/xarray.CFTimeIndex.unique.md#xarray.CFTimeIndex.unique)([level]) | Return unique values in the index. | | [`CFTimeIndex.value_counts`](generated/xarray.CFTimeIndex.value_counts.md#xarray.CFTimeIndex.value_counts)([normalize, sort, ...]) | Return a Series containing counts of unique values. | | [`CFTimeIndex.view`](generated/xarray.CFTimeIndex.view.md#xarray.CFTimeIndex.view)([cls]) | Return a view of the Index with the specified dtype or a new Index instance. | | [`CFTimeIndex.where`](generated/xarray.CFTimeIndex.where.md#xarray.CFTimeIndex.where)(cond[, other]) | Replace values where the condition is False. | | [`CFTimeIndex.T`](generated/xarray.CFTimeIndex.T.md#xarray.CFTimeIndex.T) | Return the transpose, which is by definition self. | | [`CFTimeIndex.array`](generated/xarray.CFTimeIndex.array.md#xarray.CFTimeIndex.array) | The ExtensionArray of the data backing this Index. | | [`CFTimeIndex.asi8`](generated/xarray.CFTimeIndex.asi8.md#xarray.CFTimeIndex.asi8) | Convert to integers with units of microseconds since 1970-01-01. | | [`CFTimeIndex.date_type`](generated/xarray.CFTimeIndex.date_type.md#xarray.CFTimeIndex.date_type) | | | [`CFTimeIndex.day`](generated/xarray.CFTimeIndex.day.md#xarray.CFTimeIndex.day) | The days of the datetime | | [`CFTimeIndex.dayofweek`](generated/xarray.CFTimeIndex.dayofweek.md#xarray.CFTimeIndex.dayofweek) | The day of week of the datetime | | [`CFTimeIndex.dayofyear`](generated/xarray.CFTimeIndex.dayofyear.md#xarray.CFTimeIndex.dayofyear) | The ordinal day of year of the datetime | | [`CFTimeIndex.dtype`](generated/xarray.CFTimeIndex.dtype.md#xarray.CFTimeIndex.dtype) | Return the dtype object of the underlying data. | | [`CFTimeIndex.empty`](generated/xarray.CFTimeIndex.empty.md#xarray.CFTimeIndex.empty) | Indicator whether Index is empty. | | [`CFTimeIndex.freq`](generated/xarray.CFTimeIndex.freq.md#xarray.CFTimeIndex.freq) | The frequency used by the dates in the index. | | [`CFTimeIndex.has_duplicates`](generated/xarray.CFTimeIndex.has_duplicates.md#xarray.CFTimeIndex.has_duplicates) | Check if the Index has duplicate values. | | [`CFTimeIndex.hasnans`](generated/xarray.CFTimeIndex.hasnans.md#xarray.CFTimeIndex.hasnans) | Return True if there are any NaNs. | | [`CFTimeIndex.hour`](generated/xarray.CFTimeIndex.hour.md#xarray.CFTimeIndex.hour) | The hours of the datetime | | [`CFTimeIndex.inferred_type`](generated/xarray.CFTimeIndex.inferred_type.md#xarray.CFTimeIndex.inferred_type) | Return a string of the type inferred from the values. | | [`CFTimeIndex.is_monotonic_increasing`](generated/xarray.CFTimeIndex.is_monotonic_increasing.md#xarray.CFTimeIndex.is_monotonic_increasing) | Return a boolean if the values are equal or increasing. | | [`CFTimeIndex.is_monotonic_decreasing`](generated/xarray.CFTimeIndex.is_monotonic_decreasing.md#xarray.CFTimeIndex.is_monotonic_decreasing) | Return a boolean if the values are equal or decreasing. | | [`CFTimeIndex.is_unique`](generated/xarray.CFTimeIndex.is_unique.md#xarray.CFTimeIndex.is_unique) | Return if the index has unique values. | | [`CFTimeIndex.microsecond`](generated/xarray.CFTimeIndex.microsecond.md#xarray.CFTimeIndex.microsecond) | The microseconds of the datetime | | [`CFTimeIndex.minute`](generated/xarray.CFTimeIndex.minute.md#xarray.CFTimeIndex.minute) | The minutes of the datetime | | [`CFTimeIndex.month`](generated/xarray.CFTimeIndex.month.md#xarray.CFTimeIndex.month) | The month of the datetime | | [`CFTimeIndex.name`](generated/xarray.CFTimeIndex.name.md#xarray.CFTimeIndex.name) | Return Index or MultiIndex name. | | [`CFTimeIndex.names`](generated/xarray.CFTimeIndex.names.md#xarray.CFTimeIndex.names) | Get names on index. | | [`CFTimeIndex.nbytes`](generated/xarray.CFTimeIndex.nbytes.md#xarray.CFTimeIndex.nbytes) | Return the number of bytes in the underlying data. | | [`CFTimeIndex.ndim`](generated/xarray.CFTimeIndex.ndim.md#xarray.CFTimeIndex.ndim) | Number of dimensions of the underlying data, by definition 1. | | [`CFTimeIndex.nlevels`](generated/xarray.CFTimeIndex.nlevels.md#xarray.CFTimeIndex.nlevels) | Number of levels. | | [`CFTimeIndex.second`](generated/xarray.CFTimeIndex.second.md#xarray.CFTimeIndex.second) | The seconds of the datetime | | [`CFTimeIndex.shape`](generated/xarray.CFTimeIndex.shape.md#xarray.CFTimeIndex.shape) | Return a tuple of the shape of the underlying data. | | [`CFTimeIndex.size`](generated/xarray.CFTimeIndex.size.md#xarray.CFTimeIndex.size) | Return the number of elements in the underlying data. | | [`CFTimeIndex.values`](generated/xarray.CFTimeIndex.values.md#xarray.CFTimeIndex.values) | Return an array representing the data in the Index. | | [`CFTimeIndex.year`](generated/xarray.CFTimeIndex.year.md#xarray.CFTimeIndex.year) | The year of the datetime | | [`indexes.RangeIndex.start`](generated/xarray.indexes.RangeIndex.start.md#xarray.indexes.RangeIndex.start) | Returns the start of the interval (the interval includes this value). | | [`indexes.RangeIndex.stop`](generated/xarray.indexes.RangeIndex.stop.md#xarray.indexes.RangeIndex.stop) | Returns the end of the interval (the interval does not include this value). | | [`indexes.RangeIndex.step`](generated/xarray.indexes.RangeIndex.step.md#xarray.indexes.RangeIndex.step) | Returns the spacing between values. | | [`backends.NetCDF4DataStore.close`](generated/xarray.backends.NetCDF4DataStore.close.md#xarray.backends.NetCDF4DataStore.close)(\*\*kwargs) | | | [`backends.NetCDF4DataStore.encode`](generated/xarray.backends.NetCDF4DataStore.encode.md#xarray.backends.NetCDF4DataStore.encode)(variables, ...) | Encode the variables and attributes in this store | | [`backends.NetCDF4DataStore.encode_attribute`](generated/xarray.backends.NetCDF4DataStore.encode_attribute.md#xarray.backends.NetCDF4DataStore.encode_attribute)(a) | encode one attribute | | [`backends.NetCDF4DataStore.encode_variable`](generated/xarray.backends.NetCDF4DataStore.encode_variable.md#xarray.backends.NetCDF4DataStore.encode_variable)(...) | encode one variable | | [`backends.NetCDF4DataStore.get_attrs`](generated/xarray.backends.NetCDF4DataStore.get_attrs.md#xarray.backends.NetCDF4DataStore.get_attrs)() | | | [`backends.NetCDF4DataStore.get_dimensions`](generated/xarray.backends.NetCDF4DataStore.get_dimensions.md#xarray.backends.NetCDF4DataStore.get_dimensions)() | | | [`backends.NetCDF4DataStore.get_encoding`](generated/xarray.backends.NetCDF4DataStore.get_encoding.md#xarray.backends.NetCDF4DataStore.get_encoding)() | | | [`backends.NetCDF4DataStore.get_variables`](generated/xarray.backends.NetCDF4DataStore.get_variables.md#xarray.backends.NetCDF4DataStore.get_variables)() | | | [`backends.NetCDF4DataStore.load`](generated/xarray.backends.NetCDF4DataStore.load.md#xarray.backends.NetCDF4DataStore.load)() | This loads the variables and attributes simultaneously. | | [`backends.NetCDF4DataStore.open`](generated/xarray.backends.NetCDF4DataStore.open.md#xarray.backends.NetCDF4DataStore.open)(filename[, ...]) | | | [`backends.NetCDF4DataStore.open_store_variable`](generated/xarray.backends.NetCDF4DataStore.open_store_variable.md#xarray.backends.NetCDF4DataStore.open_store_variable)(...) | | | [`backends.NetCDF4DataStore.prepare_variable`](generated/xarray.backends.NetCDF4DataStore.prepare_variable.md#xarray.backends.NetCDF4DataStore.prepare_variable)(...) | | | [`backends.NetCDF4DataStore.set_attribute`](generated/xarray.backends.NetCDF4DataStore.set_attribute.md#xarray.backends.NetCDF4DataStore.set_attribute)(key, ...) | | | [`backends.NetCDF4DataStore.set_attributes`](generated/xarray.backends.NetCDF4DataStore.set_attributes.md#xarray.backends.NetCDF4DataStore.set_attributes)(...) | This provides a centralized method to set the dataset attributes on the data store. | | [`backends.NetCDF4DataStore.set_dimension`](generated/xarray.backends.NetCDF4DataStore.set_dimension.md#xarray.backends.NetCDF4DataStore.set_dimension)(...) | | | [`backends.NetCDF4DataStore.set_dimensions`](generated/xarray.backends.NetCDF4DataStore.set_dimensions.md#xarray.backends.NetCDF4DataStore.set_dimensions)(...) | This provides a centralized method to set the dimensions on the data store. | | [`backends.NetCDF4DataStore.set_variable`](generated/xarray.backends.NetCDF4DataStore.set_variable.md#xarray.backends.NetCDF4DataStore.set_variable)(k, v) | | | [`backends.NetCDF4DataStore.set_variables`](generated/xarray.backends.NetCDF4DataStore.set_variables.md#xarray.backends.NetCDF4DataStore.set_variables)(...) | This provides a centralized method to set the variables on the data store. | | [`backends.NetCDF4DataStore.store`](generated/xarray.backends.NetCDF4DataStore.store.md#xarray.backends.NetCDF4DataStore.store)(variables, ...) | Top level method for putting data on this store, this method: | | [`backends.NetCDF4DataStore.store_dataset`](generated/xarray.backends.NetCDF4DataStore.store_dataset.md#xarray.backends.NetCDF4DataStore.store_dataset)(dataset) | in stores, variables are all variables AND coordinates in xarray.Dataset variables are variables NOT coordinates, so here we pass the whole dataset in instead of doing dataset.variables | | [`backends.NetCDF4DataStore.sync`](generated/xarray.backends.NetCDF4DataStore.sync.md#xarray.backends.NetCDF4DataStore.sync)() | Write all buffered data to disk. | | [`backends.NetCDF4DataStore.autoclose`](generated/xarray.backends.NetCDF4DataStore.autoclose.md#xarray.backends.NetCDF4DataStore.autoclose) | | | [`backends.NetCDF4DataStore.ds`](generated/xarray.backends.NetCDF4DataStore.ds.md#xarray.backends.NetCDF4DataStore.ds) | | | [`backends.NetCDF4DataStore.format`](generated/xarray.backends.NetCDF4DataStore.format.md#xarray.backends.NetCDF4DataStore.format) | | | [`backends.NetCDF4DataStore.is_remote`](generated/xarray.backends.NetCDF4DataStore.is_remote.md#xarray.backends.NetCDF4DataStore.is_remote) | | | [`backends.NetCDF4DataStore.lock`](generated/xarray.backends.NetCDF4DataStore.lock.md#xarray.backends.NetCDF4DataStore.lock) | | | [`backends.NetCDF4BackendEntrypoint.description`](generated/xarray.backends.NetCDF4BackendEntrypoint.description.md#xarray.backends.NetCDF4BackendEntrypoint.description) | | | [`backends.NetCDF4BackendEntrypoint.url`](generated/xarray.backends.NetCDF4BackendEntrypoint.url.md#xarray.backends.NetCDF4BackendEntrypoint.url) | | | [`backends.NetCDF4BackendEntrypoint.guess_can_open`](generated/xarray.backends.NetCDF4BackendEntrypoint.guess_can_open.md#xarray.backends.NetCDF4BackendEntrypoint.guess_can_open)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.NetCDF4BackendEntrypoint.open_dataset`](generated/xarray.backends.NetCDF4BackendEntrypoint.open_dataset.md#xarray.backends.NetCDF4BackendEntrypoint.open_dataset)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.H5NetCDFStore.autoclose`](generated/xarray.backends.H5NetCDFStore.autoclose.md#xarray.backends.H5NetCDFStore.autoclose) | | | [`backends.H5NetCDFStore.close`](generated/xarray.backends.H5NetCDFStore.close.md#xarray.backends.H5NetCDFStore.close)(\*\*kwargs) | | | [`backends.H5NetCDFStore.encode`](generated/xarray.backends.H5NetCDFStore.encode.md#xarray.backends.H5NetCDFStore.encode)(variables, ...) | Encode the variables and attributes in this store | | [`backends.H5NetCDFStore.encode_attribute`](generated/xarray.backends.H5NetCDFStore.encode_attribute.md#xarray.backends.H5NetCDFStore.encode_attribute)(a) | encode one attribute | | [`backends.H5NetCDFStore.encode_variable`](generated/xarray.backends.H5NetCDFStore.encode_variable.md#xarray.backends.H5NetCDFStore.encode_variable)(variable) | encode one variable | | [`backends.H5NetCDFStore.format`](generated/xarray.backends.H5NetCDFStore.format.md#xarray.backends.H5NetCDFStore.format) | | | [`backends.H5NetCDFStore.get_attrs`](generated/xarray.backends.H5NetCDFStore.get_attrs.md#xarray.backends.H5NetCDFStore.get_attrs)() | | | [`backends.H5NetCDFStore.get_dimensions`](generated/xarray.backends.H5NetCDFStore.get_dimensions.md#xarray.backends.H5NetCDFStore.get_dimensions)() | | | [`backends.H5NetCDFStore.get_encoding`](generated/xarray.backends.H5NetCDFStore.get_encoding.md#xarray.backends.H5NetCDFStore.get_encoding)() | | | [`backends.H5NetCDFStore.get_variables`](generated/xarray.backends.H5NetCDFStore.get_variables.md#xarray.backends.H5NetCDFStore.get_variables)() | | | [`backends.H5NetCDFStore.is_remote`](generated/xarray.backends.H5NetCDFStore.is_remote.md#xarray.backends.H5NetCDFStore.is_remote) | | | [`backends.H5NetCDFStore.load`](generated/xarray.backends.H5NetCDFStore.load.md#xarray.backends.H5NetCDFStore.load)() | This loads the variables and attributes simultaneously. | | [`backends.H5NetCDFStore.lock`](generated/xarray.backends.H5NetCDFStore.lock.md#xarray.backends.H5NetCDFStore.lock) | | | [`backends.H5NetCDFStore.open`](generated/xarray.backends.H5NetCDFStore.open.md#xarray.backends.H5NetCDFStore.open)(filename[, ...]) | | | [`backends.H5NetCDFStore.open_store_variable`](generated/xarray.backends.H5NetCDFStore.open_store_variable.md#xarray.backends.H5NetCDFStore.open_store_variable)(...) | | | [`backends.H5NetCDFStore.prepare_variable`](generated/xarray.backends.H5NetCDFStore.prepare_variable.md#xarray.backends.H5NetCDFStore.prepare_variable)(...) | | | [`backends.H5NetCDFStore.set_attribute`](generated/xarray.backends.H5NetCDFStore.set_attribute.md#xarray.backends.H5NetCDFStore.set_attribute)(key, value) | | | [`backends.H5NetCDFStore.set_attributes`](generated/xarray.backends.H5NetCDFStore.set_attributes.md#xarray.backends.H5NetCDFStore.set_attributes)(attributes) | This provides a centralized method to set the dataset attributes on the data store. | | [`backends.H5NetCDFStore.set_dimension`](generated/xarray.backends.H5NetCDFStore.set_dimension.md#xarray.backends.H5NetCDFStore.set_dimension)(name, ...) | | | [`backends.H5NetCDFStore.set_dimensions`](generated/xarray.backends.H5NetCDFStore.set_dimensions.md#xarray.backends.H5NetCDFStore.set_dimensions)(variables) | This provides a centralized method to set the dimensions on the data store. | | [`backends.H5NetCDFStore.set_variable`](generated/xarray.backends.H5NetCDFStore.set_variable.md#xarray.backends.H5NetCDFStore.set_variable)(k, v) | | | [`backends.H5NetCDFStore.set_variables`](generated/xarray.backends.H5NetCDFStore.set_variables.md#xarray.backends.H5NetCDFStore.set_variables)(...[, ...]) | This provides a centralized method to set the variables on the data store. | | [`backends.H5NetCDFStore.store`](generated/xarray.backends.H5NetCDFStore.store.md#xarray.backends.H5NetCDFStore.store)(variables, ...) | Top level method for putting data on this store, this method: | | [`backends.H5NetCDFStore.store_dataset`](generated/xarray.backends.H5NetCDFStore.store_dataset.md#xarray.backends.H5NetCDFStore.store_dataset)(dataset) | in stores, variables are all variables AND coordinates in xarray.Dataset variables are variables NOT coordinates, so here we pass the whole dataset in instead of doing dataset.variables | | [`backends.H5NetCDFStore.sync`](generated/xarray.backends.H5NetCDFStore.sync.md#xarray.backends.H5NetCDFStore.sync)() | Write all buffered data to disk. | | [`backends.H5NetCDFStore.ds`](generated/xarray.backends.H5NetCDFStore.ds.md#xarray.backends.H5NetCDFStore.ds) | | | [`backends.H5netcdfBackendEntrypoint.description`](generated/xarray.backends.H5netcdfBackendEntrypoint.description.md#xarray.backends.H5netcdfBackendEntrypoint.description) | | | [`backends.H5netcdfBackendEntrypoint.url`](generated/xarray.backends.H5netcdfBackendEntrypoint.url.md#xarray.backends.H5netcdfBackendEntrypoint.url) | | | [`backends.H5netcdfBackendEntrypoint.guess_can_open`](generated/xarray.backends.H5netcdfBackendEntrypoint.guess_can_open.md#xarray.backends.H5netcdfBackendEntrypoint.guess_can_open)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.H5netcdfBackendEntrypoint.open_dataset`](generated/xarray.backends.H5netcdfBackendEntrypoint.open_dataset.md#xarray.backends.H5netcdfBackendEntrypoint.open_dataset)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.PydapDataStore.close`](generated/xarray.backends.PydapDataStore.close.md#xarray.backends.PydapDataStore.close)() | | | [`backends.PydapDataStore.get_attrs`](generated/xarray.backends.PydapDataStore.get_attrs.md#xarray.backends.PydapDataStore.get_attrs)() | Remove any opendap specific attributes | | [`backends.PydapDataStore.get_dimensions`](generated/xarray.backends.PydapDataStore.get_dimensions.md#xarray.backends.PydapDataStore.get_dimensions)() | | | [`backends.PydapDataStore.get_encoding`](generated/xarray.backends.PydapDataStore.get_encoding.md#xarray.backends.PydapDataStore.get_encoding)() | | | [`backends.PydapDataStore.get_variables`](generated/xarray.backends.PydapDataStore.get_variables.md#xarray.backends.PydapDataStore.get_variables)() | | | [`backends.PydapDataStore.load`](generated/xarray.backends.PydapDataStore.load.md#xarray.backends.PydapDataStore.load)() | This loads the variables and attributes simultaneously. | | [`backends.PydapDataStore.open`](generated/xarray.backends.PydapDataStore.open.md#xarray.backends.PydapDataStore.open)(url[, group, ...]) | | | [`backends.PydapDataStore.open_store_variable`](generated/xarray.backends.PydapDataStore.open_store_variable.md#xarray.backends.PydapDataStore.open_store_variable)(var) | | | [`backends.PydapBackendEntrypoint.description`](generated/xarray.backends.PydapBackendEntrypoint.description.md#xarray.backends.PydapBackendEntrypoint.description) | | | [`backends.PydapBackendEntrypoint.url`](generated/xarray.backends.PydapBackendEntrypoint.url.md#xarray.backends.PydapBackendEntrypoint.url) | | | [`backends.PydapBackendEntrypoint.guess_can_open`](generated/xarray.backends.PydapBackendEntrypoint.guess_can_open.md#xarray.backends.PydapBackendEntrypoint.guess_can_open)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.PydapBackendEntrypoint.open_dataset`](generated/xarray.backends.PydapBackendEntrypoint.open_dataset.md#xarray.backends.PydapBackendEntrypoint.open_dataset)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.ScipyDataStore.close`](generated/xarray.backends.ScipyDataStore.close.md#xarray.backends.ScipyDataStore.close)() | | | [`backends.ScipyDataStore.encode`](generated/xarray.backends.ScipyDataStore.encode.md#xarray.backends.ScipyDataStore.encode)(variables, ...) | Encode the variables and attributes in this store | | [`backends.ScipyDataStore.encode_attribute`](generated/xarray.backends.ScipyDataStore.encode_attribute.md#xarray.backends.ScipyDataStore.encode_attribute)(a) | encode one attribute | | [`backends.ScipyDataStore.encode_variable`](generated/xarray.backends.ScipyDataStore.encode_variable.md#xarray.backends.ScipyDataStore.encode_variable)(variable) | encode one variable | | [`backends.ScipyDataStore.get_attrs`](generated/xarray.backends.ScipyDataStore.get_attrs.md#xarray.backends.ScipyDataStore.get_attrs)() | | | [`backends.ScipyDataStore.get_dimensions`](generated/xarray.backends.ScipyDataStore.get_dimensions.md#xarray.backends.ScipyDataStore.get_dimensions)() | | | [`backends.ScipyDataStore.get_encoding`](generated/xarray.backends.ScipyDataStore.get_encoding.md#xarray.backends.ScipyDataStore.get_encoding)() | | | [`backends.ScipyDataStore.get_variables`](generated/xarray.backends.ScipyDataStore.get_variables.md#xarray.backends.ScipyDataStore.get_variables)() | | | [`backends.ScipyDataStore.load`](generated/xarray.backends.ScipyDataStore.load.md#xarray.backends.ScipyDataStore.load)() | This loads the variables and attributes simultaneously. | | [`backends.ScipyDataStore.open_store_variable`](generated/xarray.backends.ScipyDataStore.open_store_variable.md#xarray.backends.ScipyDataStore.open_store_variable)(...) | | | [`backends.ScipyDataStore.prepare_variable`](generated/xarray.backends.ScipyDataStore.prepare_variable.md#xarray.backends.ScipyDataStore.prepare_variable)(...) | | | [`backends.ScipyDataStore.set_attribute`](generated/xarray.backends.ScipyDataStore.set_attribute.md#xarray.backends.ScipyDataStore.set_attribute)(key, value) | | | [`backends.ScipyDataStore.set_attributes`](generated/xarray.backends.ScipyDataStore.set_attributes.md#xarray.backends.ScipyDataStore.set_attributes)(...) | This provides a centralized method to set the dataset attributes on the data store. | | [`backends.ScipyDataStore.set_dimension`](generated/xarray.backends.ScipyDataStore.set_dimension.md#xarray.backends.ScipyDataStore.set_dimension)(name, ...) | | | [`backends.ScipyDataStore.set_dimensions`](generated/xarray.backends.ScipyDataStore.set_dimensions.md#xarray.backends.ScipyDataStore.set_dimensions)(variables) | This provides a centralized method to set the dimensions on the data store. | | [`backends.ScipyDataStore.set_variable`](generated/xarray.backends.ScipyDataStore.set_variable.md#xarray.backends.ScipyDataStore.set_variable)(k, v) | | | [`backends.ScipyDataStore.set_variables`](generated/xarray.backends.ScipyDataStore.set_variables.md#xarray.backends.ScipyDataStore.set_variables)(...[, ...]) | This provides a centralized method to set the variables on the data store. | | [`backends.ScipyDataStore.store`](generated/xarray.backends.ScipyDataStore.store.md#xarray.backends.ScipyDataStore.store)(variables, ...) | Top level method for putting data on this store, this method: | | [`backends.ScipyDataStore.store_dataset`](generated/xarray.backends.ScipyDataStore.store_dataset.md#xarray.backends.ScipyDataStore.store_dataset)(dataset) | in stores, variables are all variables AND coordinates in xarray.Dataset variables are variables NOT coordinates, so here we pass the whole dataset in instead of doing dataset.variables | | [`backends.ScipyDataStore.sync`](generated/xarray.backends.ScipyDataStore.sync.md#xarray.backends.ScipyDataStore.sync)() | Write all buffered data to disk. | | [`backends.ScipyDataStore.ds`](generated/xarray.backends.ScipyDataStore.ds.md#xarray.backends.ScipyDataStore.ds) | | | [`backends.ScipyBackendEntrypoint.description`](generated/xarray.backends.ScipyBackendEntrypoint.description.md#xarray.backends.ScipyBackendEntrypoint.description) | | | [`backends.ScipyBackendEntrypoint.url`](generated/xarray.backends.ScipyBackendEntrypoint.url.md#xarray.backends.ScipyBackendEntrypoint.url) | | | [`backends.ScipyBackendEntrypoint.guess_can_open`](generated/xarray.backends.ScipyBackendEntrypoint.guess_can_open.md#xarray.backends.ScipyBackendEntrypoint.guess_can_open)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.ScipyBackendEntrypoint.open_dataset`](generated/xarray.backends.ScipyBackendEntrypoint.open_dataset.md#xarray.backends.ScipyBackendEntrypoint.open_dataset)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.ZarrStore.close`](generated/xarray.backends.ZarrStore.close.md#xarray.backends.ZarrStore.close)() | | | [`backends.ZarrStore.encode_attribute`](generated/xarray.backends.ZarrStore.encode_attribute.md#xarray.backends.ZarrStore.encode_attribute)(a) | encode one attribute | | [`backends.ZarrStore.encode_variable`](generated/xarray.backends.ZarrStore.encode_variable.md#xarray.backends.ZarrStore.encode_variable)(variable) | encode one variable | | [`backends.ZarrStore.get_attrs`](generated/xarray.backends.ZarrStore.get_attrs.md#xarray.backends.ZarrStore.get_attrs)() | | | [`backends.ZarrStore.get_dimensions`](generated/xarray.backends.ZarrStore.get_dimensions.md#xarray.backends.ZarrStore.get_dimensions)() | | | [`backends.ZarrStore.get_variables`](generated/xarray.backends.ZarrStore.get_variables.md#xarray.backends.ZarrStore.get_variables)() | | | [`backends.ZarrStore.open_group`](generated/xarray.backends.ZarrStore.open_group.md#xarray.backends.ZarrStore.open_group)(store[, mode, ...]) | | | [`backends.ZarrStore.open_store_variable`](generated/xarray.backends.ZarrStore.open_store_variable.md#xarray.backends.ZarrStore.open_store_variable)(name) | | | [`backends.ZarrStore.set_attributes`](generated/xarray.backends.ZarrStore.set_attributes.md#xarray.backends.ZarrStore.set_attributes)(attributes) | This provides a centralized method to set the dataset attributes on the data store. | | [`backends.ZarrStore.set_dimensions`](generated/xarray.backends.ZarrStore.set_dimensions.md#xarray.backends.ZarrStore.set_dimensions)(variables) | This provides a centralized method to set the dimensions on the data store. | | [`backends.ZarrStore.set_variables`](generated/xarray.backends.ZarrStore.set_variables.md#xarray.backends.ZarrStore.set_variables)(variables, ...) | This provides a centralized method to set the variables on the data store. | | [`backends.ZarrStore.store`](generated/xarray.backends.ZarrStore.store.md#xarray.backends.ZarrStore.store)(variables, attributes) | Top level method for putting data on this store, this method: | | [`backends.ZarrStore.sync`](generated/xarray.backends.ZarrStore.sync.md#xarray.backends.ZarrStore.sync)() | Write all buffered data to disk. | | [`backends.ZarrStore.ds`](generated/xarray.backends.ZarrStore.ds.md#xarray.backends.ZarrStore.ds) | | | [`backends.ZarrBackendEntrypoint.description`](generated/xarray.backends.ZarrBackendEntrypoint.description.md#xarray.backends.ZarrBackendEntrypoint.description) | | | [`backends.ZarrBackendEntrypoint.url`](generated/xarray.backends.ZarrBackendEntrypoint.url.md#xarray.backends.ZarrBackendEntrypoint.url) | | | [`backends.ZarrBackendEntrypoint.guess_can_open`](generated/xarray.backends.ZarrBackendEntrypoint.guess_can_open.md#xarray.backends.ZarrBackendEntrypoint.guess_can_open)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.ZarrBackendEntrypoint.open_dataset`](generated/xarray.backends.ZarrBackendEntrypoint.open_dataset.md#xarray.backends.ZarrBackendEntrypoint.open_dataset)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.StoreBackendEntrypoint.description`](generated/xarray.backends.StoreBackendEntrypoint.description.md#xarray.backends.StoreBackendEntrypoint.description) | | | [`backends.StoreBackendEntrypoint.url`](generated/xarray.backends.StoreBackendEntrypoint.url.md#xarray.backends.StoreBackendEntrypoint.url) | | | [`backends.StoreBackendEntrypoint.guess_can_open`](generated/xarray.backends.StoreBackendEntrypoint.guess_can_open.md#xarray.backends.StoreBackendEntrypoint.guess_can_open)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.StoreBackendEntrypoint.open_dataset`](generated/xarray.backends.StoreBackendEntrypoint.open_dataset.md#xarray.backends.StoreBackendEntrypoint.open_dataset)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.FileManager.acquire`](generated/xarray.backends.FileManager.acquire.md#xarray.backends.FileManager.acquire)([needs_lock]) | Acquire the file object from this manager. | | [`backends.FileManager.acquire_context`](generated/xarray.backends.FileManager.acquire_context.md#xarray.backends.FileManager.acquire_context)([...]) | Context manager for acquiring a file. | | [`backends.FileManager.close`](generated/xarray.backends.FileManager.close.md#xarray.backends.FileManager.close)([needs_lock]) | Close the file object associated with this manager, if needed. | | [`backends.CachingFileManager.acquire`](generated/xarray.backends.CachingFileManager.acquire.md#xarray.backends.CachingFileManager.acquire)([needs_lock]) | Acquire a file object from the manager. | | [`backends.CachingFileManager.acquire_context`](generated/xarray.backends.CachingFileManager.acquire_context.md#xarray.backends.CachingFileManager.acquire_context)([...]) | Context manager for acquiring a file. | | [`backends.CachingFileManager.close`](generated/xarray.backends.CachingFileManager.close.md#xarray.backends.CachingFileManager.close)([needs_lock]) | Explicitly close any associated file object (if necessary). | | [`backends.DummyFileManager.acquire`](generated/xarray.backends.DummyFileManager.acquire.md#xarray.backends.DummyFileManager.acquire)([needs_lock]) | Acquire the file object from this manager. | | [`backends.DummyFileManager.acquire_context`](generated/xarray.backends.DummyFileManager.acquire_context.md#xarray.backends.DummyFileManager.acquire_context)([...]) | Context manager for acquiring a file. | | [`backends.DummyFileManager.close`](generated/xarray.backends.DummyFileManager.close.md#xarray.backends.DummyFileManager.close)([needs_lock]) | Close the file object associated with this manager, if needed. | | [`backends.BackendArray`](generated/xarray.backends.BackendArray.md#xarray.backends.BackendArray)() | | | [`backends.BackendEntrypoint.guess_can_open`](generated/xarray.backends.BackendEntrypoint.guess_can_open.md#xarray.backends.BackendEntrypoint.guess_can_open)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`backends.BackendEntrypoint.open_dataset`](generated/xarray.backends.BackendEntrypoint.open_dataset.md#xarray.backends.BackendEntrypoint.open_dataset)(...) | Backend open_dataset method used by Xarray in [`open_dataset()`](generated/xarray.open_dataset.md#xarray.open_dataset). | | [`core.indexing.IndexingSupport`](generated/xarray.core.indexing.IndexingSupport.md#xarray.core.indexing.IndexingSupport)(\*values) | | | [`core.indexing.explicit_indexing_adapter`](generated/xarray.core.indexing.explicit_indexing_adapter.md#xarray.core.indexing.explicit_indexing_adapter)(key, ...) | Support explicit indexing by delegating to a raw indexing method. | | [`core.indexing.BasicIndexer`](generated/xarray.core.indexing.BasicIndexer.md#xarray.core.indexing.BasicIndexer)(key) | Tuple for basic indexing. | | [`core.indexing.OuterIndexer`](generated/xarray.core.indexing.OuterIndexer.md#xarray.core.indexing.OuterIndexer)(key) | Tuple for outer/orthogonal indexing. | | [`core.indexing.VectorizedIndexer`](generated/xarray.core.indexing.VectorizedIndexer.md#xarray.core.indexing.VectorizedIndexer)(key) | Tuple for vectorized indexing. | | [`core.indexing.LazilyIndexedArray`](generated/xarray.core.indexing.LazilyIndexedArray.md#xarray.core.indexing.LazilyIndexedArray)(array[, key]) | Wrap an array to make basic and outer indexing lazy. | | [`core.indexing.LazilyVectorizedIndexedArray`](generated/xarray.core.indexing.LazilyVectorizedIndexedArray.md#xarray.core.indexing.LazilyVectorizedIndexedArray)(...) | Wrap an array to make vectorized indexing lazy. | | [`conventions.decode_cf_variables`](generated/xarray.conventions.decode_cf_variables.md#xarray.conventions.decode_cf_variables)(variables, ...) | Decode several CF encoded variables. | | [`coding.variables.CFMaskCoder`](generated/xarray.coding.variables.CFMaskCoder.md#xarray.coding.variables.CFMaskCoder)([decode_times, ...]) | Mask or unmask fill values according to CF conventions. | | [`coding.variables.CFScaleOffsetCoder`](generated/xarray.coding.variables.CFScaleOffsetCoder.md#xarray.coding.variables.CFScaleOffsetCoder)([...]) | Scale and offset variables according to CF conventions. | | [`coding.strings.CharacterArrayCoder`](generated/xarray.coding.strings.CharacterArrayCoder.md#xarray.coding.strings.CharacterArrayCoder)() | Transforms between arrays containing bytes and character arrays. | | [`coding.strings.EncodedStringCoder`](generated/xarray.coding.strings.EncodedStringCoder.md#xarray.coding.strings.EncodedStringCoder)([...]) | Transforms between unicode strings and fixed-width UTF-8 bytes. | | [`coding.times.CFTimedeltaCoder`](generated/xarray.coding.times.CFTimedeltaCoder.md#xarray.coding.times.CFTimedeltaCoder)([time_unit, ...]) | Coder for CF Timedelta coding. | | [`coding.times.CFDatetimeCoder`](generated/xarray.coding.times.CFDatetimeCoder.md#xarray.coding.times.CFDatetimeCoder)([use_cftime, ...]) | Coder for CF Datetime coding. | | [`groupers.Grouper`](generated/xarray.groupers.Grouper.md#xarray.groupers.Grouper)() | Abstract base class for Grouper objects that allow specializing GroupBy instructions. | | [`groupers.Resampler`](generated/xarray.groupers.Resampler.md#xarray.groupers.Resampler)() | Abstract base class for Grouper objects that allow specializing resampling-type GroupBy instructions. | | [`groupers.EncodedGroups`](generated/xarray.groupers.EncodedGroups.md#xarray.groupers.EncodedGroups)(codes, full_index[, ...]) | Dataclass for storing intermediate values for GroupBy operation. | # api.html.md # API reference This page provides an auto-generated summary of xarray’s API. For more details and examples, refer to the relevant chapters in the main part of the documentation. See also: [What parts of xarray are considered public API?](get-help/faq.md#public-api) and [How stable is Xarray’s API?](get-help/faq.md#api-stability). * [Top-level functions](api/top-level.md) * [Dataset](api/dataset.md) * [DataArray](api/dataarray.md) * [DataTree](api/datatree.md) * [Coordinates](api/coordinates.md) * [Indexes](api/indexes.md) * [Universal functions](api/ufuncs.md) * [IO / Conversion](api/io.md) * [Encoding/Decoding](api/encoding.md) * [Plotting](api/plotting.md) * [GroupBy objects](api/groupby.md) * [Rolling objects](api/rolling.md) * [Coarsen objects](api/coarsen.md) * [Exponential rolling objects](api/rolling-exp.md) * [Weighted objects](api/weighted.md) * [Resample objects](api/resample.md) * [Accessors](api/accessors.md) * [Tutorial](api/tutorial.md) * [Testing](api/testing.md) * [Hypothesis Testing Strategies](api/testing.md#hypothesis-testing-strategies) * [Backends](api/backends.md) * [Exceptions](api/exceptions.md) * [Advanced API](api/advanced.md) * [Deprecated / Pending Deprecation](api/deprecated.md) # apply_ufunc_vectorize_1d.html.md You can run this notebook in a [live session](https://mybinder.org/v2/gh/pydata/xarray/doc/examples/main?urlpath=lab/tree/doc/examples/apply_ufunc_vectorize_1d.ipynb) [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/pydata/xarray/main?urlpath=lab/tree/doc/examples/apply_ufunc_vectorize_1d.ipynb) or view it [on Github](https://github.com/pydata/xarray/blob/main/doc/examples/apply_ufunc_vectorize_1d.ipynb). # Applying unvectorized functions with `apply_ufunc` This example will illustrate how to conveniently apply an unvectorized function `func` to xarray objects using `apply_ufunc`. `func` expects 1D numpy arrays and returns a 1D numpy array. Our goal is to conveniently apply this function along a dimension of xarray objects that may or may not wrap dask arrays with a signature. We will illustrate this using `np.interp`: ```none Signature: np.interp(x, xp, fp, left=None, right=None, period=None) Docstring: One-dimensional linear interpolation. Returns the one-dimensional piecewise linear interpolant to a function with given discrete data points (`xp`, `fp`), evaluated at `x`. ``` and write an `xr_interp` function with signature ```none xr_interp(xarray_object, dimension_name, new_coordinate_to_interpolate_to) ``` ## Load data First let’s load an example dataset The function we will apply is `np.interp` which expects 1D numpy arrays. This functionality is already implemented in xarray so we use that capability to make sure we are not making mistakes. Let’s define a function that works with one vector of data along `lat` at a time. ## No errors are raised so our interpolation is working. This function consumes and returns numpy arrays, which means we need to do a lot of work to convert the result back to an xarray object with meaningful metadata. This is where `apply_ufunc` is very useful. ## `apply_ufunc` ```none Apply a vectorized function for unlabeled arrays on xarray objects. The function will be mapped over the data variable(s) of the input arguments using xarray’s standard rules for labeled computation, including alignment, broadcasting, looping over GroupBy/Dataset variables, and merging of coordinates. ``` `apply_ufunc` has many capabilities but for simplicity this example will focus on the common task of vectorizing 1D functions over nD xarray objects. We will iteratively build up the right set of arguments to `apply_ufunc` and read through many error messages in doing so. `apply_ufunc` needs to know a lot of information about what our function does so that it can reconstruct the outputs. In this case, the size of dimension lat has changed and we need to explicitly specify that this will happen. xarray helpfully tells us that we need to specify the kwarg `exclude_dims`. ## `exclude_dims` ```none exclude_dims : set, optional Core dimensions on the inputs to exclude from alignment and broadcasting entirely. Any input coordinates along these dimensions will be dropped. Each excluded dimension must also appear in ``input_core_dims`` for at least one argument. Only dimensions listed here are allowed to change size between input and output objects. ``` ## Core dimensions Core dimensions are central to using `apply_ufunc`. In our case, our function expects to receive a 1D vector along `lat` — this is the dimension that is “core” to the function’s functionality. Multiple core dimensions are possible. `apply_ufunc` needs to know which dimensions of each variable are core dimensions. ```none input_core_dims : Sequence[Sequence], optional List of the same length as ``args`` giving the list of core dimensions on each input argument that should not be broadcast. By default, we assume there are no core dimensions on any input arguments. For example, ``input_core_dims=[[], ['time']]`` indicates that all dimensions on the first argument and all dimensions other than 'time' on the second argument should be broadcast. Core dimensions are automatically moved to the last axes of input variables before applying ``func``, which facilitates using NumPy style generalized ufuncs [2]_. output_core_dims : List[tuple], optional List of the same length as the number of output arguments from ``func``, giving the list of core dimensions on each output that were not broadcast on the inputs. By default, we assume that ``func`` outputs exactly one array, with axes corresponding to each broadcast dimension. Core dimensions are assumed to appear as the last dimensions of each output in the provided order. ``` Next we specify `"lat"` as `input_core_dims` on both `air` and `air.lat` xarray is telling us that it expected to receive back a numpy array with 0 dimensions but instead received an array with 1 dimension corresponding to `newlat`. We can fix this by specifying `output_core_dims` Finally we get some output! Let’s check that this is right No errors are raised so it is right! ## Vectorization with `np.vectorize` Now our function currently only works on one vector of data which is not so useful given our 3D dataset. Let’s try passing the whole dataset. We add a `print` statement so we can see what our function receives. That’s a hard-to-interpret error but our `print` call helpfully printed the shapes of the input data: ```none data: (10, 53, 25) | x: (25,) | xi: (100,) ``` We see that `air` has been passed as a 3D numpy array which is not what `np.interp` expects. Instead we want loop over all combinations of `lon` and `time`; and apply our function to each corresponding vector of data along `lat`. `apply_ufunc` makes this easy by specifying `vectorize=True`: ```none vectorize : bool, optional If True, then assume ``func`` only takes arrays defined over core dimensions as input and vectorize it automatically with :py:func:`numpy.vectorize`. This option exists for convenience, but is almost always slower than supplying a pre-vectorized function. Using this option requires NumPy version 1.12 or newer. ``` Also see the documentation for `np.vectorize`: [https://docs.scipy.org/doc/numpy/reference/generated/numpy.vectorize.html](https://docs.scipy.org/doc/numpy/reference/generated/numpy.vectorize.html). Most importantly ```none The vectorize function is provided primarily for convenience, not for performance. The implementation is essentially a for loop. ``` This unfortunately is another cryptic error from numpy. Notice that `newlat` is not an xarray object. Let’s add a dimension name `new_lat` and modify the call. Note this cannot be `lat` because xarray expects dimensions to be the same size (or broadcastable) among all inputs. `output_core_dims` needs to be modified appropriately. We’ll manually rename `new_lat` back to `lat` for easy checking. Notice that the printed input shapes are all 1D and correspond to one vector along the `lat` dimension. The result is now an xarray object with coordinate values copied over from `data`. This is why `apply_ufunc` is so convenient; it takes care of a lot of boilerplate necessary to apply functions that consume and produce numpy arrays to xarray objects. One final point: `lat` is now the *last* dimension in `interped`. This is a “property” of core dimensions: they are moved to the end before being sent to `interp1d_np` as was noted in the docstring for `input_core_dims` ```none Core dimensions are automatically moved to the last axes of input variables before applying ``func``, which facilitates using NumPy style generalized ufuncs [2]_. ``` ## Parallelization with dask So far our function can only handle numpy arrays. A real benefit of `apply_ufunc` is the ability to easily parallelize over dask chunks *when needed*. We want to apply this function in a vectorized fashion over each chunk of the dask array. This is possible using dask’s `blockwise`, `map_blocks`, or `apply_gufunc`. Xarray’s `apply_ufunc` wraps dask’s `apply_gufunc` and asking it to map the function over chunks using `apply_gufunc` is as simple as specifying `dask="parallelized"`. With this level of flexibility we need to provide dask with some extra information: 1. `output_dtypes`: dtypes of all returned objects, and 2. `output_sizes`: lengths of any new dimensions. Here we need to specify `output_dtypes` since `apply_ufunc` can infer the size of the new dimension `new_lat` from the argument corresponding to the third element in `input_core_dims`. Here I choose the chunk sizes to illustrate that `np.vectorize` is still applied so that our function receives 1D vectors even though the blocks are 3D. Yay! our function is receiving 1D vectors, so we’ve successfully parallelized applying a 1D function over a block. If you have a distributed dashboard up, you should see computes happening as equality is checked. ## High performance vectorization: gufuncs, numba & guvectorize `np.vectorize` is a very convenient function but is unfortunately slow. It is only marginally faster than writing a for loop in Python and looping. A common way to get around this is to write a base interpolation function that can handle nD arrays in a compiled language like Fortran and then pass that to `apply_ufunc`. Another option is to use the numba package which provides a very convenient `guvectorize` decorator: [https://numba.pydata.org/numba-doc/latest/user/vectorize.html#the-guvectorize-decorator](https://numba.pydata.org/numba-doc/latest/user/vectorize.html#the-guvectorize-decorator) Any decorated function gets compiled and will loop over any non-core dimension in parallel when necessary. We need to specify some extra information: 1. Our function cannot return a variable any more. Instead it must receive a variable (the last argument) whose contents the function will modify. So we change from `def interp1d_np(data, x, xi)` to `def interp1d_np_gufunc(data, x, xi, out)`. Our computed results must be assigned to `out`. All values of `out` must be assigned explicitly. 2. `guvectorize` needs to know the dtypes of the input and output. This is specified in string form as the first argument. Each element of the tuple corresponds to each argument of the function. In this case, we specify `float64` for all inputs and outputs: `"(float64[:], float64[:], float64[:], float64[:])"` corresponding to `data, x, xi, out` 3. Now we need to tell numba the size of the dimensions the function takes as inputs and returns as output i.e. core dimensions. This is done in symbolic form i.e. `data` and `x` are vectors of the same length, say `n`; `xi` and the output `out` have a different length, say `m`. So the second argument is (again as a string) `"(n), (n), (m) -> (m)."` corresponding again to `data, x, xi, out` The warnings are about object-mode compilation relating to the `print` statement. This means we don’t get much speed up: [https://numba.pydata.org/numba-doc/latest/user/performance-tips.html#no-python-mode-vs-object-mode](https://numba.pydata.org/numba-doc/latest/user/performance-tips.html#no-python-mode-vs-object-mode). We’ll keep the `print` statement temporarily to make sure that `guvectorize` acts like we want it to. Yay! Our function is receiving 1D vectors and is working automatically with dask arrays. Finally let’s comment out the print line and wrap everything up in a nice reusable function This technique is generalizable to any 1D function. # area_weighted_temperature.html.md You can run this notebook in a [live session](https://mybinder.org/v2/gh/pydata/xarray/doc/examples/main?urlpath=lab/tree/doc/examples/area_weighted_temperature.ipynb) [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/pydata/xarray/main?urlpath=lab/tree/doc/examples/area_weighted_temperature.ipynb) or view it [on Github](https://github.com/pydata/xarray/blob/main/doc/examples/area_weighted_temperature.ipynb).

Table of Contents

# Compare weighted and unweighted mean temperature Author: [Mathias Hauser](https://github.com/mathause/) We use the `air_temperature` example dataset to calculate the area-weighted temperature over its domain. This dataset has a regular latitude/ longitude grid, thus the grid cell area decreases towards the pole. For this grid we can use the cosine of the latitude as proxy for the grid cell area. ## Data Load the data, convert to celsius, and resample to daily values Plot the first timestep: ## Creating weights For a rectangular grid the cosine of the latitude is proportional to the grid cell area. ## Weighted mean ## Plot: comparison with unweighted mean Note how the weighted mean temperature is higher than the unweighted. # backends.html.md # Backends | [`backends.BackendArray`](../generated/xarray.backends.BackendArray.md#xarray.backends.BackendArray)() | | |-----------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [`backends.BackendEntrypoint`](../generated/xarray.backends.BackendEntrypoint.md#xarray.backends.BackendEntrypoint)() | `BackendEntrypoint` is a class container and it is the main interface for the backend plugins, see [BackendEntrypoint subclassing](../internals/how-to-add-new-backend.md#rst-backend-entrypoint). | | [`backends.list_engines`](../generated/xarray.backends.list_engines.md#xarray.backends.list_engines)() | Return a dictionary of available engines and their BackendEntrypoint objects. | | [`backends.refresh_engines`](../generated/xarray.backends.refresh_engines.md#xarray.backends.refresh_engines)() | Refreshes the backend engines based on installed packages. | These backends provide a low-level interface for lazily loading data from external file-formats or protocols, and can be manually invoked to create arguments for the `load_store` and `dump_to_store` Dataset methods: | [`backends.NetCDF4DataStore`](../generated/xarray.backends.NetCDF4DataStore.md#xarray.backends.NetCDF4DataStore)(manager[, group, ...]) | Store for reading and writing data via the Python-NetCDF4 library. | |-----------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------| | [`backends.H5NetCDFStore`](../generated/xarray.backends.H5NetCDFStore.md#xarray.backends.H5NetCDFStore)(manager[, group, ...]) | Store for reading and writing data via h5netcdf | | [`backends.PydapDataStore`](../generated/xarray.backends.PydapDataStore.md#xarray.backends.PydapDataStore)(dataset[, group, ...]) | Store for accessing OpenDAP datasets with pydap. | | [`backends.ScipyDataStore`](../generated/xarray.backends.ScipyDataStore.md#xarray.backends.ScipyDataStore)(filename_or_obj[, ...]) | Store for reading and writing data via scipy.io.netcdf_file. | | [`backends.ZarrStore`](../generated/xarray.backends.ZarrStore.md#xarray.backends.ZarrStore)(zarr_group[, mode, ...]) | Store for reading and writing data via zarr | | [`backends.FileManager`](../generated/xarray.backends.FileManager.md#xarray.backends.FileManager)() | Manager for acquiring and closing a file object. | | [`backends.CachingFileManager`](../generated/xarray.backends.CachingFileManager.md#xarray.backends.CachingFileManager)(opener, \*args[, ...]) | Wrapper for automatically opening and closing file objects. | | [`backends.DummyFileManager`](../generated/xarray.backends.DummyFileManager.md#xarray.backends.DummyFileManager)(value, \*[, close, ...]) | FileManager that simply wraps an open file in the FileManager interface. | These BackendEntrypoints provide a basic interface to the most commonly used filetypes in the xarray universe. | [`backends.NetCDF4BackendEntrypoint`](../generated/xarray.backends.NetCDF4BackendEntrypoint.md#xarray.backends.NetCDF4BackendEntrypoint)() | Backend for netCDF files based on the netCDF4 package. | |-----------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------| | [`backends.H5netcdfBackendEntrypoint`](../generated/xarray.backends.H5netcdfBackendEntrypoint.md#xarray.backends.H5netcdfBackendEntrypoint)() | Backend for netCDF files based on the h5netcdf package. | | [`backends.PydapBackendEntrypoint`](../generated/xarray.backends.PydapBackendEntrypoint.md#xarray.backends.PydapBackendEntrypoint)() | Backend for steaming datasets over the internet using the Data Access Protocol, also known as DODS or OPeNDAP based on the pydap package. | | [`backends.ScipyBackendEntrypoint`](../generated/xarray.backends.ScipyBackendEntrypoint.md#xarray.backends.ScipyBackendEntrypoint)() | Backend for netCDF files based on the scipy package. | | [`backends.StoreBackendEntrypoint`](../generated/xarray.backends.StoreBackendEntrypoint.md#xarray.backends.StoreBackendEntrypoint)() | | | [`backends.ZarrBackendEntrypoint`](../generated/xarray.backends.ZarrBackendEntrypoint.md#xarray.backends.ZarrBackendEntrypoint)() | Backend for ".zarr" files based on the zarr package. | # blank_template.html.md You can run this notebook in a [live session](https://mybinder.org/v2/gh/pydata/xarray/doc/examples/main?urlpath=lab/tree/doc/examples/blank_template.ipynb) [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/pydata/xarray/main?urlpath=lab/tree/doc/examples/blank_template.ipynb) or view it [on Github](https://github.com/pydata/xarray/blob/main/doc/examples/blank_template.ipynb). # Blank template Use this notebook from Binder to test an issue or reproduce a bug report # chunked-arrays.html.md # Alternative chunked array types #### WARNING This is a *highly* experimental feature. Please report any bugs or other difficulties on [xarray’s issue tracker](https://github.com/pydata/xarray/issues). In particular see discussion on [xarray issue #6807](https://github.com/pydata/xarray/issues/6807) Xarray can wrap chunked dask arrays (see [Parallel Computing with Dask](../user-guide/dask.md#dask)), but can also wrap any other chunked array type that exposes the correct interface. This allows us to support using other frameworks for distributed and out-of-core processing, with user code still written as xarray commands. In particular xarray also supports wrapping [`cubed.Array`](https://cubed-dev.github.io/cubed/generated/cubed.Array.html#cubed.Array) objects (see [Cubed’s documentation](https://cubed-dev.github.io/cubed/) and the [cubed-xarray package](https://github.com/xarray-contrib/cubed-xarray)). The basic idea is that by wrapping an array that has an explicit notion of `.chunks`, xarray can expose control over the choice of chunking scheme to users via methods like [`DataArray.chunk()`](../generated/xarray.DataArray.chunk.md#xarray.DataArray.chunk) whilst the wrapped array actually implements the handling of processing all of the chunks. ## Chunked array methods and “core operations” A chunked array needs to meet all the [requirements for normal duck arrays](duck-arrays-integration.md#internals-duckarrays-requirements), but must also implement additional features. Chunked arrays have additional attributes and methods, such as `.chunks` and `.rechunk`. Furthermore, Xarray dispatches chunk-aware computations across one or more chunked arrays using special functions known as “core operations”. Examples include `map_blocks`, `blockwise`, and `apply_gufunc`. The core operations are generalizations of functions first implemented in `dask.array`. The implementation of these functions is specific to the type of arrays passed to them. For example, when applying the `map_blocks` core operation, [`dask.array.Array`](https://docs.dask.org/en/latest/generated/dask.array.Array.html#dask.array.Array) objects must be processed by [`dask.array.map_blocks()`](https://docs.dask.org/en/latest/generated/dask.array.map_blocks.html#dask.array.map_blocks), whereas [`cubed.Array`](https://cubed-dev.github.io/cubed/generated/cubed.Array.html#cubed.Array) objects must be processed by [`cubed.map_blocks()`](https://cubed-dev.github.io/cubed/generated/cubed.map_blocks.html#cubed.map_blocks). In order to use the correct implementation of a core operation for the array type encountered, xarray dispatches to the corresponding subclass of [`ChunkManagerEntrypoint`](#xarray.namedarray.parallelcompat.ChunkManagerEntrypoint), also known as a “Chunk Manager”. Therefore **a full list of the operations that need to be defined is set by the API of the** [`ChunkManagerEntrypoint`](#xarray.namedarray.parallelcompat.ChunkManagerEntrypoint) **abstract base class**. Note that chunked array methods are also currently dispatched using this class. Chunked array creation is also handled by this class. As chunked array objects have a one-to-one correspondence with in-memory numpy arrays, it should be possible to create a chunked array from a numpy array by passing the desired chunking pattern to an implementation of `from_array``. #### NOTE The [`ChunkManagerEntrypoint`](#xarray.namedarray.parallelcompat.ChunkManagerEntrypoint) abstract base class is mostly just acting as a namespace for containing the chunked-aware function primitives. Ideally in the future we would have an API standard for chunked array types which codified this structure, making the entrypoint system unnecessary. ### *class* xarray.namedarray.parallelcompat.ChunkManagerEntrypoint Interface between a particular parallel computing framework and xarray. This abstract base class must be subclassed by libraries implementing chunked array types, and registered via the `chunkmanagers` entrypoint. Abstract methods on this class must be implemented, whereas non-abstract methods are only required in order to enable a subset of xarray functionality, and by default will raise a `NotImplementedError` if called. #### array_cls Type of the array class this parallel computing framework provides. Parallel frameworks need to provide an array class that supports the array API standard. This attribute is used for array instance type checking at runtime. * **Type:** `type[xarray.namedarray.parallelcompat.T_ChunkedArray]` #### *abstract* apply_gufunc(func, signature, \*args, axes=None, keepdims=False, output_dtypes=None, vectorize=None, \*\*kwargs) Apply a generalized ufunc or similar python function to arrays. `signature` determines if the function consumes or produces core dimensions. The remaining dimensions in given input arrays (`*args`) are considered loop dimensions and are required to broadcast naturally against each other. In other terms, this function is like `np.vectorize`, but for the blocks of chunked arrays. If the function itself shall also be vectorized use `vectorize=True` for convenience. Called inside `xarray.apply_ufunc`, which is called internally for most xarray operations. Therefore this method must be implemented for the vast majority of xarray computations to be supported. * **Parameters:** * **func** ([`callable()`](https://docs.python.org/3/library/functions.html#callable)) – Function to call like `func(*args, **kwargs)` on input arrays (`*args`) that returns an array or tuple of arrays. If multiple arguments with non-matching dimensions are supplied, this function is expected to vectorize (broadcast) over axes of positional arguments in the style of NumPy universal functions [1](#id3) (if this is not the case, set `vectorize=True`). If this function returns multiple outputs, `output_core_dims` has to be set as well. * **signature** ([`string`](https://docs.python.org/3/library/stdtypes.html#str)) – Specifies what core dimensions are consumed and produced by `func`. According to the specification of numpy.gufunc signature [2](#id4) * **\*args** (`numeric`) – Input arrays or scalars to the callable function. * **axes** (`List` of `tuples`, *optional*, `keyword only`) – A list of tuples with indices of axes a generalized ufunc should operate on. For instance, for a signature of `"(i,j),(j,k)->(i,k)"` appropriate for matrix multiplication, the base elements are two-dimensional matrices and these are taken to be stored in the two last axes of each argument. The corresponding axes keyword would be `[(-2, -1), (-2, -1), (-2, -1)]`. For simplicity, for generalized ufuncs that operate on 1-dimensional arrays (vectors), a single integer is accepted instead of a single-element tuple, and for generalized ufuncs for which all outputs are scalars, the output tuples can be omitted. * **keepdims** ([`bool`](https://docs.python.org/3/library/functions.html#bool), *optional*, `keyword only`) – If this is set to True, axes which are reduced over will be left in the result as a dimension with size one, so that the result will broadcast correctly against the inputs. This option can only be used for generalized ufuncs that operate on inputs that all have the same number of core dimensions and with outputs that have no core dimensions , i.e., with signatures like `"(i),(i)->()"` or `"(m,m)->()"`. If used, the location of the dimensions in the output can be controlled with axes and axis. * **output_dtypes** (`Optional`, [`dtype`](https://numpy.org/doc/stable/reference/generated/numpy.dtype.html#numpy.dtype) or [`list`](https://docs.python.org/3/library/stdtypes.html#list) of `dtypes`, `keyword only`) – Valid numpy dtype specification or list thereof. If not given, a call of `func` with a small set of data is performed in order to try to automatically determine the output dtypes. * **vectorize** ([`bool`](https://docs.python.org/3/library/functions.html#bool), `keyword only`) – If set to `True`, `np.vectorize` is applied to `func` for convenience. Defaults to `False`. * **\*\*kwargs** ([`dict`](https://docs.python.org/3/library/stdtypes.html#dict)) – Extra keyword arguments to pass to func * **Returns:** `Single chunked array` or [`tuple`](https://docs.python.org/3/library/stdtypes.html#tuple) of `chunked arrays` #### SEE ALSO [`dask.array.gufunc.apply_gufunc`](https://docs.dask.org/en/latest/generated/dask.array.gufunc.apply_gufunc.html#dask.array.gufunc.apply_gufunc), [`cubed.apply_gufunc`](https://cubed-dev.github.io/cubed/generated/cubed.apply_gufunc.html#cubed.apply_gufunc) ### References * **[1]** [https://docs.scipy.org/doc/numpy/reference/ufuncs.html](https://docs.scipy.org/doc/numpy/reference/ufuncs.html) * **[2]** [https://docs.scipy.org/doc/numpy/reference/c-api/generalized-ufuncs.html](https://docs.scipy.org/doc/numpy/reference/c-api/generalized-ufuncs.html) #### *property* array_api Return the array_api namespace following the python array API standard. See [https://data-apis.org/array-api/latest/](https://data-apis.org/array-api/latest/) . Currently used to access the array API function `full_like`, which is called within the xarray constructors `xarray.full_like`, `xarray.ones_like`, `xarray.zeros_like`, etc. #### SEE ALSO `dask.array`, `cubed.array_api` #### blockwise(func, out_ind, \*args, adjust_chunks=None, new_axes=None, align_arrays=True, \*\*kwargs) Tensor operation: Generalized inner and outer products. A broad class of blocked algorithms and patterns can be specified with a concise multi-index notation. The `blockwise` function applies an in-memory function across multiple blocks of multiple inputs in a variety of ways. Many chunked array operations are special cases of blockwise including elementwise, broadcasting, reductions, tensordot, and transpose. Currently only called explicitly in xarray when performing multidimensional interpolation. * **Parameters:** * **func** ([`callable()`](https://docs.python.org/3/library/functions.html#callable)) – Function to apply to individual tuples of blocks * **out_ind** ([iterable](https://docs.python.org/3/glossary.html#term-iterable)) – Block pattern of the output, something like ‘ijk’ or (1, 2, 3) * **\*args** ([sequence](https://docs.python.org/3/glossary.html#term-sequence) of `Array`, `index pairs`) – You may also pass literal arguments, accompanied by None index e.g. (x, ‘ij’, y, ‘jk’, z, ‘i’, some_literal, None) * **\*\*kwargs** ([`dict`](https://docs.python.org/3/library/stdtypes.html#dict)) – Extra keyword arguments to pass to function * **adjust_chunks** ([`dict`](https://docs.python.org/3/library/stdtypes.html#dict)) – Dictionary mapping index to function to be applied to chunk sizes * **new_axes** ([`dict`](https://docs.python.org/3/library/stdtypes.html#dict), `keyword only`) – New indexes and their dimension lengths * **align_arrays** ([`bool`](https://docs.python.org/3/library/functions.html#bool)) – Whether or not to align chunks along equally sized dimensions when multiple arrays are provided. This allows for larger chunks in some arrays to be broken into smaller ones that match chunk sizes in other arrays such that they are compatible for block function mapping. If this is false, then an error will be thrown if arrays do not already have the same number of blocks in each dimension. #### SEE ALSO [`dask.array.blockwise`](https://docs.dask.org/en/latest/generated/dask.array.blockwise.html#dask.array.blockwise), `cubed.core.blockwise` #### *abstract* chunks(data) Return the current chunks of the given array. Returns chunks explicitly as a tuple of tuple of ints. Used internally by xarray objects’ .chunks and .chunksizes properties. * **Parameters:** **data** (`chunked array`) * **Returns:** **chunks** (`tuple[tuple[int`, `]`, `]`) #### SEE ALSO [`dask.array.Array.chunks`](https://docs.dask.org/en/latest/generated/dask.array.Array.chunks.html#dask.array.Array.chunks), `cubed.Array.chunks` #### *abstract* compute(\*data, \*\*kwargs) Computes one or more chunked arrays, returning them as eager numpy arrays. Called anytime something needs to computed, including multiple arrays at once. Used by .compute, .persist, .values. * **Parameters:** **\*data** ([`object`](https://docs.python.org/3/library/functions.html#object)) – Any number of objects. If an object is an instance of the chunked array type, it is computed and the in-memory result returned as a numpy array. All other types should be passed through unchanged. * **Returns:** `objs` – The input, but with all chunked arrays now computed. #### SEE ALSO [`dask.compute`](https://docs.dask.org/en/latest/api.html#dask.compute), [`cubed.compute`](https://cubed-dev.github.io/cubed/generated/cubed.compute.html#cubed.compute) #### *abstract* from_array(data, chunks, \*\*kwargs) Create a chunked array from a non-chunked numpy-like array. Generally input should have a `.shape`, `.ndim`, `.dtype` and support numpy-style slicing. Called when the .chunk method is called on an xarray object that is not already chunked. Also called within open_dataset (when chunks is not None) to create a chunked array from an xarray lazily indexed array. * **Parameters:** * **data** ([array_like](https://numpy.org/doc/stable/glossary.html#term-array_like)) * **chunks** ([`int`](https://docs.python.org/3/library/functions.html#int), [`tuple`](https://docs.python.org/3/library/stdtypes.html#tuple)) – How to chunk the array. #### SEE ALSO [`dask.array.from_array`](https://docs.dask.org/en/latest/generated/dask.array.from_array.html#dask.array.from_array), [`cubed.from_array`](https://cubed-dev.github.io/cubed/generated/cubed.from_array.html#cubed.from_array) #### get_auto_chunk_size() Get the default chunk size for a variable. This is used to determine the chunk size when opening a dataset with `chunks="auto"` or when rechunking an array with `chunks="auto"`. * **Parameters:** **target_chunksize** ([`int`](https://docs.python.org/3/library/functions.html#int), *optional*) – The target chunk size in bytes. If not provided, a default value is used. * **Returns:** **chunk_size** ([`int`](https://docs.python.org/3/library/functions.html#int)) – The chunk size in bytes. #### is_chunked_array(data) Check if the given object is an instance of this type of chunked array. Compares against the type stored in the array_cls attribute by default. * **Parameters:** **data** (`Any`) * **Returns:** **is_chunked** ([`bool`](https://docs.python.org/3/library/functions.html#bool)) #### SEE ALSO [`dask.is_dask_collection`](https://docs.dask.org/en/latest/api.html#dask.is_dask_collection) #### map_blocks(func, \*args, dtype=None, chunks=None, drop_axis=None, new_axis=None, \*\*kwargs) Map a function across all blocks of a chunked array. Called in elementwise operations, but notably not (currently) called within xarray.map_blocks. * **Parameters:** * **func** ([`callable()`](https://docs.python.org/3/library/functions.html#callable)) – Function to apply to every block in the array. If `func` accepts `block_info=` or `block_id=` as keyword arguments, these will be passed dictionaries containing information about input and output chunks/arrays during computation. See examples for details. * **args** (`dask arrays` or `other objects`) * **dtype** (`np.dtype`, *optional*) – The `dtype` of the output array. It is recommended to provide this. If not provided, will be inferred by applying the function to a small set of fake data. * **chunks** ([`tuple`](https://docs.python.org/3/library/stdtypes.html#tuple), *optional*) – Chunk shape of resulting blocks if the function does not preserve shape. If not provided, the resulting array is assumed to have the same block structure as the first input array. * **drop_axis** (`number` or [iterable](https://docs.python.org/3/glossary.html#term-iterable), *optional*) – Dimensions lost by the function. * **new_axis** (`number` or [iterable](https://docs.python.org/3/glossary.html#term-iterable), *optional*) – New dimensions created by the function. Note that these are applied after `drop_axis` (if present). * **\*\*kwargs** – Other keyword arguments to pass to function. Values must be constants (not dask.arrays) #### SEE ALSO [`dask.array.map_blocks`](https://docs.dask.org/en/latest/generated/dask.array.map_blocks.html#dask.array.map_blocks), [`cubed.map_blocks`](https://cubed-dev.github.io/cubed/generated/cubed.map_blocks.html#cubed.map_blocks) #### *abstract* normalize_chunks(chunks, shape=None, limit=None, dtype=None, previous_chunks=None) Normalize given chunking pattern into an explicit tuple of tuples representation. Exposed primarily because different chunking backends may want to make different decisions about how to automatically chunk along dimensions not given explicitly in the input chunks. Called internally by xarray.open_dataset. * **Parameters:** * **chunks** ([`tuple`](https://docs.python.org/3/library/stdtypes.html#tuple), [`int`](https://docs.python.org/3/library/functions.html#int), [`dict`](https://docs.python.org/3/library/stdtypes.html#dict), or [`string`](https://docs.python.org/3/library/stdtypes.html#str)) – The chunks to be normalized. * **shape** (`Tuple[int]`) – The shape of the array * **limit** (`int (optional)`) – The maximum block size to target in bytes, if freedom is given to choose * **dtype** (`np.dtype`) * **previous_chunks** (`Tuple[Tuple[int]]`, *optional*) – Chunks from a previous array that we should use for inspiration when rechunking dimensions automatically. #### SEE ALSO [`dask.array.core.normalize_chunks`](https://docs.dask.org/en/latest/generated/dask.array.core.normalize_chunks.html#dask.array.core.normalize_chunks) #### persist(\*data, \*\*kwargs) Persist one or more chunked arrays in memory. * **Parameters:** **\*data** ([`object`](https://docs.python.org/3/library/functions.html#object)) – Any number of objects. If an object is an instance of the chunked array type, it is persisted as a chunked array in memory. All other types should be passed through unchanged. * **Returns:** `objs` – The input, but with all chunked arrays now persisted in memory. #### SEE ALSO [`dask.persist`](https://docs.dask.org/en/latest/api.html#dask.persist) #### rechunk(data, chunks, \*\*kwargs) Changes the chunking pattern of the given array. Called when the .chunk method is called on an xarray object that is already chunked. * **Parameters:** * **data** (`dask array`) – Array to be rechunked. * **chunks** ([`int`](https://docs.python.org/3/library/functions.html#int), [`tuple`](https://docs.python.org/3/library/stdtypes.html#tuple), [`dict`](https://docs.python.org/3/library/stdtypes.html#dict) or [`str`](https://docs.python.org/3/library/stdtypes.html#str), *optional*) – The new block dimensions to create. -1 indicates the full size of the corresponding dimension. Default is “auto” which automatically determines chunk sizes. * **Returns:** `chunked array` #### SEE ALSO [`dask.array.Array.rechunk`](https://docs.dask.org/en/latest/generated/dask.array.Array.rechunk.html#dask.array.Array.rechunk), [`cubed.Array.rechunk`](https://cubed-dev.github.io/cubed/generated/cubed.Array.rechunk.html#cubed.Array.rechunk) #### reduction(arr, func, combine_func=None, aggregate_func=None, axis=None, dtype=None, keepdims=False) A general version of array reductions along one or more axes. Used inside some reductions like nanfirst, which is used by `groupby.first`. * **Parameters:** * **arr** (`chunked array`) – Data to be reduced along one or more axes. * **func** (`Callable(x_chunk`, `axis`, `keepdims)`) – First function to be executed when resolving the dask graph. This function is applied in parallel to all original chunks of x. See below for function parameters. * **combine_func** (`Callable(x_chunk`, `axis`, `keepdims)`, *optional*) – Function used for intermediate recursive aggregation (see split_every below). If omitted, it defaults to aggregate_func. * **aggregate_func** (`Callable(x_chunk`, `axis`, `keepdims)`) – Last function to be executed, producing the final output. It is always invoked, even when the reduced Array counts a single chunk along the reduced axes. * **axis** ([`int`](https://docs.python.org/3/library/functions.html#int) or [sequence](https://docs.python.org/3/glossary.html#term-sequence) of `ints`, *optional*) – Axis or axes to aggregate upon. If omitted, aggregate along all axes. * **dtype** (`np.dtype`) – data type of output. This argument was previously optional, but leaving as `None` will now raise an exception. * **keepdims** (`boolean`, *optional*) – Whether the reduction function should preserve the reduced axes, leaving them at size `output_size`, or remove them. * **Returns:** `chunked array` #### SEE ALSO [`dask.array.reduction`](https://docs.dask.org/en/latest/generated/dask.array.reduction.html#dask.array.reduction), `cubed.core.reduction` #### scan(func, binop, ident, arr, axis=None, dtype=None, \*\*kwargs) General version of a 1D scan, also known as a cumulative array reduction. Used in `ffill` and `bfill` in xarray. * **Parameters:** * **func** ([`callable()`](https://docs.python.org/3/library/functions.html#callable)) – Cumulative function like np.cumsum or np.cumprod * **binop** ([`callable()`](https://docs.python.org/3/library/functions.html#callable)) – Associated binary operator like `np.cumsum->add` or `np.cumprod->mul` * **ident** (`Number`) – Associated identity like `np.cumsum->0` or `np.cumprod->1` * **arr** (`dask Array`) * **axis** ([`int`](https://docs.python.org/3/library/functions.html#int), *optional*) * **dtype** ([`dtype`](https://numpy.org/doc/stable/reference/generated/numpy.dtype.html#numpy.dtype)) * **Returns:** `Chunked array` #### SEE ALSO `dask.array.cumreduction` #### store(sources, targets, \*\*kwargs) Store chunked arrays in array-like objects, overwriting data in target. This stores chunked arrays into object that supports numpy-style setitem indexing (e.g. a Zarr Store). Allows storing values chunk by chunk so that it does not have to fill up memory. For best performance you likely want to align the block size of the storage target with the block size of your array. Used when writing to any registered xarray I/O backend. * **Parameters:** * **sources** (`Array` or `collection` of `Arrays`) * **targets** ([array-like](https://numpy.org/doc/stable/glossary.html#term-array_like) or `collection` of `array-likes`) – These should support setitem syntax `target[10:20] = ...`. If sources is a single item, targets must be a single item; if sources is a collection of arrays, targets must be a matching collection. * **kwargs** – Parameters passed to compute/persist (only used if compute=True) #### SEE ALSO [`dask.array.store`](https://docs.dask.org/en/latest/generated/dask.array.store.html#dask.array.store), [`cubed.store`](https://cubed-dev.github.io/cubed/generated/cubed.store.html#cubed.store) #### unify_chunks(\*args, \*\*kwargs) Unify chunks across a sequence of arrays. Called by xarray.unify_chunks. * **Parameters:** **\*args** ([sequence](https://docs.python.org/3/glossary.html#term-sequence) of `Array`, `index pairs`) – Sequence like (x, ‘ij’, y, ‘jk’, z, ‘i’) #### SEE ALSO [`dask.array.core.unify_chunks`](https://docs.dask.org/en/latest/generated/dask.array.core.unify_chunks.html#dask.array.core.unify_chunks), `cubed.core.unify_chunks` ## Registering a new ChunkManagerEntrypoint subclass Rather than hard-coding various chunk managers to deal with specific chunked array implementations, xarray uses an entrypoint system to allow developers of new chunked array implementations to register their corresponding subclass of [`ChunkManagerEntrypoint`](#xarray.namedarray.parallelcompat.ChunkManagerEntrypoint). To register a new entrypoint you need to add an entry to the `setup.cfg` like this: ```default [options.entry_points] xarray.chunkmanagers = dask = xarray.namedarray.daskmanager:DaskManager ``` See also [cubed-xarray](https://github.com/xarray-contrib/cubed-xarray) for another example. To check that the entrypoint has worked correctly, you may find it useful to display the available chunkmanagers using the internal function [`list_chunkmanagers()`](#xarray.namedarray.parallelcompat.list_chunkmanagers). ### xarray.namedarray.parallelcompat.list_chunkmanagers() Return a dictionary of available chunk managers and their ChunkManagerEntrypoint subclass objects. * **Returns:** **chunkmanagers** ([`dict`](https://docs.python.org/3/library/stdtypes.html#dict)) – Dictionary whose values are registered ChunkManagerEntrypoint subclass instances, and whose values are the strings under which they are registered. ## User interface Once the chunkmanager subclass has been registered, xarray objects wrapping the desired array type can be created in 3 ways: 1. By manually passing the array type to the [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) constructor, see the examples for [numpy-like arrays](../user-guide/duckarrays.md#userguide-duckarrays), 2. Calling [`chunk()`](../generated/xarray.DataArray.chunk.md#xarray.DataArray.chunk), passing the keyword arguments `chunked_array_type` and `from_array_kwargs`, 3. Calling [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset), passing the keyword arguments `chunked_array_type` and `from_array_kwargs`. The latter two methods ultimately call the chunkmanager’s implementation of `.from_array`, to which they pass the `from_array_kwargs` dict. The `chunked_array_type` kwarg selects which registered chunkmanager subclass to dispatch to. It defaults to `'dask'` if Dask is installed, otherwise it defaults to whichever chunkmanager is registered if only one is registered. If multiple chunkmanagers are registered, the `chunk_manager` configuration option (which can be set using `set_options()`) will be used to determine which chunkmanager to use, defaulting to `'dask'`. ## Parallel processing without chunks To use a parallel array type that does not expose a concept of chunks explicitly, none of the information on this page is theoretically required. Such an array type (e.g. [Ramba](https://github.com/Python-for-HPC/ramba) or [Arkouda](https://github.com/Bears-R-Us/arkouda)) could be wrapped using xarray’s existing support for [numpy-like “duck” arrays](../user-guide/duckarrays.md#userguide-duckarrays). # coarsen.html.md # Coarsen objects ## Dataset | [`DatasetCoarsen`](../generated/xarray.computation.rolling.DatasetCoarsen.md#xarray.computation.rolling.DatasetCoarsen)(obj, windows, boundary, side, ...) | | |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------| | [`DatasetCoarsen.all`](../generated/xarray.computation.rolling.DatasetCoarsen.all.md#xarray.computation.rolling.DatasetCoarsen.all)([keep_attrs]) | Reduce this DatasetCoarsen's data by applying all along some dimension(s). | | [`DatasetCoarsen.any`](../generated/xarray.computation.rolling.DatasetCoarsen.any.md#xarray.computation.rolling.DatasetCoarsen.any)([keep_attrs]) | Reduce this DatasetCoarsen's data by applying any along some dimension(s). | | [`DatasetCoarsen.construct`](../generated/xarray.computation.rolling.DatasetCoarsen.construct.md#xarray.computation.rolling.DatasetCoarsen.construct)([window_dim, ...]) | Convert this Coarsen object to a DataArray or Dataset, where the coarsening dimension is split or reshaped to two new dimensions. | | [`DatasetCoarsen.count`](../generated/xarray.computation.rolling.DatasetCoarsen.count.md#xarray.computation.rolling.DatasetCoarsen.count)([keep_attrs]) | Reduce this DatasetCoarsen's data by applying count along some dimension(s). | | [`DatasetCoarsen.max`](../generated/xarray.computation.rolling.DatasetCoarsen.max.md#xarray.computation.rolling.DatasetCoarsen.max)([keep_attrs]) | Reduce this DatasetCoarsen's data by applying max along some dimension(s). | | [`DatasetCoarsen.mean`](../generated/xarray.computation.rolling.DatasetCoarsen.mean.md#xarray.computation.rolling.DatasetCoarsen.mean)([keep_attrs]) | Reduce this DatasetCoarsen's data by applying mean along some dimension(s). | | [`DatasetCoarsen.median`](../generated/xarray.computation.rolling.DatasetCoarsen.median.md#xarray.computation.rolling.DatasetCoarsen.median)([keep_attrs]) | Reduce this DatasetCoarsen's data by applying median along some dimension(s). | | [`DatasetCoarsen.min`](../generated/xarray.computation.rolling.DatasetCoarsen.min.md#xarray.computation.rolling.DatasetCoarsen.min)([keep_attrs]) | Reduce this DatasetCoarsen's data by applying min along some dimension(s). | | [`DatasetCoarsen.prod`](../generated/xarray.computation.rolling.DatasetCoarsen.prod.md#xarray.computation.rolling.DatasetCoarsen.prod)([keep_attrs]) | Reduce this DatasetCoarsen's data by applying prod along some dimension(s). | | [`DatasetCoarsen.reduce`](../generated/xarray.computation.rolling.DatasetCoarsen.reduce.md#xarray.computation.rolling.DatasetCoarsen.reduce)(func[, keep_attrs]) | Reduce the items in this group by applying func along some dimension(s). | | [`DatasetCoarsen.std`](../generated/xarray.computation.rolling.DatasetCoarsen.std.md#xarray.computation.rolling.DatasetCoarsen.std)([keep_attrs]) | Reduce this DatasetCoarsen's data by applying std along some dimension(s). | | [`DatasetCoarsen.sum`](../generated/xarray.computation.rolling.DatasetCoarsen.sum.md#xarray.computation.rolling.DatasetCoarsen.sum)([keep_attrs]) | Reduce this DatasetCoarsen's data by applying sum along some dimension(s). | | [`DatasetCoarsen.var`](../generated/xarray.computation.rolling.DatasetCoarsen.var.md#xarray.computation.rolling.DatasetCoarsen.var)([keep_attrs]) | Reduce this DatasetCoarsen's data by applying var along some dimension(s). | ## DataArray | [`DataArrayCoarsen`](../generated/xarray.computation.rolling.DataArrayCoarsen.md#xarray.computation.rolling.DataArrayCoarsen)(obj, windows, boundary, ...) | | |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------| | [`DataArrayCoarsen.all`](../generated/xarray.computation.rolling.DataArrayCoarsen.all.md#xarray.computation.rolling.DataArrayCoarsen.all)([keep_attrs]) | Reduce this DataArrayCoarsen's data by applying all along some dimension(s). | | [`DataArrayCoarsen.any`](../generated/xarray.computation.rolling.DataArrayCoarsen.any.md#xarray.computation.rolling.DataArrayCoarsen.any)([keep_attrs]) | Reduce this DataArrayCoarsen's data by applying any along some dimension(s). | | [`DataArrayCoarsen.construct`](../generated/xarray.computation.rolling.DataArrayCoarsen.construct.md#xarray.computation.rolling.DataArrayCoarsen.construct)([window_dim, ...]) | Convert this Coarsen object to a DataArray or Dataset, where the coarsening dimension is split or reshaped to two new dimensions. | | [`DataArrayCoarsen.count`](../generated/xarray.computation.rolling.DataArrayCoarsen.count.md#xarray.computation.rolling.DataArrayCoarsen.count)([keep_attrs]) | Reduce this DataArrayCoarsen's data by applying count along some dimension(s). | | [`DataArrayCoarsen.max`](../generated/xarray.computation.rolling.DataArrayCoarsen.max.md#xarray.computation.rolling.DataArrayCoarsen.max)([keep_attrs]) | Reduce this DataArrayCoarsen's data by applying max along some dimension(s). | | [`DataArrayCoarsen.mean`](../generated/xarray.computation.rolling.DataArrayCoarsen.mean.md#xarray.computation.rolling.DataArrayCoarsen.mean)([keep_attrs]) | Reduce this DataArrayCoarsen's data by applying mean along some dimension(s). | | [`DataArrayCoarsen.median`](../generated/xarray.computation.rolling.DataArrayCoarsen.median.md#xarray.computation.rolling.DataArrayCoarsen.median)([keep_attrs]) | Reduce this DataArrayCoarsen's data by applying median along some dimension(s). | | [`DataArrayCoarsen.min`](../generated/xarray.computation.rolling.DataArrayCoarsen.min.md#xarray.computation.rolling.DataArrayCoarsen.min)([keep_attrs]) | Reduce this DataArrayCoarsen's data by applying min along some dimension(s). | | [`DataArrayCoarsen.prod`](../generated/xarray.computation.rolling.DataArrayCoarsen.prod.md#xarray.computation.rolling.DataArrayCoarsen.prod)([keep_attrs]) | Reduce this DataArrayCoarsen's data by applying prod along some dimension(s). | | [`DataArrayCoarsen.reduce`](../generated/xarray.computation.rolling.DataArrayCoarsen.reduce.md#xarray.computation.rolling.DataArrayCoarsen.reduce)(func[, keep_attrs]) | Reduce the items in this group by applying func along some dimension(s). | | [`DataArrayCoarsen.std`](../generated/xarray.computation.rolling.DataArrayCoarsen.std.md#xarray.computation.rolling.DataArrayCoarsen.std)([keep_attrs]) | Reduce this DataArrayCoarsen's data by applying std along some dimension(s). | | [`DataArrayCoarsen.sum`](../generated/xarray.computation.rolling.DataArrayCoarsen.sum.md#xarray.computation.rolling.DataArrayCoarsen.sum)([keep_attrs]) | Reduce this DataArrayCoarsen's data by applying sum along some dimension(s). | | [`DataArrayCoarsen.var`](../generated/xarray.computation.rolling.DataArrayCoarsen.var.md#xarray.computation.rolling.DataArrayCoarsen.var)([keep_attrs]) | Reduce this DataArrayCoarsen's data by applying var along some dimension(s). | # combining.html.md # Combining data * For combining datasets or data arrays along a single dimension, see [concatenate](). * For combining datasets with different variables, see [merge](). * For combining datasets or data arrays with different indexes or missing values, see [combine](). * For combining datasets or data arrays along multiple dimensions see [combining.multi](). ## Concatenate To combine [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) / [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) objects along an existing or new dimension into a larger object, you can use [`concat()`](../generated/xarray.concat.md#xarray.concat). `concat` takes an iterable of `DataArray` or `Dataset` objects, as well as a dimension name, and concatenates along that dimension: ```ipython3 da = xr.DataArray( np.arange(6).reshape(2, 3), [("x", ["a", "b"]), ("y", [10, 20, 30])] ) da.isel(y=slice(0, 1)) # same as da[:, :1] ``` ```none Size: 16B array([[0], [3]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 1)> Size: 16B
array([[0],
       [3]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 8B 10
```ipython3 # This resembles how you would use np.concatenate: xr.concat([da[:, :1], da[:, 1:]], dim="y") ``` ```none Size: 48B array([[0, 1, 2], [3, 4, 5]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[0, 1, 2],
       [3, 4, 5]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
```ipython3 # For more friendly pandas-like indexing you can use: xr.concat([da.isel(y=slice(0, 1)), da.isel(y=slice(1, None))], dim="y") ``` ```none Size: 48B array([[0, 1, 2], [3, 4, 5]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[0, 1, 2],
       [3, 4, 5]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
In addition to combining along an existing dimension, `concat` can create a new dimension by stacking lower dimensional arrays together: ```ipython3 da.sel(x="a") ``` ```none Size: 24B array([0, 1, 2]) Coordinates: * y (y) int64 24B 10 20 30 x
<xarray.DataArray (y: 3)> Size: 24B
array([0, 1, 2])
Coordinates:
  \* y        (y) int64 24B 10 20 30
    x        <U1 4B 'a'
```ipython3 xr.concat([da.isel(x=0), da.isel(x=1)], "x") ``` ```none Size: 48B array([[0, 1, 2], [3, 4, 5]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[0, 1, 2],
       [3, 4, 5]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
If the second argument to `concat` is a new dimension name, the arrays will be concatenated along that new dimension, which is always inserted as the first dimension: ```ipython3 da0 = da.isel(x=0, drop=True) da1 = da.isel(x=1, drop=True) xr.concat([da0, da1], "new_dim") ``` ```none Size: 48B array([[0, 1, 2], [3, 4, 5]]) Coordinates: * y (y) int64 24B 10 20 30 Dimensions without coordinates: new_dim ```
<xarray.DataArray (new_dim: 2, y: 3)> Size: 48B
array([[0, 1, 2],
       [3, 4, 5]])
Coordinates:
  \* y        (y) int64 24B 10 20 30
Dimensions without coordinates: new_dim
The second argument to `concat` can also be an [`Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index) or [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) object as well as a string, in which case it is used to label the values along the new dimension: ```ipython3 xr.concat([da0, da1], pd.Index([-90, -100], name="new_dim")) ``` ```none Size: 48B array([[0, 1, 2], [3, 4, 5]]) Coordinates: * new_dim (new_dim) int64 16B -90 -100 * y (y) int64 24B 10 20 30 ```
<xarray.DataArray (new_dim: 2, y: 3)> Size: 48B
array([[0, 1, 2],
       [3, 4, 5]])
Coordinates:
  \* new_dim  (new_dim) int64 16B -90 -100
  \* y        (y) int64 24B 10 20 30
Of course, `concat` also works on `Dataset` objects: ```ipython3 ds = da.to_dataset(name="foo") xr.concat([ds.sel(x="a"), ds.sel(x="b")], "x") ``` ```none Size: 80B Dimensions: (x: 2, y: 3) Coordinates: * x (x)
<xarray.Dataset> Size: 80B
Dimensions:  (x: 2, y: 3)
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
Data variables:
    foo      (x, y) int64 48B 0 1 2 3 4 5
[`concat()`](../generated/xarray.concat.md#xarray.concat) has a number of options which provide deeper control over which variables are concatenated and how it handles conflicting variables between datasets. With the default parameters, xarray will load some coordinate variables into memory to compare them between datasets. This may be prohibitively expensive if you are manipulating your dataset lazily using [Parallel Computing with Dask](dask.md#dask). #### NOTE In a future version of xarray the default values for many of these options will change. You can opt into the new default values early using `xr.set_options(use_new_combine_kwarg_defaults=True)`. ## Merge To combine variables and coordinates between multiple `DataArray` and/or `Dataset` objects, use [`merge()`](../generated/xarray.merge.md#xarray.merge). It can merge a list of `Dataset`, `DataArray` or dictionaries of objects convertible to `DataArray` objects: ```ipython3 xr.merge([ds, ds.rename({"foo": "bar"})]) ``` ```none Size: 128B Dimensions: (x: 2, y: 3) Coordinates: * x (x)
<xarray.Dataset> Size: 128B
Dimensions:  (x: 2, y: 3)
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
Data variables:
    foo      (x, y) int64 48B 0 1 2 3 4 5
    bar      (x, y) int64 48B 0 1 2 3 4 5
```ipython3 xr.merge([xr.DataArray(n, name="var%d" % n) for n in range(5)]) ``` ```none Size: 40B Dimensions: () Data variables: var0 int64 8B 0 var1 int64 8B 1 var2 int64 8B 2 var3 int64 8B 3 var4 int64 8B 4 ```
<xarray.Dataset> Size: 40B
Dimensions:  ()
Data variables:
    var0     int64 8B 0
    var1     int64 8B 1
    var2     int64 8B 2
    var3     int64 8B 3
    var4     int64 8B 4
If you merge another dataset (or a dictionary including data array objects), by default the resulting dataset will be aligned on the **union** of all index coordinates: #### NOTE In a future version of xarray the default value for `join` and `compat` will change. This change will mean that xarray will no longer attempt to align the indices of the merged dataset. You can opt into the new default values early using `xr.set_options(use_new_combine_kwarg_defaults=True)`. Or explicitly set `join='outer'` to preserve old behavior. ```ipython3 other = xr.Dataset({"bar": ("x", [1, 2, 3, 4]), "x": list("abcd")}) xr.merge([ds, other], join="outer") ``` ```none Size: 168B Dimensions: (x: 4, y: 3) Coordinates: * x (x)
<xarray.Dataset> Size: 168B
Dimensions:  (x: 4, y: 3)
Coordinates:
  \* x        (x) <U1 16B 'a' 'b' 'c' 'd'
  \* y        (y) int64 24B 10 20 30
Data variables:
    foo      (x, y) float64 96B 0.0 1.0 2.0 3.0 4.0 5.0 nan nan nan nan nan nan
    bar      (x) int64 32B 1 2 3 4
This ensures that `merge` is non-destructive. `xarray.MergeError` is raised if you attempt to merge two variables with the same name but different values: ```ipython3 xr.merge([ds, ds + 1]) ``` ```ipythontb MergeError: conflicting values for variable 'foo' on objects to be combined. You can skip this check by specifying compat='override'. ``` #### NOTE In a future version of xarray the default value for `compat` will change from `compat='no_conflicts'` to `compat='override'`. In this scenario the values in the first object override all the values in other objects. ```ipython3 xr.merge([ds, ds + 1], compat="override") ``` ```none Size: 80B Dimensions: (x: 2, y: 3) Coordinates: * x (x)
<xarray.Dataset> Size: 80B
Dimensions:  (x: 2, y: 3)
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
Data variables:
    foo      (x, y) int64 48B 0 1 2 3 4 5
The same non-destructive merging between `DataArray` index coordinates is used in the [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) constructor: ```ipython3 xr.Dataset({"a": da.isel(x=slice(0, 1)), "b": da.isel(x=slice(1, 2))}) ``` ```none Size: 128B Dimensions: (x: 2, y: 3) Coordinates: * x (x)
<xarray.Dataset> Size: 128B
Dimensions:  (x: 2, y: 3)
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
Data variables:
    a        (x, y) float64 48B 0.0 1.0 2.0 nan nan nan
    b        (x, y) float64 48B nan nan nan 3.0 4.0 5.0
## Combine The instance method [`combine_first()`](../generated/xarray.DataArray.combine_first.md#xarray.DataArray.combine_first) combines two datasets/data arrays and defaults to non-null values in the calling object, using values from the called object to fill holes. The resulting coordinates are the union of coordinate labels. Vacant cells as a result of the outer-join are filled with `NaN`. For example: ```ipython3 ar0 = xr.DataArray([[0, 0], [0, 0]], [("x", ["a", "b"]), ("y", [-1, 0])]) ar1 = xr.DataArray([[1, 1], [1, 1]], [("x", ["b", "c"]), ("y", [0, 1])]) ar0.combine_first(ar1) ``` ```none Size: 72B array([[ 0., 0., nan], [ 0., 0., 1.], [nan, 1., 1.]]) Coordinates: * x (x)
<xarray.DataArray (x: 3, y: 3)> Size: 72B
array([[ 0.,  0., nan],
       [ 0.,  0.,  1.],
       [nan,  1.,  1.]])
Coordinates:
  \* x        (x) <U1 12B 'a' 'b' 'c'
  \* y        (y) int64 24B -1 0 1
```ipython3 ar1.combine_first(ar0) ``` ```none Size: 72B array([[ 0., 0., nan], [ 0., 1., 1.], [nan, 1., 1.]]) Coordinates: * x (x)
<xarray.DataArray (x: 3, y: 3)> Size: 72B
array([[ 0.,  0., nan],
       [ 0.,  1.,  1.],
       [nan,  1.,  1.]])
Coordinates:
  \* x        (x) <U1 12B 'a' 'b' 'c'
  \* y        (y) int64 24B -1 0 1
For datasets, `ds0.combine_first(ds1)` works similarly to `xr.merge([ds0, ds1])`, except that `xr.merge` raises `MergeError` when there are conflicting values in variables to be merged, whereas `.combine_first` defaults to the calling object’s values. #### NOTE In a future version of xarray the default options for `xr.merge` will change such that the behavior matches `combine_first`. ## Update In contrast to `merge`, [`update()`](../generated/xarray.Dataset.update.md#xarray.Dataset.update) modifies a dataset in-place without checking for conflicts, and will overwrite any existing variables with new values: ```ipython3 ds.update({"space": ("space", [10.2, 9.4, 3.9])}) ``` However, dimensions are still required to be consistent between different Dataset variables, so you cannot change the size of a dimension unless you replace all dataset variables that use it. `update` also performs automatic alignment if necessary. Unlike `merge`, it maintains the alignment of the original array instead of merging indexes: ```ipython3 ds.update(other) ``` The exact same alignment logic when setting a variable with `__setitem__` syntax: ```ipython3 ds["baz"] = xr.DataArray([9, 9, 9, 9, 9], coords=[("x", list("abcde"))]) ds.baz ``` ```none Size: 16B array([9, 9]) Coordinates: * x (x)
<xarray.DataArray 'baz' (x: 2)> Size: 16B
array([9, 9])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
## Equals and identical Xarray objects can be compared by using the [`equals()`](../generated/xarray.Dataset.equals.md#xarray.Dataset.equals), [`identical()`](../generated/xarray.Dataset.identical.md#xarray.Dataset.identical) and [`broadcast_equals()`](../generated/xarray.Dataset.broadcast_equals.md#xarray.Dataset.broadcast_equals) methods. These methods are used by the optional `compat` argument on `concat` and `merge`. [`equals`](../generated/xarray.Dataset.equals.md#xarray.Dataset.equals) checks dimension names, indexes and array values: ```ipython3 da.equals(da.copy()) ``` ```none True ``` [`identical`](../generated/xarray.Dataset.identical.md#xarray.Dataset.identical) also checks attributes, and the name of each object: ```ipython3 da.identical(da.rename("bar")) ``` ```none False ``` [`broadcast_equals`](../generated/xarray.Dataset.broadcast_equals.md#xarray.Dataset.broadcast_equals) does a more relaxed form of equality check that allows variables to have different dimensions, as long as values are constant along those new dimensions: ```ipython3 left = xr.Dataset(coords={"x": 0}) right = xr.Dataset({"x": [0, 0, 0]}) left.broadcast_equals(right) ``` ```none True ``` Like pandas objects, two xarray objects are still equal or identical if they have missing values marked by `NaN` in the same locations. In contrast, the `==` operation performs element-wise comparison (like numpy): ```ipython3 da == da.copy() ``` ```none Size: 6B array([[ True, True, True], [ True, True, True]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 3)> Size: 6B
array([[ True,  True,  True],
       [ True,  True,  True]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
Note that `NaN` does not compare equal to `NaN` in element-wise comparison; you may need to deal with missing values explicitly. ## Merging with ‘no_conflicts’ The `compat` argument `'no_conflicts'` is only available when combining xarray objects with `merge`. In addition to the above comparison methods it allows the merging of xarray objects with locations where *either* have `NaN` values. This can be used to combine data with overlapping coordinates as long as any non-missing values agree or are disjoint: ```ipython3 ds1 = xr.Dataset({"a": ("x", [10, 20, 30, np.nan])}, {"x": [1, 2, 3, 4]}) ds2 = xr.Dataset({"a": ("x", [np.nan, 30, 40, 50])}, {"x": [2, 3, 4, 5]}) xr.merge([ds1, ds2], join="outer", compat="no_conflicts") ``` ```none Size: 80B Dimensions: (x: 5) Coordinates: * x (x) int64 40B 1 2 3 4 5 Data variables: a (x) float64 40B 10.0 20.0 30.0 40.0 50.0 ```
<xarray.Dataset> Size: 80B
Dimensions:  (x: 5)
Coordinates:
  \* x        (x) int64 40B 1 2 3 4 5
Data variables:
    a        (x) float64 40B 10.0 20.0 30.0 40.0 50.0
Note that due to the underlying representation of missing values as floating point numbers (`NaN`), variable data type is not always preserved when merging in this manner. ## Combining along multiple dimensions For combining many objects along multiple dimensions xarray provides [`combine_nested()`](../generated/xarray.combine_nested.md#xarray.combine_nested) and [`combine_by_coords()`](../generated/xarray.combine_by_coords.md#xarray.combine_by_coords). These functions use a combination of `concat` and `merge` across different variables to combine many objects into one. [`combine_nested()`](../generated/xarray.combine_nested.md#xarray.combine_nested) requires specifying the order in which the objects should be combined, while [`combine_by_coords()`](../generated/xarray.combine_by_coords.md#xarray.combine_by_coords) attempts to infer this ordering automatically from the coordinates in the data. [`combine_nested()`](../generated/xarray.combine_nested.md#xarray.combine_nested) is useful when you know the spatial relationship between each object in advance. The datasets must be provided in the form of a nested list, which specifies their relative position and ordering. A common task is collecting data from a parallelized simulation where each processor wrote out data to a separate file. A domain which was decomposed into 4 parts, 2 each along both the x and y axes, requires organising the datasets into a doubly-nested list, e.g: ```ipython3 arr = xr.DataArray( name="temperature", data=np.random.randint(5, size=(2, 2)), dims=["x", "y"] ) arr ``` ```none Size: 32B array([[1, 2], [2, 1]]) Dimensions without coordinates: x, y ```
<xarray.DataArray 'temperature' (x: 2, y: 2)> Size: 32B
array([[1, 2],
       [2, 1]])
Dimensions without coordinates: x, y
```ipython3 ds_grid = [[arr, arr], [arr, arr]] xr.combine_nested(ds_grid, concat_dim=["x", "y"]) ``` ```none Size: 128B array([[1, 2, 1, 2], [2, 1, 2, 1], [1, 2, 1, 2], [2, 1, 2, 1]]) Dimensions without coordinates: x, y ```
<xarray.DataArray 'temperature' (x: 4, y: 4)> Size: 128B
array([[1, 2, 1, 2],
       [2, 1, 2, 1],
       [1, 2, 1, 2],
       [2, 1, 2, 1]])
Dimensions without coordinates: x, y
[`combine_nested()`](../generated/xarray.combine_nested.md#xarray.combine_nested) can also be used to explicitly merge datasets with different variables. For example if we have 4 datasets, which are divided along two times, and contain two different variables, we can pass `None` to `'concat_dim'` to specify the dimension of the nested list over which we wish to use `merge` instead of `concat`: ```ipython3 temp = xr.DataArray(name="temperature", data=np.random.randn(2), dims=["t"]) precip = xr.DataArray(name="precipitation", data=np.random.randn(2), dims=["t"]) ds_grid = [[temp, precip], [temp, precip]] xr.combine_nested(ds_grid, concat_dim=["t", None]) ``` ```none Size: 64B Dimensions: (t: 4) Dimensions without coordinates: t Data variables: temperature (t) float64 32B 0.4691 -0.2829 0.4691 -0.2829 precipitation (t) float64 32B -1.509 -1.136 -1.509 -1.136 ```
<xarray.Dataset> Size: 64B
Dimensions:        (t: 4)
Dimensions without coordinates: t
Data variables:
    temperature    (t) float64 32B 0.4691 -0.2829 0.4691 -0.2829
    precipitation  (t) float64 32B -1.509 -1.136 -1.509 -1.136
[`combine_by_coords()`](../generated/xarray.combine_by_coords.md#xarray.combine_by_coords) is for combining objects which have dimension coordinates which specify their relationship to and order relative to one another, for example a linearly-increasing ‘time’ dimension coordinate. Here we combine two datasets using their common dimension coordinates. Notice they are concatenated in order based on the values in their dimension coordinates, not on their position in the list passed to `combine_by_coords`. ```ipython3 x1 = xr.DataArray(name="foo", data=np.random.randn(3), coords=[("x", [0, 1, 2])]) x2 = xr.DataArray(name="foo", data=np.random.randn(3), coords=[("x", [3, 4, 5])]) xr.combine_by_coords([x2, x1]) ``` ```none Size: 96B Dimensions: (x: 6) Coordinates: * x (x) int64 48B 0 1 2 3 4 5 Data variables: foo (x) float64 48B 1.212 -0.1732 0.1192 -1.044 -0.8618 -2.105 ```
<xarray.Dataset> Size: 96B
Dimensions:  (x: 6)
Coordinates:
  \* x        (x) int64 48B 0 1 2 3 4 5
Data variables:
    foo      (x) float64 48B 1.212 -0.1732 0.1192 -1.044 -0.8618 -2.105
These functions are used by [`open_mfdataset()`](../generated/xarray.open_mfdataset.md#xarray.open_mfdataset) to open many files as one dataset. The particular function used is specified by setting the argument `'combine'` to `'by_coords'` or `'nested'`. This is useful for situations where your data is split across many files in multiple locations, which have some known relationship between one another. # complex-numbers.html.md # Complex Numbers Xarray leverages NumPy to seamlessly handle complex numbers in [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) and [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) objects. In the examples below, we are using a DataArray named `da` with complex elements (of $\mathbb{C}$): ```ipython3 data = np.array([[1 + 2j, 3 + 4j], [5 + 6j, 7 + 8j]]) da = xr.DataArray( data, dims=["x", "y"], coords={"x": ["a", "b"], "y": [1, 2]}, name="complex_nums", ) ``` ## Operations on Complex Data You can access real and imaginary components using the `.real` and `.imag` attributes. Most NumPy universal functions (ufuncs) like [numpy.abs](https://numpy.org/doc/stable/reference/generated/numpy.absolute.html) or [numpy.angle](https://numpy.org/doc/stable/reference/generated/numpy.angle.html) work directly. ```ipython3 da.real ``` ```none Size: 32B array([[1., 3.], [5., 7.]]) Coordinates: * x (x)
<xarray.DataArray 'complex_nums' (x: 2, y: 2)> Size: 32B
array([[1., 3.],
       [5., 7.]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 16B 1 2
```ipython3 np.abs(da) ``` ```none Size: 32B array([[ 2.23606798, 5. ], [ 7.81024968, 10.63014581]]) Coordinates: * x (x)
<xarray.DataArray 'complex_nums' (x: 2, y: 2)> Size: 32B
array([[ 2.23606798,  5.        ],
       [ 7.81024968, 10.63014581]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 16B 1 2
#### NOTE Like NumPy, `.real` and `.imag` typically return *views*, not copies, of the original data. ## Reading and Writing Complex Data Writing complex data to NetCDF files (see [netCDF](io.md#io-netcdf)) is supported via [`to_netcdf()`](../generated/xarray.DataArray.to_netcdf.md#xarray.DataArray.to_netcdf) using specific backend engines that handle complex types: This requires the [h5netcdf](https://h5netcdf.org) library to be installed. ```ipython3 complex_nums_h5_filename = "complex_nums_h5.nc" ``` ```ipython3 # write the data to disk da.to_netcdf(complex_nums_h5_filename, engine="h5netcdf") # read the file back into memory ds_h5 = xr.open_dataset(complex_nums_h5_filename, engine="h5netcdf") # check the dtype ds_h5[da.name].dtype ``` ```none dtype('complex128') ``` Requires the [netcdf4-python (>= 1.7.1)](https://github.com/Unidata/netcdf4-python) library and you have to enable `auto_complex=True`. ```ipython3 complex_nums_nc4_filename = "complex_nums_nc4.nc" ``` ```ipython3 # write the data to disk da.to_netcdf(complex_nums_nc4_filename, engine="netcdf4", auto_complex=True) # read the file back into memory ds_nc4 = xr.open_dataset( complex_nums_nc4_filename, engine="netcdf4", auto_complex=True ) # check the dtype ds_nc4[da.name].dtype ``` ```none dtype('complex128') ``` #### WARNING The `scipy` engine only supports NetCDF V3 and does *not* support complex arrays; writing with `engine="scipy"` raises a `TypeError`. ### Alternative: Manual Handling If direct writing is not supported (e.g., targeting NetCDF3), you can manually split the complex array into separate real and imaginary variables before saving: ```ipython3 complex_manual_filename = "complex_manual.nc" ``` ```ipython3 # Write data to file ds_manual = xr.Dataset( { f"{da.name}_real": da.real, f"{da.name}_imag": da.imag, } ) ds_manual.to_netcdf(complex_manual_filename, engine="scipy") # Example # Read data from file ds = xr.open_dataset(complex_manual_filename, engine="scipy") reconstructed = ds[f"{da.name}_real"] + 1j * ds[f"{da.name}_imag"] ``` ### Recommendations - Use `engine="netcdf4"` with `auto_complex=True` for full compliance and ease. - Use `h5netcdf` for HDF5-based storage when interoperability with HDF5 is desired. - For maximum legacy support (NetCDF3), manually handle real/imaginary components. ## See also - [netCDF](io.md#io-netcdf) — full NetCDF I/O guide - [NumPy complex numbers](https://numpy.org/doc/stable/user/basics.types.html#complex) # computation.html.md # Computation The labels associated with [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) and [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) objects enables some powerful shortcuts for computation, notably including aggregation and broadcasting by dimension names. ## Basic array math Arithmetic operations with a single DataArray automatically vectorize (like numpy) over all array values: ```ipython3 arr = xr.DataArray( np.random.default_rng(0).random((2, 3)), [("x", ["a", "b"]), ("y", [10, 20, 30])], ) arr - 3 ``` ```none Size: 48B array([[-2.36303831, -2.73021329, -2.95902648], [-2.98347236, -2.18672976, -2.08724442]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[-2.36303831, -2.73021329, -2.95902648],
       [-2.98347236, -2.18672976, -2.08724442]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
```ipython3 abs(arr) ``` ```none Size: 48B array([[0.63696169, 0.26978671, 0.04097352], [0.01652764, 0.81327024, 0.91275558]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[0.63696169, 0.26978671, 0.04097352],
       [0.01652764, 0.81327024, 0.91275558]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
You can also use any of numpy’s or scipy’s many [ufunc](https://numpy.org/doc/stable/reference/ufuncs.html) functions directly on a DataArray: ```ipython3 np.sin(arr) ``` ```none Size: 48B array([[0.59475567, 0.26652587, 0.04096206], [0.01652688, 0.72653812, 0.79119196]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[0.59475567, 0.26652587, 0.04096206],
       [0.01652688, 0.72653812, 0.79119196]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
Use [`where()`](../generated/xarray.where.md#xarray.where) to conditionally switch between values: ```ipython3 xr.where(arr > 0, "positive", "negative") ``` ```none Size: 192B array([['positive', 'positive', 'positive'], ['positive', 'positive', 'positive']], dtype='
<xarray.DataArray (x: 2, y: 3)> Size: 192B
array([['positive', 'positive', 'positive'],
       ['positive', 'positive', 'positive']], dtype='<U8')
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
Use `@` to compute the [`dot()`](../generated/xarray.dot.md#xarray.dot) product: ```ipython3 arr @ arr ``` ```none Size: 8B array(1.97498828) ```
<xarray.DataArray ()> Size: 8B
array(1.97498828)
Data arrays also implement many [`numpy.ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) methods: ```ipython3 arr.round(2) ``` ```none Size: 48B array([[0.64, 0.27, 0.04], [0.02, 0.81, 0.91]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[0.64, 0.27, 0.04],
       [0.02, 0.81, 0.91]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
```ipython3 arr.T ``` ```none Size: 48B array([[0.63696169, 0.01652764], [0.26978671, 0.81327024], [0.04097352, 0.91275558]]) Coordinates: * y (y) int64 24B 10 20 30 * x (x)
<xarray.DataArray (y: 3, x: 2)> Size: 48B
array([[0.63696169, 0.01652764],
       [0.26978671, 0.81327024],
       [0.04097352, 0.91275558]])
Coordinates:
  \* y        (y) int64 24B 10 20 30
  \* x        (x) <U1 8B 'a' 'b'
```ipython3 intarr = xr.DataArray([0, 1, 2, 3, 4, 5]) intarr << 2 # only supported for int types ``` ```none Size: 48B array([ 0, 4, 8, 12, 16, 20]) Dimensions without coordinates: dim_0 ```
<xarray.DataArray (dim_0: 6)> Size: 48B
array([ 0,  4,  8, 12, 16, 20])
Dimensions without coordinates: dim_0
```ipython3 intarr >> 1 ``` ```none Size: 48B array([0, 0, 1, 1, 2, 2]) Dimensions without coordinates: dim_0 ```
<xarray.DataArray (dim_0: 6)> Size: 48B
array([0, 0, 1, 1, 2, 2])
Dimensions without coordinates: dim_0
## Missing values Xarray represents missing values using the “NaN” (Not a Number) value from NumPy, which is a special floating-point value that indicates a value that is undefined or unrepresentable. There are several methods for handling missing values in xarray: Xarray objects borrow the [`isnull()`](../generated/xarray.DataArray.isnull.md#xarray.DataArray.isnull), [`notnull()`](../generated/xarray.DataArray.notnull.md#xarray.DataArray.notnull), [`count()`](../generated/xarray.DataArray.count.md#xarray.DataArray.count), [`dropna()`](../generated/xarray.DataArray.dropna.md#xarray.DataArray.dropna), [`fillna()`](../generated/xarray.DataArray.fillna.md#xarray.DataArray.fillna), [`ffill()`](../generated/xarray.DataArray.ffill.md#xarray.DataArray.ffill), and [`bfill()`](../generated/xarray.DataArray.bfill.md#xarray.DataArray.bfill) methods for working with missing data from pandas: [`isnull()`](../generated/xarray.DataArray.isnull.md#xarray.DataArray.isnull) is a method in xarray that can be used to check for missing or null values in an xarray object. It returns a new xarray object with the same dimensions as the original object, but with boolean values indicating where **missing values** are present. ```ipython3 x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"]) x.isnull() ``` ```none Size: 5B array([False, False, True, True, False]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 5)> Size: 5B
array([False, False,  True,  True, False])
Dimensions without coordinates: x
In this example, the third and fourth elements of ‘x’ are NaN, so the resulting [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) object has ‘True’ values in the third and fourth positions and ‘False’ values in the other positions. [`notnull()`](../generated/xarray.DataArray.notnull.md#xarray.DataArray.notnull) is a method in xarray that can be used to check for non-missing or non-null values in an xarray object. It returns a new xarray object with the same dimensions as the original object, but with boolean values indicating where **non-missing values** are present. ```ipython3 x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"]) x.notnull() ``` ```none Size: 5B array([ True, True, False, False, True]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 5)> Size: 5B
array([ True,  True, False, False,  True])
Dimensions without coordinates: x
In this example, the first two and the last elements of x are not NaN, so the resulting [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) object has ‘True’ values in these positions, and ‘False’ values in the third and fourth positions where NaN is located. [`count()`](../generated/xarray.DataArray.count.md#xarray.DataArray.count) is a method in xarray that can be used to count the number of non-missing values along one or more dimensions of an xarray object. It returns a new xarray object with the same dimensions as the original object, but with each element replaced by the count of non-missing values along the specified dimensions. ```ipython3 x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"]) x.count() ``` ```none Size: 8B array(3) ```
<xarray.DataArray ()> Size: 8B
array(3)
In this example, ‘x’ has five elements, but two of them are NaN, so the resulting [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) object having a single element containing the value ‘3’, which represents the number of non-null elements in x. [`dropna()`](../generated/xarray.DataArray.dropna.md#xarray.DataArray.dropna) is a method in xarray that can be used to remove missing or null values from an xarray object. It returns a new xarray object with the same dimensions as the original object, but with missing values removed. ```ipython3 x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"]) x.dropna(dim="x") ``` ```none Size: 24B array([0., 1., 2.]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 3)> Size: 24B
array([0., 1., 2.])
Dimensions without coordinates: x
In this example, on calling x.dropna(dim=”x”) removes any missing values and returns a new [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) object with only the non-null elements [0, 1, 2] of ‘x’, in the original order. [`fillna()`](../generated/xarray.DataArray.fillna.md#xarray.DataArray.fillna) is a method in xarray that can be used to fill missing or null values in an xarray object with a specified value or method. It returns a new xarray object with the same dimensions as the original object, but with missing values filled. ```ipython3 x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"]) x.fillna(-1) ``` ```none Size: 40B array([ 0., 1., -1., -1., 2.]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 5)> Size: 40B
array([ 0.,  1., -1., -1.,  2.])
Dimensions without coordinates: x
In this example, there are two NaN values in ‘x’, so calling x.fillna(-1) replaces these values with -1 and returns a new [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) object with five elements, containing the values [0, 1, -1, -1, 2] in the original order. [`ffill()`](../generated/xarray.DataArray.ffill.md#xarray.DataArray.ffill) is a method in xarray that can be used to forward fill (or fill forward) missing values in an xarray object along one or more dimensions. It returns a new xarray object with the same dimensions as the original object, but with missing values replaced by the last non-missing value along the specified dimensions. ```ipython3 x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"]) x.ffill("x") ``` ```none Size: 40B array([0., 1., 1., 1., 2.]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 5)> Size: 40B
array([0., 1., 1., 1., 2.])
Dimensions without coordinates: x
In this example, there are two NaN values in ‘x’, so calling x.ffill(“x”) fills these values with the last non-null value in the same dimension, which are 0 and 1, respectively. The resulting [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) object has five elements, containing the values [0, 1, 1, 1, 2] in the original order. [`bfill()`](../generated/xarray.DataArray.bfill.md#xarray.DataArray.bfill) is a method in xarray that can be used to backward fill (or fill backward) missing values in an xarray object along one or more dimensions. It returns a new xarray object with the same dimensions as the original object, but with missing values replaced by the next non-missing value along the specified dimensions. ```ipython3 x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"]) x.bfill("x") ``` ```none Size: 40B array([0., 1., 2., 2., 2.]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 5)> Size: 40B
array([0., 1., 2., 2., 2.])
Dimensions without coordinates: x
In this example, there are two NaN values in ‘x’, so calling x.bfill(“x”) fills these values with the next non-null value in the same dimension, which are 2 and 2, respectively. The resulting [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) object has five elements, containing the values [0, 1, 2, 2, 2] in the original order. Like pandas, xarray uses the float value `np.nan` (not-a-number) to represent missing values. Xarray objects also have an [`interpolate_na()`](../generated/xarray.DataArray.interpolate_na.md#xarray.DataArray.interpolate_na) method for filling missing values via 1D interpolation. It returns a new xarray object with the same dimensions as the original object, but with missing values interpolated. ```ipython3 x = xr.DataArray( [0, 1, np.nan, np.nan, 2], dims=["x"], coords={"xx": xr.Variable("x", [0, 1, 1.1, 1.9, 3])}, ) x.interpolate_na(dim="x", method="linear", use_coordinate="xx") ``` ```none Size: 40B array([0. , 1. , 1.05, 1.45, 2. ]) Coordinates: xx (x) float64 40B 0.0 1.0 1.1 1.9 3.0 Dimensions without coordinates: x ```
<xarray.DataArray (x: 5)> Size: 40B
array([0.  , 1.  , 1.05, 1.45, 2.  ])
Coordinates:
    xx       (x) float64 40B 0.0 1.0 1.1 1.9 3.0
Dimensions without coordinates: x
In this example, there are two NaN values in ‘x’, so calling x.interpolate_na(dim=”x”, method=”linear”, use_coordinate=”xx”) fills these values with interpolated values along the “x” dimension using linear interpolation based on the values of the xx coordinate. The resulting [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) object has five elements, containing the values [0., 1., 1.05, 1.45, 2.] in the original order. Note that the interpolated values are calculated based on the values of the ‘xx’ coordinate, which has non-integer values, resulting in non-integer interpolated values. Note that xarray slightly diverges from the pandas `interpolate` syntax by providing the `use_coordinate` keyword which facilitates a clear specification of which values to use as the index in the interpolation. Xarray also provides the `max_gap` keyword argument to limit the interpolation to data gaps of length `max_gap` or smaller. See [`interpolate_na()`](../generated/xarray.DataArray.interpolate_na.md#xarray.DataArray.interpolate_na) for more. ## Aggregation Aggregation methods have been updated to take a `dim` argument instead of `axis`. This allows for very intuitive syntax for aggregation methods that are applied along particular dimension(s): ```ipython3 arr.sum(dim="x") ``` ```none Size: 24B array([0.65348932, 1.08305695, 0.9537291 ]) Coordinates: * y (y) int64 24B 10 20 30 ```
<xarray.DataArray (y: 3)> Size: 24B
array([0.65348932, 1.08305695, 0.9537291 ])
Coordinates:
  \* y        (y) int64 24B 10 20 30
```ipython3 arr.std(["x", "y"]) ``` ```none Size: 8B array(0.35793963) ```
<xarray.DataArray ()> Size: 8B
array(0.35793963)
```ipython3 arr.min() ``` ```none Size: 8B array(0.01652764) ```
<xarray.DataArray ()> Size: 8B
array(0.01652764)
If you need to figure out the axis number for a dimension yourself (say, for wrapping code designed to work with numpy arrays), you can use the [`get_axis_num()`](../generated/xarray.DataArray.get_axis_num.md#xarray.DataArray.get_axis_num) method: ```ipython3 arr.get_axis_num("y") ``` ```none 1 ``` These operations automatically skip missing values, like in pandas: ```ipython3 xr.DataArray([1, 2, np.nan, 3]).mean() ``` ```none Size: 8B array(2.) ```
<xarray.DataArray ()> Size: 8B
array(2.)
If desired, you can disable this behavior by invoking the aggregation method with `skipna=False`. ## Rolling window operations `DataArray` objects include a [`rolling()`](../generated/xarray.DataArray.rolling.md#xarray.DataArray.rolling) method. This method supports rolling window aggregation: ```ipython3 arr = xr.DataArray(np.arange(0, 7.5, 0.5).reshape(3, 5), dims=("x", "y")) arr ``` ```none Size: 120B array([[0. , 0.5, 1. , 1.5, 2. ], [2.5, 3. , 3.5, 4. , 4.5], [5. , 5.5, 6. , 6.5, 7. ]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 3, y: 5)> Size: 120B
array([[0. , 0.5, 1. , 1.5, 2. ],
       [2.5, 3. , 3.5, 4. , 4.5],
       [5. , 5.5, 6. , 6.5, 7. ]])
Dimensions without coordinates: x, y
[`rolling()`](../generated/xarray.DataArray.rolling.md#xarray.DataArray.rolling) is applied along one dimension using the name of the dimension as a key (e.g. `y`) and the window size as the value (e.g. `3`). We get back a `Rolling` object: ```ipython3 arr.rolling(y=3) ``` ```none DataArrayRolling [y->3] ``` Aggregation and summary methods can be applied directly to the `Rolling` object: ```ipython3 r = arr.rolling(y=3) r.reduce(np.std) ``` ```none Size: 120B array([[ nan, nan, 0.40824829, 0.40824829, 0.40824829], [ nan, nan, 0.40824829, 0.40824829, 0.40824829], [ nan, nan, 0.40824829, 0.40824829, 0.40824829]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 3, y: 5)> Size: 120B
array([[       nan,        nan, 0.40824829, 0.40824829, 0.40824829],
       [       nan,        nan, 0.40824829, 0.40824829, 0.40824829],
       [       nan,        nan, 0.40824829, 0.40824829, 0.40824829]])
Dimensions without coordinates: x, y
```ipython3 r.mean() ``` ```none Size: 120B array([[nan, nan, 0.5, 1. , 1.5], [nan, nan, 3. , 3.5, 4. ], [nan, nan, 5.5, 6. , 6.5]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 3, y: 5)> Size: 120B
array([[nan, nan, 0.5, 1. , 1.5],
       [nan, nan, 3. , 3.5, 4. ],
       [nan, nan, 5.5, 6. , 6.5]])
Dimensions without coordinates: x, y
Aggregation results are assigned the coordinate at the end of each window by default, but can be centered by passing `center=True` when constructing the `Rolling` object: ```ipython3 r = arr.rolling(y=3, center=True) r.mean() ``` ```none Size: 120B array([[nan, 0.5, 1. , 1.5, nan], [nan, 3. , 3.5, 4. , nan], [nan, 5.5, 6. , 6.5, nan]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 3, y: 5)> Size: 120B
array([[nan, 0.5, 1. , 1.5, nan],
       [nan, 3. , 3.5, 4. , nan],
       [nan, 5.5, 6. , 6.5, nan]])
Dimensions without coordinates: x, y
As can be seen above, aggregations of windows which overlap the border of the array produce `nan`s. Setting `min_periods` in the call to `rolling` changes the minimum number of observations within the window required to have a value when aggregating: ```ipython3 r = arr.rolling(y=3, min_periods=2) r.mean() ``` ```none Size: 120B array([[ nan, 0.25, 0.5 , 1. , 1.5 ], [ nan, 2.75, 3. , 3.5 , 4. ], [ nan, 5.25, 5.5 , 6. , 6.5 ]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 3, y: 5)> Size: 120B
array([[ nan, 0.25, 0.5 , 1.  , 1.5 ],
       [ nan, 2.75, 3.  , 3.5 , 4.  ],
       [ nan, 5.25, 5.5 , 6.  , 6.5 ]])
Dimensions without coordinates: x, y
```ipython3 r = arr.rolling(y=3, center=True, min_periods=2) r.mean() ``` ```none Size: 120B array([[0.25, 0.5 , 1. , 1.5 , 1.75], [2.75, 3. , 3.5 , 4. , 4.25], [5.25, 5.5 , 6. , 6.5 , 6.75]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 3, y: 5)> Size: 120B
array([[0.25, 0.5 , 1.  , 1.5 , 1.75],
       [2.75, 3.  , 3.5 , 4.  , 4.25],
       [5.25, 5.5 , 6.  , 6.5 , 6.75]])
Dimensions without coordinates: x, y
From version 0.17, xarray supports multidimensional rolling, ```ipython3 r = arr.rolling(x=2, y=3, min_periods=2) r.mean() ``` ```none Size: 120B array([[ nan, 0.25, 0.5 , 1. , 1.5 ], [1.25, 1.5 , 1.75, 2.25, 2.75], [3.75, 4. , 4.25, 4.75, 5.25]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 3, y: 5)> Size: 120B
array([[ nan, 0.25, 0.5 , 1.  , 1.5 ],
       [1.25, 1.5 , 1.75, 2.25, 2.75],
       [3.75, 4.  , 4.25, 4.75, 5.25]])
Dimensions without coordinates: x, y
We can also manually iterate through `Rolling` objects: ```python for label, arr_window in r: # arr_window is a view of x ... ``` While `rolling` provides a simple moving average, `DataArray` also supports an exponential moving average with [`rolling_exp()`](../generated/xarray.DataArray.rolling_exp.md#xarray.DataArray.rolling_exp). This is similar to pandas’ `ewm` method. [numbagg](https://github.com/numbagg/numbagg) is required. ```python arr.rolling_exp(y=3).mean() ``` The `rolling_exp` method takes a `window_type` kwarg, which can be `'alpha'`, `'com'` (for `center-of-mass`), `'span'`, and `'halflife'`. The default is `span`. Finally, the rolling object has a `construct` method which returns a view of the original `DataArray` with the windowed dimension in the last position. You can use this for more advanced rolling operations such as strided rolling, windowed rolling, convolution, short-time FFT etc. ```ipython3 # rolling with 2-point stride rolling_da = r.construct(x="x_win", y="y_win", stride=2) rolling_da ``` ```none Size: 288B array([[[[nan, nan, nan], [nan, nan, 0. ]], [[nan, nan, nan], [0. , 0.5, 1. ]], [[nan, nan, nan], [1. , 1.5, 2. ]]], [[[nan, nan, 2.5], [nan, nan, 5. ]], [[2.5, 3. , 3.5], [5. , 5.5, 6. ]], [[3.5, 4. , 4.5], [6. , 6.5, 7. ]]]]) Dimensions without coordinates: x, y, x_win, y_win ```
<xarray.DataArray (x: 2, y: 3, x_win: 2, y_win: 3)> Size: 288B
array([[[[nan, nan, nan],
         [nan, nan, 0. ]],

        [[nan, nan, nan],
         [0. , 0.5, 1. ]],

        [[nan, nan, nan],
         [1. , 1.5, 2. ]]],


       [[[nan, nan, 2.5],
         [nan, nan, 5. ]],

        [[2.5, 3. , 3.5],
         [5. , 5.5, 6. ]],

        [[3.5, 4. , 4.5],
         [6. , 6.5, 7. ]]]])
Dimensions without coordinates: x, y, x_win, y_win
```ipython3 rolling_da.mean(["x_win", "y_win"], skipna=False) ``` ```none Size: 48B array([[ nan, nan, nan], [ nan, 4.25, 5.25]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[ nan,  nan,  nan],
       [ nan, 4.25, 5.25]])
Dimensions without coordinates: x, y
Because the `DataArray` given by `r.construct('window_dim')` is a view of the original array, it is memory efficient. You can also use `construct` to compute a weighted rolling sum: ```ipython3 weight = xr.DataArray([0.25, 0.5, 0.25], dims=["window"]) arr.rolling(y=3).construct(y="window").dot(weight) ``` ```none Size: 120B array([[nan, nan, 0.5, 1. , 1.5], [nan, nan, 3. , 3.5, 4. ], [nan, nan, 5.5, 6. , 6.5]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 3, y: 5)> Size: 120B
array([[nan, nan, 0.5, 1. , 1.5],
       [nan, nan, 3. , 3.5, 4. ],
       [nan, nan, 5.5, 6. , 6.5]])
Dimensions without coordinates: x, y
#### NOTE numpy’s Nan-aggregation functions such as `nansum` copy the original array. In xarray, we internally use these functions in our aggregation methods (such as `.sum()`) if `skipna` argument is not specified or set to True. This means `rolling_da.mean('window_dim')` is memory inefficient. To avoid this, use `skipna=False` as the above example. ## Weighted array reductions [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) and [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) objects include [`DataArray.weighted()`](../generated/xarray.DataArray.weighted.md#xarray.DataArray.weighted) and [`Dataset.weighted()`](../generated/xarray.Dataset.weighted.md#xarray.Dataset.weighted) array reduction methods. They currently support weighted `sum`, `mean`, `std`, `var` and `quantile`. ```ipython3 coords = dict(month=("month", [1, 2, 3])) prec = xr.DataArray([1.1, 1.0, 0.9], dims=("month",), coords=coords) weights = xr.DataArray([31, 28, 31], dims=("month",), coords=coords) ``` Create a weighted object: ```ipython3 weighted_prec = prec.weighted(weights) weighted_prec ``` ```none DataArrayWeighted with weights along dimensions: month ``` Calculate the weighted sum: ```ipython3 weighted_prec.sum() ``` ```none Size: 8B array(90.) ```
<xarray.DataArray ()> Size: 8B
array(90.)
Calculate the weighted mean: ```ipython3 weighted_prec.mean(dim="month") ``` ```none Size: 8B array(1.) ```
<xarray.DataArray ()> Size: 8B
array(1.)
Calculate the weighted quantile: ```ipython3 weighted_prec.quantile(q=0.5, dim="month") ``` ```none Size: 8B array(1.) Coordinates: quantile float64 8B 0.5 ```
<xarray.DataArray ()> Size: 8B
array(1.)
Coordinates:
    quantile  float64 8B 0.5
The weighted sum corresponds to: ```ipython3 weighted_sum = (prec * weights).sum() weighted_sum ``` ```none Size: 8B array(90.) ```
<xarray.DataArray ()> Size: 8B
array(90.)
the weighted mean to: ```ipython3 weighted_mean = weighted_sum / weights.sum() weighted_mean ``` ```none Size: 8B array(1.) ```
<xarray.DataArray ()> Size: 8B
array(1.)
the weighted variance to: ```ipython3 weighted_var = weighted_prec.sum_of_squares() / weights.sum() weighted_var ``` ```none Size: 8B array(0.00688889) ```
<xarray.DataArray ()> Size: 8B
array(0.00688889)
and the weighted standard deviation to: ```ipython3 weighted_std = np.sqrt(weighted_var) weighted_std ``` ```none Size: 8B array(0.08299933) ```
<xarray.DataArray ()> Size: 8B
array(0.08299933)
However, the functions also take missing values in the data into account: ```ipython3 data = xr.DataArray([np.nan, 2, 4]) weights = xr.DataArray([8, 1, 1]) data.weighted(weights).mean() ``` ```none Size: 8B array(3.) ```
<xarray.DataArray ()> Size: 8B
array(3.)
Using `(data * weights).sum() / weights.sum()` would (incorrectly) result in 0.6. If the weights add up to to 0, `sum` returns 0: ```ipython3 data = xr.DataArray([1.0, 1.0]) weights = xr.DataArray([-1.0, 1.0]) data.weighted(weights).sum() ``` ```none Size: 8B array(0.) ```
<xarray.DataArray ()> Size: 8B
array(0.)
and `mean`, `std` and `var` return `nan`: ```ipython3 data.weighted(weights).mean() ``` ```none Size: 8B array(nan) ```
<xarray.DataArray ()> Size: 8B
array(nan)
#### NOTE `weights` must be a [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) and cannot contain missing values. Missing values can be replaced manually by `weights.fillna(0)`. ## Coarsen large arrays [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) and [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) objects include a [`coarsen()`](../generated/xarray.DataArray.coarsen.md#xarray.DataArray.coarsen) and [`coarsen()`](../generated/xarray.Dataset.coarsen.md#xarray.Dataset.coarsen) methods. This supports block aggregation along multiple dimensions, ```ipython3 x = np.linspace(0, 10, 300) t = pd.date_range("1999-12-15", periods=364) da = xr.DataArray( np.sin(x) * np.cos(np.linspace(0, 1, 364)[:, np.newaxis]), dims=["time", "x"], coords={"time": t, "x": x}, ) da ``` ```none Size: 874kB array([[ 0. , 0.03343858, 0.06683976, ..., -0.48672119, -0.51565952, -0.54402111], [ 0. , 0.03343845, 0.06683951, ..., -0.48671934, -0.51565756, -0.54401905], [ 0. , 0.03343807, 0.06683875, ..., -0.4867138 , -0.51565169, -0.54401285], ..., [ 0. , 0.0182217 , 0.03642301, ..., -0.26522911, -0.28099849, -0.29645358], [ 0. , 0.01814439, 0.03626848, ..., -0.26410385, -0.27980632, -0.29519584], [ 0. , 0.01806694, 0.03611368, ..., -0.26297658, -0.27861203, -0.29393586]], shape=(364, 300)) Coordinates: * time (time) datetime64[us] 3kB 1999-12-15 1999-12-16 ... 2000-12-12 * x (x) float64 2kB 0.0 0.03344 0.06689 0.1003 ... 9.9 9.933 9.967 10.0 ```
<xarray.DataArray (time: 364, x: 300)> Size: 874kB
array([[ 0.        ,  0.03343858,  0.06683976, ..., -0.48672119,
        -0.51565952, -0.54402111],
       [ 0.        ,  0.03343845,  0.06683951, ..., -0.48671934,
        -0.51565756, -0.54401905],
       [ 0.        ,  0.03343807,  0.06683875, ..., -0.4867138 ,
        -0.51565169, -0.54401285],
       ...,
       [ 0.        ,  0.0182217 ,  0.03642301, ..., -0.26522911,
        -0.28099849, -0.29645358],
       [ 0.        ,  0.01814439,  0.03626848, ..., -0.26410385,
        -0.27980632, -0.29519584],
       [ 0.        ,  0.01806694,  0.03611368, ..., -0.26297658,
        -0.27861203, -0.29393586]], shape=(364, 300))
Coordinates:
  \* time     (time) datetime64[us] 3kB 1999-12-15 1999-12-16 ... 2000-12-12
  \* x        (x) float64 2kB 0.0 0.03344 0.06689 0.1003 ... 9.9 9.933 9.967 10.0
In order to take a block mean for every 7 days along `time` dimension and every 2 points along `x` dimension, ```ipython3 da.coarsen(time=7, x=2).mean() ``` ```none Size: 62kB array([[ 0.01671847, 0.08349886, 0.14990579, ..., -0.41198807, -0.47195655, -0.52981418], [ 0.01671269, 0.08347003, 0.14985403, ..., -0.41184582, -0.47179359, -0.52963124], [ 0.01670071, 0.08341016, 0.14974655, ..., -0.41155042, -0.47145519, -0.52925136], ..., [ 0.00968205, 0.04835611, 0.0868139 , ..., -0.23859177, -0.2733209 , -0.30682759], [ 0.00941742, 0.04703446, 0.08444113, ..., -0.23207067, -0.26585059, -0.29844148], [ 0.00914929, 0.04569531, 0.08203696, ..., -0.22546326, -0.25828142, -0.2899444 ]], shape=(52, 150)) Coordinates: * time (time) datetime64[us] 416B 1999-12-18 1999-12-25 ... 2000-12-09 * x (x) float64 1kB 0.01672 0.08361 0.1505 0.2174 ... 9.849 9.916 9.983 ```
<xarray.DataArray (time: 52, x: 150)> Size: 62kB
array([[ 0.01671847,  0.08349886,  0.14990579, ..., -0.41198807,
        -0.47195655, -0.52981418],
       [ 0.01671269,  0.08347003,  0.14985403, ..., -0.41184582,
        -0.47179359, -0.52963124],
       [ 0.01670071,  0.08341016,  0.14974655, ..., -0.41155042,
        -0.47145519, -0.52925136],
       ...,
       [ 0.00968205,  0.04835611,  0.0868139 , ..., -0.23859177,
        -0.2733209 , -0.30682759],
       [ 0.00941742,  0.04703446,  0.08444113, ..., -0.23207067,
        -0.26585059, -0.29844148],
       [ 0.00914929,  0.04569531,  0.08203696, ..., -0.22546326,
        -0.25828142, -0.2899444 ]], shape=(52, 150))
Coordinates:
  \* time     (time) datetime64[us] 416B 1999-12-18 1999-12-25 ... 2000-12-09
  \* x        (x) float64 1kB 0.01672 0.08361 0.1505 0.2174 ... 9.849 9.916 9.983
[`coarsen()`](../generated/xarray.DataArray.coarsen.md#xarray.DataArray.coarsen) raises a `ValueError` if the data length is not a multiple of the corresponding window size. You can choose `boundary='trim'` or `boundary='pad'` options for trimming the excess entries or padding `nan` to insufficient entries, ```ipython3 da.coarsen(time=30, x=2, boundary="trim").mean() ``` ```none Size: 14kB array([[ 0.01670121, 0.08341265, 0.14975103, ..., -0.41156272, -0.47146929, -0.52926718], [ 0.0165891 , 0.08285275, 0.14874584, ..., -0.40880017, -0.46830462, -0.52571455], [ 0.01636376, 0.08172729, 0.14672529, ..., -0.40324704, -0.46194319, -0.51857326], ..., [ 0.01183847, 0.05912615, 0.10614938, ..., -0.29173175, -0.33419587, -0.37516528], [ 0.01082401, 0.05405954, 0.09705329, ..., -0.26673283, -0.30555813, -0.34301681], [ 0.00973567, 0.04862391, 0.08729468, ..., -0.23991312, -0.27483458, -0.30852683]], shape=(12, 150)) Coordinates: * time (time) datetime64[us] 96B 1999-12-29T12:00:00 ... 2000-11-23T12:... * x (x) float64 1kB 0.01672 0.08361 0.1505 0.2174 ... 9.849 9.916 9.983 ```
<xarray.DataArray (time: 12, x: 150)> Size: 14kB
array([[ 0.01670121,  0.08341265,  0.14975103, ..., -0.41156272,
        -0.47146929, -0.52926718],
       [ 0.0165891 ,  0.08285275,  0.14874584, ..., -0.40880017,
        -0.46830462, -0.52571455],
       [ 0.01636376,  0.08172729,  0.14672529, ..., -0.40324704,
        -0.46194319, -0.51857326],
       ...,
       [ 0.01183847,  0.05912615,  0.10614938, ..., -0.29173175,
        -0.33419587, -0.37516528],
       [ 0.01082401,  0.05405954,  0.09705329, ..., -0.26673283,
        -0.30555813, -0.34301681],
       [ 0.00973567,  0.04862391,  0.08729468, ..., -0.23991312,
        -0.27483458, -0.30852683]], shape=(12, 150))
Coordinates:
  \* time     (time) datetime64[us] 96B 1999-12-29T12:00:00 ... 2000-11-23T12:...
  \* x        (x) float64 1kB 0.01672 0.08361 0.1505 0.2174 ... 9.849 9.916 9.983
If you want to apply a specific function to coordinate, you can pass the function or method name to `coord_func` option, ```ipython3 da.coarsen(time=7, x=2, coord_func={"time": "min"}).mean() ``` ```none Size: 62kB array([[ 0.01671847, 0.08349886, 0.14990579, ..., -0.41198807, -0.47195655, -0.52981418], [ 0.01671269, 0.08347003, 0.14985403, ..., -0.41184582, -0.47179359, -0.52963124], [ 0.01670071, 0.08341016, 0.14974655, ..., -0.41155042, -0.47145519, -0.52925136], ..., [ 0.00968205, 0.04835611, 0.0868139 , ..., -0.23859177, -0.2733209 , -0.30682759], [ 0.00941742, 0.04703446, 0.08444113, ..., -0.23207067, -0.26585059, -0.29844148], [ 0.00914929, 0.04569531, 0.08203696, ..., -0.22546326, -0.25828142, -0.2899444 ]], shape=(52, 150)) Coordinates: * time (time) datetime64[us] 416B 1999-12-15 1999-12-22 ... 2000-12-06 * x (x) float64 1kB 0.01672 0.08361 0.1505 0.2174 ... 9.849 9.916 9.983 ```
<xarray.DataArray (time: 52, x: 150)> Size: 62kB
array([[ 0.01671847,  0.08349886,  0.14990579, ..., -0.41198807,
        -0.47195655, -0.52981418],
       [ 0.01671269,  0.08347003,  0.14985403, ..., -0.41184582,
        -0.47179359, -0.52963124],
       [ 0.01670071,  0.08341016,  0.14974655, ..., -0.41155042,
        -0.47145519, -0.52925136],
       ...,
       [ 0.00968205,  0.04835611,  0.0868139 , ..., -0.23859177,
        -0.2733209 , -0.30682759],
       [ 0.00941742,  0.04703446,  0.08444113, ..., -0.23207067,
        -0.26585059, -0.29844148],
       [ 0.00914929,  0.04569531,  0.08203696, ..., -0.22546326,
        -0.25828142, -0.2899444 ]], shape=(52, 150))
Coordinates:
  \* time     (time) datetime64[us] 416B 1999-12-15 1999-12-22 ... 2000-12-06
  \* x        (x) float64 1kB 0.01672 0.08361 0.1505 0.2174 ... 9.849 9.916 9.983
You can also [use coarsen to reshape](reshaping.md#reshape-coarsen) without applying a computation. ## Computation using Coordinates Xarray objects have some handy methods for the computation with their coordinates. [`differentiate()`](../generated/xarray.DataArray.differentiate.md#xarray.DataArray.differentiate) computes derivatives by central finite differences using their coordinates, ```ipython3 a = xr.DataArray([0, 1, 2, 3], dims=["x"], coords=[[0.1, 0.11, 0.2, 0.3]]) a.differentiate("x") ``` ```none Size: 32B array([100. , 91.11111111, 10.58479532, 10. ]) Coordinates: * x (x) float64 32B 0.1 0.11 0.2 0.3 ```
<xarray.DataArray (x: 4)> Size: 32B
array([100.        ,  91.11111111,  10.58479532,  10.        ])
Coordinates:
  \* x        (x) float64 32B 0.1 0.11 0.2 0.3
This method can be used also for multidimensional arrays, ```ipython3 a = xr.DataArray( np.arange(8).reshape(4, 2), dims=["x", "y"], coords={"x": [0.1, 0.11, 0.2, 0.3]} ) a.differentiate("x") ``` ```none Size: 64B array([[200. , 200. ], [182.22222222, 182.22222222], [ 21.16959064, 21.16959064], [ 20. , 20. ]]) Coordinates: * x (x) float64 32B 0.1 0.11 0.2 0.3 Dimensions without coordinates: y ```
<xarray.DataArray (x: 4, y: 2)> Size: 64B
array([[200.        , 200.        ],
       [182.22222222, 182.22222222],
       [ 21.16959064,  21.16959064],
       [ 20.        ,  20.        ]])
Coordinates:
  \* x        (x) float64 32B 0.1 0.11 0.2 0.3
Dimensions without coordinates: y
[`integrate()`](../generated/xarray.DataArray.integrate.md#xarray.DataArray.integrate) computes integration based on trapezoidal rule using their coordinates, ```ipython3 a.integrate("x") ``` ```none Size: 16B array([0.78, 0.98]) Dimensions without coordinates: y ```
<xarray.DataArray (y: 2)> Size: 16B
array([0.78, 0.98])
Dimensions without coordinates: y
#### NOTE These methods are limited to simple cartesian geometry. Differentiation and integration along multidimensional coordinate are not supported. ## Fitting polynomials Xarray objects provide an interface for performing linear or polynomial regressions using the least-squares method. [`polyfit()`](../generated/xarray.DataArray.polyfit.md#xarray.DataArray.polyfit) computes the best fitting coefficients along a given dimension and for a given order, ```ipython3 x = xr.DataArray(np.arange(10), dims=["x"], name="x") a = xr.DataArray(3 + 4 * x, dims=["x"], coords={"x": x}) out = a.polyfit(dim="x", deg=1, full=True) out ``` ```none Size: 64B Dimensions: (degree: 2) Coordinates: * degree (degree) int64 16B 1 0 Data variables: x_matrix_rank int64 8B 2 x_singular_values (degree) float64 16B 1.358 0.3963 polyfit_coefficients (degree) float64 16B 4.0 3.0 polyfit_residuals float64 8B 1.799e-28 ```
<xarray.Dataset> Size: 64B
Dimensions:               (degree: 2)
Coordinates:
  \* degree                (degree) int64 16B 1 0
Data variables:
    x_matrix_rank         int64 8B 2
    x_singular_values     (degree) float64 16B 1.358 0.3963
    polyfit_coefficients  (degree) float64 16B 4.0 3.0
    polyfit_residuals     float64 8B 1.799e-28
The method outputs a dataset containing the coefficients (and more if `full=True`). The inverse operation is done with [`polyval()`](../generated/xarray.polyval.md#xarray.polyval), ```ipython3 xr.polyval(coord=x, coeffs=out.polyfit_coefficients) ``` ```none Size: 80B array([ 3., 7., 11., 15., 19., 23., 27., 31., 35., 39.]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 10)> Size: 80B
array([ 3.,  7., 11., 15., 19., 23., 27., 31., 35., 39.])
Dimensions without coordinates: x
#### NOTE These methods replicate the behaviour of [`numpy.polyfit()`](https://numpy.org/doc/stable/reference/generated/numpy.polyfit.html#numpy.polyfit) and [`numpy.polyval()`](https://numpy.org/doc/stable/reference/generated/numpy.polyval.html#numpy.polyval). ## Fitting arbitrary functions Xarray objects also provide an interface for fitting more complex functions using [`scipy.optimize.curve_fit()`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html#scipy.optimize.curve_fit). [`curvefit()`](../generated/xarray.DataArray.curvefit.md#xarray.DataArray.curvefit) accepts user-defined functions and can fit along multiple coordinates. For example, we can fit a relationship between two `DataArray` objects, maintaining a unique fit at each spatial coordinate but aggregating over the time dimension: ```ipython3 def exponential(x, a, xc): return np.exp((x - xc) / a) x = np.arange(-5, 5, 0.1) t = np.arange(-5, 5, 0.1) X, T = np.meshgrid(x, t) Z1 = np.random.uniform(low=-5, high=5, size=X.shape) Z2 = exponential(Z1, 3, X) Z3 = exponential(Z1, 1, -X) ds = xr.Dataset( data_vars=dict( var1=(["t", "x"], Z1), var2=(["t", "x"], Z2), var3=(["t", "x"], Z3) ), coords={"t": t, "x": x}, ) ds[["var2", "var3"]].curvefit( coords=ds.var1, func=exponential, reduce_dims="t", bounds={"a": (0.5, 5), "xc": (-5, 5)}, ) ``` ```none Size: 10kB Dimensions: (x: 100, param: 2, cov_i: 2, cov_j: 2) Coordinates: * x (x) float64 800B -5.0 -4.9 -4.8 ... 4.7 4.8 4.9 * param (param)
<xarray.Dataset> Size: 10kB
Dimensions:                     (x: 100, param: 2, cov_i: 2, cov_j: 2)
Coordinates:
  \* x                           (x) float64 800B -5.0 -4.9 -4.8 ... 4.7 4.8 4.9
  \* param                       (param) <U2 16B 'a' 'xc'
  \* cov_i                       (cov_i) <U2 16B 'a' 'xc'
  \* cov_j                       (cov_j) <U2 16B 'a' 'xc'
Data variables:
    var2_curvefit_coefficients  (x, param) float64 2kB 3.0 -5.0 3.0 ... 3.0 4.9
    var2_curvefit_covariance    (x, cov_i, cov_j) float64 3kB 9.286e-14 ... 1...
    var3_curvefit_coefficients  (x, param) float64 2kB 0.9999 5.0 ... 1.0 -4.9
    var3_curvefit_covariance    (x, cov_i, cov_j) float64 3kB 5.825e-11 ... 1...
We can also fit multi-dimensional functions, and even use a wrapper function to simultaneously fit a summation of several functions, such as this field containing two gaussian peaks: ```ipython3 def gaussian_2d(coords, a, xc, yc, xalpha, yalpha): x, y = coords z = a * np.exp( -np.square(x - xc) / 2 / np.square(xalpha) - np.square(y - yc) / 2 / np.square(yalpha) ) return z def multi_peak(coords, *args): z = np.zeros(coords[0].shape) for i in range(len(args) // 5): z += gaussian_2d(coords, *args[i * 5 : i * 5 + 5]) return z x = np.arange(-5, 5, 0.1) y = np.arange(-5, 5, 0.1) X, Y = np.meshgrid(x, y) n_peaks = 2 names = ["a", "xc", "yc", "xalpha", "yalpha"] names = [f"{name}{i}" for i in range(n_peaks) for name in names] Z = gaussian_2d((X, Y), 3, 1, 1, 2, 1) + gaussian_2d((X, Y), 2, -1, -2, 1, 1) Z += np.random.normal(scale=0.1, size=Z.shape) da = xr.DataArray(Z, dims=["y", "x"], coords={"y": y, "x": x}) da.curvefit( coords=["x", "y"], func=multi_peak, param_names=names, kwargs={"maxfev": 10000}, ) ``` ```none Size: 2kB Dimensions: (param: 10, cov_i: 10, cov_j: 10) Coordinates: * param (param)
<xarray.Dataset> Size: 2kB
Dimensions:                (param: 10, cov_i: 10, cov_j: 10)
Coordinates:
  \* param                  (param) <U7 280B 'a0' 'xc0' ... 'xalpha1' 'yalpha1'
  \* cov_i                  (cov_i) <U7 280B 'a0' 'xc0' ... 'xalpha1' 'yalpha1'
  \* cov_j                  (cov_j) <U7 280B 'a0' 'xc0' ... 'xalpha1' 'yalpha1'
Data variables:
    curvefit_coefficients  (param) float64 80B 3.0 1.004 1.003 ... 1.007 1.008
    curvefit_covariance    (cov_i, cov_j) float64 800B 3.362e-05 ... 2.125e-05
#### NOTE This method replicates the behavior of [`scipy.optimize.curve_fit()`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html#scipy.optimize.curve_fit). ## Broadcasting by dimension name `DataArray` objects automatically align themselves (“broadcasting” in the numpy parlance) by dimension name instead of axis order. With xarray, you do not need to transpose arrays or insert dimensions of length 1 to get array operations to work, as commonly done in numpy with [`numpy.reshape()`](https://numpy.org/doc/stable/reference/generated/numpy.reshape.html#numpy.reshape) or [`numpy.newaxis`](https://numpy.org/doc/stable/reference/constants.html#numpy.newaxis). This is best illustrated by a few examples. Consider two one-dimensional arrays with different sizes aligned along different dimensions: ```ipython3 a = xr.DataArray([1, 2], [("x", ["a", "b"])]) a ``` ```none Size: 16B array([1, 2]) Coordinates: * x (x)
<xarray.DataArray (x: 2)> Size: 16B
array([1, 2])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
```ipython3 b = xr.DataArray([-1, -2, -3], [("y", [10, 20, 30])]) b ``` ```none Size: 24B array([-1, -2, -3]) Coordinates: * y (y) int64 24B 10 20 30 ```
<xarray.DataArray (y: 3)> Size: 24B
array([-1, -2, -3])
Coordinates:
  \* y        (y) int64 24B 10 20 30
With xarray, we can apply binary mathematical operations to these arrays, and their dimensions are expanded automatically: ```ipython3 a * b ``` ```none Size: 48B array([[-1, -2, -3], [-2, -4, -6]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[-1, -2, -3],
       [-2, -4, -6]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
Moreover, dimensions are always reordered to the order in which they first appeared: ```ipython3 c = xr.DataArray(np.arange(6).reshape(3, 2), [b["y"], a["x"]]) c ``` ```none Size: 48B array([[0, 1], [2, 3], [4, 5]]) Coordinates: * y (y) int64 24B 10 20 30 * x (x)
<xarray.DataArray (y: 3, x: 2)> Size: 48B
array([[0, 1],
       [2, 3],
       [4, 5]])
Coordinates:
  \* y        (y) int64 24B 10 20 30
  \* x        (x) <U1 8B 'a' 'b'
```ipython3 a + c ``` ```none Size: 48B array([[1, 3, 5], [3, 5, 7]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[1, 3, 5],
       [3, 5, 7]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
This means, for example, that you always subtract an array from its transpose: ```ipython3 c - c.T ``` ```none Size: 48B array([[0, 0], [0, 0], [0, 0]]) Coordinates: * y (y) int64 24B 10 20 30 * x (x)
<xarray.DataArray (y: 3, x: 2)> Size: 48B
array([[0, 0],
       [0, 0],
       [0, 0]])
Coordinates:
  \* y        (y) int64 24B 10 20 30
  \* x        (x) <U1 8B 'a' 'b'
You can explicitly broadcast xarray data structures by using the [`broadcast()`](../generated/xarray.broadcast.md#xarray.broadcast) function: ```ipython3 a2, b2 = xr.broadcast(a, b) a2 ``` ```none Size: 48B array([[1, 1, 1], [2, 2, 2]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[1, 1, 1],
       [2, 2, 2]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
```ipython3 b2 ``` ```none Size: 48B array([[-1, -2, -3], [-1, -2, -3]]) Coordinates: * x (x)
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[-1, -2, -3],
       [-1, -2, -3]])
Coordinates:
  \* x        (x) <U1 8B 'a' 'b'
  \* y        (y) int64 24B 10 20 30
## Automatic alignment Xarray enforces alignment between *index* [Coordinates](data-structures.md#coordinates) (that is, coordinates with the same name as a dimension, marked by `*`) on objects used in binary operations. Similarly to pandas, this alignment is automatic for arithmetic on binary operations. The default result of a binary operation is by the *intersection* (not the union) of coordinate labels: ```ipython3 arr = xr.DataArray(np.arange(3), [("x", range(3))]) arr + arr[:-1] ``` ```none Size: 16B array([0, 2]) Coordinates: * x (x) int64 16B 0 1 ```
<xarray.DataArray (x: 2)> Size: 16B
array([0, 2])
Coordinates:
  \* x        (x) int64 16B 0 1
If coordinate values for a dimension are missing on either argument, all matching dimensions must have the same size: ```ipython3 arr + xr.DataArray([1, 2], dims="x") ``` ```ipythontb AlignmentError: cannot reindex or align along dimension 'x' because of conflicting dimension sizes: {2, 3} (note: an index is found along that dimension with size=3) ``` However, one can explicitly change this default automatic alignment type (“inner”) via [`set_options()`](../generated/xarray.set_options.md#xarray.set_options) in context manager: ```ipython3 with xr.set_options(arithmetic_join="outer"): arr + arr[:1] arr + arr[:1] ``` ```none Size: 8B array([0]) Coordinates: * x (x) int64 8B 0 ```
<xarray.DataArray (x: 1)> Size: 8B
array([0])
Coordinates:
  \* x        (x) int64 8B 0
Before loops or performance critical code, it’s a good idea to align arrays explicitly (e.g., by putting them in the same Dataset or using [`align()`](../generated/xarray.align.md#xarray.align)) to avoid the overhead of repeated alignment with each operation. See [Align and reindex](indexing.md#align-and-reindex) for more details. #### NOTE There is no automatic alignment between arguments when performing in-place arithmetic operations such as `+=`. You will need to use [manual alignment](indexing.md#align-and-reindex). This ensures in-place arithmetic never needs to modify data types. ## Coordinates Although index coordinates are aligned, other coordinates are not, and if their values conflict, they will be dropped. This is necessary, for example, because indexing turns 1D coordinates into scalar coordinates: ```ipython3 arr[0] ``` ```none Size: 8B array(0) Coordinates: x int64 8B 0 ```
<xarray.DataArray ()> Size: 8B
array(0)
Coordinates:
    x        int64 8B 0
```ipython3 arr[1] ``` ```none Size: 8B array(1) Coordinates: x int64 8B 1 ```
<xarray.DataArray ()> Size: 8B
array(1)
Coordinates:
    x        int64 8B 1
```ipython3 # notice that the scalar coordinate 'x' is silently dropped arr[1] - arr[0] ``` ```none Size: 8B array(1) ```
<xarray.DataArray ()> Size: 8B
array(1)
Still, xarray will persist other coordinates in arithmetic, as long as there are no conflicting values: ```ipython3 # only one argument has the 'x' coordinate arr[0] + 1 ``` ```none Size: 8B array(1) Coordinates: x int64 8B 0 ```
<xarray.DataArray ()> Size: 8B
array(1)
Coordinates:
    x        int64 8B 0
```ipython3 # both arguments have the same 'x' coordinate arr[0] - arr[0] ``` ```none Size: 8B array(0) Coordinates: x int64 8B 0 ```
<xarray.DataArray ()> Size: 8B
array(0)
Coordinates:
    x        int64 8B 0
## Math with datasets Datasets support arithmetic operations by automatically looping over all data variables: ```ipython3 ds = xr.Dataset( { "x_and_y": (("x", "y"), np.random.randn(3, 5)), "x_only": ("x", np.random.randn(3)), }, coords=arr.coords, ) ds > 0 ``` ```none Size: 42B Dimensions: (x: 3, y: 5) Coordinates: * x (x) int64 24B 0 1 2 Dimensions without coordinates: y Data variables: x_and_y (x, y) bool 15B True True False True ... True False False False x_only (x) bool 3B False True False ```
<xarray.Dataset> Size: 42B
Dimensions:  (x: 3, y: 5)
Coordinates:
  \* x        (x) int64 24B 0 1 2
Dimensions without coordinates: y
Data variables:
    x_and_y  (x, y) bool 15B True True False True ... True False False False
    x_only   (x) bool 3B False True False
Datasets support most of the same methods found on data arrays: ```ipython3 ds.mean(dim="x") ``` ```none Size: 48B Dimensions: (y: 5) Dimensions without coordinates: y Data variables: x_and_y (y) float64 40B -0.1779 0.449 -0.6525 0.2515 0.09179 x_only float64 8B -0.371 ```
<xarray.Dataset> Size: 48B
Dimensions:  (y: 5)
Dimensions without coordinates: y
Data variables:
    x_and_y  (y) float64 40B -0.1779 0.449 -0.6525 0.2515 0.09179
    x_only   float64 8B -0.371
```ipython3 abs(ds) ``` ```none Size: 168B Dimensions: (x: 3, y: 5) Coordinates: * x (x) int64 24B 0 1 2 Dimensions without coordinates: y Data variables: x_and_y (x, y) float64 120B 0.4281 0.9399 0.884 ... 0.7523 0.1212 0.3989 x_only (x) float64 24B 0.5093 0.2509 0.8548 ```
<xarray.Dataset> Size: 168B
Dimensions:  (x: 3, y: 5)
Coordinates:
  \* x        (x) int64 24B 0 1 2
Dimensions without coordinates: y
Data variables:
    x_and_y  (x, y) float64 120B 0.4281 0.9399 0.884 ... 0.7523 0.1212 0.3989
    x_only   (x) float64 24B 0.5093 0.2509 0.8548
Datasets also support NumPy ufuncs (requires NumPy v1.13 or newer), or alternatively you can use [`map()`](../generated/xarray.Dataset.map.md#xarray.Dataset.map) to map a function to each variable in a dataset: ```ipython3 np.sin(ds) # equivalent to ds.map(np.sin) ``` ```none Size: 168B Dimensions: (x: 3, y: 5) Coordinates: * x (x) int64 24B 0 1 2 Dimensions without coordinates: y Data variables: x_and_y (x, y) float64 120B 0.4152 0.8075 -0.7733 ... -0.1209 -0.3884 x_only (x) float64 24B -0.4875 0.2483 -0.7544 ```
<xarray.Dataset> Size: 168B
Dimensions:  (x: 3, y: 5)
Coordinates:
  \* x        (x) int64 24B 0 1 2
Dimensions without coordinates: y
Data variables:
    x_and_y  (x, y) float64 120B 0.4152 0.8075 -0.7733 ... -0.1209 -0.3884
    x_only   (x) float64 24B -0.4875 0.2483 -0.7544
Datasets also use looping over variables for *broadcasting* in binary arithmetic. You can do arithmetic between any `DataArray` and a dataset: ```ipython3 ds + arr ``` ```none Size: 168B Dimensions: (x: 3, y: 5) Coordinates: * x (x) int64 24B 0 1 2 Dimensions without coordinates: y Data variables: x_and_y (x, y) float64 120B 0.4281 0.9399 -0.884 ... 1.248 1.879 1.601 x_only (x) float64 24B -0.5093 1.251 1.145 ```
<xarray.Dataset> Size: 168B
Dimensions:  (x: 3, y: 5)
Coordinates:
  \* x        (x) int64 24B 0 1 2
Dimensions without coordinates: y
Data variables:
    x_and_y  (x, y) float64 120B 0.4281 0.9399 -0.884 ... 1.248 1.879 1.601
    x_only   (x) float64 24B -0.5093 1.251 1.145
Arithmetic between two datasets matches data variables of the same name: ```ipython3 ds2 = xr.Dataset({"x_and_y": 0, "x_only": 100}) ds - ds2 ``` ```none Size: 168B Dimensions: (x: 3, y: 5) Coordinates: * x (x) int64 24B 0 1 2 Dimensions without coordinates: y Data variables: x_and_y (x, y) float64 120B 0.4281 0.9399 -0.884 ... -0.1212 -0.3989 x_only (x) float64 24B -100.5 -99.75 -100.9 ```
<xarray.Dataset> Size: 168B
Dimensions:  (x: 3, y: 5)
Coordinates:
  \* x        (x) int64 24B 0 1 2
Dimensions without coordinates: y
Data variables:
    x_and_y  (x, y) float64 120B 0.4281 0.9399 -0.884 ... -0.1212 -0.3989
    x_only   (x) float64 24B -100.5 -99.75 -100.9
Similarly to index based alignment, the result has the intersection of all matching data variables. ## Wrapping custom computation It doesn’t always make sense to do computation directly with xarray objects: > - In the inner loop of performance limited code, using xarray can add > considerable overhead compared to using NumPy or native Python types. > This is particularly true when working with scalars or small arrays (less > than ~1e6 elements). Keeping track of labels and ensuring their consistency > adds overhead, and xarray’s core itself is not especially fast, because it’s > written in Python rather than a compiled language like C. Also, xarray’s > high level label-based APIs removes low-level control over how operations > are implemented. > - Even if speed doesn’t matter, it can be important to wrap existing code, or > to support alternative interfaces that don’t use xarray objects. For these reasons, it is often well-advised to write low-level routines that work with NumPy arrays, and to wrap these routines to work with xarray objects. However, adding support for labels on both [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) and [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) can be a bit of a chore. To make this easier, xarray supplies the [`apply_ufunc()`](../generated/xarray.apply_ufunc.md#xarray.apply_ufunc) helper function, designed for wrapping functions that support broadcasting and vectorization on unlabeled arrays in the style of a NumPy [universal function](https://numpy.org/doc/stable/reference/ufuncs.html) (“ufunc” for short). `apply_ufunc` takes care of everything needed for an idiomatic xarray wrapper, including alignment, broadcasting, looping over `Dataset` variables (if needed), and merging of coordinates. In fact, many internal xarray functions/methods are written using `apply_ufunc`. Simple functions that act independently on each value should work without any additional arguments: ```ipython3 squared_error = lambda x, y: (x - y) ** 2 arr1 = xr.DataArray([0, 1, 2, 3], dims="x") xr.apply_ufunc(squared_error, arr1, 1) ``` ```none Size: 32B array([1, 0, 1, 4]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 4)> Size: 32B
array([1, 0, 1, 4])
Dimensions without coordinates: x
For using more complex operations that consider some array values collectively, it’s important to understand the idea of “core dimensions” from NumPy’s [generalized ufuncs](https://numpy.org/doc/stable/reference/c-api/generalized-ufuncs.html). Core dimensions are defined as dimensions that should *not* be broadcast over. Usually, they correspond to the fundamental dimensions over which an operation is defined, e.g., the summed axis in `np.sum`. A good clue that core dimensions are needed is the presence of an `axis` argument on the corresponding NumPy function. With `apply_ufunc`, core dimensions are recognized by name, and then moved to the last dimension of any input arguments before applying the given function. This means that for functions that accept an `axis` argument, you usually need to set `axis=-1`. As an example, here is how we would wrap [`numpy.linalg.norm()`](https://numpy.org/doc/stable/reference/generated/numpy.linalg.norm.html#numpy.linalg.norm) to calculate the vector norm: ```python def vector_norm(x, dim, ord=None): return xr.apply_ufunc( np.linalg.norm, x, input_core_dims=[[dim]], kwargs={"ord": ord, "axis": -1} ) ``` ```ipython3 vector_norm(arr1, dim="x") ``` ```none Size: 8B array(3.74165739) ```
<xarray.DataArray ()> Size: 8B
array(3.74165739)
Because `apply_ufunc` follows a standard convention for ufuncs, it plays nicely with tools for building vectorized functions, like [`numpy.broadcast_arrays()`](https://numpy.org/doc/stable/reference/generated/numpy.broadcast_arrays.html#numpy.broadcast_arrays) and [`numpy.vectorize`](https://numpy.org/doc/stable/reference/generated/numpy.vectorize.html#numpy.vectorize). For high performance needs, consider using [Numba’s vectorize and guvectorize](https://numba.readthedocs.io/en/stable/user/vectorize.html). In addition to wrapping functions, `apply_ufunc` can automatically parallelize many functions when using dask by setting `dask='parallelized'`. See [Parallelize custom functions with apply_ufunc and map_blocks](dask.md#dask-automatic-parallelization) for details. [`apply_ufunc()`](../generated/xarray.apply_ufunc.md#xarray.apply_ufunc) also supports some advanced options for controlling alignment of variables and the form of the result. See the docstring for full details and more examples. # contributing.html.md # Contributing to xarray #### NOTE Large parts of this document came from the [Pandas Contributing Guide](https://pandas.pydata.org/pandas-docs/stable/development/contributing.html). ## Overview We welcome your skills and enthusiasm at the xarray project!. There are numerous opportunities to contribute beyond just writing code. All contributions, including bug reports, bug fixes, documentation improvements, enhancement suggestions, and other ideas are welcome. LLM generated contributions are welcome, but they must follow [our AI policy](ai-policy.md). If you have any questions on the process or how to fix something feel free to ask us! The recommended places to ask questions are [GitHub Discussions](https://github.com/pydata/xarray/discussions) or the Xarray channel in the [OSSci Zulip](https://ossci.zulipchat.com/#narrow/channel/582428-Xarray). In the past, we had a [Discord](https://discord.com/invite/wEKPCt4PDu) and a [mailing list](https://groups.google.com/g/xarray). Feel free to browse historical conversations there. We also have a biweekly community call, details of which are announced on the [Developers meeting](https://docs.xarray.dev/en/stable/developers-meeting.html). You are very welcome to join! Though we would love to hear from you, there is no expectation to contribute during the meeting either - you are always welcome to just sit in and listen. This project is a community effort, and everyone is welcome to contribute. Everyone within the community is expected to abide by our [code of conduct](https://github.com/pydata/xarray/blob/main/CODE_OF_CONDUCT.md). ## Where to start? If you are brand new to *xarray* or open-source development, we recommend going through the [GitHub “issues” tab](https://github.com/pydata/xarray/issues) to find issues that interest you. Some issues are particularly suited for new contributors by the label [Documentation](https://github.com/pydata/xarray/labels/topic-documentation) and [good first issue](https://github.com/pydata/xarray/labels/contrib-good-first-issue) where you could start out. These are well documented issues, that do not require a deep understanding of the internals of xarray. Once you’ve found an interesting issue, you can return here to get your development environment setup. The xarray project does not assign issues. Issues are “assigned” by opening a Pull Request(PR). ## Bug reports and enhancement requests Bug reports are an important part of making *xarray* more stable. Having a complete bug report will allow others to reproduce the bug and provide insight into fixing. Trying out the bug-producing code on the *main* branch is often a worthwhile exercise to confirm that the bug still exists. It is also worth searching existing bug reports and pull requests to see if the issue has already been reported and/or fixed. ### Submitting a bug report If you find a bug in the code or documentation, do not hesitate to submit a ticket to the [Issue Tracker](https://github.com/pydata/xarray/issues). You are also welcome to post feature requests or pull requests. If you are reporting a bug, please use the provided template which includes the following: 1. Include a short, self-contained Python snippet reproducing the problem. You can format the code nicely by using [GitHub Flavored Markdown](https://github.github.com/github-flavored-markdown/): ```default ```python import xarray as xr ds = xr.Dataset(...) ... ``` ``` 2. Include the full version string of *xarray* and its dependencies. You can use the built in function: ```default ```python import xarray as xr xr.show_versions() ... ``` ``` 3. Explain why the current behavior is wrong/not desired and what you expect instead. The issue will then show up to the *xarray* community and be open to comments/ideas from others. See this [stackoverflow article for tips on writing a good bug report](https://stackoverflow.com/help/mcve) . Now that you have an issue you want to fix, enhancement to add, or documentation to improve, you need to learn how to work with GitHub and the *xarray* code base. ## Version control, Git, and GitHub The code is hosted on [GitHub](https://www.github.com/pydata/xarray). To contribute you will need to sign up for a [free GitHub account](https://github.com/signup/free). We use [Git](https://git-scm.com/) for version control to allow many people to work together on the project. Some great resources for learning Git: * the [GitHub help pages](https://help.github.com/). * the [NumPy’s documentation](https://numpy.org/doc/stable/dev/index.html). * Matthew Brett’s [Pydagogue](https://matthew-brett.github.io/pydagogue/). ### Getting started with Git [GitHub has instructions for setting up Git](https://help.github.com/set-up-git-redirect) including installing git, setting up your SSH key, and configuring git. All these steps need to be completed before you can work seamlessly between your local repository and GitHub. #### NOTE The following instructions assume you want to learn how to interact with github via the git command-line utility, but contributors who are new to git may find it easier to use other tools instead such as [Github Desktop](https://desktop.github.com/). ## Development workflow To keep your work well organized, with readable history, and in turn make it easier for project maintainers to see what you’ve done, and why you did it, we recommend you to follow workflow: 1. [Create an account](https://github.com/) on GitHub if you do not already have one. 2. You will need your own fork to work on the code. Go to the [xarray project page](https://github.com/pydata/xarray) and hit the `Fork` button near the top of the page. This creates a copy of the code under your account on the GitHub server. 3. Clone your fork to your machine: ```default git clone https://github.com/your-user-name/xarray.git cd xarray git remote add upstream https://github.com/pydata/xarray.git ``` This creates the directory `xarray` and connects your repository to the upstream (main project) *xarray* repository. 4. Copy tags across from the xarray repository: ```default git fetch --tags upstream ``` This will ensure that when you create a development environment a reasonable version number is created. ### Creating a development environment To test out code changes locally, you’ll need to build *xarray* from source, which requires a Python environment. If you’re making documentation changes, you can skip to [Contributing to the documentation](#contributing-documentation) but you won’t be able to build the documentation locally before pushing your changes. #### NOTE For small changes, such as fixing a typo, you don’t necessarily need to build and test xarray locally. If you make your changes then [commit and push them to a new branch](#contributing-changes), xarray’s automated [continuous integration tests](#contributing-ci) will run and check your code in various ways. You can then try to fix these problems by committing and pushing more commits to the same branch. You can also avoid building the documentation locally by instead [viewing the updated documentation via the CI](#contributing-pr). To speed up this feedback loop or for more complex development tasks you should build and test xarray locally. ### Creating a Python Environment #### ATTENTION Xarray recently switched development workflows to use [Pixi](https://pixi.sh/latest/) instead of Conda (PR [https://github.com/pydata/xarray/pull/10888](https://github.com/pydata/xarray/pull/10888) ). If there are any edits to the contributing instructions that would improve clarity, please open a PR! Xarray uses [Pixi](https://pixi.sh/latest/) to manage development environments. Before starting any development, you’ll need to create an isolated xarray development environment: - [Install Pixi](https://pixi.sh/latest/installation/) - Xarray uses some Pixi features that are in active development. You might be prompted to upgrade your Pixi version to contribute to Xarray (this is controlled by the `requires-pixi` field in `pixi.toml`) - Make sure that you have [cloned the repository](#contributing-dev-workflow) - `cd` to the *xarray* source directory That’s it! Now you’re ready to contribute to Xarray. Pixi defines multiple environments as well as tasks to help you with development (view these by running `pixi task list`). These include tasks for: - running the test suite - building the documentation - running the static type checker - running code formatters and linters Some of these tasks can be run in several environments (e.g., the test suite is run in environments with different, dependencies as well as different Python versions to make sure we have wide support for Xarray). Some of these tasks are only run in a single environment (e.g., building the documentation or running pre-commit hooks). You can see all available environments and tasks by running: ```default pixi info ``` When running a test you may be prompted to select which environment you want to use. You can specify the environment directly by providing the `-e` flag, e.g., `pixi run -e my_environment test` . Our CI setup uses Pixi as well - you can easily reproduce CI tests by running the same tasks in the same environments as defined in the CI. You can enter any of the defined environments with: ```default pixi shell -e my_environment ``` This is similar to “activating” an environment in Conda. To exit this shell type `exit` or press `Ctrl-D`. All these Pixi environments and tasks are defined in the `pixi.toml` file in the root of the repository. ### Install pre-commit hooks You can either run pre-commit manually via Pixi as described above, or set up git hooks to run pre-commit automatically. This is done by: ```shell pixi shell -e pre-commit # enter the pre-commit environment pre-commit install # install the git hooks # or pre-commit uninstall # uninstall the git hooks ``` Now, every time you make a git commit, all the pre-commit hooks will be run automatically using the pre-commit that comes with Pixi. Alternatively you can use a separate installation of `pre-commit` (e.g., install globally using Pixi (`pixi install -g pre_commit`), or via [Homebrew](https://formulae.brew.sh/formula/pre-commit) ). If you want to commit without running `pre-commit` hooks, you can use `git commit --no-verify`. ### Update the `main` branch First make sure you have [created a development environment](#contributing-dev-env). Before starting a new set of changes, fetch all changes from `upstream/main`, and start a new feature branch from that. From time to time you should fetch the upstream changes from GitHub: ```default git fetch --tags upstream git merge upstream/main ``` This will combine your commits with the latest *xarray* git `main`. If this leads to merge conflicts, you must resolve these before submitting your pull request. If you have uncommitted changes, you will need to `git stash` them prior to updating. This will effectively store your changes, which can be reapplied after updating. ### Create a new feature branch Create a branch to save your changes, even before you start making changes. You want your `main branch` to contain only production-ready code: ```default git checkout -b shiny-new-feature ``` This changes your working directory to the `shiny-new-feature` branch. Keep any changes in this branch specific to one bug or feature so it is clear what the branch brings to *xarray*. You can have many “shiny-new-features” and switch in between them using the `git checkout` command. Generally, you will want to keep your feature branches on your public GitHub fork of xarray. To do this, you `git push` this new branch up to your GitHub repo. Generally (if you followed the instructions in these pages, and by default), git will have a link to your fork of the GitHub repo, called `origin`. You push up to your own fork with: ```default git push origin shiny-new-feature ``` In git >= 1.7 you can ensure that the link is correctly set by using the `--set-upstream` option: ```default git push --set-upstream origin shiny-new-feature ``` From now on git will know that `shiny-new-feature` is related to the `shiny-new-feature branch` in the GitHub repo. ### The editing workflow 1. Make some changes 2. See which files have changed with `git status`. You’ll see a listing like this one: ```default # On branch shiny-new-feature # Changed but not updated: # (use "git add ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) # # modified: README ``` 3. Check what the actual changes are with `git diff`. 4. Build the [documentation](https://docs.xarray.dev/en/stable/contributing.html#building-the-documentation) for the documentation changes. 1. [Run the test suite](https://docs.xarray.dev/en/stable/contributing.html#running-the-test-suite) for code changes. ### Commit and push your changes 1. To commit all modified files into the local copy of your repo, do `git commit -am 'A commit message'`. 2. To push the changes up to your forked repo on GitHub, do a `git push`. ### Open a pull request When you’re ready or need feedback on your code, open a Pull Request (PR) so that the xarray developers can give feedback and eventually include your suggested code into the `main` branch. [Pull requests (PRs) on GitHub](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) are the mechanism for contributing to xarray’s code and documentation. Enter a title for the set of changes with some explanation of what you’ve done. Follow the PR template, which looks like this. ```default [ ]Closes #xxxx [ ]Tests added [ ]User visible changes (including notable bug fixes) are documented in whats-new.rst [ ]New functions/methods are listed in api.rst ``` Mention anything you’d like particular attention for - such as a complicated change or some code you are not happy with. If you don’t think your request is ready to be merged, just say so in your pull request message and use the “Draft PR” feature of GitHub. This is a good way of getting some preliminary code review. ## Contributing to the documentation If you’re not the developer type, contributing to the documentation is still of huge value. You don’t even have to be an expert on *xarray* to do so! In fact, there are sections of the docs that are worse off after being written by experts. If something in the docs doesn’t make sense to you, updating the relevant section after you figure it out is a great way to ensure it will help the next person. > ##### Documentation: > > * [About the *xarray* documentation](#about-the-xarray-documentation) > * [How to build the *xarray* documentation](#how-to-build-the-xarray-documentation) > * [Requirements](#requirements) > * [Writing ReST pages](#writing-rest-pages) > * [Section formatting](#section-formatting) > * [Referring to other documents and sections](#referring-to-other-documents-and-sections) > * [Including figures and files](#including-figures-and-files) ### About the *xarray* documentation The documentation is written in **reStructuredText**, which is almost like writing in plain English, and built using [Sphinx](https://www.sphinx-doc.org/). The Sphinx Documentation has an excellent [introduction to reST](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html). Review the Sphinx docs to perform more complex changes to the documentation as well. Some other important things to know about the docs: - The *xarray* documentation consists of two parts: the docstrings in the code itself and the docs in this folder `xarray/doc/`. The docstrings are meant to provide a clear explanation of the usage of the individual functions, while the documentation in this folder consists of tutorial-like overviews per topic together with some other information (what’s new, installation, etc). - The docstrings follow the **NumPy Docstring Standard**, which is used widely in the Scientific Python community. This standard specifies the format of the different sections of the docstring. Refer to the [documentation for the Numpy docstring format](https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard) for a detailed explanation, or look at some of the existing functions to extend it in a similar manner. - The documentation makes heavy use of the [jupyter-sphinx extension](https://jupyter-sphinx.readthedocs.io). The `jupyter-execute` directive lets you put code in the documentation which will be run during the doc build. For example: ```rst .. jupyter-execute:: x = 2 x**3 ``` will be rendered as: ```ipython3 x = 2 x**3 ``` ```none 8 ``` Almost all code examples in the docs are run (and the output saved) during the doc build. This approach means that code examples will always be up to date, but it does make building the docs a bit more complex. - Our API documentation in `doc/api.rst` houses the auto-generated documentation from the docstrings. For classes, there are a few subtleties around controlling which methods and attributes have pages auto-generated. Every method should be included in a `toctree` in `api.rst`, else Sphinx will emit a warning. ### How to build the *xarray* documentation #### Requirements Make sure to follow the instructions on [creating a development environment](#contributing-dev-env) above. Once you have Pixi installed - you can build the documentation using the command: ```default pixi run doc ``` Then you can find the HTML output files in the folder `xarray/doc/_build/html/`. To see what the documentation now looks like with your changes, you can view the HTML build locally by opening the files in your local browser. For example, if you normally use Google Chrome as your browser, you could enter: ```default google-chrome _build/html/quick-overview.html ``` in the terminal, running from within the `doc/` folder. You should now see a new tab pop open in your local browser showing the `quick-overview` page of the documentation. The different pages of this local build of the documentation are linked together, so you can browse the whole documentation by following links the same way you would on the officially-hosted xarray docs site. The first time you build the docs, it will take quite a while because it has to run all the code examples and build all the generated docstring pages. In subsequent evocations, Sphinx will try to only build the pages that have been modified. If you want to do a full clean build, do: ```default pixi run doc-clean ``` ### Writing ReST pages Most documentation is either in the docstrings of individual classes and methods, in explicit `.rst` files, or in examples and tutorials. All of these use the [ReST](https://docutils.sourceforge.io/rst.html) syntax and are processed by [Sphinx](https://www.sphinx-doc.org/en/master/). This section contains additional information and conventions how ReST is used in the xarray documentation. #### Section formatting We aim to follow the recommendations from the [Python documentation](https://devguide.python.org/documentation/start-documenting/index.html#sections) and the [Sphinx reStructuredText documentation](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#sections) for section markup characters, - `*` with overline, for chapters - `=`, for heading - `-`, for sections - `~`, for subsections - `**` text `**`, for **bold** text #### Referring to other documents and sections [Sphinx](https://www.sphinx-doc.org/en/master/) allows internal [references](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html) between documents. Documents can be linked with the `:doc:` directive: ```default See the :doc:`/getting-started-guide/installing` See the :doc:`/getting-started-guide/quick-overview` ``` will render as: See the [Installation](https://docs.xarray.dev/en/stable/getting-started-guide/installing.html) See the [Quick Overview](https://docs.xarray.dev/en/stable/getting-started-guide/quick-overview.html) #### Including figures and files Image files can be directly included in pages with the `image::` directive. ## Contributing to the code base > ##### Code Base: > > * [Code standards](#code-standards) > * [Code Formatting](#code-formatting) > * [Backwards Compatibility](#backwards-compatibility) > * [Testing With Continuous Integration](#testing-with-continuous-integration) > * [Test-driven development/code writing](#test-driven-development-code-writing) > * [Writing tests](#writing-tests) > * [Transitioning to `pytest`](#transitioning-to-pytest) > * [Using `pytest`](#using-pytest) > * [Running the test suite](#running-the-test-suite) > * [Running the performance test suite](#running-the-performance-test-suite) > * [Documenting your code](#documenting-your-code) ### Code standards Writing good code is not just about what you write. It is also about *how* you write it. During [Continuous Integration](#contributing-ci) testing, several tools will be run to check your code for stylistic errors. Generating any warnings will cause the test to fail. Thus, good style is a requirement for submitting code to *xarray*. In addition, because a lot of people use our library, it is important that we do not make sudden changes to the code that could have the potential to break a lot of user code as a result, that is, we need it to be as *backwards compatible* as possible to avoid mass breakages. #### Code Formatting xarray uses several tools to ensure a consistent code format throughout the project: - [ruff](https://github.com/astral-sh/ruff) for formatting, code quality checks and standardized order in imports, and - [mypy](https://mypy-lang.org/) for static type checking on [type hints](https://docs.python.org/3/library/typing.html). We highly recommend that you setup [pre-commit hooks](https://pre-commit.com/) to automatically run all the above tools every time you make a git commit. This can be done by running: ```default pre-commit install ``` from the root of the xarray repository. You can skip the pre-commit checks with `git commit --no-verify`. #### Backwards Compatibility Please try to maintain backwards compatibility. *xarray* has a growing number of users with lots of existing code, so don’t break it if at all possible. If you think breakage is required, clearly state why as part of the pull request. Be especially careful when changing function and method signatures, because any change may require a deprecation warning. For example, if your pull request means that the argument `old_arg` to `func` is no longer valid, instead of simply raising an error if a user passes `old_arg`, we would instead catch it: ```python def func(new_arg, old_arg=None): if old_arg is not None: from xarray.core.utils import emit_user_level_warning emit_user_level_warning( "`old_arg` has been deprecated, and in the future will raise an error." "Please use `new_arg` from now on.", FutureWarning, ) # Still do what the user intended here ``` This temporary check would then be removed in a subsequent version of xarray. This process of first warning users before actually breaking their code is known as a “deprecation cycle”, and makes changes significantly easier to handle both for users of xarray, and for developers of other libraries that depend on xarray. ### Testing With Continuous Integration The *xarray* test suite runs automatically via the [GitHub Actions](https://docs.github.com/en/free-pro-team@latest/actions), continuous integration service, once your pull request is submitted. A pull-request will be considered for merging when you have an all ‘green’ build. If any tests are failing, then you will get a red ‘X’, where you can click through to see the individual failed tests. This is an example of a green build. ![image](_static/ci.png) #### NOTE Each time you push to your PR branch, a new run of the tests will be triggered on the CI. If they haven’t already finished, tests for any older commits on the same branch will be automatically cancelled. ### Test-driven development/code writing *xarray* is serious about testing and strongly encourages contributors to embrace [test-driven development (TDD)](https://en.wikipedia.org/wiki/Test-driven_development). This development process “relies on the repetition of a very short development cycle: first the developer writes an (initially failing) automated test case that defines a desired improvement or new function, then produces the minimum amount of code to pass that test.” So, before actually writing any code, you should write your tests. Often the test can be taken from the original GitHub issue. However, it is always worth considering additional use cases and writing corresponding tests. Adding tests is one of the most common requests after code is pushed to *xarray*. Therefore, it is worth getting in the habit of writing tests ahead of time so that this is never an issue. Like many packages, *xarray* uses [pytest](https://doc.pytest.org/en/latest/) and the convenient extensions in [numpy.testing](https://numpy.org/doc/stable/reference/routines.testing.html). #### Writing tests All tests should go into the `tests` subdirectory of the specific package. This folder contains many current examples of tests, and we suggest looking to these for inspiration. The `xarray.testing` module has many special `assert` functions that make it easier to make statements about whether DataArray or Dataset objects are equivalent. The easiest way to verify that your code is correct is to explicitly construct the result you expect, then compare the actual result to the expected correct result: ```default def test_constructor_from_0d(): expected = Dataset({None: ([], 0)})[None] actual = DataArray(0) assert_identical(expected, actual) ``` #### Transitioning to `pytest` *xarray* existing test structure is *mostly* class-based, meaning that you will typically find tests wrapped in a class. ```python class TestReallyCoolFeature: ... ``` Going forward, we are moving to a more *functional* style using the [pytest](https://doc.pytest.org/en/latest/) framework, which offers a richer testing framework that will facilitate testing and developing. Thus, instead of writing test classes, we will write test functions like this: ```python def test_really_cool_feature(): ... ``` #### Using `pytest` Here is an example of a self-contained set of tests that illustrate multiple features that we like to use. - functional style: tests are like `test_*` and *only* take arguments that are either fixtures or parameters - `pytest.mark` can be used to set metadata on test functions, e.g. `skip` or `xfail`. - using `parametrize`: allow testing of multiple cases - to set a mark on a parameter, `pytest.param(..., marks=...)` syntax should be used - `fixture`, code for object construction, on a per-test basis - using bare `assert` for scalars and truth-testing - `assert_equal` and `assert_identical` from the `xarray.testing` module for xarray object comparisons. - the typical pattern of constructing an `expected` and comparing versus the `result` We would name this file `test_cool_feature.py` and put in an appropriate place in the `xarray/tests/` structure. ```python import pytest import numpy as np import xarray as xr from xarray.testing import assert_equal @pytest.mark.parametrize("dtype", ["int8", "int16", "int32", "int64"]) def test_dtypes(dtype): assert str(np.dtype(dtype)) == dtype @pytest.mark.parametrize( "dtype", [ "float32", pytest.param("int16", marks=pytest.mark.skip), pytest.param( "int32", marks=pytest.mark.xfail(reason="to show how it works") ), ], ) def test_mark(dtype): assert str(np.dtype(dtype)) == "float32" @pytest.fixture def dataarray(): return xr.DataArray([1, 2, 3]) @pytest.fixture(params=["int8", "int16", "int32", "int64"]) def dtype(request): return request.param def test_series(dataarray, dtype): result = dataarray.astype(dtype) assert result.dtype == dtype expected = xr.DataArray(np.array([1, 2, 3], dtype=dtype)) assert_equal(result, expected) ``` A test run of this yields ```shell ((xarray) $ pytest test_cool_feature.py -v ================================= test session starts ================================== platform darwin -- Python 3.10.6, pytest-7.2.0, pluggy-1.0.0 -- cachedir: .pytest_cache plugins: hypothesis-6.56.3, cov-4.0.0 collected 11 items xarray/tests/test_cool_feature.py::test_dtypes[int8] PASSED [ 9%] xarray/tests/test_cool_feature.py::test_dtypes[int16] PASSED [ 18%] xarray/tests/test_cool_feature.py::test_dtypes[int32] PASSED [ 27%] xarray/tests/test_cool_feature.py::test_dtypes[int64] PASSED [ 36%] xarray/tests/test_cool_feature.py::test_mark[float32] PASSED [ 45%] xarray/tests/test_cool_feature.py::test_mark[int16] SKIPPED (unconditional skip) [ 54%] xarray/tests/test_cool_feature.py::test_mark[int32] XFAIL (to show how it works) [ 63%] xarray/tests/test_cool_feature.py::test_series[int8] PASSED [ 72%] xarray/tests/test_cool_feature.py::test_series[int16] PASSED [ 81%] xarray/tests/test_cool_feature.py::test_series[int32] PASSED [ 90%] xarray/tests/test_cool_feature.py::test_series[int64] PASSED [100%] ==================== 9 passed, 1 skipped, 1 xfailed in 1.83 seconds ==================== ``` Tests that we have `parametrized` are now accessible via the test name, for example we could run these with `-k int8` to sub-select *only* those tests which match `int8`. ```shell ((xarray) bash-3.2$ pytest test_cool_feature.py -v -k int8 ================================== test session starts ================================== platform darwin -- Python 3.10.6, pytest-7.2.0, pluggy-1.0.0 -- cachedir: .pytest_cache plugins: hypothesis-6.56.3, cov-4.0.0 collected 11 items test_cool_feature.py::test_dtypes[int8] PASSED test_cool_feature.py::test_series[int8] PASSED ``` ### Running the test suite The tests can then be run directly inside your Git clone (without having to install *xarray*) by typing: ```default pytest xarray ``` The tests suite is exhaustive and takes a few minutes. Often it is worth running only a subset of tests first around your changes before running the entire suite. The easiest way to do this is with: ```default pytest xarray/path/to/test.py -k regex_matching_test_name ``` Or with one of the following constructs: ```default pytest xarray/tests/[test-module].py pytest xarray/tests/[test-module].py::[TestClass] pytest xarray/tests/[test-module].py::[TestClass]::[test_method] ``` Using [pytest-xdist](https://pypi.python.org/pypi/pytest-xdist), one can speed up local testing on multicore machines, by running pytest with the optional -n argument: ```default pytest xarray -n 4 ``` This can significantly reduce the time it takes to locally run tests before submitting a pull request. For more, see the [pytest](https://doc.pytest.org/en/latest/) documentation. ### Running the performance test suite Performance matters and it is worth considering whether your code has introduced performance regressions. *xarray* is starting to write a suite of benchmarking tests using [asv](https://github.com/airspeed-velocity/asv) to enable easy monitoring of the performance of critical *xarray* operations. These benchmarks are all found in the `xarray/asv_bench` directory. To use all features of asv, you will need either `conda` or `virtualenv`. For more details please check the [asv installation webpage](https://asv.readthedocs.io/en/stable/installing.html). To install asv: ```default python -m pip install asv ``` If you need to run a benchmark, change your directory to `asv_bench/` and run: ```default asv continuous -f 1.1 upstream/main HEAD ``` You can replace `HEAD` with the name of the branch you are working on, and report benchmarks that changed by more than 10%. The command uses `conda` by default for creating the benchmark environments. If you want to use virtualenv instead, write: ```default asv continuous -f 1.1 -E virtualenv upstream/main HEAD ``` The `-E virtualenv` option should be added to all `asv` commands that run benchmarks. The default value is defined in `asv.conf.json`. Running the full benchmark suite can take up to one hour and use up a few GBs of RAM. Usually it is sufficient to paste only a subset of the results into the pull request to show that the committed changes do not cause unexpected performance regressions. You can run specific benchmarks using the `-b` flag, which takes a regular expression. For example, this will only run tests from a `xarray/asv_bench/benchmarks/groupby.py` file: ```default asv continuous -f 1.1 upstream/main HEAD -b ^groupby ``` If you want to only run a specific group of tests from a file, you can do it using `.` as a separator. For example: ```default asv continuous -f 1.1 upstream/main HEAD -b groupby.GroupByMethods ``` will only run the `GroupByMethods` benchmark defined in `groupby.py`. You can also run the benchmark suite using the version of *xarray* already installed in your current Python environment. This can be useful if you do not have `virtualenv` or `conda`, or are using the `setup.py develop` approach discussed above; for the in-place build you need to set `PYTHONPATH`, e.g. `PYTHONPATH="$PWD/.." asv [remaining arguments]`. You can run benchmarks using an existing Python environment by: ```default asv run -e -E existing ``` or, to use a specific Python interpreter,: ```default asv run -e -E existing:python3.10 ``` This will display stderr from the benchmarks, and use your local `python` that comes from your `$PATH`. Learn [how to write a benchmark and how to use asv from the documentation](https://asv.readthedocs.io/en/latest/writing_benchmarks.html) . ### Documenting your code Changes should be reflected in the release notes located in `doc/whats-new.rst`. This file contains an ongoing change log for each release. Add an entry to this file to document your fix, enhancement or (unavoidable) breaking change. Make sure to include the GitHub issue number when adding your entry (using `:issue:`1234``, where `1234` is the issue/pull request number). If your code is an enhancement, it is most likely necessary to add usage examples to the existing documentation. This can be done by following the [guidelines for contributing to the documentation](#contributing-documentation). ## Contributing your changes to *xarray* ### Committing your code Keep style fixes to a separate commit to make your pull request more readable. Once you’ve made changes, you can see them by typing: ```default git status ``` If you have created a new file, it is not being tracked by git. Add it by typing: ```default git add path/to/file-to-be-added.py ``` Doing ‘git status’ again should give something like: ```default # On branch shiny-new-feature # # modified: /relative/path/to/file-you-added.py # ``` The following defines how a commit message should ideally be structured: * A subject line with `< 72` chars. * One blank line. * Optionally, a commit message body. Please reference the relevant GitHub issues in your commit message using `GH1234` or `#1234`. Either style is fine, but the former is generally preferred. Now you can commit your changes in your local repository: ```default git commit -m ``` ### Pushing your changes When you want your changes to appear publicly on your GitHub page, push your forked feature branch’s commits: ```default git push origin shiny-new-feature ``` Here `origin` is the default name given to your remote repository on GitHub. You can see the remote repositories: ```default git remote -v ``` If you added the upstream repository as described above you will see something like: ```default origin git@github.com:yourname/xarray.git (fetch) origin git@github.com:yourname/xarray.git (push) upstream git://github.com/pydata/xarray.git (fetch) upstream git://github.com/pydata/xarray.git (push) ``` Now your code is on GitHub, but it is not yet a part of the *xarray* project. For that to happen, a pull request needs to be submitted on GitHub. ### Review your code When you’re ready to ask for a code review, file a pull request. Before you do, once again make sure that you have followed all the guidelines outlined in this document regarding code style, tests, performance tests, and documentation. You should also double check your branch changes against the branch it was based on: 1. Navigate to your repository on GitHub – [https://github.com/your-user-name/xarray](https://github.com/your-user-name/xarray) 2. Click on `Branches` 3. Click on the `Compare` button for your feature branch 4. Select the `base` and `compare` branches, if necessary. This will be `main` and `shiny-new-feature`, respectively. ### Finally, make the pull request If everything looks good, you are ready to make a pull request. A pull request is how code from a local repository becomes available to the GitHub community and can be looked at and eventually merged into the `main` version. This pull request and its associated changes will eventually be committed to the `main` branch and available in the next release. To submit a pull request: 1. Navigate to your repository on GitHub 2. Click on the `Pull Request` button 3. You can then click on `Commits` and `Files Changed` to make sure everything looks okay one last time 4. Write a description of your changes in the `Preview Discussion` tab 5. Click `Send Pull Request`. This request then goes to the repository maintainers, and they will review the code. If you have made updates to the documentation, you can now see a preview of the updated docs by clicking on “Details” under the `docs/readthedocs.org` check near the bottom of the list of checks that run automatically when submitting a PR, then clicking on the “View Docs” button on the right (not the big green button, the small black one further down). ![image](_static/view-docs.png) If you need to make more changes, you can make them in your branch, add them to a new commit, push them to GitHub, and the pull request will automatically be updated. Pushing them to GitHub again is done by: ```default git push origin shiny-new-feature ``` This will automatically update your pull request with the latest code and restart the [Continuous Integration](#contributing-ci) tests. ### Delete your merged branch (optional) Once your feature branch is accepted into upstream, you’ll probably want to get rid of the branch. First, update your `main` branch to check that the merge was successful: ```default git fetch upstream git checkout main git merge upstream/main ``` Then you can do: ```default git branch -D shiny-new-feature ``` You need to use an upper-case `-D` because the branch was squashed into a single commit before merging. Be careful with this because `git` won’t warn you if you accidentally delete an unmerged branch. If you didn’t delete your branch using GitHub’s interface, then it will still exist on GitHub. To delete it there do: ```default git push origin --delete shiny-new-feature ``` ### PR checklist - **Properly comment and document your code.** See [“Documenting your code”](https://docs.xarray.dev/en/stable/contributing.html#documenting-your-code). - **Test that the documentation builds correctly** by typing `make html` in the `doc` directory. This is not strictly necessary, but this may be easier than waiting for CI to catch a mistake. See [“Contributing to the documentation”](https://docs.xarray.dev/en/stable/contributing.html#contributing-to-the-documentation). - **Test your code**. - Write new tests if needed. See [“Test-driven development/code writing”](https://docs.xarray.dev/en/stable/contributing.html#test-driven-development-code-writing). - Test the code using [Pytest](https://doc.pytest.org/en/latest/). Running all tests (type `pytest` in the root directory) takes a while, so feel free to only run the tests you think are needed based on your PR (example: `pytest xarray/tests/test_dataarray.py`). CI will catch any failing tests. - By default, the upstream dev CI is disabled on pull request and push events. You can override this behavior per commit by adding a `[test-upstream]` tag to the first line of the commit message. For documentation-only commits, you can skip the CI per commit by adding a `[skip-ci]` tag to the first line of the commit message. - **Properly format your code** and verify that it passes the formatting guidelines set by [ruff](https://github.com/astral-sh/ruff). See [“Code formatting”](https://docs.xarray.dev/en/stable/contributing.html#code-formatting). You can use [pre-commit](https://pre-commit.com/) to run these automatically on each commit. - Run `pre-commit run --all-files` in the root directory. This may modify some files. Confirm and commit any formatting changes. - **Push your code** and [create a PR on GitHub](https://help.github.com/en/articles/creating-a-pull-request). - **Use a helpful title for your pull request** by summarizing the main contributions rather than using the latest commit message. If the PR addresses an [issue](https://github.com/pydata/xarray/issues), please [reference it](https://help.github.com/en/articles/autolinked-references-and-urls). # coordinates.html.md # Coordinates ## Creating coordinates | [`Coordinates`](../generated/xarray.Coordinates.md#xarray.Coordinates)([coords, indexes]) | Dictionary like container for Xarray coordinates (variables + indexes). | |--------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------| | [`Coordinates.from_xindex`](../generated/xarray.Coordinates.from_xindex.md#xarray.Coordinates.from_xindex)(index) | Create Xarray coordinates from an existing Xarray index. | | [`Coordinates.from_pandas_multiindex`](../generated/xarray.Coordinates.from_pandas_multiindex.md#xarray.Coordinates.from_pandas_multiindex)(midx, dim) | Wrap a pandas multi-index as Xarray coordinates (dimension + levels). | ## Attributes | [`Coordinates.dims`](../generated/xarray.Coordinates.dims.md#xarray.Coordinates.dims) | Mapping from dimension names to lengths or tuple of dimension names. | |------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------| | [`Coordinates.sizes`](../generated/xarray.Coordinates.sizes.md#xarray.Coordinates.sizes) | Mapping from dimension names to lengths. | | [`Coordinates.dtypes`](../generated/xarray.Coordinates.dtypes.md#xarray.Coordinates.dtypes) | Mapping from coordinate names to dtypes. | | [`Coordinates.variables`](../generated/xarray.Coordinates.variables.md#xarray.Coordinates.variables) | Low level interface to Coordinates contents as dict of Variable objects. | | [`Coordinates.indexes`](../generated/xarray.Coordinates.indexes.md#xarray.Coordinates.indexes) | Mapping of pandas.Index objects used for label based indexing. | | [`Coordinates.xindexes`](../generated/xarray.Coordinates.xindexes.md#xarray.Coordinates.xindexes) | Mapping of `Index` objects used for label based indexing. | ## Dictionary Interface Coordinates implement the mapping interface with keys given by variable names and values given by `DataArray` objects. | [`Coordinates.__getitem__`](../generated/xarray.Coordinates.__getitem__.md#xarray.Coordinates.__getitem__)(key) | | |------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------| | [`Coordinates.__setitem__`](../generated/xarray.Coordinates.__setitem__.md#xarray.Coordinates.__setitem__)(key, value) | | | [`Coordinates.__delitem__`](../generated/xarray.Coordinates.__delitem__.md#xarray.Coordinates.__delitem__)(key) | | | [`Coordinates.__or__`](../generated/xarray.Coordinates.__or__.md#xarray.Coordinates.__or__)(other) | Merge two sets of coordinates to create a new Coordinates object | | [`Coordinates.update`](../generated/xarray.Coordinates.update.md#xarray.Coordinates.update)(other) | Update this Coordinates variables with other coordinate variables. | | [`Coordinates.get`](../generated/xarray.Coordinates.get.md#xarray.Coordinates.get)(k[,d]) | | | [`Coordinates.items`](../generated/xarray.Coordinates.items.md#xarray.Coordinates.items)() | | | [`Coordinates.keys`](../generated/xarray.Coordinates.keys.md#xarray.Coordinates.keys)() | | | [`Coordinates.values`](../generated/xarray.Coordinates.values.md#xarray.Coordinates.values)() | | ## Coordinates contents | [`Coordinates.to_dataset`](../generated/xarray.Coordinates.to_dataset.md#xarray.Coordinates.to_dataset)() | Convert these coordinates into a new Dataset. | |-------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------| | [`Coordinates.to_index`](../generated/xarray.Coordinates.to_index.md#xarray.Coordinates.to_index)([ordered_dims]) | Convert all index coordinates into a [`pandas.Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index). | | [`Coordinates.assign`](../generated/xarray.Coordinates.assign.md#xarray.Coordinates.assign)([coords]) | Assign new coordinates (and indexes) to a Coordinates object, returning a new object with all the original coordinates in addition to the new ones. | | [`Coordinates.drop_dims`](../generated/xarray.Coordinates.drop_dims.md#xarray.Coordinates.drop_dims)(drop_dims, \*[, errors]) | Drop dimensions and associated variables from this dataset. | | [`Coordinates.drop_vars`](../generated/xarray.Coordinates.drop_vars.md#xarray.Coordinates.drop_vars)(names, \*[, errors]) | Drop variables from this Coordinates object. | | [`Coordinates.merge`](../generated/xarray.Coordinates.merge.md#xarray.Coordinates.merge)(other, \*[, compat]) | Merge two sets of coordinates to create a new Dataset | | [`Coordinates.copy`](../generated/xarray.Coordinates.copy.md#xarray.Coordinates.copy)([deep, memo]) | Return a copy of this Coordinates object. | | [`Coordinates.rename_vars`](../generated/xarray.Coordinates.rename_vars.md#xarray.Coordinates.rename_vars)([name_dict]) | Returns a new object with renamed variables. | | [`Coordinates.rename_dims`](../generated/xarray.Coordinates.rename_dims.md#xarray.Coordinates.rename_dims)([dims_dict]) | Returns a new object with renamed dimensions only. | ## Comparisons | [`Coordinates.equals`](../generated/xarray.Coordinates.equals.md#xarray.Coordinates.equals)(other) | Two Coordinates objects are equal if they have matching variables, all of which are equal. | |-------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------| | [`Coordinates.identical`](../generated/xarray.Coordinates.identical.md#xarray.Coordinates.identical)(other) | Like equals, but also checks all variable attributes. | ## Proxies Coordinates that are accessed from the `coords` property of Dataset, DataArray and DataTree objects, respectively. | [`DatasetCoordinates`](../generated/xarray.core.coordinates.DatasetCoordinates.md#xarray.core.coordinates.DatasetCoordinates)(dataset) | Dictionary like container for Dataset coordinates (variables + indexes). | |------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------| | [`DataArrayCoordinates`](../generated/xarray.core.coordinates.DataArrayCoordinates.md#xarray.core.coordinates.DataArrayCoordinates)(dataarray) | Dictionary like container for DataArray coordinates (variables + indexes). | | [`DataTreeCoordinates`](../generated/xarray.core.coordinates.DataTreeCoordinates.md#xarray.core.coordinates.DataTreeCoordinates)(datatree) | Dictionary like container for coordinates of a DataTree node (variables + indexes). | # dask.html.md # Parallel Computing with Dask ```ipython3 # Note that it's not necessary to import dask to use xarray with dask. import numpy as np import pandas as pd import xarray as xr import bottleneck ``` Xarray integrates with [Dask](https://dask.org/?utm_source=xarray-docs), a general purpose library for parallel computing, to handle larger-than-memory computations. If you’ve been using Xarray to read in large datasets or split up data across a number of files, you may already be using Dask: ```python ds = xr.open_zarr("/path/to/data.zarr") timeseries = ds["temp"].mean(dim=["x", "y"]).compute() # Compute result ``` Using Dask with Xarray feels similar to working with NumPy arrays, but on much larger datasets. The Dask integration is transparent, so you usually don’t need to manage the parallelism directly; Xarray and Dask handle these aspects behind the scenes. This makes it easy to write code that scales from small, in-memory datasets on a single machine to large datasets that are distributed across a cluster, with minimal code changes. ## Examples If you’re new to using Xarray with Dask, we recommend the [Xarray + Dask Tutorial](https://tutorial.xarray.dev/intermediate/xarray_and_dask.html). Here are some examples for using Xarray with Dask at scale: - [Zonal averaging with the NOAA National Water Model](https://docs.coiled.io/user_guide/xarray.html?utm_source=xarray-docs) - [CMIP6 Precipitation Frequency Analysis](https://gallery.pangeo.io/repos/pangeo-gallery/cmip6/precip_frequency_change.html) - [Using Dask + Cloud Optimized GeoTIFFs](https://gallery.pangeo.io/repos/pangeo-data/landsat-8-tutorial-gallery/landsat8.html#Dask-Chunks-and-Cloud-Optimized-Geotiffs) Find more examples at the [Project Pythia cookbook gallery](https://cookbooks.projectpythia.org/). ## Using Dask with Xarray ![A Dask array](_static/dask-array.svg) Dask divides arrays into smaller parts called chunks. These chunks are small, manageable pieces of the larger dataset, that Dask is able to process in parallel (see the [Dask Array docs on chunks](https://docs.dask.org/en/stable/array-chunks.html?utm_source=xarray-docs)). Commonly chunks are set when reading data, but you can also set the chunksize manually at any point in your workflow using [`Dataset.chunk()`](../generated/xarray.Dataset.chunk.md#xarray.Dataset.chunk) and [`DataArray.chunk()`](../generated/xarray.DataArray.chunk.md#xarray.DataArray.chunk). See [Chunking and performance](#dask-chunks) for more. Xarray operations on Dask-backed arrays are lazy. This means computations are not executed immediately, but are instead queued up as tasks in a Dask graph. When a result is requested (e.g., for plotting, writing to disk, or explicitly computing), Dask executes the task graph. The computations are carried out in parallel, with each chunk being processed independently. This parallel execution is key to handling large datasets efficiently. Nearly all Xarray methods have been extended to work automatically with Dask Arrays. This includes things like indexing, concatenating, rechunking, grouped operations, etc. Common operations are covered in more detail in each of the sections below. ### Reading and writing data When reading data, Dask divides your dataset into smaller chunks. You can specify the size of chunks with the `chunks` argument. Specifying `chunks="auto"` will set the dask chunk sizes to be a multiple of the on-disk chunk sizes. This can be a good idea, but usually the appropriate dask chunk size will depend on your workflow. The [Zarr](https://zarr.readthedocs.io/en/stable/) format is ideal for working with large datasets. Each chunk is stored in a separate file, allowing parallel reading and writing with Dask. You can also use Zarr to read/write directly from cloud storage buckets (see the [Dask documentation on connecting to remote data](https://docs.dask.org/en/stable/how-to/connect-to-remote-data.html?utm_source=xarray-docs)) When you open a Zarr dataset with [`open_zarr()`](../generated/xarray.open_zarr.md#xarray.open_zarr), it is loaded as a Dask array by default (if Dask is installed): ```default ds = xr.open_zarr("path/to/directory.zarr") ``` See [Zarr](io.md#io-zarr) for more details. Open a single netCDF file with [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) and supplying a `chunks` argument: ```default ds = xr.open_dataset("example-data.nc", chunks={"time": 10}) ``` Or open multiple files in parallel with py:func:~xarray.open_mfdataset: ```default xr.open_mfdataset('my/files/*.nc', parallel=True) ``` Save larger-than-memory netCDF files: ```default ds.to_netcdf("my-big-file.nc") ``` Or set `compute=False` to return a dask.delayed object that can be computed later: ```default delayed_write = ds.to_netcdf("my-big-file.nc", compute=False) delayed_write.compute() ``` #### NOTE When using Dask’s distributed scheduler to write NETCDF4 files, it may be necessary to set the environment variable `HDF5_USE_FILE_LOCKING=FALSE` to avoid competing locks within the HDF5 SWMR file locking scheme. Note that writing netCDF files with Dask’s distributed scheduler is only supported for the netcdf4 backend. See [netCDF](io.md#io-netcdf) for more details. Open HDF5 files with [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset): ```default xr.open_dataset("/path/to/my/file.h5", chunks='auto') ``` See [HDF5](io.md#io-hdf5) for more details. Open large geoTIFF files with rioxarray: ```default xds = rioxarray.open_rasterio("my-satellite-image.tif", chunks='auto') ``` See [Rasterio](io.md#io-rasterio) for more details. ### Loading Dask Arrays There are a few common cases where you may want to convert lazy Dask arrays into eager, in-memory Xarray data structures: - You want to inspect smaller intermediate results when working interactively or debugging - You’ve reduced the dataset (by filtering or with a groupby, for example) and now have something much smaller that fits in memory - You need to compute intermediate results since Dask is unable (or struggles) to perform a certain computation. The canonical example of this is normalizing a dataset, e.g., `ds - ds.mean()`, when `ds` is larger than memory. Typically, you should either save `ds` to disk or compute `ds.mean()` eagerly. To do this, you can use [`Dataset.compute()`](../generated/xarray.Dataset.compute.md#xarray.Dataset.compute) or [`DataArray.compute()`](../generated/xarray.DataArray.compute.md#xarray.DataArray.compute): ```ipython3 ds.compute() ``` ```none Size: 8MB Dimensions: (time: 30, latitude: 180, longitude: 180) Coordinates: * time (time) datetime64[us] 240B 2015-01-01 2015-01-02 ... 2015-01-30 * latitude (latitude) float64 1kB 89.5 88.5 87.5 ... -87.5 -88.5 -89.5 * longitude (longitude) int64 1kB 0 1 2 3 4 5 6 ... 174 175 176 177 178 179 Data variables: temperature (time, latitude, longitude) float64 8MB 0.4691 ... -0.2467 ```
<xarray.Dataset> Size: 8MB
Dimensions:      (time: 30, latitude: 180, longitude: 180)
Coordinates:
  \* time         (time) datetime64[us] 240B 2015-01-01 2015-01-02 ... 2015-01-30
  \* latitude     (latitude) float64 1kB 89.5 88.5 87.5 ... -87.5 -88.5 -89.5
  \* longitude    (longitude) int64 1kB 0 1 2 3 4 5 6 ... 174 175 176 177 178 179
Data variables:
    temperature  (time, latitude, longitude) float64 8MB 0.4691 ... -0.2467
#### NOTE Using [`Dataset.compute()`](../generated/xarray.Dataset.compute.md#xarray.Dataset.compute) is preferred to [`Dataset.load()`](../generated/xarray.Dataset.load.md#xarray.Dataset.load), which changes the results in-place. You can also access [`DataArray.values`](../generated/xarray.DataArray.values.md#xarray.DataArray.values), which will always be a NumPy array: ```ipython3 ds.temperature.values ``` ```none array([[[ 4.691e-01, -2.829e-01, ..., -5.577e-01, 3.814e-01], [ 1.337e+00, -1.531e+00, ..., 8.726e-01, -1.538e+00], ... # truncated for brevity ``` NumPy ufuncs like `numpy.sin()` transparently work on all xarray objects, including those that store lazy Dask arrays: ```ipython3 np.sin(ds) ``` ```none Size: 8MB Dimensions: (time: 30, latitude: 180, longitude: 180) Coordinates: * time (time) datetime64[us] 240B 2015-01-01 2015-01-02 ... 2015-01-30 * latitude (latitude) float64 1kB 89.5 88.5 87.5 ... -87.5 -88.5 -89.5 * longitude (longitude) int64 1kB 0 1 2 3 4 5 6 ... 174 175 176 177 178 179 Data variables: temperature (time, latitude, longitude) float64 8MB 0.4521 ... -0.2442 ```
<xarray.Dataset> Size: 8MB
Dimensions:      (time: 30, latitude: 180, longitude: 180)
Coordinates:
  \* time         (time) datetime64[us] 240B 2015-01-01 2015-01-02 ... 2015-01-30
  \* latitude     (latitude) float64 1kB 89.5 88.5 87.5 ... -87.5 -88.5 -89.5
  \* longitude    (longitude) int64 1kB 0 1 2 3 4 5 6 ... 174 175 176 177 178 179
Data variables:
    temperature  (time, latitude, longitude) float64 8MB 0.4521 ... -0.2442
To access Dask arrays directly, use the [`DataArray.data`](../generated/xarray.DataArray.data.md#xarray.DataArray.data) attribute which exposes the DataArray’s underlying array type. If you’re using a Dask cluster, you can also use [`Dataset.persist()`](../generated/xarray.Dataset.persist.md#xarray.Dataset.persist) for quickly accessing intermediate outputs. This is most helpful after expensive operations like rechunking or setting an index. It’s a way of telling the cluster that it should start executing the computations that you have defined so far, and that it should try to keep those results in memory. You will get back a new Dask array that is semantically equivalent to your old array, but now points to running data. ```python ds = ds.persist() ``` ### Chunking and performance The way a dataset is chunked can be critical to performance when working with large datasets. You’ll want chunk sizes large enough to reduce the number of chunks that Dask has to think about (to reduce overhead from the task graph) but also small enough so that many of them can fit in memory at once. It can be helpful to choose chunk sizes based on your downstream analyses and to chunk as early as possible. Datasets with smaller chunks along the time axis, for example, can make time domain problems easier to parallelize since Dask can perform the same operation on each time chunk. If you’re working with a large dataset with chunks that make downstream analyses challenging, you may need to rechunk your data. This is an expensive operation though, so is only recommended when needed. You can chunk or rechunk a dataset by: - Specifying the `chunks` kwarg when reading in your dataset. If you know you’ll want to do some spatial subsetting, for example, you could use `chunks={'latitude': 10, 'longitude': 10}` to specify small chunks across space. This can avoid loading subsets of data that span multiple chunks, thus reducing the number of file reads. Note that this will only work, though, for chunks that are similar to how the data is chunked on disk. Otherwise, it will be very slow and require a lot of network bandwidth. - Many array file formats are chunked on disk. You can specify `chunks={}` to have a single dask chunk map to a single on-disk chunk, and `chunks="auto"` to have a single dask chunk be an automatically chosen multiple of the on-disk chunks. - Using [`Dataset.chunk()`](../generated/xarray.Dataset.chunk.md#xarray.Dataset.chunk) after you’ve already read in your dataset. For time domain problems, for example, you can use `ds.chunk(time=TimeResampler())` to rechunk according to a specified unit of time. `ds.chunk(time=TimeResampler("MS"))`, for example, will set the chunks so that a month of data is contained in one chunk. For large-scale rechunking tasks (e.g., converting a simulation dataset stored with chunking only along time to a dataset with chunking only across space), consider writing another copy of your data on disk and/or using dedicated tools such as [Rechunker](https://rechunker.readthedocs.io/en/latest/). ### Parallelize custom functions with `apply_ufunc` and `map_blocks` Almost all of Xarray’s built-in operations work on Dask arrays. If you want to use a function that isn’t wrapped by Xarray, and have it applied in parallel on each block of your xarray object, you have three options: 1. Use [`apply_ufunc()`](../generated/xarray.apply_ufunc.md#xarray.apply_ufunc) to apply functions that consume and return NumPy arrays. 2. Use [`map_blocks()`](../generated/xarray.map_blocks.md#xarray.map_blocks), [`Dataset.map_blocks()`](../generated/xarray.Dataset.map_blocks.md#xarray.Dataset.map_blocks) or [`DataArray.map_blocks()`](../generated/xarray.DataArray.map_blocks.md#xarray.DataArray.map_blocks) to apply functions that consume and return xarray objects. 3. Extract Dask Arrays from xarray objects with [`DataArray.data`](../generated/xarray.DataArray.data.md#xarray.DataArray.data) and use Dask directly. #### `apply_ufunc` [`apply_ufunc()`](../generated/xarray.apply_ufunc.md#xarray.apply_ufunc) automates [embarrassingly parallel](https://en.wikipedia.org/wiki/Embarrassingly_parallel) “map” type operations where a function written for processing NumPy arrays should be repeatedly applied to Xarray objects containing Dask Arrays. It works similarly to [`dask.array.map_blocks()`](https://docs.dask.org/en/latest/generated/dask.array.map_blocks.html#dask.array.map_blocks) and [`dask.array.blockwise()`](https://docs.dask.org/en/latest/generated/dask.array.blockwise.html#dask.array.blockwise), but without requiring an intermediate layer of abstraction. See the [Dask documentation](https://docs.dask.org/en/stable/array-gufunc.html?utm_source=xarray-docs) for more details. For the best performance when using Dask’s multi-threaded scheduler, wrap a function that already releases the global interpreter lock, which fortunately already includes most NumPy and Scipy functions. Here we show an example using NumPy operations and a fast function from [bottleneck](https://github.com/pydata/bottleneck), which we use to calculate [Spearman’s rank-correlation coefficient](https://en.wikipedia.org/wiki/Spearman%27s_rank_correlation_coefficient): ```python def covariance_gufunc(x, y): return ( (x - x.mean(axis=-1, keepdims=True)) * (y - y.mean(axis=-1, keepdims=True)) ).mean(axis=-1) def pearson_correlation_gufunc(x, y): return covariance_gufunc(x, y) / (x.std(axis=-1) * y.std(axis=-1)) def spearman_correlation_gufunc(x, y): x_ranks = bottleneck.rankdata(x, axis=-1) y_ranks = bottleneck.rankdata(y, axis=-1) return pearson_correlation_gufunc(x_ranks, y_ranks) def spearman_correlation(x, y, dim): return xr.apply_ufunc( spearman_correlation_gufunc, x, y, input_core_dims=[[dim], [dim]], dask="parallelized", output_dtypes=[float], ) ``` The only aspect of this example that is different from standard usage of `apply_ufunc()` is that we needed to supply the `output_dtypes` arguments. (Read up on [Wrapping custom computation](computation.md#compute-wrapping-custom) for an explanation of the “core dimensions” listed in `input_core_dims`.) Our new `spearman_correlation()` function achieves near linear speedup when run on large arrays across the four cores on my laptop. It would also work as a streaming operation, when run on arrays loaded from disk: ```ipython3 rs = np.random.default_rng(0) array1 = xr.DataArray(rs.randn(1000, 100000), dims=["place", "time"]) # 800MB array2 = array1 + 0.5 * rs.randn(1000, 100000) # using one core, on NumPy arrays %time _ = spearman_correlation(array1, array2, 'time') # CPU times: user 21.6 s, sys: 2.84 s, total: 24.5 s # Wall time: 24.9 s chunked1 = array1.chunk({"place": 10}) chunked2 = array2.chunk({"place": 10}) # using all my laptop's cores, with Dask r = spearman_correlation(chunked1, chunked2, "time").compute() %time _ = r.compute() # CPU times: user 30.9 s, sys: 1.74 s, total: 32.6 s # Wall time: 4.59 s ``` One limitation of `apply_ufunc()` is that it cannot be applied to arrays with multiple chunks along a core dimension: ```ipython3 spearman_correlation(chunked1, chunked2, "place") ``` ```none ValueError: dimension 'place' on 0th function argument to apply_ufunc with dask='parallelized' consists of multiple chunks, but is also a core dimension. To fix, rechunk into a single Dask array chunk along this dimension, i.e., ``.rechunk({'place': -1})``, but beware that this may significantly increase memory usage. ``` This reflects the nature of core dimensions, in contrast to broadcast (non-core) dimensions that allow operations to be split into arbitrary chunks for application. #### `map_blocks` Functions that consume and return Xarray objects can be easily applied in parallel using [`map_blocks()`](../generated/xarray.map_blocks.md#xarray.map_blocks). Your function will receive an Xarray Dataset or DataArray subset to one chunk along each chunked dimension. ```ipython3 ds.temperature ``` ```none Size: 8MB 0.4691 -0.2829 -1.509 -1.136 1.212 ... -0.6995 -0.4183 0.8119 -0.2485 -0.2467 Coordinates: * time (time) datetime64[us] 240B 2015-01-01 2015-01-02 ... 2015-01-30 * latitude (latitude) float64 1kB 89.5 88.5 87.5 86.5 ... -87.5 -88.5 -89.5 * longitude (longitude) int64 1kB 0 1 2 3 4 5 6 ... 174 175 176 177 178 179 ```
<xarray.DataArray 'temperature' (time: 30, latitude: 180, longitude: 180)> Size: 8MB
0.4691 -0.2829 -1.509 -1.136 1.212 ... -0.6995 -0.4183 0.8119 -0.2485 -0.2467
Coordinates:
  \* time       (time) datetime64[us] 240B 2015-01-01 2015-01-02 ... 2015-01-30
  \* latitude   (latitude) float64 1kB 89.5 88.5 87.5 86.5 ... -87.5 -88.5 -89.5
  \* longitude  (longitude) int64 1kB 0 1 2 3 4 5 6 ... 174 175 176 177 178 179
This DataArray has 3 chunks each with length 10 along the time dimension. At compute time, a function applied with [`map_blocks()`](../generated/xarray.map_blocks.md#xarray.map_blocks) will receive a DataArray corresponding to a single block of shape 10x180x180 (time x latitude x longitude) with values loaded. The following snippet illustrates how to check the shape of the object received by the applied function. ```ipython3 def func(da): print(da.sizes) return da.time mapped = xr.map_blocks(func, ds.temperature) mapped ``` ```none Frozen({'time': 30, 'latitude': 180, 'longitude': 180}) ``` ```none Size: 240B 2015-01-01 2015-01-02 2015-01-03 2015-01-04 ... 2015-01-28 2015-01-29 2015-01-30 Coordinates: * time (time) datetime64[us] 240B 2015-01-01 2015-01-02 ... 2015-01-30 ```
<xarray.DataArray 'time' (time: 30)> Size: 240B
2015-01-01 2015-01-02 2015-01-03 2015-01-04 ... 2015-01-28 2015-01-29 2015-01-30
Coordinates:
  \* time     (time) datetime64[us] 240B 2015-01-01 2015-01-02 ... 2015-01-30
Notice that the [`map_blocks()`](../generated/xarray.map_blocks.md#xarray.map_blocks) call printed `Frozen({'time': 0, 'latitude': 0, 'longitude': 0})` to screen. `func` is received 0-sized blocks! [`map_blocks()`](../generated/xarray.map_blocks.md#xarray.map_blocks) needs to know what the final result looks like in terms of dimensions, shapes etc. It does so by running the provided function on 0-shaped inputs (*automated inference*). This works in many cases, but not all. If automatic inference does not work for your function, provide the `template` kwarg (see [below](#template-note)). In this case, automatic inference has worked so let’s check that the result is as expected. ```ipython3 mapped.load(scheduler="single-threaded") mapped.identical(ds.time) ``` ```none True ``` Note that we use `.load(scheduler="single-threaded")` to execute the computation. This executes the Dask graph in serial using a for loop, but allows for printing to screen and other debugging techniques. We can easily see that our function is receiving blocks of shape 10x180x180 and the returned result is identical to `ds.time` as expected. Here is a common example where automated inference will not work. ```ipython3 def func(da): print(da.sizes) return da.isel(time=[1]) mapped = xr.map_blocks(func, ds.temperature) ``` ```none Frozen({'time': 30, 'latitude': 180, 'longitude': 180}) ``` `func` cannot be run on 0-shaped inputs because it is not possible to extract element 1 along a dimension of size 0. In this case we need to tell [`map_blocks()`](../generated/xarray.map_blocks.md#xarray.map_blocks) what the returned result looks like using the `template` kwarg. `template` must be an xarray Dataset or DataArray (depending on what the function returns) with dimensions, shapes, chunk sizes, attributes, coordinate variables *and* data variables that look exactly like the expected result. The variables should be dask-backed and hence not incur much memory cost. #### NOTE Note that when `template` is provided, `attrs` from `template` are copied over to the result. Any `attrs` set in `func` will be ignored. ```ipython3 template = ds.temperature.isel(time=[1, 11, 21]) mapped = xr.map_blocks(func, ds.temperature, template=template) ``` ```none Frozen({'time': 30, 'latitude': 180, 'longitude': 180}) ``` Notice that the 0-shaped sizes were not printed to screen. Since `template` has been provided [`map_blocks()`](../generated/xarray.map_blocks.md#xarray.map_blocks) does not need to infer it by running `func` on 0-shaped inputs. ```ipython3 mapped.identical(template) ``` ```none False ``` [`map_blocks()`](../generated/xarray.map_blocks.md#xarray.map_blocks) also allows passing `args` and `kwargs` down to the user function `func`. `func` will be executed as `func(block_xarray, *args, **kwargs)` so `args` must be a list and `kwargs` must be a dictionary. ```ipython3 def func(obj, a, b=0): return obj + a + b mapped = ds.map_blocks(func, args=[10], kwargs={"b": 10}) expected = ds + 10 + 10 mapped.identical(expected) ``` ```none True ``` ## Deploying Dask By default, Dask uses the multi-threaded scheduler, which distributes work across multiple cores on a single machine and allows for processing some datasets that do not fit into memory. However, this has two limitations: - You are limited by the size of your hard drive - Downloading data can be slow and expensive Instead, it can be faster and cheaper to run your computations close to where your data is stored, distributed across many machines on a Dask cluster. Often, this means deploying Dask on HPC clusters or on the cloud. See the [Dask deployment documentation](https://docs.dask.org/en/stable/deploying.html?utm_source=xarray-docs) for more details. ## Best Practices Dask is pretty easy to use but there are some gotchas, many of which are under active development. Here are some tips we have found through experience. We also recommend checking out the [Dask best practices](https://docs.dask.org/en/stable/array-best-practices.html?utm_source=xarray-docs). 1. Do your spatial and temporal indexing (e.g. `.sel()` or `.isel()`) early, especially before calling `resample()` or `groupby()`. Grouping and resampling triggers some computation on all the blocks, which in theory should commute with indexing, but this optimization hasn’t been implemented in Dask yet. (See [Dask issue #746](https://github.com/dask/dask/issues/746)). 2. More generally, `groupby()` is a costly operation and will perform a lot better if the `flox` package is installed. See the [flox documentation](https://flox.readthedocs.io) for more. By default Xarray will use `flox` if installed. 3. Save intermediate results to disk as a netCDF files (using `to_netcdf()`) and then load them again with `open_dataset()` for further computations. For example, if subtracting temporal mean from a dataset, save the temporal mean to disk before subtracting. Again, in theory, Dask should be able to do the computation in a streaming fashion, but in practice this is a fail case for the Dask scheduler, because it tries to keep every chunk of an array that it computes in memory. (See [Dask issue #874](https://github.com/dask/dask/issues/874)) 4. Use the [Dask dashboard](https://docs.dask.org/en/latest/dashboard.html?utm_source=xarray-docs) to identify performance bottlenecks. Here’s an example of a simplified workflow putting some of these tips together: ```python ds = xr.open_zarr( # Since we're doing a spatial reduction, increase chunk size in x, y "my-data.zarr", chunks={"x": 100, "y": 100} ) time_subset = ds.sea_temperature.sel( time=slice("2020-01-01", "2020-12-31") # Filter early ) # faster resampling when flox is installed daily = ds.resample(time="D").mean() daily.load() # Pull smaller results into memory after reducing the dataset ``` # data-structures.html.md # Data Structures ## DataArray [`xarray.DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) is xarray’s implementation of a labeled, multi-dimensional array. It has several key properties: - `values`: a [`numpy.ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) or [numpy-like array](duckarrays.md#userguide-duckarrays) holding the array’s values - `dims`: dimension names for each axis (e.g., `('x', 'y', 'z')`) - `coords`: a dict-like container of arrays (*coordinates*) that label each point (e.g., 1-dimensional arrays of numbers, datetime objects or strings) - `attrs`: [`dict`](https://docs.python.org/3/library/stdtypes.html#dict) to hold arbitrary metadata (*attributes*) Xarray uses `dims` and `coords` to enable its core metadata aware operations. Dimensions provide names that xarray uses instead of the `axis` argument found in many numpy functions. Coordinates enable fast label based indexing and alignment, building on the functionality of the `index` found on a pandas [`DataFrame`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html#pandas.DataFrame) or [`Series`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.html#pandas.Series). DataArray objects also can have a `name` and can hold arbitrary metadata in the form of their `attrs` property. Names and attributes are strictly for users and user-written code: xarray makes no attempt to interpret them, and propagates them only in unambiguous cases. For reading and writing attributes xarray relies on the capabilities of the supported backends. (see FAQ, [What is your approach to metadata?](../get-help/faq.md#approach-to-metadata)). ### Creating a DataArray The [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) constructor takes: - `data`: a multi-dimensional array of values (e.g., a numpy ndarray, a [numpy-like array](duckarrays.md#userguide-duckarrays), [`Series`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.html#pandas.Series), [`DataFrame`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html#pandas.DataFrame) or `pandas.Panel`) - `coords`: a list or dictionary of coordinates. If a list, it should be a list of tuples where the first element is the dimension name and the second element is the corresponding coordinate array_like object. - `dims`: a list of dimension names. If omitted and `coords` is a list of tuples, dimension names are taken from `coords`. - `attrs`: a dictionary of attributes to add to the instance - `name`: a string that names the instance ```ipython3 data = np.random.rand(4, 3) locs = ["IA", "IL", "IN"] times = pd.date_range("2000-01-01", periods=4) foo = xr.DataArray(data, coords=[times, locs], dims=["time", "space"]) foo ``` ```none Size: 96B array([[0.12696983, 0.96671784, 0.26047601], [0.89723652, 0.37674972, 0.33622174], [0.45137647, 0.84025508, 0.12310214], [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3)) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.DataArray (time: 4, space: 3)> Size: 96B
array([[0.12696983, 0.96671784, 0.26047601],
       [0.89723652, 0.37674972, 0.33622174],
       [0.45137647, 0.84025508, 0.12310214],
       [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3))
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
Only `data` is required; all of other arguments will be filled in with default values: ```ipython3 xr.DataArray(data) ``` ```none Size: 96B array([[0.12696983, 0.96671784, 0.26047601], [0.89723652, 0.37674972, 0.33622174], [0.45137647, 0.84025508, 0.12310214], [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3)) Dimensions without coordinates: dim_0, dim_1 ```
<xarray.DataArray (dim_0: 4, dim_1: 3)> Size: 96B
array([[0.12696983, 0.96671784, 0.26047601],
       [0.89723652, 0.37674972, 0.33622174],
       [0.45137647, 0.84025508, 0.12310214],
       [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3))
Dimensions without coordinates: dim_0, dim_1
As you can see, dimension names are always present in the xarray data model: if you do not provide them, defaults of the form `dim_N` will be created. However, coordinates are always optional, and dimensions do not have automatic coordinate labels. #### NOTE This is different from pandas, where axes always have tick labels, which default to the integers `[0, ..., n-1]`. Prior to xarray v0.9, xarray copied this behavior: default coordinates for each dimension would be created if coordinates were not supplied explicitly. This is no longer the case. Coordinates can be specified in the following ways: - A list of values with length equal to the number of dimensions, providing coordinate labels for each dimension. Each value must be of one of the following forms: * A [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) or [`Variable`](../generated/xarray.Variable.md#xarray.Variable) * A tuple of the form `(dims, data[, attrs])`, which is converted into arguments for [`Variable`](../generated/xarray.Variable.md#xarray.Variable) * A pandas object or scalar value, which is converted into a `DataArray` * A 1D array or list, which is interpreted as values for a one dimensional coordinate variable along the same dimension as its name - A dictionary of `{coord_name: coord}` where values are of the same form as the list. Supplying coordinates as a dictionary allows other coordinates than those corresponding to dimensions (more on these later). If you supply `coords` as a dictionary, you must explicitly provide `dims`. As a list of tuples: ```ipython3 xr.DataArray(data, coords=[("time", times), ("space", locs)]) ``` ```none Size: 96B array([[0.12696983, 0.96671784, 0.26047601], [0.89723652, 0.37674972, 0.33622174], [0.45137647, 0.84025508, 0.12310214], [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3)) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.DataArray (time: 4, space: 3)> Size: 96B
array([[0.12696983, 0.96671784, 0.26047601],
       [0.89723652, 0.37674972, 0.33622174],
       [0.45137647, 0.84025508, 0.12310214],
       [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3))
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
As a dictionary: ```ipython3 xr.DataArray( data, coords={ "time": times, "space": locs, "const": 42, "ranking": ("space", [1, 2, 3]), }, dims=["time", "space"], ) ``` ```none Size: 96B array([[0.12696983, 0.96671784, 0.26047601], [0.89723652, 0.37674972, 0.33622174], [0.45137647, 0.84025508, 0.12310214], [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3)) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.DataArray (time: 4, space: 3)> Size: 96B
array([[0.12696983, 0.96671784, 0.26047601],
       [0.89723652, 0.37674972, 0.33622174],
       [0.45137647, 0.84025508, 0.12310214],
       [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3))
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
    ranking  (space) int64 24B 1 2 3
    const    int64 8B 42
As a dictionary with coords across multiple dimensions: ```ipython3 xr.DataArray( data, coords={ "time": times, "space": locs, "const": 42, "ranking": (("time", "space"), np.arange(12).reshape(4, 3)), }, dims=["time", "space"], ) ``` ```none Size: 96B array([[0.12696983, 0.96671784, 0.26047601], [0.89723652, 0.37674972, 0.33622174], [0.45137647, 0.84025508, 0.12310214], [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3)) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.DataArray (time: 4, space: 3)> Size: 96B
array([[0.12696983, 0.96671784, 0.26047601],
       [0.89723652, 0.37674972, 0.33622174],
       [0.45137647, 0.84025508, 0.12310214],
       [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3))
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
    ranking  (time, space) int64 96B 0 1 2 3 4 5 6 7 8 9 10 11
    const    int64 8B 42
If you create a `DataArray` by supplying a pandas [`Series`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.html#pandas.Series), [`DataFrame`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html#pandas.DataFrame) or `pandas.Panel`, any non-specified arguments in the `DataArray` constructor will be filled in from the pandas object: ```ipython3 df = pd.DataFrame({"x": [0, 1], "y": [2, 3]}, index=["a", "b"]) df.index.name = "abc" df.columns.name = "xyz" df ``` ```none xyz x y abc a 0 2 b 1 3 ```
xyz x y
abc
a 0 2
b 1 3
```ipython3 xr.DataArray(df) ``` ```none Size: 32B array([[0, 2], [1, 3]]) Coordinates: * abc (abc) object 16B 'a' 'b' * xyz (xyz) object 16B 'x' 'y' ```
<xarray.DataArray (abc: 2, xyz: 2)> Size: 32B
array([[0, 2],
       [1, 3]])
Coordinates:
  \* abc      (abc) object 16B 'a' 'b'
  \* xyz      (xyz) object 16B 'x' 'y'
### DataArray properties Let’s take a look at the important properties on our array: ```ipython3 foo.values ``` ```none array([[0.12696983, 0.96671784, 0.26047601], [0.89723652, 0.37674972, 0.33622174], [0.45137647, 0.84025508, 0.12310214], [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3)) ``` ```ipython3 foo.dims ``` ```none ('time', 'space') ``` ```ipython3 foo.coords ``` ```none Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space) Size: 96B array([[0.12696983, 0.96671784, 0.26047601], [0.89723652, 0.37674972, 0.33622174], [0.45137647, 0.84025508, 0.12310214], [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3)) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.DataArray 'foo' (time: 4, space: 3)> Size: 96B
array([[0.12696983, 0.96671784, 0.26047601],
       [0.89723652, 0.37674972, 0.33622174],
       [0.45137647, 0.84025508, 0.12310214],
       [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3))
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
Attributes:
    units:    meters
The [`rename()`](../generated/xarray.DataArray.rename.md#xarray.DataArray.rename) method is another option, returning a new data array: ```ipython3 foo.rename("bar") ``` ```none Size: 96B array([[0.12696983, 0.96671784, 0.26047601], [0.89723652, 0.37674972, 0.33622174], [0.45137647, 0.84025508, 0.12310214], [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3)) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.DataArray 'bar' (time: 4, space: 3)> Size: 96B
array([[0.12696983, 0.96671784, 0.26047601],
       [0.89723652, 0.37674972, 0.33622174],
       [0.45137647, 0.84025508, 0.12310214],
       [0.5430262 , 0.37301223, 0.44799682]], shape=(4, 3))
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
Attributes:
    units:    meters
### DataArray Coordinates The `coords` property is `dict` like. Individual coordinates can be accessed from the coordinates by name, or even by indexing the data array itself: ```ipython3 foo.coords["time"] ``` ```none Size: 32B array(['2000-01-01T00:00:00.000000', '2000-01-02T00:00:00.000000', '2000-01-03T00:00:00.000000', '2000-01-04T00:00:00.000000'], dtype='datetime64[us]') Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 ```
<xarray.DataArray 'time' (time: 4)> Size: 32B
array(['2000-01-01T00:00:00.000000', '2000-01-02T00:00:00.000000',
       '2000-01-03T00:00:00.000000', '2000-01-04T00:00:00.000000'],
      dtype='datetime64[us]')
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
```ipython3 foo["time"] ``` ```none Size: 32B array(['2000-01-01T00:00:00.000000', '2000-01-02T00:00:00.000000', '2000-01-03T00:00:00.000000', '2000-01-04T00:00:00.000000'], dtype='datetime64[us]') Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 ```
<xarray.DataArray 'time' (time: 4)> Size: 32B
array(['2000-01-01T00:00:00.000000', '2000-01-02T00:00:00.000000',
       '2000-01-03T00:00:00.000000', '2000-01-04T00:00:00.000000'],
      dtype='datetime64[us]')
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
These are also [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) objects, which contain tick-labels for each dimension. Coordinates can also be set or removed by using the dictionary like syntax: ```ipython3 foo["ranking"] = ("space", [1, 2, 3]) foo.coords ``` ```none Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space) [1](#id11) for more background on this example). ### Creating a Dataset To make an [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) from scratch, supply dictionaries for any variables (`data_vars`), coordinates (`coords`) and attributes (`attrs`). - `data_vars` should be a dictionary with each key as the name of the variable and each value as one of: * A [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) or [`Variable`](../generated/xarray.Variable.md#xarray.Variable) * A tuple of the form `(dims, data[, attrs])`, which is converted into arguments for [`Variable`](../generated/xarray.Variable.md#xarray.Variable) * A pandas object, which is converted into a `DataArray` * A 1D array or list, which is interpreted as values for a one dimensional coordinate variable along the same dimension as its name - `coords` should be a dictionary of the same form as `data_vars`. - `attrs` should be a dictionary. Let’s create some fake data for the example we show above. In this example dataset, we will represent measurements of the temperature and pressure that were made under various conditions: * the measurements were made on four different days; * they were made at two separate locations, which we will represent using their latitude and longitude; and * they were made using instruments by three different manufacturers, which we will refer to as `'manufac1'`, `'manufac2'`, and `'manufac3'`. ```ipython3 np.random.seed(0) temperature = 15 + 8 * np.random.randn(2, 3, 4) precipitation = 10 * np.random.rand(2, 3, 4) lon = [-99.83, -99.32] lat = [42.25, 42.21] instruments = ["manufac1", "manufac2", "manufac3"] time = pd.date_range("2014-09-06", periods=4) reference_time = pd.Timestamp("2014-09-05") # for real use cases, its good practice to supply array attributes such as # units, but we won't bother here for the sake of brevity ds = xr.Dataset( { "temperature": (["loc", "instrument", "time"], temperature), "precipitation": (["loc", "instrument", "time"], precipitation), }, coords={ "lon": (["loc"], lon), "lat": (["loc"], lat), "instrument": instruments, "time": time, "reference_time": reference_time, }, ) ds ``` ```none Size: 552B Dimensions: (loc: 2, instrument: 3, time: 4) Coordinates: lon (loc) float64 16B -99.83 -99.32 lat (loc) float64 16B 42.25 42.21 * instrument (instrument)
<xarray.Dataset> Size: 552B
Dimensions:         (loc: 2, instrument: 3, time: 4)
Coordinates:
    lon             (loc) float64 16B -99.83 -99.32
    lat             (loc) float64 16B 42.25 42.21
  \* instrument      (instrument) <U8 96B 'manufac1' 'manufac2' 'manufac3'
  \* time            (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    reference_time  datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc
Data variables:
    temperature     (loc, instrument, time) float64 192B 29.11 18.2 ... 9.063
    precipitation   (loc, instrument, time) float64 192B 4.562 5.684 ... 1.613
Here we pass [`xarray.DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) objects or a pandas object as values in the dictionary: ```ipython3 xr.Dataset(dict(bar=foo)) ``` ```none Size: 152B Dimensions: (time: 4, space: 3) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.Dataset> Size: 152B
Dimensions:  (time: 4, space: 3)
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
Data variables:
    bar      (time, space) float64 96B 0.127 0.9667 0.2605 ... 0.543 0.373 0.448
```ipython3 xr.Dataset(dict(bar=foo.to_pandas())) ``` ```none Size: 152B Dimensions: (time: 4, space: 3) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space) object 24B 'IA' 'IL' 'IN' Data variables: bar (time, space) float64 96B 0.127 0.9667 0.2605 ... 0.543 0.373 0.448 ```
<xarray.Dataset> Size: 152B
Dimensions:  (time: 4, space: 3)
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) object 24B 'IA' 'IL' 'IN'
Data variables:
    bar      (time, space) float64 96B 0.127 0.9667 0.2605 ... 0.543 0.373 0.448
Where a pandas object is supplied as a value, the names of its indexes are used as dimension names, and its data is aligned to any existing dimensions. You can also create a dataset from: - A [`pandas.DataFrame`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html#pandas.DataFrame) or `pandas.Panel` along its columns and items respectively, by passing it into the [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) directly - A [`pandas.DataFrame`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html#pandas.DataFrame) with [`Dataset.from_dataframe`](../generated/xarray.Dataset.from_dataframe.md#xarray.Dataset.from_dataframe), which will additionally handle MultiIndexes See [Working with pandas](pandas.md#pandas) - A netCDF file on disk with [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset). See [Reading and writing files](io.md#io). ### Dataset contents [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) implements the Python mapping interface, with values given by [`xarray.DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) objects: ```ipython3 print("temperature" in ds) ds["temperature"] ``` ```none True ``` ```none Size: 192B array([[[29.11241877, 18.20125767, 22.82990387, 32.92714559], [29.94046392, 7.18177696, 22.60070734, 13.78914233], [14.17424919, 18.28478802, 16.15234857, 26.63418806]], [[21.0883018 , 15.97340013, 18.55090586, 17.66939462], [26.95263259, 13.35873389, 17.50454161, 8.16723409], [-5.42391853, 20.22894876, 21.91548959, 9.06267984]]], shape=(2, 3, 4)) Coordinates: lon (loc) float64 16B -99.83 -99.32 lat (loc) float64 16B 42.25 42.21 * instrument (instrument)
<xarray.DataArray 'temperature' (loc: 2, instrument: 3, time: 4)> Size: 192B
array([[[29.11241877, 18.20125767, 22.82990387, 32.92714559],
        [29.94046392,  7.18177696, 22.60070734, 13.78914233],
        [14.17424919, 18.28478802, 16.15234857, 26.63418806]],

       [[21.0883018 , 15.97340013, 18.55090586, 17.66939462],
        [26.95263259, 13.35873389, 17.50454161,  8.16723409],
        [-5.42391853, 20.22894876, 21.91548959,  9.06267984]]],
      shape=(2, 3, 4))
Coordinates:
    lon             (loc) float64 16B -99.83 -99.32
    lat             (loc) float64 16B 42.25 42.21
  \* instrument      (instrument) <U8 96B 'manufac1' 'manufac2' 'manufac3'
  \* time            (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    reference_time  datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc
Valid keys include each listed coordinate and data variable. Data and coordinate variables are also contained separately in the [`data_vars`](../generated/xarray.Dataset.data_vars.md#xarray.Dataset.data_vars) and [`coords`](../generated/xarray.Dataset.coords.md#xarray.Dataset.coords) dictionary-like attributes: ```ipython3 ds.data_vars ``` ```none Data variables: temperature (loc, instrument, time) float64 192B 29.11 18.2 ... 9.063 precipitation (loc, instrument, time) float64 192B 4.562 5.684 ... 1.613 ``` ```ipython3 ds.coords ``` ```none Coordinates: lon (loc) float64 16B -99.83 -99.32 lat (loc) float64 16B 42.25 42.21 * instrument (instrument) Size: 552B Dimensions: (loc: 2, instrument: 3, time: 4) Coordinates: lon (loc) float64 16B -99.83 -99.32 lat (loc) float64 16B 42.25 42.21 * instrument (instrument)
<xarray.Dataset> Size: 552B
Dimensions:         (loc: 2, instrument: 3, time: 4)
Coordinates:
    lon             (loc) float64 16B -99.83 -99.32
    lat             (loc) float64 16B 42.25 42.21
  \* instrument      (instrument) <U8 96B 'manufac1' 'manufac2' 'manufac3'
  \* time            (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    reference_time  datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc
Data variables:
    temperature     (loc, instrument, time) float64 192B 29.11 18.2 ... 9.063
    precipitation   (loc, instrument, time) float64 192B 4.562 5.684 ... 1.613
Attributes:
    title:    example attribute
Xarray does not enforce any restrictions on attributes, but serialization to some file formats may fail if you use objects that are not strings, numbers or [`numpy.ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) objects. As a useful shortcut, you can use attribute style access for reading (but not setting) variables and attributes: ```ipython3 ds.temperature ``` ```none Size: 192B array([[[29.11241877, 18.20125767, 22.82990387, 32.92714559], [29.94046392, 7.18177696, 22.60070734, 13.78914233], [14.17424919, 18.28478802, 16.15234857, 26.63418806]], [[21.0883018 , 15.97340013, 18.55090586, 17.66939462], [26.95263259, 13.35873389, 17.50454161, 8.16723409], [-5.42391853, 20.22894876, 21.91548959, 9.06267984]]], shape=(2, 3, 4)) Coordinates: lon (loc) float64 16B -99.83 -99.32 lat (loc) float64 16B 42.25 42.21 * instrument (instrument)
<xarray.DataArray 'temperature' (loc: 2, instrument: 3, time: 4)> Size: 192B
array([[[29.11241877, 18.20125767, 22.82990387, 32.92714559],
        [29.94046392,  7.18177696, 22.60070734, 13.78914233],
        [14.17424919, 18.28478802, 16.15234857, 26.63418806]],

       [[21.0883018 , 15.97340013, 18.55090586, 17.66939462],
        [26.95263259, 13.35873389, 17.50454161,  8.16723409],
        [-5.42391853, 20.22894876, 21.91548959,  9.06267984]]],
      shape=(2, 3, 4))
Coordinates:
    lon             (loc) float64 16B -99.83 -99.32
    lat             (loc) float64 16B 42.25 42.21
  \* instrument      (instrument) <U8 96B 'manufac1' 'manufac2' 'manufac3'
  \* time            (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    reference_time  datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc
This is particularly useful in an exploratory context, because you can tab-complete these variable names with tools like IPython. ### Dictionary like methods We can update a dataset in-place using Python’s standard dictionary syntax. For example, to create this example dataset from scratch, we could have written: ```ipython3 ds = xr.Dataset() ds["temperature"] = (("loc", "instrument", "time"), temperature) ds["temperature_double"] = (("loc", "instrument", "time"), temperature * 2) ds["precipitation"] = (("loc", "instrument", "time"), precipitation) ds.coords["lat"] = (("loc",), lat) ds.coords["lon"] = (("loc",), lon) ds.coords["time"] = pd.date_range("2014-09-06", periods=4) ds.coords["reference_time"] = pd.Timestamp("2014-09-05") ``` To change the variables in a `Dataset`, you can use all the standard dictionary methods, including `values`, `items`, `__delitem__`, `get` and [`update()`](../generated/xarray.Dataset.update.md#xarray.Dataset.update). Note that assigning a `DataArray` or pandas object to a `Dataset` variable using `__setitem__` or `update` will [automatically align](combining.md#update) the array(s) to the original dataset’s indexes. You can copy a `Dataset` by calling the [`copy()`](../generated/xarray.Dataset.copy.md#xarray.Dataset.copy) method. By default, the copy is shallow, so only the container will be copied: the arrays in the `Dataset` will still be stored in the same underlying [`numpy.ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) objects. You can copy all data by calling `ds.copy(deep=True)`. ### Transforming datasets In addition to dictionary-like methods (described above), xarray has additional methods (like pandas) for transforming datasets into new objects. For removing variables, you can select and drop an explicit list of variables by indexing with a list of names or using the [`drop_vars()`](../generated/xarray.Dataset.drop_vars.md#xarray.Dataset.drop_vars) methods to return a new `Dataset`. These operations keep around coordinates: ```ipython3 ds[["temperature"]] ``` ```none Size: 264B Dimensions: (loc: 2, instrument: 3, time: 4) Coordinates: lat (loc) float64 16B 42.25 42.21 lon (loc) float64 16B -99.83 -99.32 * time (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09 reference_time datetime64[us] 8B 2014-09-05 Dimensions without coordinates: loc, instrument Data variables: temperature (loc, instrument, time) float64 192B 29.11 18.2 ... 9.063 ```
<xarray.Dataset> Size: 264B
Dimensions:         (loc: 2, instrument: 3, time: 4)
Coordinates:
    lat             (loc) float64 16B 42.25 42.21
    lon             (loc) float64 16B -99.83 -99.32
  \* time            (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    reference_time  datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc, instrument
Data variables:
    temperature     (loc, instrument, time) float64 192B 29.11 18.2 ... 9.063
```ipython3 ds[["temperature", "temperature_double"]] ``` ```none Size: 456B Dimensions: (loc: 2, instrument: 3, time: 4) Coordinates: lat (loc) float64 16B 42.25 42.21 lon (loc) float64 16B -99.83 -99.32 * time (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09 reference_time datetime64[us] 8B 2014-09-05 Dimensions without coordinates: loc, instrument Data variables: temperature (loc, instrument, time) float64 192B 29.11 ... 9.063 temperature_double (loc, instrument, time) float64 192B 58.22 ... 18.13 ```
<xarray.Dataset> Size: 456B
Dimensions:             (loc: 2, instrument: 3, time: 4)
Coordinates:
    lat                 (loc) float64 16B 42.25 42.21
    lon                 (loc) float64 16B -99.83 -99.32
  \* time                (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    reference_time      datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc, instrument
Data variables:
    temperature         (loc, instrument, time) float64 192B 29.11 ... 9.063
    temperature_double  (loc, instrument, time) float64 192B 58.22 ... 18.13
```ipython3 ds.drop_vars("temperature") ``` ```none Size: 456B Dimensions: (loc: 2, instrument: 3, time: 4) Coordinates: lat (loc) float64 16B 42.25 42.21 lon (loc) float64 16B -99.83 -99.32 * time (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09 reference_time datetime64[us] 8B 2014-09-05 Dimensions without coordinates: loc, instrument Data variables: temperature_double (loc, instrument, time) float64 192B 58.22 ... 18.13 precipitation (loc, instrument, time) float64 192B 4.562 ... 1.613 ```
<xarray.Dataset> Size: 456B
Dimensions:             (loc: 2, instrument: 3, time: 4)
Coordinates:
    lat                 (loc) float64 16B 42.25 42.21
    lon                 (loc) float64 16B -99.83 -99.32
  \* time                (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    reference_time      datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc, instrument
Data variables:
    temperature_double  (loc, instrument, time) float64 192B 58.22 ... 18.13
    precipitation       (loc, instrument, time) float64 192B 4.562 ... 1.613
To remove a dimension, you can use [`drop_dims()`](../generated/xarray.Dataset.drop_dims.md#xarray.Dataset.drop_dims) method. Any variables using that dimension are dropped: ```ipython3 ds.drop_dims("time") ``` ```none Size: 40B Dimensions: (loc: 2) Coordinates: lat (loc) float64 16B 42.25 42.21 lon (loc) float64 16B -99.83 -99.32 reference_time datetime64[us] 8B 2014-09-05 Dimensions without coordinates: loc Data variables: *empty* ```
<xarray.Dataset> Size: 40B
Dimensions:         (loc: 2)
Coordinates:
    lat             (loc) float64 16B 42.25 42.21
    lon             (loc) float64 16B -99.83 -99.32
    reference_time  datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc
Data variables:
    \*empty\*
As an alternate to dictionary-like modifications, you can use [`assign()`](../generated/xarray.Dataset.assign.md#xarray.Dataset.assign) and [`assign_coords()`](../generated/xarray.Dataset.assign_coords.md#xarray.Dataset.assign_coords). These methods return a new dataset with additional (or replaced) values: ```ipython3 ds.assign(temperature2=2 * ds.temperature) ``` ```none Size: 840B Dimensions: (loc: 2, instrument: 3, time: 4) Coordinates: lat (loc) float64 16B 42.25 42.21 lon (loc) float64 16B -99.83 -99.32 * time (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09 reference_time datetime64[us] 8B 2014-09-05 Dimensions without coordinates: loc, instrument Data variables: temperature (loc, instrument, time) float64 192B 29.11 ... 9.063 temperature_double (loc, instrument, time) float64 192B 58.22 ... 18.13 precipitation (loc, instrument, time) float64 192B 4.562 ... 1.613 temperature2 (loc, instrument, time) float64 192B 58.22 ... 18.13 ```
<xarray.Dataset> Size: 840B
Dimensions:             (loc: 2, instrument: 3, time: 4)
Coordinates:
    lat                 (loc) float64 16B 42.25 42.21
    lon                 (loc) float64 16B -99.83 -99.32
  \* time                (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    reference_time      datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc, instrument
Data variables:
    temperature         (loc, instrument, time) float64 192B 29.11 ... 9.063
    temperature_double  (loc, instrument, time) float64 192B 58.22 ... 18.13
    precipitation       (loc, instrument, time) float64 192B 4.562 ... 1.613
    temperature2        (loc, instrument, time) float64 192B 58.22 ... 18.13
There is also the [`pipe()`](../generated/xarray.Dataset.pipe.md#xarray.Dataset.pipe) method that allows you to use a method call with an external function (e.g., `ds.pipe(func)`) instead of simply calling it (e.g., `func(ds)`). This allows you to write pipelines for transforming your data (using “method chaining”) instead of writing hard to follow nested function calls: ```ipython3 # these lines are equivalent, but with pipe we can make the logic flow # entirely from left to right plt.plot((2 * ds.temperature.sel(loc=0)).mean("instrument")) (ds.temperature.sel(loc=0).pipe(lambda x: 2 * x).mean("instrument").pipe(plt.plot)) ``` Both `pipe` and `assign` replicate the pandas methods of the same names ([`DataFrame.pipe`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.pipe.html#pandas.DataFrame.pipe) and [`DataFrame.assign`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.assign.html#pandas.DataFrame.assign)). With xarray, there is no performance penalty for creating new datasets, even if variables are lazily loaded from a file on disk. Creating new objects instead of mutating existing objects often results in easier to understand code, so we encourage using this approach. ### Renaming variables Another useful option is the [`rename()`](../generated/xarray.Dataset.rename.md#xarray.Dataset.rename) method to rename dataset variables: ```ipython3 ds.rename({"temperature": "temp", "precipitation": "precip"}) ``` ```none Size: 648B Dimensions: (loc: 2, instrument: 3, time: 4) Coordinates: lat (loc) float64 16B 42.25 42.21 lon (loc) float64 16B -99.83 -99.32 * time (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09 reference_time datetime64[us] 8B 2014-09-05 Dimensions without coordinates: loc, instrument Data variables: temp (loc, instrument, time) float64 192B 29.11 ... 9.063 temperature_double (loc, instrument, time) float64 192B 58.22 ... 18.13 precip (loc, instrument, time) float64 192B 4.562 ... 1.613 ```
<xarray.Dataset> Size: 648B
Dimensions:             (loc: 2, instrument: 3, time: 4)
Coordinates:
    lat                 (loc) float64 16B 42.25 42.21
    lon                 (loc) float64 16B -99.83 -99.32
  \* time                (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    reference_time      datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc, instrument
Data variables:
    temp                (loc, instrument, time) float64 192B 29.11 ... 9.063
    temperature_double  (loc, instrument, time) float64 192B 58.22 ... 18.13
    precip              (loc, instrument, time) float64 192B 4.562 ... 1.613
The related [`swap_dims()`](../generated/xarray.Dataset.swap_dims.md#xarray.Dataset.swap_dims) method allows you do to swap dimension and non-dimension variables: ```ipython3 ds.coords["day"] = ("time", [6, 7, 8, 9]) ds.swap_dims({"time": "day"}) ``` ```none Size: 680B Dimensions: (loc: 2, instrument: 3, day: 4) Coordinates: lat (loc) float64 16B 42.25 42.21 lon (loc) float64 16B -99.83 -99.32 * day (day) int64 32B 6 7 8 9 time (day) datetime64[us] 32B 2014-09-06 ... 2014-09-09 reference_time datetime64[us] 8B 2014-09-05 Dimensions without coordinates: loc, instrument Data variables: temperature (loc, instrument, day) float64 192B 29.11 18.2 ... 9.063 temperature_double (loc, instrument, day) float64 192B 58.22 36.4 ... 18.13 precipitation (loc, instrument, day) float64 192B 4.562 ... 1.613 ```
<xarray.Dataset> Size: 680B
Dimensions:             (loc: 2, instrument: 3, day: 4)
Coordinates:
    lat                 (loc) float64 16B 42.25 42.21
    lon                 (loc) float64 16B -99.83 -99.32
  \* day                 (day) int64 32B 6 7 8 9
    time                (day) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    reference_time      datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc, instrument
Data variables:
    temperature         (loc, instrument, day) float64 192B 29.11 18.2 ... 9.063
    temperature_double  (loc, instrument, day) float64 192B 58.22 36.4 ... 18.13
    precipitation       (loc, instrument, day) float64 192B 4.562 ... 1.613
## DataTree [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) is `xarray`’s highest-level data structure, able to organise heterogeneous data which could not be stored inside a single [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) object. This includes representing the recursive structure of multiple [groups](https://www.unidata.ucar.edu/software/netcdf/workshops/2011/groups-types/GroupsIntro.html) within a netCDF file or [Zarr Store](https://zarr.readthedocs.io/en/stable/user-guide/groups/#groups). Each [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) object (or “node”) contains the same data that a single [`xarray.Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) would (i.e. [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) objects stored under hashable keys), and so has the same key properties: - `dims`: a dictionary mapping of dimension names to lengths, for the variables in this node, and this node’s ancestors, - `data_vars`: a dict-like container of DataArrays corresponding to variables in this node, - `coords`: another dict-like container of DataArrays, corresponding to coordinate variables in this node, and this node’s ancestors, - `attrs`: dict to hold arbitrary metadata relevant to data in this node. A single [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) object acts much like a single [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) object, and has a similar set of dict-like methods defined upon it. However, [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree)s can also contain other [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) objects, so they can be thought of as nested dict-like containers of both [`xarray.DataArray`](../generated/xarray.DataArray.md#xarray.DataArray)s and [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree)s. A single datatree object is known as a “node”, and its position relative to other nodes is defined by two more key properties: - `children`: A dictionary mapping from names to other [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) objects, known as its “child nodes”. - `parent`: The single [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) object whose children this datatree is a member of, known as its “parent node”. Each child automatically knows about its parent node, and a node without a parent is known as a “root” node (represented by the `parent` attribute pointing to `None`). Nodes can have multiple children, but as each child node has at most one parent, there can only ever be one root node in a given tree. The overall structure is technically a connected acyclic undirected rooted graph, otherwise known as a [“Tree”](https://en.wikipedia.org/wiki/Tree_(graph_theory)). [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) objects can also optionally have a `name` as well as `attrs`, just like a [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray). Again these are not normally used unless explicitly accessed by the user. ### Creating a DataTree One way to create a [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) from scratch is to create each node individually, specifying the nodes’ relationship to one another as you create each one. The [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) constructor takes: - `dataset`: The data that will be stored in this node, represented by a single [`xarray.Dataset`](../generated/xarray.Dataset.md#xarray.Dataset). - `children`: The various child nodes (if there are any), given as a mapping from string keys to [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) objects. - `name`: A string to use as the name of this node. Let’s make a single datatree node with some example data in it: ```ipython3 ds1 = xr.Dataset({"foo": "orange"}) dt = xr.DataTree(name="root", dataset=ds1) dt ``` ```none Group: / Dimensions: () Data variables: foo
<xarray.DataTree 'root'>
Group: /
    Dimensions:  ()
    Data variables:
        foo      <U6 24B 'orange'
At this point we have created a single node datatree with no parent and no children. ```ipython3 print(dt.parent is None) dt.children ``` ```none True ``` ```none Frozen({}) ``` We can add a second node to this tree, assigning it to the parent node `dt`: ```ipython3 dataset2 = xr.Dataset({"bar": 0}, coords={"y": ("y", [0, 1, 2])}) dt2 = xr.DataTree(name="a", dataset=dataset2) # Add the child Datatree to the root node dt.children = {"child-node": dt2} dt ``` ```none Group: / │ Dimensions: () │ Data variables: │ foo
<xarray.DataTree 'root'>
Group: /
│   Dimensions:  ()
│   Data variables:
│       foo      <U6 24B 'orange'
└── Group: /child-node
        Dimensions:  (y: 3)
        Coordinates:
          \* y        (y) int64 24B 0 1 2
        Data variables:
            bar      int64 8B 0
More idiomatically you can create a tree from a dictionary of `Datasets` and `DataTrees`. In this case we add a new node under `dt["child-node"]` by providing the explicit path under `"child-node"` as the dictionary key: ```ipython3 # create a third Dataset ds3 = xr.Dataset({"zed": np.nan}) # create a tree from a dictionary of DataTrees and Datasets dt = xr.DataTree.from_dict({"/": dt, "/child-node/new-zed-node": ds3}) ``` We have created a tree with three nodes in it: ```ipython3 dt ``` ```none Group: / │ Dimensions: () │ Data variables: │ foo
<xarray.DataTree>
Group: /
│   Dimensions:  ()
│   Data variables:
│       foo      <U6 24B 'orange'
└── Group: /child-node
    │   Dimensions:  (y: 3)
    │   Coordinates:
    │     \* y        (y) int64 24B 0 1 2
    │   Data variables:
    │       bar      int64 8B 0
    └── Group: /child-node/new-zed-node
            Dimensions:  ()
            Data variables:
                zed      float64 8B nan
Consistency checks are enforced. For instance, if we try to create a cycle, where the root node is also a child of a descendant, the constructor will raise an ([`InvalidTreeError`](../generated/xarray.InvalidTreeError.md#xarray.InvalidTreeError)): ```ipython3 dt["child-node"].children = {"new-child": dt} ``` ```ipythontb InvalidTreeError: Cannot set parent, as intended parent is already a descendant of this node. ``` Alternatively you can also create a [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) object from: - A dictionary mapping directory-like paths to either [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) nodes or data, using [`xarray.DataTree.from_dict()`](../generated/xarray.DataTree.from_dict.md#xarray.DataTree.from_dict), - A well formed netCDF or Zarr file on disk with [`open_datatree()`](../generated/xarray.open_datatree.md#xarray.open_datatree). See [reading and writing files](io.md#io). For data files with groups that do not align see [`xarray.open_groups()`](../generated/xarray.open_groups.md#xarray.open_groups) or target each group individually [`xarray.open_dataset(group='groupname')`](../generated/xarray.open_dataset.md#xarray.open_dataset). For more information about coordinate alignment see [DataTree Inheritance](#datatree-inheritance) ### DataTree Contents Like [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset), [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) implements the python mapping interface, but with values given by either [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) objects or other [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) objects. ```ipython3 dt["child-node"] ``` ```none Group: /child-node │ Dimensions: (y: 3) │ Coordinates: │ * y (y) int64 24B 0 1 2 │ Data variables: │ bar int64 8B 0 └── Group: /child-node/new-zed-node Dimensions: () Data variables: zed float64 8B nan ```
<xarray.DataTree 'child-node'>
Group: /child-node
│   Dimensions:  (y: 3)
│   Coordinates:
│     \* y        (y) int64 24B 0 1 2
│   Data variables:
│       bar      int64 8B 0
└── Group: /child-node/new-zed-node
        Dimensions:  ()
        Data variables:
            zed      float64 8B nan
```ipython3 dt["foo"] ``` ```none Size: 24B array('orange', dtype='
<xarray.DataArray 'foo' ()> Size: 24B
array('orange', dtype='<U6')
Iterating over keys will iterate over both the names of variables and child nodes. We can also access all the data in a single node, and its inherited coordinates, through a dataset-like view ```ipython3 dt["child-node"].dataset ``` ```none Size: 32B Dimensions: (y: 3) Coordinates: * y (y) int64 24B 0 1 2 Data variables: bar int64 8B 0 ```
<xarray.DatasetView> Size: 32B
Dimensions:  (y: 3)
Coordinates:
  \* y        (y) int64 24B 0 1 2
Data variables:
    bar      int64 8B 0
This demonstrates the fact that the data in any one node is equivalent to the contents of a single [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) object. The [`DataTree.dataset`](../generated/xarray.DataTree.dataset.md#xarray.DataTree.dataset) property returns an immutable view, but we can instead extract the node’s data contents as a new and mutable [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) object via [`DataTree.to_dataset()`](../generated/xarray.DataTree.to_dataset.md#xarray.DataTree.to_dataset): ```ipython3 dt["child-node"].to_dataset() ``` ```none Size: 32B Dimensions: (y: 3) Coordinates: * y (y) int64 24B 0 1 2 Data variables: bar int64 8B 0 ```
<xarray.Dataset> Size: 32B
Dimensions:  (y: 3)
Coordinates:
  \* y        (y) int64 24B 0 1 2
Data variables:
    bar      int64 8B 0
Like with [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset), you can access the data and coordinate variables of a node separately via the [`data_vars`](../generated/xarray.DataTree.data_vars.md#xarray.DataTree.data_vars) and [`coords`](../generated/xarray.DataTree.coords.md#xarray.DataTree.coords) attributes: ```ipython3 dt["child-node"].data_vars ``` ```none Data variables: bar int64 8B 0 ``` ```ipython3 dt["child-node"].coords ``` ```none Coordinates: * y (y) int64 24B 0 1 2 ``` ### Dictionary-like methods We can update a datatree in-place using Python’s standard dictionary syntax, similar to how we can for Dataset objects. For example, to create this example DataTree from scratch, we could have written: ```ipython3 dt = xr.DataTree(name="root") dt["foo"] = "orange" dt["child-node"] = xr.DataTree( dataset=xr.Dataset({"bar": 0}, coords={"y": ("y", [0, 1, 2])}) ) dt["child-node/new-zed-node/zed"] = np.nan dt ``` ```none Group: / │ Dimensions: () │ Data variables: │ foo
<xarray.DataTree 'root'>
Group: /
│   Dimensions:  ()
│   Data variables:
│       foo      <U6 24B 'orange'
└── Group: /child-node
    │   Dimensions:  (y: 3)
    │   Coordinates:
    │     \* y        (y) int64 24B 0 1 2
    │   Data variables:
    │       bar      int64 8B 0
    └── Group: /child-node/new-zed-node
            Dimensions:  ()
            Data variables:
                zed      float64 8B nan
To change the variables in a node of a [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree), you can use all the standard dictionary methods, including `values`, `items`, `__delitem__`, `get` and [`xarray.DataTree.update()`](../generated/xarray.DataTree.update.md#xarray.DataTree.update). Note that assigning a [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) object to a [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) variable using `__setitem__` or [`update()`](../generated/xarray.DataTree.update.md#xarray.DataTree.update) will [automatically align](combining.md#update) the array(s) to the original node’s indexes. If you copy a [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) using the `copy()` function or the [`xarray.DataTree.copy()`](../generated/xarray.DataTree.copy.md#xarray.DataTree.copy) method it will copy the subtree, meaning that node and children below it, but no parents above it. Like for [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset), this copy is shallow by default, but you can copy all the underlying data arrays by calling `dt.copy(deep=True)`. ### DataTree Inheritance DataTree implements a simple inheritance mechanism. Coordinates, dimensions and their associated indices are propagated from downward starting from the root node to all descendent nodes. Coordinate inheritance was inspired by the NetCDF-CF inherited dimensions, but DataTree’s inheritance is slightly stricter yet easier to reason about. The constraint that this puts on a DataTree is that dimensions and indices that are inherited must be aligned with any direct descendant node’s existing dimension or index. This allows descendants to use dimensions defined in ancestor nodes, without duplicating that information. But as a consequence, if a dimension-name is defined in on a node and that same dimension-name exists in one of its ancestors, they must align (have the same index and size). Some examples: ```ipython3 # Set up coordinates time = xr.DataArray(data=["2022-01", "2023-01"], dims="time") stations = xr.DataArray(data=list("abcdef"), dims="station") lon = [-100, -80, -60] lat = [10, 20, 30] # Set up fake data wind_speed = xr.DataArray(np.ones((2, 6)) * 2, dims=("time", "station")) pressure = xr.DataArray(np.ones((2, 6)) * 3, dims=("time", "station")) air_temperature = xr.DataArray(np.ones((2, 6)) * 4, dims=("time", "station")) dewpoint = xr.DataArray(np.ones((2, 6)) * 5, dims=("time", "station")) infrared = xr.DataArray(np.ones((2, 3, 3)) * 6, dims=("time", "lon", "lat")) true_color = xr.DataArray(np.ones((2, 3, 3)) * 7, dims=("time", "lon", "lat")) dt2 = xr.DataTree.from_dict( { "/": xr.Dataset( coords={"time": time}, ), "/weather": xr.Dataset( coords={"station": stations}, data_vars={ "wind_speed": wind_speed, "pressure": pressure, }, ), "/weather/temperature": xr.Dataset( data_vars={ "air_temperature": air_temperature, "dewpoint": dewpoint, }, ), "/satellite": xr.Dataset( coords={"lat": lat, "lon": lon}, data_vars={ "infrared": infrared, "true_color": true_color, }, ), }, ) dt2 ``` ```none Group: / │ Dimensions: (time: 2) │ Coordinates: │ * time (time)
<xarray.DataTree>
Group: /
│   Dimensions:  (time: 2)
│   Coordinates:
│     \* time     (time) <U7 56B '2022-01' '2023-01'
├── Group: /weather
│   │   Dimensions:     (station: 6, time: 2)
│   │   Coordinates:
│   │     \* station     (station) <U1 24B 'a' 'b' 'c' 'd' 'e' 'f'
│   │   Data variables:
│   │       wind_speed  (time, station) float64 96B 2.0 2.0 2.0 2.0 ... 2.0 2.0 2.0 2.0
│   │       pressure    (time, station) float64 96B 3.0 3.0 3.0 3.0 ... 3.0 3.0 3.0 3.0
│   └── Group: /weather/temperature
│           Dimensions:          (time: 2, station: 6)
│           Data variables:
│               air_temperature  (time, station) float64 96B 4.0 4.0 4.0 4.0 ... 4.0 4.0 4.0
│               dewpoint         (time, station) float64 96B 5.0 5.0 5.0 5.0 ... 5.0 5.0 5.0
└── Group: /satellite
        Dimensions:     (lat: 3, lon: 3, time: 2)
        Coordinates:
          \* lat         (lat) int64 24B 10 20 30
          \* lon         (lon) int64 24B -100 -80 -60
        Data variables:
            infrared    (time, lon, lat) float64 144B 6.0 6.0 6.0 6.0 ... 6.0 6.0 6.0
            true_color  (time, lon, lat) float64 144B 7.0 7.0 7.0 7.0 ... 7.0 7.0 7.0
Here there are four different coordinate variables, which apply to variables in the DataTree in different ways: `time` is a shared coordinate used by both `weather` and `satellite` variables `station` is used only for `weather` variables `lat` and `lon` are only use for `satellite` images Coordinate variables are inherited to descendent nodes, which is only possible because variables at different levels of a hierarchical DataTree are always aligned. Placing the `time` variable at the root node automatically indicates that it applies to all descendent nodes. Similarly, `station` is in the base `weather` node, because it applies to all weather variables, both directly in `weather` and in the `temperature` sub-tree. Notice the inherited coordinates are explicitly shown in the tree representation under `Inherited coordinates:`. ```ipython3 dt2["/weather"] ``` ```none Group: /weather │ Dimensions: (time: 2, station: 6) │ Coordinates: │ * station (station)
<xarray.DataTree 'weather'>
Group: /weather
│   Dimensions:     (time: 2, station: 6)
│   Coordinates:
│     \* station     (station) <U1 24B 'a' 'b' 'c' 'd' 'e' 'f'
│   Inherited coordinates:
│     \* time        (time) <U7 56B '2022-01' '2023-01'
│   Data variables:
│       wind_speed  (time, station) float64 96B 2.0 2.0 2.0 2.0 ... 2.0 2.0 2.0 2.0
│       pressure    (time, station) float64 96B 3.0 3.0 3.0 3.0 ... 3.0 3.0 3.0 3.0
└── Group: /weather/temperature
        Dimensions:          (time: 2, station: 6)
        Data variables:
            air_temperature  (time, station) float64 96B 4.0 4.0 4.0 4.0 ... 4.0 4.0 4.0
            dewpoint         (time, station) float64 96B 5.0 5.0 5.0 5.0 ... 5.0 5.0 5.0
Accessing any of the lower level trees through the [`.dataset`](../generated/xarray.DataTree.dataset.md#xarray.DataTree.dataset) property automatically includes coordinates from higher levels (e.g., `time` and `station`): ```ipython3 dt2["/weather/temperature"].dataset ``` ```none Size: 272B Dimensions: (time: 2, station: 6) Coordinates: * time (time)
<xarray.DatasetView> Size: 272B
Dimensions:          (time: 2, station: 6)
Coordinates:
  \* time             (time) <U7 56B '2022-01' '2023-01'
  \* station          (station) <U1 24B 'a' 'b' 'c' 'd' 'e' 'f'
Data variables:
    air_temperature  (time, station) float64 96B 4.0 4.0 4.0 4.0 ... 4.0 4.0 4.0
    dewpoint         (time, station) float64 96B 5.0 5.0 5.0 5.0 ... 5.0 5.0 5.0
Similarly, when you retrieve a Dataset through [`to_dataset()`](../generated/xarray.DataTree.to_dataset.md#xarray.DataTree.to_dataset) , the inherited coordinates are included by default unless you exclude them with the `inherit` flag: ```ipython3 dt2["/weather/temperature"].to_dataset() ``` ```none Size: 272B Dimensions: (time: 2, station: 6) Coordinates: * time (time)
<xarray.Dataset> Size: 272B
Dimensions:          (time: 2, station: 6)
Coordinates:
  \* time             (time) <U7 56B '2022-01' '2023-01'
  \* station          (station) <U1 24B 'a' 'b' 'c' 'd' 'e' 'f'
Data variables:
    air_temperature  (time, station) float64 96B 4.0 4.0 4.0 4.0 ... 4.0 4.0 4.0
    dewpoint         (time, station) float64 96B 5.0 5.0 5.0 5.0 ... 5.0 5.0 5.0
```ipython3 dt2["/weather/temperature"].to_dataset(inherit=False) ``` ```none Size: 192B Dimensions: (time: 2, station: 6) Dimensions without coordinates: time, station Data variables: air_temperature (time, station) float64 96B 4.0 4.0 4.0 4.0 ... 4.0 4.0 4.0 dewpoint (time, station) float64 96B 5.0 5.0 5.0 5.0 ... 5.0 5.0 5.0 ```
<xarray.Dataset> Size: 192B
Dimensions:          (time: 2, station: 6)
Dimensions without coordinates: time, station
Data variables:
    air_temperature  (time, station) float64 96B 4.0 4.0 4.0 4.0 ... 4.0 4.0 4.0
    dewpoint         (time, station) float64 96B 5.0 5.0 5.0 5.0 ... 5.0 5.0 5.0
For more examples and further discussion see [alignment and coordinate inheritance](hierarchical-data.md#hierarchical-data-alignment-and-coordinate-inheritance). ## Coordinates Coordinates are ancillary variables stored for `DataArray` and `Dataset` objects in the `coords` attribute: ```ipython3 ds.coords ``` ```none Coordinates: lat (loc) float64 16B 42.25 42.21 lon (loc) float64 16B -99.83 -99.32 * time (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09 day (time) int64 32B 6 7 8 9 reference_time datetime64[us] 8B 2014-09-05 ``` Unlike attributes, xarray *does* interpret and persist coordinates in operations that transform xarray objects. There are two types of coordinates in xarray: - **dimension coordinates** are one dimensional coordinates with a name equal to their sole dimension (marked by `*` when printing a dataset or data array). They are used for label based indexing and alignment, like the `index` found on a pandas [`DataFrame`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html#pandas.DataFrame) or [`Series`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.html#pandas.Series). Indeed, these “dimension” coordinates use a [`pandas.Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index) internally to store their values. - **non-dimension coordinates** are variables that contain coordinate data, but are not a dimension coordinate. They can be multidimensional (see [Working with Multidimensional Coordinates](../examples/multidimensional-coords.md)), and there is no relationship between the name of a non-dimension coordinate and the name(s) of its dimension(s). Non-dimension coordinates can be useful for indexing or plotting; otherwise, xarray does not make any direct use of the values associated with them. They are not used for alignment or automatic indexing, nor are they required to match when doing arithmetic (see [Coordinates](computation.md#coordinates-math)). #### NOTE Xarray’s terminology differs from the [CF terminology](https://cfconventions.org/cf-conventions/v1.6.0/cf-conventions.html#terminology), where the “dimension coordinates” are called “coordinate variables”, and the “non-dimension coordinates” are called “auxiliary coordinate variables” (see [GH1295](https://github.com/pydata/xarray/issues/1295) for more details). ### Modifying coordinates To entirely add or remove coordinate arrays, you can use dictionary like syntax, as shown above. To convert back and forth between data and coordinates, you can use the [`set_coords()`](../generated/xarray.Dataset.set_coords.md#xarray.Dataset.set_coords) and [`reset_coords()`](../generated/xarray.Dataset.reset_coords.md#xarray.Dataset.reset_coords) methods: ```ipython3 ds.reset_coords() ``` ```none Size: 680B Dimensions: (loc: 2, instrument: 3, time: 4) Coordinates: * time (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09 Dimensions without coordinates: loc, instrument Data variables: temperature (loc, instrument, time) float64 192B 29.11 ... 9.063 temperature_double (loc, instrument, time) float64 192B 58.22 ... 18.13 precipitation (loc, instrument, time) float64 192B 4.562 ... 1.613 lat (loc) float64 16B 42.25 42.21 lon (loc) float64 16B -99.83 -99.32 reference_time datetime64[us] 8B 2014-09-05 day (time) int64 32B 6 7 8 9 ```
<xarray.Dataset> Size: 680B
Dimensions:             (loc: 2, instrument: 3, time: 4)
Coordinates:
  \* time                (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
Dimensions without coordinates: loc, instrument
Data variables:
    temperature         (loc, instrument, time) float64 192B 29.11 ... 9.063
    temperature_double  (loc, instrument, time) float64 192B 58.22 ... 18.13
    precipitation       (loc, instrument, time) float64 192B 4.562 ... 1.613
    lat                 (loc) float64 16B 42.25 42.21
    lon                 (loc) float64 16B -99.83 -99.32
    reference_time      datetime64[us] 8B 2014-09-05
    day                 (time) int64 32B 6 7 8 9
```ipython3 ds.set_coords(["temperature", "precipitation"]) ``` ```none Size: 680B Dimensions: (loc: 2, instrument: 3, time: 4) Coordinates: lat (loc) float64 16B 42.25 42.21 lon (loc) float64 16B -99.83 -99.32 * time (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09 temperature (loc, instrument, time) float64 192B 29.11 ... 9.063 precipitation (loc, instrument, time) float64 192B 4.562 ... 1.613 day (time) int64 32B 6 7 8 9 reference_time datetime64[us] 8B 2014-09-05 Dimensions without coordinates: loc, instrument Data variables: temperature_double (loc, instrument, time) float64 192B 58.22 ... 18.13 ```
<xarray.Dataset> Size: 680B
Dimensions:             (loc: 2, instrument: 3, time: 4)
Coordinates:
    lat                 (loc) float64 16B 42.25 42.21
    lon                 (loc) float64 16B -99.83 -99.32
  \* time                (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    temperature         (loc, instrument, time) float64 192B 29.11 ... 9.063
    precipitation       (loc, instrument, time) float64 192B 4.562 ... 1.613
    day                 (time) int64 32B 6 7 8 9
    reference_time      datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc, instrument
Data variables:
    temperature_double  (loc, instrument, time) float64 192B 58.22 ... 18.13
```ipython3 ds["temperature"].reset_coords(drop=True) ``` ```none Size: 192B array([[[29.11241877, 18.20125767, 22.82990387, 32.92714559], [29.94046392, 7.18177696, 22.60070734, 13.78914233], [14.17424919, 18.28478802, 16.15234857, 26.63418806]], [[21.0883018 , 15.97340013, 18.55090586, 17.66939462], [26.95263259, 13.35873389, 17.50454161, 8.16723409], [-5.42391853, 20.22894876, 21.91548959, 9.06267984]]], shape=(2, 3, 4)) Coordinates: * time (time) datetime64[us] 32B 2014-09-06 2014-09-07 ... 2014-09-09 Dimensions without coordinates: loc, instrument ```
<xarray.DataArray 'temperature' (loc: 2, instrument: 3, time: 4)> Size: 192B
array([[[29.11241877, 18.20125767, 22.82990387, 32.92714559],
        [29.94046392,  7.18177696, 22.60070734, 13.78914233],
        [14.17424919, 18.28478802, 16.15234857, 26.63418806]],

       [[21.0883018 , 15.97340013, 18.55090586, 17.66939462],
        [26.95263259, 13.35873389, 17.50454161,  8.16723409],
        [-5.42391853, 20.22894876, 21.91548959,  9.06267984]]],
      shape=(2, 3, 4))
Coordinates:
  \* time     (time) datetime64[us] 32B 2014-09-06 2014-09-07 ... 2014-09-09
Dimensions without coordinates: loc, instrument
Notice that these operations skip coordinates with names given by dimensions, as used for indexing. This mostly because we are not entirely sure how to design the interface around the fact that xarray cannot store a coordinate and variable with the name but different values in the same dictionary. But we do recognize that supporting something like this would be useful. ### Coordinates methods `Coordinates` objects also have a few useful methods, mostly for converting them into dataset objects: ```ipython3 ds.coords.to_dataset() ``` ```none Size: 104B Dimensions: (loc: 2, time: 4) Coordinates: lat (loc) float64 16B 42.25 42.21 lon (loc) float64 16B -99.83 -99.32 * time (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09 day (time) int64 32B 6 7 8 9 reference_time datetime64[us] 8B 2014-09-05 Dimensions without coordinates: loc Data variables: *empty* ```
<xarray.Dataset> Size: 104B
Dimensions:         (loc: 2, time: 4)
Coordinates:
    lat             (loc) float64 16B 42.25 42.21
    lon             (loc) float64 16B -99.83 -99.32
  \* time            (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    day             (time) int64 32B 6 7 8 9
    reference_time  datetime64[us] 8B 2014-09-05
Dimensions without coordinates: loc
Data variables:
    \*empty\*
The merge method is particularly interesting, because it implements the same logic used for merging coordinates in arithmetic operations (see [Computation](computation.md#compute)): ```ipython3 alt = xr.Dataset(coords={"z": [10], "lat": 0, "lon": 0}) ds.coords.merge(alt.coords) ``` ```none Size: 80B Dimensions: (time: 4, z: 1) Coordinates: * time (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09 day (time) int64 32B 6 7 8 9 * z (z) int64 8B 10 reference_time datetime64[us] 8B 2014-09-05 Data variables: *empty* ```
<xarray.Dataset> Size: 80B
Dimensions:         (time: 4, z: 1)
Coordinates:
  \* time            (time) datetime64[us] 32B 2014-09-06 ... 2014-09-09
    day             (time) int64 32B 6 7 8 9
  \* z               (z) int64 8B 10
    reference_time  datetime64[us] 8B 2014-09-05
Data variables:
    \*empty\*
The `coords.merge` method may be useful if you want to implement your own binary operations that act on xarray objects. In the future, we hope to write more helper functions so that you can easily make your functions act like xarray’s built-in arithmetic. ### Indexes To convert a coordinate (or any `DataArray`) into an actual [`pandas.Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index), use the [`to_index()`](../generated/xarray.DataArray.to_index.md#xarray.DataArray.to_index) method: ```ipython3 ds["time"].to_index() ``` ```none DatetimeIndex(['2014-09-06', '2014-09-07', '2014-09-08', '2014-09-09'], dtype='datetime64[us]', name='time', freq='D') ``` A useful shortcut is the `indexes` property (on both `DataArray` and `Dataset`), which lazily constructs a dictionary whose keys are given by each dimension and whose the values are `Index` objects: ```ipython3 ds.indexes ``` ```none Indexes: time DatetimeIndex(['2014-09-06', '2014-09-07', '2014-09-08', '2014-09-09'], dtype='datetime64[us]', name='time', freq='D') ``` ### MultiIndex coordinates Xarray supports labeling coordinate values with a [`pandas.MultiIndex`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.MultiIndex.html#pandas.MultiIndex): ```ipython3 midx = pd.MultiIndex.from_arrays( [["R", "R", "V", "V"], [0.1, 0.2, 0.7, 0.9]], names=("band", "wn") ) mda = xr.DataArray(np.random.rand(4), coords={"spec": midx}, dims="spec") mda ``` ```none Size: 32B array([0.65310833, 0.2532916 , 0.46631077, 0.24442559]) Coordinates: * spec (spec) object 32B MultiIndex * band (spec) object 32B 'R' 'R' 'V' 'V' * wn (spec) float64 32B 0.1 0.2 0.7 0.9 ```
<xarray.DataArray (spec: 4)> Size: 32B
array([0.65310833, 0.2532916 , 0.46631077, 0.24442559])
Coordinates:
  \* spec     (spec) object 32B MultiIndex
  \* band     (spec) object 32B 'R' 'R' 'V' 'V'
  \* wn       (spec) float64 32B 0.1 0.2 0.7 0.9
For convenience multi-index levels are directly accessible as “virtual” or “derived” coordinates (marked by `-` when printing a dataset or data array): ```ipython3 mda["band"] ``` ```none Size: 32B [4 values with dtype=object] Coordinates: * spec (spec) object 32B MultiIndex * band (spec) object 32B 'R' 'R' 'V' 'V' * wn (spec) float64 32B 0.1 0.2 0.7 0.9 ```
<xarray.DataArray 'band' (spec: 4)> Size: 32B
[4 values with dtype=object]
Coordinates:
  \* spec     (spec) object 32B MultiIndex
  \* band     (spec) object 32B 'R' 'R' 'V' 'V'
  \* wn       (spec) float64 32B 0.1 0.2 0.7 0.9
```ipython3 mda.wn ``` ```none Size: 32B [4 values with dtype=float64] Coordinates: * spec (spec) object 32B MultiIndex * band (spec) object 32B 'R' 'R' 'V' 'V' * wn (spec) float64 32B 0.1 0.2 0.7 0.9 ```
<xarray.DataArray 'wn' (spec: 4)> Size: 32B
[4 values with dtype=float64]
Coordinates:
  \* spec     (spec) object 32B MultiIndex
  \* band     (spec) object 32B 'R' 'R' 'V' 'V'
  \* wn       (spec) float64 32B 0.1 0.2 0.7 0.9
Indexing with multi-index levels is also possible using the `sel` method (see [Multi-level indexing](indexing.md#multi-level-indexing)). Unlike other coordinates, “virtual” level coordinates are not stored in the `coords` attribute of `DataArray` and `Dataset` objects (although they are shown when printing the `coords` attribute). Consequently, most of the coordinates related methods don’t apply for them. It also can’t be used to replace one particular level. Because in a `DataArray` or `Dataset` object each multi-index level is accessible as a “virtual” coordinate, its name must not conflict with the names of the other levels, coordinates and data variables of the same object. Even though xarray sets default names for multi-indexes with unnamed levels, it is recommended that you explicitly set the names of the levels. * **[1]** Latitude and longitude are 2D arrays because the dataset uses [projected coordinates](https://en.wikipedia.org/wiki/Map_projection). `reference_time` refers to the reference time at which the forecast was made, rather than `time` which is the valid time for which the forecast applies. # dataarray.html.md # DataArray | [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray)([data, coords, dims, name, attrs, ...]) | N-dimensional array with labeled coordinates and dimensions. | |------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------| ## Attributes | [`DataArray.values`](../generated/xarray.DataArray.values.md#xarray.DataArray.values) | The array's data converted to numpy.ndarray. | |---------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------| | [`DataArray.data`](../generated/xarray.DataArray.data.md#xarray.DataArray.data) | The DataArray's data as an array. | | [`DataArray.coords`](../generated/xarray.DataArray.coords.md#xarray.DataArray.coords) | Mapping of [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) objects corresponding to coordinate variables. | | [`DataArray.dims`](../generated/xarray.DataArray.dims.md#xarray.DataArray.dims) | Tuple of dimension names associated with this array. | | [`DataArray.sizes`](../generated/xarray.DataArray.sizes.md#xarray.DataArray.sizes) | Ordered mapping from dimension names to lengths. | | [`DataArray.name`](../generated/xarray.DataArray.name.md#xarray.DataArray.name) | The name of this array. | | [`DataArray.attrs`](../generated/xarray.DataArray.attrs.md#xarray.DataArray.attrs) | Dictionary storing arbitrary metadata with this array. | | [`DataArray.encoding`](../generated/xarray.DataArray.encoding.md#xarray.DataArray.encoding) | Dictionary of format-specific settings for how this array should be serialized. | | [`DataArray.indexes`](../generated/xarray.DataArray.indexes.md#xarray.DataArray.indexes) | Mapping of pandas.Index objects used for label based indexing. | | [`DataArray.xindexes`](../generated/xarray.DataArray.xindexes.md#xarray.DataArray.xindexes) | Mapping of `Index` objects used for label based indexing. | | [`DataArray.chunksizes`](../generated/xarray.DataArray.chunksizes.md#xarray.DataArray.chunksizes) | Mapping from dimension names to block lengths for this dataarray's data. | ## ndarray attributes | [`DataArray.ndim`](../generated/xarray.DataArray.ndim.md#xarray.DataArray.ndim) | Number of array dimensions. | |---------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------| | [`DataArray.nbytes`](../generated/xarray.DataArray.nbytes.md#xarray.DataArray.nbytes) | Total bytes consumed by the elements of this DataArray's data. | | [`DataArray.shape`](../generated/xarray.DataArray.shape.md#xarray.DataArray.shape) | Tuple of array dimensions. | | [`DataArray.size`](../generated/xarray.DataArray.size.md#xarray.DataArray.size) | Number of elements in the array. | | [`DataArray.dtype`](../generated/xarray.DataArray.dtype.md#xarray.DataArray.dtype) | Data-type of the array’s elements. | | [`DataArray.chunks`](../generated/xarray.DataArray.chunks.md#xarray.DataArray.chunks) | Tuple of block lengths for this dataarray's data, in order of dimensions, or None if the underlying data is not a dask array. | ## DataArray contents | [`DataArray.assign_coords`](../generated/xarray.DataArray.assign_coords.md#xarray.DataArray.assign_coords)([coords]) | Assign new coordinates to this object. | |-------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------| | [`DataArray.assign_attrs`](../generated/xarray.DataArray.assign_attrs.md#xarray.DataArray.assign_attrs)(\*args, \*\*kwargs) | Assign new attrs to this object. | | [`DataArray.pipe`](../generated/xarray.DataArray.pipe.md#xarray.DataArray.pipe)(func, \*args, \*\*kwargs) | Apply `func(self, *args, **kwargs)` | | [`DataArray.rename`](../generated/xarray.DataArray.rename.md#xarray.DataArray.rename)([new_name_or_name_dict]) | Returns a new DataArray with renamed coordinates, dimensions or a new name. | | [`DataArray.swap_dims`](../generated/xarray.DataArray.swap_dims.md#xarray.DataArray.swap_dims)([dims_dict]) | Returns a new DataArray with swapped dimensions. | | [`DataArray.expand_dims`](../generated/xarray.DataArray.expand_dims.md#xarray.DataArray.expand_dims)([dim, axis, ...]) | Return a new object with an additional axis (or axes) inserted at the corresponding position in the array shape. | | [`DataArray.drop_vars`](../generated/xarray.DataArray.drop_vars.md#xarray.DataArray.drop_vars)(names, \*[, errors]) | Returns an array with dropped variables. | | [`DataArray.drop_indexes`](../generated/xarray.DataArray.drop_indexes.md#xarray.DataArray.drop_indexes)(coord_names, \*[, errors]) | Drop the indexes assigned to the given coordinates. | | [`DataArray.drop_duplicates`](../generated/xarray.DataArray.drop_duplicates.md#xarray.DataArray.drop_duplicates)(dim, \*[, keep]) | Returns a new DataArray with duplicate dimension values removed. | | [`DataArray.drop_encoding`](../generated/xarray.DataArray.drop_encoding.md#xarray.DataArray.drop_encoding)() | Return a new DataArray without encoding on the array or any attached coords. | | [`DataArray.drop_attrs`](../generated/xarray.DataArray.drop_attrs.md#xarray.DataArray.drop_attrs)(\*[, deep]) | Removes all attributes from the DataArray. | | [`DataArray.reset_coords`](../generated/xarray.DataArray.reset_coords.md#xarray.DataArray.reset_coords)([names, drop]) | Given names of coordinates, reset them to become variables. | | [`DataArray.copy`](../generated/xarray.DataArray.copy.md#xarray.DataArray.copy)([deep, data]) | Returns a copy of this array. | | [`DataArray.convert_calendar`](../generated/xarray.DataArray.convert_calendar.md#xarray.DataArray.convert_calendar)(calendar[, dim, ...]) | Convert the DataArray to another calendar. | | [`DataArray.interp_calendar`](../generated/xarray.DataArray.interp_calendar.md#xarray.DataArray.interp_calendar)(target[, dim]) | Interpolates the DataArray to another calendar based on decimal year measure. | | [`DataArray.get_index`](../generated/xarray.DataArray.get_index.md#xarray.DataArray.get_index)(key) | Get an index for a dimension, with fall-back to a default RangeIndex | | [`DataArray.astype`](../generated/xarray.DataArray.astype.md#xarray.DataArray.astype)(dtype, \*[, order, casting, ...]) | Copy of the xarray object, with data cast to a specified type. | | [`DataArray.item`](../generated/xarray.DataArray.item.md#xarray.DataArray.item)(\*args) | Copy an element of an array to a standard Python scalar and return it. | ## Indexing | [`DataArray.__getitem__`](../generated/xarray.DataArray.__getitem__.md#xarray.DataArray.__getitem__)(key) | | |-----------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [`DataArray.__setitem__`](../generated/xarray.DataArray.__setitem__.md#xarray.DataArray.__setitem__)(key, value) | | | [`DataArray.loc`](../generated/xarray.DataArray.loc.md#xarray.DataArray.loc) | Attribute for location based indexing like pandas. | | [`DataArray.isel`](../generated/xarray.DataArray.isel.md#xarray.DataArray.isel)([indexers, drop, missing_dims]) | Return a new DataArray whose data is given by selecting indexes along the specified dimension(s). | | [`DataArray.sel`](../generated/xarray.DataArray.sel.md#xarray.DataArray.sel)([indexers, method, tolerance, ...]) | Return a new DataArray whose data is given by selecting index labels along the specified dimension(s). | | [`DataArray.drop_sel`](../generated/xarray.DataArray.drop_sel.md#xarray.DataArray.drop_sel)([labels, errors]) | Drop index labels from this DataArray. | | [`DataArray.drop_isel`](../generated/xarray.DataArray.drop_isel.md#xarray.DataArray.drop_isel)([indexers]) | Drop index positions from this DataArray. | | [`DataArray.head`](../generated/xarray.DataArray.head.md#xarray.DataArray.head)([indexers]) | Return a new DataArray whose data is given by the first n values along the specified dimension(s). | | [`DataArray.tail`](../generated/xarray.DataArray.tail.md#xarray.DataArray.tail)([indexers]) | Return a new DataArray whose data is given by the last n values along the specified dimension(s). | | [`DataArray.thin`](../generated/xarray.DataArray.thin.md#xarray.DataArray.thin)([indexers]) | Return a new DataArray whose data is given by each n value along the specified dimension(s). | | [`DataArray.squeeze`](../generated/xarray.DataArray.squeeze.md#xarray.DataArray.squeeze)([dim, drop, axis]) | Return a new object with squeezed data. | | [`DataArray.interp`](../generated/xarray.DataArray.interp.md#xarray.DataArray.interp)([coords, method, ...]) | Interpolate a DataArray onto new coordinates. | | [`DataArray.interp_like`](../generated/xarray.DataArray.interp_like.md#xarray.DataArray.interp_like)(other[, method, ...]) | Interpolate this object onto the coordinates of another object, filling out of range values with NaN. | | [`DataArray.reindex`](../generated/xarray.DataArray.reindex.md#xarray.DataArray.reindex)([indexers, method, ...]) | Conform this object onto the indexes of another object, filling in missing values with `fill_value`. | | [`DataArray.reindex_like`](../generated/xarray.DataArray.reindex_like.md#xarray.DataArray.reindex_like)(other, \*[, method, ...]) | Conform this object onto the indexes of another object, for indexes which the objects share. | | [`DataArray.set_index`](../generated/xarray.DataArray.set_index.md#xarray.DataArray.set_index)([indexes, append]) | Set DataArray (multi-)indexes using one or more existing coordinates. | | [`DataArray.reset_index`](../generated/xarray.DataArray.reset_index.md#xarray.DataArray.reset_index)(dims_or_levels[, drop]) | Reset the specified index(es) or multi-index level(s). | | [`DataArray.set_xindex`](../generated/xarray.DataArray.set_xindex.md#xarray.DataArray.set_xindex)(coord_names[, index_cls]) | Set a new, Xarray-compatible index from one or more existing coordinate(s). | | [`DataArray.reorder_levels`](../generated/xarray.DataArray.reorder_levels.md#xarray.DataArray.reorder_levels)([dim_order]) | Rearrange index levels using input order. | | [`DataArray.query`](../generated/xarray.DataArray.query.md#xarray.DataArray.query)([queries, parser, engine, ...]) | Return a new data array indexed along the specified dimension(s), where the indexers are given as strings containing Python expressions to be evaluated against the values in the array. | ## Missing value handling | [`DataArray.isnull`](../generated/xarray.DataArray.isnull.md#xarray.DataArray.isnull)([keep_attrs]) | Test each value in the array for whether it is a missing value. | |-----------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------| | [`DataArray.notnull`](../generated/xarray.DataArray.notnull.md#xarray.DataArray.notnull)([keep_attrs]) | Test each value in the array for whether it is not a missing value. | | [`DataArray.combine_first`](../generated/xarray.DataArray.combine_first.md#xarray.DataArray.combine_first)(other) | Combine two DataArray objects, with union of coordinates. | | [`DataArray.count`](../generated/xarray.DataArray.count.md#xarray.DataArray.count)([dim, keep_attrs]) | Reduce this DataArray's data by applying `count` along some dimension(s). | | [`DataArray.dropna`](../generated/xarray.DataArray.dropna.md#xarray.DataArray.dropna)(dim, \*[, how, thresh]) | Returns a new array with dropped labels for missing values along the provided dimension. | | [`DataArray.fillna`](../generated/xarray.DataArray.fillna.md#xarray.DataArray.fillna)(value) | Fill missing values in this object. | | [`DataArray.ffill`](../generated/xarray.DataArray.ffill.md#xarray.DataArray.ffill)(dim[, limit]) | Fill NaN values by propagating values forward | | [`DataArray.bfill`](../generated/xarray.DataArray.bfill.md#xarray.DataArray.bfill)(dim[, limit]) | Fill NaN values by propagating values backward | | [`DataArray.interpolate_na`](../generated/xarray.DataArray.interpolate_na.md#xarray.DataArray.interpolate_na)([dim, method, ...]) | Fill in NaNs by interpolating according to different methods. | | [`DataArray.where`](../generated/xarray.DataArray.where.md#xarray.DataArray.where)(cond[, other, drop]) | Filter elements from this object according to a condition. | | [`DataArray.isin`](../generated/xarray.DataArray.isin.md#xarray.DataArray.isin)(test_elements) | Tests each value in the array for whether it is in test elements. | ## Comparisons | [`DataArray.equals`](../generated/xarray.DataArray.equals.md#xarray.DataArray.equals)(other) | True if two DataArrays have the same dimensions, coordinates and values; otherwise False. | |----------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------| | [`DataArray.identical`](../generated/xarray.DataArray.identical.md#xarray.DataArray.identical)(other) | Like equals, but also checks the array name, attributes, attributes on all coordinates, and indexes. | | [`DataArray.broadcast_equals`](../generated/xarray.DataArray.broadcast_equals.md#xarray.DataArray.broadcast_equals)(other) | Two DataArrays are broadcast equal if they are equal after broadcasting them against each other such that they have the same dimensions. | ## Computation | [`DataArray.reduce`](../generated/xarray.DataArray.reduce.md#xarray.DataArray.reduce)(func[, dim, axis, ...]) | Reduce this array by applying func along some dimension(s). | |--------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| | [`DataArray.groupby`](../generated/xarray.DataArray.groupby.md#xarray.DataArray.groupby)([group, squeeze, ...]) | Returns a DataArrayGroupBy object for performing grouped operations. | | [`DataArray.groupby_bins`](../generated/xarray.DataArray.groupby_bins.md#xarray.DataArray.groupby_bins)(group, bins[, right, ...]) | Returns a DataArrayGroupBy object for performing grouped operations. | | [`DataArray.rolling`](../generated/xarray.DataArray.rolling.md#xarray.DataArray.rolling)([dim, min_periods, center]) | Rolling window object for DataArrays. | | [`DataArray.rolling_exp`](../generated/xarray.DataArray.rolling_exp.md#xarray.DataArray.rolling_exp)([window, window_type]) | Exponentially-weighted moving window. | | [`DataArray.cumulative`](../generated/xarray.DataArray.cumulative.md#xarray.DataArray.cumulative)(dim[, min_periods]) | Accumulating object for DataArrays. | | [`DataArray.weighted`](../generated/xarray.DataArray.weighted.md#xarray.DataArray.weighted)(weights) | Weighted DataArray operations. | | [`DataArray.coarsen`](../generated/xarray.DataArray.coarsen.md#xarray.DataArray.coarsen)([dim, boundary, side, ...]) | Coarsen object for DataArrays. | | [`DataArray.resample`](../generated/xarray.DataArray.resample.md#xarray.DataArray.resample)([indexer, skipna, ...]) | Returns a Resample object for performing resampling operations. | | [`DataArray.get_axis_num`](../generated/xarray.DataArray.get_axis_num.md#xarray.DataArray.get_axis_num)(dim) | Return axis number(s) corresponding to dimension(s) in this array. | | [`DataArray.diff`](../generated/xarray.DataArray.diff.md#xarray.DataArray.diff)(dim[, n, label]) | Calculate the n-th order discrete difference along given axis. | | [`DataArray.dot`](../generated/xarray.DataArray.dot.md#xarray.DataArray.dot)(other[, dim]) | Perform dot product of two DataArrays along their shared dims. | | [`DataArray.quantile`](../generated/xarray.DataArray.quantile.md#xarray.DataArray.quantile)(q[, dim, method, ...]) | Compute the qth quantile of the data along the specified dimension. | | [`DataArray.differentiate`](../generated/xarray.DataArray.differentiate.md#xarray.DataArray.differentiate)(coord[, edge_order, ...]) | Differentiate the array with the second order accurate central differences. | | [`DataArray.integrate`](../generated/xarray.DataArray.integrate.md#xarray.DataArray.integrate)([coord, datetime_unit]) | Integrate along the given coordinate using the trapezoidal rule. | | [`DataArray.polyfit`](../generated/xarray.DataArray.polyfit.md#xarray.DataArray.polyfit)(dim, deg[, skipna, rcond, ...]) | Least squares polynomial fit. | | [`DataArray.map_blocks`](../generated/xarray.DataArray.map_blocks.md#xarray.DataArray.map_blocks)(func[, args, kwargs, ...]) | Apply a function to each block of this DataArray. | | [`DataArray.curvefit`](../generated/xarray.DataArray.curvefit.md#xarray.DataArray.curvefit)(coords, func[, ...]) | Curve fitting optimization for arbitrary functions. | ## Aggregation | [`DataArray.all`](../generated/xarray.DataArray.all.md#xarray.DataArray.all)([dim, keep_attrs]) | Reduce this DataArray's data by applying `all` along some dimension(s). | |------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------| | [`DataArray.any`](../generated/xarray.DataArray.any.md#xarray.DataArray.any)([dim, keep_attrs]) | Reduce this DataArray's data by applying `any` along some dimension(s). | | [`DataArray.argmax`](../generated/xarray.DataArray.argmax.md#xarray.DataArray.argmax)([dim, axis, keep_attrs, skipna]) | Index or indices of the maximum of the DataArray over one or more dimensions. | | [`DataArray.argmin`](../generated/xarray.DataArray.argmin.md#xarray.DataArray.argmin)([dim, axis, keep_attrs, skipna]) | Index or indices of the minimum of the DataArray over one or more dimensions. | | [`DataArray.count`](../generated/xarray.DataArray.count.md#xarray.DataArray.count)([dim, keep_attrs]) | Reduce this DataArray's data by applying `count` along some dimension(s). | | [`DataArray.idxmax`](../generated/xarray.DataArray.idxmax.md#xarray.DataArray.idxmax)([dim, skipna, fill_value, ...]) | Return the coordinate label of the maximum value along a dimension. | | [`DataArray.idxmin`](../generated/xarray.DataArray.idxmin.md#xarray.DataArray.idxmin)([dim, skipna, fill_value, ...]) | Return the coordinate label of the minimum value along a dimension. | | [`DataArray.max`](../generated/xarray.DataArray.max.md#xarray.DataArray.max)([dim, skipna, keep_attrs]) | Reduce this DataArray's data by applying `max` along some dimension(s). | | [`DataArray.min`](../generated/xarray.DataArray.min.md#xarray.DataArray.min)([dim, skipna, keep_attrs]) | Reduce this DataArray's data by applying `min` along some dimension(s). | | [`DataArray.mean`](../generated/xarray.DataArray.mean.md#xarray.DataArray.mean)([dim, skipna, keep_attrs]) | Reduce this DataArray's data by applying `mean` along some dimension(s). | | [`DataArray.median`](../generated/xarray.DataArray.median.md#xarray.DataArray.median)([dim, skipna, keep_attrs]) | Reduce this DataArray's data by applying `median` along some dimension(s). | | [`DataArray.prod`](../generated/xarray.DataArray.prod.md#xarray.DataArray.prod)([dim, skipna, min_count, ...]) | Reduce this DataArray's data by applying `prod` along some dimension(s). | | [`DataArray.sum`](../generated/xarray.DataArray.sum.md#xarray.DataArray.sum)([dim, skipna, min_count, ...]) | Reduce this DataArray's data by applying `sum` along some dimension(s). | | [`DataArray.std`](../generated/xarray.DataArray.std.md#xarray.DataArray.std)([dim, skipna, ddof, keep_attrs]) | Reduce this DataArray's data by applying `std` along some dimension(s). | | [`DataArray.var`](../generated/xarray.DataArray.var.md#xarray.DataArray.var)([dim, skipna, ddof, keep_attrs]) | Reduce this DataArray's data by applying `var` along some dimension(s). | | [`DataArray.cumsum`](../generated/xarray.DataArray.cumsum.md#xarray.DataArray.cumsum)([dim, skipna, keep_attrs]) | Reduce this DataArray's data by applying `cumsum` along some dimension(s). | | [`DataArray.cumprod`](../generated/xarray.DataArray.cumprod.md#xarray.DataArray.cumprod)([dim, skipna, keep_attrs]) | Reduce this DataArray's data by applying `cumprod` along some dimension(s). | ## ndarray methods | [`DataArray.argsort`](../generated/xarray.DataArray.argsort.md#xarray.DataArray.argsort)([axis, kind, order, stable]) | Returns the indices that would sort this array. | |----------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| | [`DataArray.clip`](../generated/xarray.DataArray.clip.md#xarray.DataArray.clip)([min, max, keep_attrs]) | Return an array whose values are limited to `[min, max]`. | | [`DataArray.conj`](../generated/xarray.DataArray.conj.md#xarray.DataArray.conj)() | Complex-conjugate all elements. | | [`DataArray.conjugate`](../generated/xarray.DataArray.conjugate.md#xarray.DataArray.conjugate)(\*args, \*\*kwargs) | a.conj() | | [`DataArray.imag`](../generated/xarray.DataArray.imag.md#xarray.DataArray.imag) | The imaginary part of the array. | | [`DataArray.searchsorted`](../generated/xarray.DataArray.searchsorted.md#xarray.DataArray.searchsorted)(v[, side, sorter]) | Find indices where elements of v should be inserted in a to maintain order. | | [`DataArray.round`](../generated/xarray.DataArray.round.md#xarray.DataArray.round)(\*args, \*\*kwargs) | | | [`DataArray.real`](../generated/xarray.DataArray.real.md#xarray.DataArray.real) | The real part of the array. | | [`DataArray.T`](../generated/xarray.DataArray.T.md#xarray.DataArray.T) | | | [`DataArray.rank`](../generated/xarray.DataArray.rank.md#xarray.DataArray.rank)(dim, \*[, pct, keep_attrs]) | Ranks the data. | ## String manipulation | [`DataArray.str`](../generated/xarray.DataArray.str.md#xarray.DataArray.str) | | |--------------------------------------------------------------------------------|----| | [`DataArray.str.capitalize`](../generated/xarray.DataArray.str.capitalize.md#xarray.DataArray.str.capitalize)() | Convert strings in the array to be capitalized. | |---------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------| | [`DataArray.str.casefold`](../generated/xarray.DataArray.str.casefold.md#xarray.DataArray.str.casefold)() | Convert strings in the array to be casefolded. | | [`DataArray.str.cat`](../generated/xarray.DataArray.str.cat.md#xarray.DataArray.str.cat)(\*others[, sep]) | Concatenate strings elementwise in the DataArray with other strings. | | [`DataArray.str.center`](../generated/xarray.DataArray.str.center.md#xarray.DataArray.str.center)(width[, fillchar]) | Pad left and right side of each string in the array. | | [`DataArray.str.contains`](../generated/xarray.DataArray.str.contains.md#xarray.DataArray.str.contains)(pat[, case, flags, regex]) | Test if pattern or regex is contained within each string of the array. | | [`DataArray.str.count`](../generated/xarray.DataArray.str.count.md#xarray.DataArray.str.count)(pat[, flags, case]) | Count occurrences of pattern in each string of the array. | | [`DataArray.str.decode`](../generated/xarray.DataArray.str.decode.md#xarray.DataArray.str.decode)(encoding[, errors]) | Decode character string in the array using indicated encoding. | | [`DataArray.str.encode`](../generated/xarray.DataArray.str.encode.md#xarray.DataArray.str.encode)(encoding[, errors]) | Encode character string in the array using indicated encoding. | | [`DataArray.str.endswith`](../generated/xarray.DataArray.str.endswith.md#xarray.DataArray.str.endswith)(pat) | Test if the end of each string in the array matches a pattern. | | [`DataArray.str.extract`](../generated/xarray.DataArray.str.extract.md#xarray.DataArray.str.extract)(pat, dim[, case, flags]) | Extract the first match of capture groups in the regex pat as a new dimension in a DataArray. | | [`DataArray.str.extractall`](../generated/xarray.DataArray.str.extractall.md#xarray.DataArray.str.extractall)(pat, group_dim, ...) | Extract all matches of capture groups in the regex pat as new dimensions in a DataArray. | | [`DataArray.str.find`](../generated/xarray.DataArray.str.find.md#xarray.DataArray.str.find)(sub[, start, end, side]) | Return lowest or highest indexes in each strings in the array where the substring is fully contained between [start:end]. | | [`DataArray.str.findall`](../generated/xarray.DataArray.str.findall.md#xarray.DataArray.str.findall)(pat[, case, flags]) | Find all occurrences of pattern or regular expression in the DataArray. | | [`DataArray.str.format`](../generated/xarray.DataArray.str.format.md#xarray.DataArray.str.format)(\*args, \*\*kwargs) | Perform python string formatting on each element of the DataArray. | | [`DataArray.str.get`](../generated/xarray.DataArray.str.get.md#xarray.DataArray.str.get)(i[, default]) | Extract character number i from each string in the array. | | [`DataArray.str.get_dummies`](../generated/xarray.DataArray.str.get_dummies.md#xarray.DataArray.str.get_dummies)(dim[, sep]) | Return DataArray of dummy/indicator variables. | | [`DataArray.str.index`](../generated/xarray.DataArray.str.index.md#xarray.DataArray.str.index)(sub[, start, end, side]) | Return lowest or highest indexes in each strings where the substring is fully contained between [start:end]. | | [`DataArray.str.isalnum`](../generated/xarray.DataArray.str.isalnum.md#xarray.DataArray.str.isalnum)() | Check whether all characters in each string are alphanumeric. | | [`DataArray.str.isalpha`](../generated/xarray.DataArray.str.isalpha.md#xarray.DataArray.str.isalpha)() | Check whether all characters in each string are alphabetic. | | [`DataArray.str.isdecimal`](../generated/xarray.DataArray.str.isdecimal.md#xarray.DataArray.str.isdecimal)() | Check whether all characters in each string are decimal. | | [`DataArray.str.isdigit`](../generated/xarray.DataArray.str.isdigit.md#xarray.DataArray.str.isdigit)() | Check whether all characters in each string are digits. | | [`DataArray.str.islower`](../generated/xarray.DataArray.str.islower.md#xarray.DataArray.str.islower)() | Check whether all characters in each string are lowercase. | | [`DataArray.str.isnumeric`](../generated/xarray.DataArray.str.isnumeric.md#xarray.DataArray.str.isnumeric)() | Check whether all characters in each string are numeric. | | [`DataArray.str.isspace`](../generated/xarray.DataArray.str.isspace.md#xarray.DataArray.str.isspace)() | Check whether all characters in each string are spaces. | | [`DataArray.str.istitle`](../generated/xarray.DataArray.str.istitle.md#xarray.DataArray.str.istitle)() | Check whether all characters in each string are titlecase. | | [`DataArray.str.isupper`](../generated/xarray.DataArray.str.isupper.md#xarray.DataArray.str.isupper)() | Check whether all characters in each string are uppercase. | | [`DataArray.str.join`](../generated/xarray.DataArray.str.join.md#xarray.DataArray.str.join)([dim, sep]) | Concatenate strings in a DataArray along a particular dimension. | | [`DataArray.str.len`](../generated/xarray.DataArray.str.len.md#xarray.DataArray.str.len)() | Compute the length of each string in the array. | | [`DataArray.str.ljust`](../generated/xarray.DataArray.str.ljust.md#xarray.DataArray.str.ljust)(width[, fillchar]) | Pad right side of each string in the array. | | [`DataArray.str.lower`](../generated/xarray.DataArray.str.lower.md#xarray.DataArray.str.lower)() | Convert strings in the array to lowercase. | | [`DataArray.str.lstrip`](../generated/xarray.DataArray.str.lstrip.md#xarray.DataArray.str.lstrip)([to_strip]) | Remove leading characters. | | [`DataArray.str.match`](../generated/xarray.DataArray.str.match.md#xarray.DataArray.str.match)(pat[, case, flags]) | Determine if each string in the array matches a regular expression. | | [`DataArray.str.normalize`](../generated/xarray.DataArray.str.normalize.md#xarray.DataArray.str.normalize)(form) | Return the Unicode normal form for the strings in the datarray. | | [`DataArray.str.pad`](../generated/xarray.DataArray.str.pad.md#xarray.DataArray.str.pad)(width[, side, fillchar]) | Pad strings in the array up to width. | | [`DataArray.str.partition`](../generated/xarray.DataArray.str.partition.md#xarray.DataArray.str.partition)(dim[, sep]) | Split the strings in the DataArray at the first occurrence of separator sep. | | [`DataArray.str.repeat`](../generated/xarray.DataArray.str.repeat.md#xarray.DataArray.str.repeat)(repeats) | Repeat each string in the array. | | [`DataArray.str.replace`](../generated/xarray.DataArray.str.replace.md#xarray.DataArray.str.replace)(pat, repl[, n, case, ...]) | Replace occurrences of pattern/regex in the array with some string. | | [`DataArray.str.rfind`](../generated/xarray.DataArray.str.rfind.md#xarray.DataArray.str.rfind)(sub[, start, end]) | Return highest indexes in each strings in the array where the substring is fully contained between [start:end]. | | [`DataArray.str.rindex`](../generated/xarray.DataArray.str.rindex.md#xarray.DataArray.str.rindex)(sub[, start, end]) | Return highest indexes in each strings where the substring is fully contained between [start:end]. | | [`DataArray.str.rjust`](../generated/xarray.DataArray.str.rjust.md#xarray.DataArray.str.rjust)(width[, fillchar]) | Pad left side of each string in the array. | | [`DataArray.str.rpartition`](../generated/xarray.DataArray.str.rpartition.md#xarray.DataArray.str.rpartition)(dim[, sep]) | Split the strings in the DataArray at the last occurrence of separator sep. | | [`DataArray.str.rsplit`](../generated/xarray.DataArray.str.rsplit.md#xarray.DataArray.str.rsplit)(dim[, sep, maxsplit]) | Split strings in a DataArray around the given separator/delimiter sep. | | [`DataArray.str.rstrip`](../generated/xarray.DataArray.str.rstrip.md#xarray.DataArray.str.rstrip)([to_strip]) | Remove trailing characters. | | [`DataArray.str.slice`](../generated/xarray.DataArray.str.slice.md#xarray.DataArray.str.slice)([start, stop, step]) | Slice substrings from each string in the array. | | [`DataArray.str.slice_replace`](../generated/xarray.DataArray.str.slice_replace.md#xarray.DataArray.str.slice_replace)([start, stop, repl]) | Replace a positional slice of a string with another value. | | [`DataArray.str.split`](../generated/xarray.DataArray.str.split.md#xarray.DataArray.str.split)(dim[, sep, maxsplit]) | Split strings in a DataArray around the given separator/delimiter sep. | | [`DataArray.str.startswith`](../generated/xarray.DataArray.str.startswith.md#xarray.DataArray.str.startswith)(pat) | Test if the start of each string in the array matches a pattern. | | [`DataArray.str.strip`](../generated/xarray.DataArray.str.strip.md#xarray.DataArray.str.strip)([to_strip, side]) | Remove leading and trailing characters. | | [`DataArray.str.swapcase`](../generated/xarray.DataArray.str.swapcase.md#xarray.DataArray.str.swapcase)() | Convert strings in the array to be swapcased. | | [`DataArray.str.title`](../generated/xarray.DataArray.str.title.md#xarray.DataArray.str.title)() | Convert strings in the array to titlecase. | | [`DataArray.str.translate`](../generated/xarray.DataArray.str.translate.md#xarray.DataArray.str.translate)(table) | Map characters of each string through the given mapping table. | | [`DataArray.str.upper`](../generated/xarray.DataArray.str.upper.md#xarray.DataArray.str.upper)() | Convert strings in the array to uppercase. | | [`DataArray.str.wrap`](../generated/xarray.DataArray.str.wrap.md#xarray.DataArray.str.wrap)(width, \*\*kwargs) | Wrap long strings in the array in paragraphs with length less than width. | | [`DataArray.str.zfill`](../generated/xarray.DataArray.str.zfill.md#xarray.DataArray.str.zfill)(width) | Pad each string in the array by prepending '0' characters. | ## Datetimelike properties **Datetime properties**: | [`DataArray.dt.year`](../generated/xarray.DataArray.dt.year.md#xarray.DataArray.dt.year) | The year of the datetime | |------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------| | [`DataArray.dt.month`](../generated/xarray.DataArray.dt.month.md#xarray.DataArray.dt.month) | The month as January=1, December=12 | | [`DataArray.dt.day`](../generated/xarray.DataArray.dt.day.md#xarray.DataArray.dt.day) | The days of the datetime | | [`DataArray.dt.hour`](../generated/xarray.DataArray.dt.hour.md#xarray.DataArray.dt.hour) | The hours of the datetime | | [`DataArray.dt.minute`](../generated/xarray.DataArray.dt.minute.md#xarray.DataArray.dt.minute) | The minutes of the datetime | | [`DataArray.dt.second`](../generated/xarray.DataArray.dt.second.md#xarray.DataArray.dt.second) | The seconds of the datetime | | [`DataArray.dt.microsecond`](../generated/xarray.DataArray.dt.microsecond.md#xarray.DataArray.dt.microsecond) | The microseconds of the datetime | | [`DataArray.dt.nanosecond`](../generated/xarray.DataArray.dt.nanosecond.md#xarray.DataArray.dt.nanosecond) | The nanoseconds of the datetime | | [`DataArray.dt.day_of_week`](../generated/xarray.DataArray.dt.day_of_week.md#xarray.DataArray.dt.day_of_week) | The day of the week with Monday=0, Sunday=6 | | [`DataArray.dt.dayofweek`](../generated/xarray.DataArray.dt.dayofweek.md#xarray.DataArray.dt.dayofweek) | The day of the week with Monday=0, Sunday=6 | | [`DataArray.dt.weekday`](../generated/xarray.DataArray.dt.weekday.md#xarray.DataArray.dt.weekday) | The day of the week with Monday=0, Sunday=6 | | [`DataArray.dt.day_of_year`](../generated/xarray.DataArray.dt.day_of_year.md#xarray.DataArray.dt.day_of_year) | The ordinal day of the year | | [`DataArray.dt.dayofyear`](../generated/xarray.DataArray.dt.dayofyear.md#xarray.DataArray.dt.dayofyear) | The ordinal day of the year | | [`DataArray.dt.quarter`](../generated/xarray.DataArray.dt.quarter.md#xarray.DataArray.dt.quarter) | The quarter of the date | | [`DataArray.dt.days_in_month`](../generated/xarray.DataArray.dt.days_in_month.md#xarray.DataArray.dt.days_in_month) | The number of days in the month | | [`DataArray.dt.daysinmonth`](../generated/xarray.DataArray.dt.daysinmonth.md#xarray.DataArray.dt.daysinmonth) | The number of days in the month | | [`DataArray.dt.days_in_year`](../generated/xarray.DataArray.dt.days_in_year.md#xarray.DataArray.dt.days_in_year) | Each datetime as the year plus the fraction of the year elapsed. | | [`DataArray.dt.season`](../generated/xarray.DataArray.dt.season.md#xarray.DataArray.dt.season) | Season of the year | | [`DataArray.dt.time`](../generated/xarray.DataArray.dt.time.md#xarray.DataArray.dt.time) | Timestamps corresponding to datetimes | | [`DataArray.dt.date`](../generated/xarray.DataArray.dt.date.md#xarray.DataArray.dt.date) | Date corresponding to datetimes | | [`DataArray.dt.decimal_year`](../generated/xarray.DataArray.dt.decimal_year.md#xarray.DataArray.dt.decimal_year) | Convert the dates as a fractional year. | | [`DataArray.dt.calendar`](../generated/xarray.DataArray.dt.calendar.md#xarray.DataArray.dt.calendar) | The name of the calendar of the dates. | | [`DataArray.dt.is_month_start`](../generated/xarray.DataArray.dt.is_month_start.md#xarray.DataArray.dt.is_month_start) | Indicate whether the date is the first day of the month | | [`DataArray.dt.is_month_end`](../generated/xarray.DataArray.dt.is_month_end.md#xarray.DataArray.dt.is_month_end) | Indicate whether the date is the last day of the month | | [`DataArray.dt.is_quarter_end`](../generated/xarray.DataArray.dt.is_quarter_end.md#xarray.DataArray.dt.is_quarter_end) | Indicate whether the date is the last day of a quarter | | [`DataArray.dt.is_year_start`](../generated/xarray.DataArray.dt.is_year_start.md#xarray.DataArray.dt.is_year_start) | Indicate whether the date is the first day of a year | | [`DataArray.dt.is_leap_year`](../generated/xarray.DataArray.dt.is_leap_year.md#xarray.DataArray.dt.is_leap_year) | Indicate if the date belongs to a leap year | **Datetime methods**: | [`DataArray.dt.floor`](../generated/xarray.DataArray.dt.floor.md#xarray.DataArray.dt.floor)(freq) | Round timestamps downward to specified frequency resolution. | |-------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------| | [`DataArray.dt.ceil`](../generated/xarray.DataArray.dt.ceil.md#xarray.DataArray.dt.ceil)(freq) | Round timestamps upward to specified frequency resolution. | | [`DataArray.dt.isocalendar`](../generated/xarray.DataArray.dt.isocalendar.md#xarray.DataArray.dt.isocalendar)() | Dataset containing ISO year, week number, and weekday. | | [`DataArray.dt.round`](../generated/xarray.DataArray.dt.round.md#xarray.DataArray.dt.round)(freq) | Round timestamps to specified frequency resolution. | | [`DataArray.dt.strftime`](../generated/xarray.DataArray.dt.strftime.md#xarray.DataArray.dt.strftime)(date_format) | Return an array of formatted strings specified by date_format, which supports the same string format as the python standard library. | **Timedelta properties**: | [`DataArray.dt.days`](../generated/xarray.DataArray.dt.days.md#xarray.DataArray.dt.days) | Number of days for each element | |---------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------| | [`DataArray.dt.seconds`](../generated/xarray.DataArray.dt.seconds.md#xarray.DataArray.dt.seconds) | Number of seconds (>= 0 and less than 1 day) for each element | | [`DataArray.dt.microseconds`](../generated/xarray.DataArray.dt.microseconds.md#xarray.DataArray.dt.microseconds) | Number of microseconds (>= 0 and less than 1 second) for each element | | [`DataArray.dt.nanoseconds`](../generated/xarray.DataArray.dt.nanoseconds.md#xarray.DataArray.dt.nanoseconds) | Number of nanoseconds (>= 0 and less than 1 microsecond) for each element | | [`DataArray.dt.total_seconds`](../generated/xarray.DataArray.dt.total_seconds.md#xarray.DataArray.dt.total_seconds) | | **Timedelta methods**: | [`DataArray.dt.floor`](../generated/xarray.DataArray.dt.floor.md#xarray.DataArray.dt.floor)(freq) | Round timestamps downward to specified frequency resolution. | |-----------------------------------------------------------------------------------------------------|----------------------------------------------------------------| | [`DataArray.dt.ceil`](../generated/xarray.DataArray.dt.ceil.md#xarray.DataArray.dt.ceil)(freq) | Round timestamps upward to specified frequency resolution. | | [`DataArray.dt.round`](../generated/xarray.DataArray.dt.round.md#xarray.DataArray.dt.round)(freq) | Round timestamps to specified frequency resolution. | ## Reshaping and reorganizing | [`DataArray.transpose`](../generated/xarray.DataArray.transpose.md#xarray.DataArray.transpose)(\*dim[, ...]) | Return a new DataArray object with transposed dimensions. | |-----------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------| | [`DataArray.stack`](../generated/xarray.DataArray.stack.md#xarray.DataArray.stack)([dim, create_index, index_cls]) | Stack any number of existing dimensions into a single new dimension. | | [`DataArray.unstack`](../generated/xarray.DataArray.unstack.md#xarray.DataArray.unstack)([dim, fill_value, sparse]) | Unstack existing dimensions corresponding to MultiIndexes into multiple new dimensions. | | [`DataArray.to_unstacked_dataset`](../generated/xarray.DataArray.to_unstacked_dataset.md#xarray.DataArray.to_unstacked_dataset)(dim[, level]) | Unstack DataArray expanding to Dataset along a given level of a stacked coordinate. | | [`DataArray.shift`](../generated/xarray.DataArray.shift.md#xarray.DataArray.shift)([shifts, fill_value]) | Shift this DataArray by an offset along one or more dimensions. | | [`DataArray.roll`](../generated/xarray.DataArray.roll.md#xarray.DataArray.roll)([shifts, roll_coords]) | Roll this array by an offset along one or more dimensions. | | [`DataArray.pad`](../generated/xarray.DataArray.pad.md#xarray.DataArray.pad)([pad_width, mode, ...]) | Pad this array along one or more dimensions. | | [`DataArray.sortby`](../generated/xarray.DataArray.sortby.md#xarray.DataArray.sortby)(variables[, ascending]) | Sort object by labels or values (along an axis). | | [`DataArray.broadcast_like`](../generated/xarray.DataArray.broadcast_like.md#xarray.DataArray.broadcast_like)(other, \*[, exclude]) | Broadcast this DataArray against another Dataset or DataArray. | # dataset.html.md # Dataset | [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset)([data_vars, coords, attrs]) | A multi-dimensional, in memory, array database. | |------------------------------------------------------------------------------------------|---------------------------------------------------| ## Attributes | [`Dataset.dims`](../generated/xarray.Dataset.dims.md#xarray.Dataset.dims) | Mapping from dimension names to lengths. | |---------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------| | [`Dataset.sizes`](../generated/xarray.Dataset.sizes.md#xarray.Dataset.sizes) | Mapping from dimension names to lengths. | | [`Dataset.dtypes`](../generated/xarray.Dataset.dtypes.md#xarray.Dataset.dtypes) | Mapping from data variable names to dtypes. | | [`Dataset.data_vars`](../generated/xarray.Dataset.data_vars.md#xarray.Dataset.data_vars) | Dictionary of DataArray objects corresponding to data variables | | [`Dataset.coords`](../generated/xarray.Dataset.coords.md#xarray.Dataset.coords) | Mapping of [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) objects corresponding to coordinate variables. | | [`Dataset.attrs`](../generated/xarray.Dataset.attrs.md#xarray.Dataset.attrs) | Dictionary of global attributes on this dataset | | [`Dataset.encoding`](../generated/xarray.Dataset.encoding.md#xarray.Dataset.encoding) | Dictionary of global encoding attributes on this dataset | | [`Dataset.indexes`](../generated/xarray.Dataset.indexes.md#xarray.Dataset.indexes) | Mapping of pandas.Index objects used for label based indexing. | | [`Dataset.xindexes`](../generated/xarray.Dataset.xindexes.md#xarray.Dataset.xindexes) | Mapping of `Index` objects used for label based indexing. | | [`Dataset.chunks`](../generated/xarray.Dataset.chunks.md#xarray.Dataset.chunks) | Mapping from dimension names to block lengths for this dataset's data. | | [`Dataset.chunksizes`](../generated/xarray.Dataset.chunksizes.md#xarray.Dataset.chunksizes) | Mapping from dimension names to block lengths for this dataset's data. | | [`Dataset.nbytes`](../generated/xarray.Dataset.nbytes.md#xarray.Dataset.nbytes) | Total bytes consumed by the data arrays of all variables in this dataset. | ## Dictionary interface Datasets implement the mapping interface with keys given by variable names and values given by `DataArray` objects. | [`Dataset.__getitem__`](../generated/xarray.Dataset.__getitem__.md#xarray.Dataset.__getitem__)(key) | Access variables or coordinates of this dataset as a [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) or a subset of variables or a indexed dataset. | |------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [`Dataset.__setitem__`](../generated/xarray.Dataset.__setitem__.md#xarray.Dataset.__setitem__)(key, value) | Add an array to this dataset. | | [`Dataset.__delitem__`](../generated/xarray.Dataset.__delitem__.md#xarray.Dataset.__delitem__)(key) | Remove a variable from this dataset. | | [`Dataset.update`](../generated/xarray.Dataset.update.md#xarray.Dataset.update)(other) | Update this dataset's variables with those from another dataset. | | [`Dataset.get`](../generated/xarray.Dataset.get.md#xarray.Dataset.get)(k[,d]) | | | [`Dataset.items`](../generated/xarray.Dataset.items.md#xarray.Dataset.items)() | | | [`Dataset.keys`](../generated/xarray.Dataset.keys.md#xarray.Dataset.keys)() | | | [`Dataset.values`](../generated/xarray.Dataset.values.md#xarray.Dataset.values)() | | ## Dataset contents | [`Dataset.copy`](../generated/xarray.Dataset.copy.md#xarray.Dataset.copy)([deep, data]) | Returns a copy of this dataset. | |-------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------| | [`Dataset.assign`](../generated/xarray.Dataset.assign.md#xarray.Dataset.assign)([variables]) | Assign new data variables to a Dataset, returning a new object with all the original variables in addition to the new ones. | | [`Dataset.assign_coords`](../generated/xarray.Dataset.assign_coords.md#xarray.Dataset.assign_coords)([coords]) | Assign new coordinates to this object. | | [`Dataset.assign_attrs`](../generated/xarray.Dataset.assign_attrs.md#xarray.Dataset.assign_attrs)(\*args, \*\*kwargs) | Assign new attrs to this object. | | [`Dataset.pipe`](../generated/xarray.Dataset.pipe.md#xarray.Dataset.pipe)(func, \*args, \*\*kwargs) | Apply `func(self, *args, **kwargs)` | | [`Dataset.merge`](../generated/xarray.Dataset.merge.md#xarray.Dataset.merge)(other[, overwrite_vars, ...]) | Merge the arrays of two datasets into a single dataset. | | [`Dataset.rename`](../generated/xarray.Dataset.rename.md#xarray.Dataset.rename)([name_dict]) | Returns a new object with renamed variables, coordinates and dimensions. | | [`Dataset.rename_vars`](../generated/xarray.Dataset.rename_vars.md#xarray.Dataset.rename_vars)([name_dict]) | Returns a new object with renamed variables including coordinates | | [`Dataset.rename_dims`](../generated/xarray.Dataset.rename_dims.md#xarray.Dataset.rename_dims)([dims_dict]) | Returns a new object with renamed dimensions only. | | [`Dataset.swap_dims`](../generated/xarray.Dataset.swap_dims.md#xarray.Dataset.swap_dims)([dims_dict]) | Returns a new object with swapped dimensions. | | [`Dataset.expand_dims`](../generated/xarray.Dataset.expand_dims.md#xarray.Dataset.expand_dims)([dim, axis, ...]) | Return a new object with an additional axis (or axes) inserted at the corresponding position in the array shape. | | [`Dataset.drop_vars`](../generated/xarray.Dataset.drop_vars.md#xarray.Dataset.drop_vars)(names, \*[, errors]) | Drop variables from this dataset. | | [`Dataset.drop_indexes`](../generated/xarray.Dataset.drop_indexes.md#xarray.Dataset.drop_indexes)(coord_names, \*[, errors]) | Drop the indexes assigned to the given coordinates. | | [`Dataset.drop_duplicates`](../generated/xarray.Dataset.drop_duplicates.md#xarray.Dataset.drop_duplicates)(dim, \*[, keep]) | Returns a new Dataset with duplicate dimension values removed. | | [`Dataset.drop_dims`](../generated/xarray.Dataset.drop_dims.md#xarray.Dataset.drop_dims)(drop_dims, \*[, errors]) | Drop dimensions and associated variables from this dataset. | | [`Dataset.drop_encoding`](../generated/xarray.Dataset.drop_encoding.md#xarray.Dataset.drop_encoding)() | Return a new Dataset without encoding on the dataset or any of its variables/coords. | | [`Dataset.drop_attrs`](../generated/xarray.Dataset.drop_attrs.md#xarray.Dataset.drop_attrs)(\*[, deep]) | Removes all attributes from the Dataset and its variables. | | [`Dataset.set_coords`](../generated/xarray.Dataset.set_coords.md#xarray.Dataset.set_coords)(names) | Given names of one or more variables, set them as coordinates | | [`Dataset.reset_coords`](../generated/xarray.Dataset.reset_coords.md#xarray.Dataset.reset_coords)([names, drop]) | Given names of coordinates, reset them to become variables | | [`Dataset.convert_calendar`](../generated/xarray.Dataset.convert_calendar.md#xarray.Dataset.convert_calendar)(calendar[, dim, ...]) | Convert the Dataset to another calendar. | | [`Dataset.interp_calendar`](../generated/xarray.Dataset.interp_calendar.md#xarray.Dataset.interp_calendar)(target[, dim]) | Interpolates the Dataset to another calendar based on decimal year measure. | | [`Dataset.get_index`](../generated/xarray.Dataset.get_index.md#xarray.Dataset.get_index)(key) | Get an index for a dimension, with fall-back to a default RangeIndex | ## Comparisons | [`Dataset.equals`](../generated/xarray.Dataset.equals.md#xarray.Dataset.equals)(other) | Two Datasets are equal if they have matching variables and coordinates, all of which are equal. | |----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------| | [`Dataset.identical`](../generated/xarray.Dataset.identical.md#xarray.Dataset.identical)(other) | Like equals, but also checks all dataset attributes, the attributes on all variables and coordinates, and indexes. | | [`Dataset.broadcast_equals`](../generated/xarray.Dataset.broadcast_equals.md#xarray.Dataset.broadcast_equals)(other) | Two Datasets are broadcast equal if they are equal after broadcasting all variables against each other. | ## Indexing | [`Dataset.loc`](../generated/xarray.Dataset.loc.md#xarray.Dataset.loc) | Attribute for location based indexing. | |----------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [`Dataset.isel`](../generated/xarray.Dataset.isel.md#xarray.Dataset.isel)([indexers, drop, missing_dims]) | Returns a new dataset with each array indexed along the specified dimension(s). | | [`Dataset.sel`](../generated/xarray.Dataset.sel.md#xarray.Dataset.sel)([indexers, method, tolerance, drop]) | Returns a new dataset with each array indexed by tick labels along the specified dimension(s). | | [`Dataset.drop_sel`](../generated/xarray.Dataset.drop_sel.md#xarray.Dataset.drop_sel)([labels, errors]) | Drop index labels from this dataset. | | [`Dataset.drop_isel`](../generated/xarray.Dataset.drop_isel.md#xarray.Dataset.drop_isel)([indexers]) | Drop index positions from this Dataset. | | [`Dataset.head`](../generated/xarray.Dataset.head.md#xarray.Dataset.head)([indexers]) | Returns a new dataset with the first n values of each array for the specified dimension(s). | | [`Dataset.tail`](../generated/xarray.Dataset.tail.md#xarray.Dataset.tail)([indexers]) | Returns a new dataset with the last n values of each array for the specified dimension(s). | | [`Dataset.thin`](../generated/xarray.Dataset.thin.md#xarray.Dataset.thin)([indexers]) | Returns a new dataset with each array indexed along every n-th value for the specified dimension(s) | | [`Dataset.squeeze`](../generated/xarray.Dataset.squeeze.md#xarray.Dataset.squeeze)([dim, drop, axis]) | Return a new object with squeezed data. | | [`Dataset.interp`](../generated/xarray.Dataset.interp.md#xarray.Dataset.interp)([coords, method, ...]) | Interpolate a Dataset onto new coordinates. | | [`Dataset.interp_like`](../generated/xarray.Dataset.interp_like.md#xarray.Dataset.interp_like)(other[, method, ...]) | Interpolate this object onto the coordinates of another object. | | [`Dataset.reindex`](../generated/xarray.Dataset.reindex.md#xarray.Dataset.reindex)([indexers, method, ...]) | Conform this object onto a new set of indexes, filling in missing values with `fill_value`. | | [`Dataset.reindex_like`](../generated/xarray.Dataset.reindex_like.md#xarray.Dataset.reindex_like)(other[, method, ...]) | Conform this object onto the indexes of another object, for indexes which the objects share. | | [`Dataset.set_index`](../generated/xarray.Dataset.set_index.md#xarray.Dataset.set_index)([indexes, append]) | Set Dataset (multi-)indexes using one or more existing coordinates or variables. | | [`Dataset.reset_index`](../generated/xarray.Dataset.reset_index.md#xarray.Dataset.reset_index)(dims_or_levels, \*[, drop]) | Reset the specified index(es) or multi-index level(s). | | [`Dataset.set_xindex`](../generated/xarray.Dataset.set_xindex.md#xarray.Dataset.set_xindex)(coord_names[, index_cls]) | Set a new, Xarray-compatible index from one or more existing coordinate(s). | | [`Dataset.reorder_levels`](../generated/xarray.Dataset.reorder_levels.md#xarray.Dataset.reorder_levels)([dim_order]) | Rearrange index levels using input order. | | [`Dataset.query`](../generated/xarray.Dataset.query.md#xarray.Dataset.query)([queries, parser, engine, ...]) | Return a new dataset with each array indexed along the specified dimension(s), where the indexers are given as strings containing Python expressions to be evaluated against the data variables in the dataset. | ## Missing value handling | [`Dataset.isnull`](../generated/xarray.Dataset.isnull.md#xarray.Dataset.isnull)([keep_attrs]) | Test each value in the array for whether it is a missing value. | |------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| | [`Dataset.notnull`](../generated/xarray.Dataset.notnull.md#xarray.Dataset.notnull)([keep_attrs]) | Test each value in the array for whether it is not a missing value. | | [`Dataset.combine_first`](../generated/xarray.Dataset.combine_first.md#xarray.Dataset.combine_first)(other) | Combine two Datasets, default to data_vars of self. | | [`Dataset.count`](../generated/xarray.Dataset.count.md#xarray.Dataset.count)([dim, keep_attrs]) | Reduce this Dataset's data by applying `count` along some dimension(s). | | [`Dataset.dropna`](../generated/xarray.Dataset.dropna.md#xarray.Dataset.dropna)(dim, \*[, how, thresh, subset]) | Returns a new dataset with dropped labels for missing values along the provided dimension. | | [`Dataset.fillna`](../generated/xarray.Dataset.fillna.md#xarray.Dataset.fillna)(value) | Fill missing values in this object. | | [`Dataset.ffill`](../generated/xarray.Dataset.ffill.md#xarray.Dataset.ffill)(dim[, limit]) | Fill NaN values by propagating values forward | | [`Dataset.bfill`](../generated/xarray.Dataset.bfill.md#xarray.Dataset.bfill)(dim[, limit]) | Fill NaN values by propagating values backward | | [`Dataset.interpolate_na`](../generated/xarray.Dataset.interpolate_na.md#xarray.Dataset.interpolate_na)([dim, method, limit, ...]) | Fill in NaNs by interpolating according to different methods. | | [`Dataset.where`](../generated/xarray.Dataset.where.md#xarray.Dataset.where)(cond[, other, drop]) | Filter elements from this object according to a condition. | | [`Dataset.isin`](../generated/xarray.Dataset.isin.md#xarray.Dataset.isin)(test_elements) | Tests each value in the array for whether it is in test elements. | ## Computation | [`Dataset.map`](../generated/xarray.Dataset.map.md#xarray.Dataset.map)(func[, keep_attrs, args]) | Apply a function to each data variable in this dataset | |--------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| | [`Dataset.reduce`](../generated/xarray.Dataset.reduce.md#xarray.Dataset.reduce)(func[, dim, keep_attrs, ...]) | Reduce this dataset by applying func along some dimension(s). | | [`Dataset.groupby`](../generated/xarray.Dataset.groupby.md#xarray.Dataset.groupby)([group, squeeze, ...]) | Returns a DatasetGroupBy object for performing grouped operations. | | [`Dataset.groupby_bins`](../generated/xarray.Dataset.groupby_bins.md#xarray.Dataset.groupby_bins)(group, bins[, right, ...]) | Returns a DatasetGroupBy object for performing grouped operations. | | [`Dataset.rolling`](../generated/xarray.Dataset.rolling.md#xarray.Dataset.rolling)([dim, min_periods, center]) | Rolling window object for Datasets. | | [`Dataset.rolling_exp`](../generated/xarray.Dataset.rolling_exp.md#xarray.Dataset.rolling_exp)([window, window_type]) | Exponentially-weighted moving window. | | [`Dataset.cumulative`](../generated/xarray.Dataset.cumulative.md#xarray.Dataset.cumulative)(dim[, min_periods]) | Accumulating object for Datasets | | [`Dataset.weighted`](../generated/xarray.Dataset.weighted.md#xarray.Dataset.weighted)(weights) | Weighted Dataset operations. | | [`Dataset.coarsen`](../generated/xarray.Dataset.coarsen.md#xarray.Dataset.coarsen)([dim, boundary, side, ...]) | Coarsen object for Datasets. | | [`Dataset.resample`](../generated/xarray.Dataset.resample.md#xarray.Dataset.resample)([indexer, skipna, closed, ...]) | Returns a Resample object for performing resampling operations. | | [`Dataset.diff`](../generated/xarray.Dataset.diff.md#xarray.Dataset.diff)(dim[, n, label]) | Calculate the n-th order discrete difference along given axis. | | [`Dataset.quantile`](../generated/xarray.Dataset.quantile.md#xarray.Dataset.quantile)(q[, dim, method, ...]) | Compute the qth quantile of the data along the specified dimension. | | [`Dataset.differentiate`](../generated/xarray.Dataset.differentiate.md#xarray.Dataset.differentiate)(coord[, edge_order, ...]) | Differentiate with the second order accurate central differences. | | [`Dataset.integrate`](../generated/xarray.Dataset.integrate.md#xarray.Dataset.integrate)(coord[, datetime_unit]) | Integrate along the given coordinate using the trapezoidal rule. | | [`Dataset.map_blocks`](../generated/xarray.Dataset.map_blocks.md#xarray.Dataset.map_blocks)(func[, args, kwargs, ...]) | Apply a function to each block of this Dataset. | | [`Dataset.polyfit`](../generated/xarray.Dataset.polyfit.md#xarray.Dataset.polyfit)(dim, deg[, skipna, rcond, ...]) | Least squares polynomial fit. | | [`Dataset.curvefit`](../generated/xarray.Dataset.curvefit.md#xarray.Dataset.curvefit)(coords, func[, ...]) | Curve fitting optimization for arbitrary functions. | | [`Dataset.eval`](../generated/xarray.Dataset.eval.md#xarray.Dataset.eval)(statement, \*[, parser]) | Calculate an expression supplied as a string in the context of the dataset. | ## Aggregation | [`Dataset.all`](../generated/xarray.Dataset.all.md#xarray.Dataset.all)([dim, keep_attrs]) | Reduce this Dataset's data by applying `all` along some dimension(s). | |-----------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------| | [`Dataset.any`](../generated/xarray.Dataset.any.md#xarray.Dataset.any)([dim, keep_attrs]) | Reduce this Dataset's data by applying `any` along some dimension(s). | | [`Dataset.argmax`](../generated/xarray.Dataset.argmax.md#xarray.Dataset.argmax)([dim]) | Indices of the maxima of the member variables. | | [`Dataset.argmin`](../generated/xarray.Dataset.argmin.md#xarray.Dataset.argmin)([dim]) | Indices of the minima of the member variables. | | [`Dataset.count`](../generated/xarray.Dataset.count.md#xarray.Dataset.count)([dim, keep_attrs]) | Reduce this Dataset's data by applying `count` along some dimension(s). | | [`Dataset.idxmax`](../generated/xarray.Dataset.idxmax.md#xarray.Dataset.idxmax)([dim, skipna, fill_value, ...]) | Return the coordinate label of the maximum value along a dimension. | | [`Dataset.idxmin`](../generated/xarray.Dataset.idxmin.md#xarray.Dataset.idxmin)([dim, skipna, fill_value, ...]) | Return the coordinate label of the minimum value along a dimension. | | [`Dataset.max`](../generated/xarray.Dataset.max.md#xarray.Dataset.max)([dim, skipna, keep_attrs]) | Reduce this Dataset's data by applying `max` along some dimension(s). | | [`Dataset.min`](../generated/xarray.Dataset.min.md#xarray.Dataset.min)([dim, skipna, keep_attrs]) | Reduce this Dataset's data by applying `min` along some dimension(s). | | [`Dataset.mean`](../generated/xarray.Dataset.mean.md#xarray.Dataset.mean)([dim, skipna, keep_attrs]) | Reduce this Dataset's data by applying `mean` along some dimension(s). | | [`Dataset.median`](../generated/xarray.Dataset.median.md#xarray.Dataset.median)([dim, skipna, keep_attrs]) | Reduce this Dataset's data by applying `median` along some dimension(s). | | [`Dataset.prod`](../generated/xarray.Dataset.prod.md#xarray.Dataset.prod)([dim, skipna, min_count, ...]) | Reduce this Dataset's data by applying `prod` along some dimension(s). | | [`Dataset.sum`](../generated/xarray.Dataset.sum.md#xarray.Dataset.sum)([dim, skipna, min_count, keep_attrs]) | Reduce this Dataset's data by applying `sum` along some dimension(s). | | [`Dataset.std`](../generated/xarray.Dataset.std.md#xarray.Dataset.std)([dim, skipna, ddof, keep_attrs]) | Reduce this Dataset's data by applying `std` along some dimension(s). | | [`Dataset.var`](../generated/xarray.Dataset.var.md#xarray.Dataset.var)([dim, skipna, ddof, keep_attrs]) | Reduce this Dataset's data by applying `var` along some dimension(s). | | [`Dataset.cumsum`](../generated/xarray.Dataset.cumsum.md#xarray.Dataset.cumsum)([dim, skipna, keep_attrs]) | Reduce this Dataset's data by applying `cumsum` along some dimension(s). | | [`Dataset.cumprod`](../generated/xarray.Dataset.cumprod.md#xarray.Dataset.cumprod)([dim, skipna, keep_attrs]) | Reduce this Dataset's data by applying `cumprod` along some dimension(s). | ## ndarray methods | [`Dataset.argsort`](../generated/xarray.Dataset.argsort.md#xarray.Dataset.argsort)([axis, kind, order, stable]) | Returns the indices that would sort this array. | |-------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------| | [`Dataset.astype`](../generated/xarray.Dataset.astype.md#xarray.Dataset.astype)(dtype, \*[, order, casting, ...]) | Copy of the xarray object, with data cast to a specified type. | | [`Dataset.clip`](../generated/xarray.Dataset.clip.md#xarray.Dataset.clip)([min, max, keep_attrs]) | Return an array whose values are limited to `[min, max]`. | | [`Dataset.conj`](../generated/xarray.Dataset.conj.md#xarray.Dataset.conj)() | Complex-conjugate all elements. | | [`Dataset.conjugate`](../generated/xarray.Dataset.conjugate.md#xarray.Dataset.conjugate)(\*args, \*\*kwargs) | a.conj() | | [`Dataset.imag`](../generated/xarray.Dataset.imag.md#xarray.Dataset.imag) | The imaginary part of each data variable. | | [`Dataset.round`](../generated/xarray.Dataset.round.md#xarray.Dataset.round)(\*args, \*\*kwargs) | | | [`Dataset.real`](../generated/xarray.Dataset.real.md#xarray.Dataset.real) | The real part of each data variable. | | [`Dataset.rank`](../generated/xarray.Dataset.rank.md#xarray.Dataset.rank)(dim, \*[, pct, keep_attrs]) | Ranks the data. | ## Reshaping and reorganizing | [`Dataset.transpose`](../generated/xarray.Dataset.transpose.md#xarray.Dataset.transpose)(\*dim[, missing_dims]) | Return a new Dataset object with all array dimensions transposed. | |-------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------| | [`Dataset.stack`](../generated/xarray.Dataset.stack.md#xarray.Dataset.stack)([dim, create_index, index_cls]) | Stack any number of existing dimensions into a single new dimension. | | [`Dataset.unstack`](../generated/xarray.Dataset.unstack.md#xarray.Dataset.unstack)([dim, fill_value, sparse]) | Unstack existing dimensions corresponding to MultiIndexes into multiple new dimensions. | | [`Dataset.to_stacked_array`](../generated/xarray.Dataset.to_stacked_array.md#xarray.Dataset.to_stacked_array)(new_dim, sample_dims) | Combine variables of differing dimensionality into a DataArray without broadcasting. | | [`Dataset.shift`](../generated/xarray.Dataset.shift.md#xarray.Dataset.shift)([shifts, fill_value]) | Shift this dataset by an offset along one or more dimensions. | | [`Dataset.roll`](../generated/xarray.Dataset.roll.md#xarray.Dataset.roll)([shifts, roll_coords]) | Roll this dataset by an offset along one or more dimensions. | | [`Dataset.pad`](../generated/xarray.Dataset.pad.md#xarray.Dataset.pad)([pad_width, mode, stat_length, ...]) | Pad this dataset along one or more dimensions. | | [`Dataset.sortby`](../generated/xarray.Dataset.sortby.md#xarray.Dataset.sortby)(variables[, ascending]) | Sort object by labels or values (along an axis). | | [`Dataset.broadcast_like`](../generated/xarray.Dataset.broadcast_like.md#xarray.Dataset.broadcast_like)(other[, exclude]) | Broadcast this DataArray against another Dataset or DataArray. | # datatree.html.md # DataTree ## Creating a DataTree Methods of creating a `DataTree`. | [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree)([dataset, children, name]) | A tree-like hierarchical collection of xarray objects. | |---------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------| | [`DataTree.from_dict`](../generated/xarray.DataTree.from_dict.md#xarray.DataTree.from_dict)([data, coords, name, nested]) | Create a datatree from a dictionary of data objects, organised by paths into the tree. | ## Tree Attributes Attributes relating to the recursive tree-like structure of a `DataTree`. | [`DataTree.parent`](../generated/xarray.DataTree.parent.md#xarray.DataTree.parent) | Parent of this node. | |---------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------| | [`DataTree.children`](../generated/xarray.DataTree.children.md#xarray.DataTree.children) | Child nodes of this node, stored under a mapping via their names. | | [`DataTree.name`](../generated/xarray.DataTree.name.md#xarray.DataTree.name) | The name of this node. | | [`DataTree.path`](../generated/xarray.DataTree.path.md#xarray.DataTree.path) | Return the file-like path from the root to this node. | | [`DataTree.root`](../generated/xarray.DataTree.root.md#xarray.DataTree.root) | Root node of the tree | | [`DataTree.is_root`](../generated/xarray.DataTree.is_root.md#xarray.DataTree.is_root) | Whether this node is the tree root. | | [`DataTree.is_leaf`](../generated/xarray.DataTree.is_leaf.md#xarray.DataTree.is_leaf) | Whether this node is a leaf node. | | [`DataTree.leaves`](../generated/xarray.DataTree.leaves.md#xarray.DataTree.leaves) | All leaf nodes. | | [`DataTree.level`](../generated/xarray.DataTree.level.md#xarray.DataTree.level) | Level of this node. | | [`DataTree.depth`](../generated/xarray.DataTree.depth.md#xarray.DataTree.depth) | Maximum level of this tree. | | [`DataTree.width`](../generated/xarray.DataTree.width.md#xarray.DataTree.width) | Number of nodes at this level in the tree. | | [`DataTree.subtree`](../generated/xarray.DataTree.subtree.md#xarray.DataTree.subtree) | Iterate over all nodes in this tree, including both self and all descendants. | | [`DataTree.subtree_with_keys`](../generated/xarray.DataTree.subtree_with_keys.md#xarray.DataTree.subtree_with_keys) | Iterate over relative paths and node pairs for all nodes in this tree. | | [`DataTree.descendants`](../generated/xarray.DataTree.descendants.md#xarray.DataTree.descendants) | Child nodes and all their child nodes. | | [`DataTree.siblings`](../generated/xarray.DataTree.siblings.md#xarray.DataTree.siblings) | Nodes with the same parent as this node. | | [`DataTree.lineage`](../generated/xarray.DataTree.lineage.md#xarray.DataTree.lineage) | All parent nodes and their parent nodes, starting with the closest. | | [`DataTree.parents`](../generated/xarray.DataTree.parents.md#xarray.DataTree.parents) | All parent nodes and their parent nodes, starting with the closest. | | [`DataTree.ancestors`](../generated/xarray.DataTree.ancestors.md#xarray.DataTree.ancestors) | All parent nodes and their parent nodes, starting with the most distant. | | [`DataTree.groups`](../generated/xarray.DataTree.groups.md#xarray.DataTree.groups) | Return all groups in the tree, given as a tuple of path-like strings. | | [`DataTree.xindexes`](../generated/xarray.DataTree.xindexes.md#xarray.DataTree.xindexes) | Mapping of xarray Index objects used for label based indexing. | ## Data Contents Interface to the data objects (optionally) stored inside a single `DataTree` node. This interface echoes that of `xarray.Dataset`. | [`DataTree.dims`](../generated/xarray.DataTree.dims.md#xarray.DataTree.dims) | Mapping from dimension names to lengths. | |-----------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------| | [`DataTree.sizes`](../generated/xarray.DataTree.sizes.md#xarray.DataTree.sizes) | Mapping from dimension names to lengths. | | [`DataTree.data_vars`](../generated/xarray.DataTree.data_vars.md#xarray.DataTree.data_vars) | Dictionary of DataArray objects corresponding to data variables | | [`DataTree.ds`](../generated/xarray.DataTree.ds.md#xarray.DataTree.ds) | An immutable Dataset-like view onto the data in this node. | | [`DataTree.coords`](../generated/xarray.DataTree.coords.md#xarray.DataTree.coords) | Dictionary of xarray.DataArray objects corresponding to coordinate variables | | [`DataTree.attrs`](../generated/xarray.DataTree.attrs.md#xarray.DataTree.attrs) | Dictionary of global attributes on this node object. | | [`DataTree.encoding`](../generated/xarray.DataTree.encoding.md#xarray.DataTree.encoding) | Dictionary of global encoding attributes on this node object. | | [`DataTree.indexes`](../generated/xarray.DataTree.indexes.md#xarray.DataTree.indexes) | Mapping of pandas.Index objects used for label based indexing. | | [`DataTree.nbytes`](../generated/xarray.DataTree.nbytes.md#xarray.DataTree.nbytes) | | | [`DataTree.dataset`](../generated/xarray.DataTree.dataset.md#xarray.DataTree.dataset) | An immutable Dataset-like view onto the data in this node. | | [`DataTree.to_dataset`](../generated/xarray.DataTree.to_dataset.md#xarray.DataTree.to_dataset)([inherit]) | Return the data in this node as a new xarray.Dataset object. | | [`DataTree.has_data`](../generated/xarray.DataTree.has_data.md#xarray.DataTree.has_data) | Whether or not there are any variables in this node. | | [`DataTree.has_attrs`](../generated/xarray.DataTree.has_attrs.md#xarray.DataTree.has_attrs) | Whether or not there are any metadata attributes in this node. | | [`DataTree.is_empty`](../generated/xarray.DataTree.is_empty.md#xarray.DataTree.is_empty) | False if node contains any data or attrs. | | [`DataTree.is_hollow`](../generated/xarray.DataTree.is_hollow.md#xarray.DataTree.is_hollow) | True if only leaf nodes contain data. | | [`DataTree.chunksizes`](../generated/xarray.DataTree.chunksizes.md#xarray.DataTree.chunksizes) | Mapping from group paths to a mapping of chunksizes. | ## Dictionary Interface `DataTree` objects also have a dict-like interface mapping keys to either `xarray.DataArray`s or to child `DataTree` nodes. | [`DataTree.__getitem__`](../generated/xarray.DataTree.__getitem__.md#xarray.DataTree.__getitem__)(key) | Access child nodes, variables, or coordinates stored anywhere in this tree. | |---------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------| | [`DataTree.__setitem__`](../generated/xarray.DataTree.__setitem__.md#xarray.DataTree.__setitem__)(key, value) | Add either a child node or an array to the tree, at any position. | | [`DataTree.__delitem__`](../generated/xarray.DataTree.__delitem__.md#xarray.DataTree.__delitem__)(key) | Remove a variable or child node from this datatree node. | | [`DataTree.update`](../generated/xarray.DataTree.update.md#xarray.DataTree.update)(other) | Update this node's children and / or variables. | | [`DataTree.get`](../generated/xarray.DataTree.get.md#xarray.DataTree.get)(key[, default]) | Access child nodes, variables, or coordinates stored in this node. | | [`DataTree.items`](../generated/xarray.DataTree.items.md#xarray.DataTree.items)() | | | [`DataTree.keys`](../generated/xarray.DataTree.keys.md#xarray.DataTree.keys)() | | | [`DataTree.values`](../generated/xarray.DataTree.values.md#xarray.DataTree.values)() | | ## Tree Manipulation For manipulating, traversing, navigating, or mapping over the tree structure. | [`DataTree.orphan`](../generated/xarray.DataTree.orphan.md#xarray.DataTree.orphan)() | Detach this node from its parent. | |---------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------| | [`DataTree.same_tree`](../generated/xarray.DataTree.same_tree.md#xarray.DataTree.same_tree)(other) | True if other node is in the same tree as this node. | | [`DataTree.relative_to`](../generated/xarray.DataTree.relative_to.md#xarray.DataTree.relative_to)(other) | Compute the relative path from this node to node other. | | [`DataTree.iter_lineage`](../generated/xarray.DataTree.iter_lineage.md#xarray.DataTree.iter_lineage)() | Iterate up the tree, starting from the current node. | | [`DataTree.find_common_ancestor`](../generated/xarray.DataTree.find_common_ancestor.md#xarray.DataTree.find_common_ancestor)(other) | Find the first common ancestor of two nodes in the same tree. | | [`DataTree.map_over_datasets`](../generated/xarray.DataTree.map_over_datasets.md#xarray.DataTree.map_over_datasets)(func, \*args[, kwargs]) | Apply a function to every dataset in this subtree, returning a new tree which stores the results. | | [`DataTree.pipe`](../generated/xarray.DataTree.pipe.md#xarray.DataTree.pipe)(func, \*args, \*\*kwargs) | Apply `func(self, *args, **kwargs)` | | [`DataTree.match`](../generated/xarray.DataTree.match.md#xarray.DataTree.match)(pattern) | Return nodes with paths matching pattern. | | [`DataTree.filter`](../generated/xarray.DataTree.filter.md#xarray.DataTree.filter)(filterfunc) | Filter nodes according to a specified condition. | | [`DataTree.filter_like`](../generated/xarray.DataTree.filter_like.md#xarray.DataTree.filter_like)(other) | Filter a datatree like another datatree. | ## Pathlib-like Interface `DataTree` objects deliberately echo some of the API of [`pathlib.PurePath`](https://docs.python.org/3/library/pathlib.html#pathlib.PurePath). | [`DataTree.name`](../generated/xarray.DataTree.name.md#xarray.DataTree.name) | The name of this node. | |----------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------| | [`DataTree.parent`](../generated/xarray.DataTree.parent.md#xarray.DataTree.parent) | Parent of this node. | | [`DataTree.parents`](../generated/xarray.DataTree.parents.md#xarray.DataTree.parents) | All parent nodes and their parent nodes, starting with the closest. | | [`DataTree.relative_to`](../generated/xarray.DataTree.relative_to.md#xarray.DataTree.relative_to)(other) | Compute the relative path from this node to node other. | ## DataTree Contents Manipulate the contents of all nodes in a `DataTree` simultaneously. | [`DataTree.copy`](../generated/xarray.DataTree.copy.md#xarray.DataTree.copy)(\*[, inherit, deep]) | Returns a copy of this subtree. | |-----------------------------------------------------------------------------------------------------|-----------------------------------| ## DataTree Node Contents Manipulate the contents of a single `DataTree` node. | [`DataTree.assign`](../generated/xarray.DataTree.assign.md#xarray.DataTree.assign)([items]) | Assign new data variables or child nodes to a DataTree, returning a new object with all the original items in addition to the new ones. | |---------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------| | [`DataTree.drop_nodes`](../generated/xarray.DataTree.drop_nodes.md#xarray.DataTree.drop_nodes)(names, \*[, errors]) | Drop child nodes from this node. | ## DataTree Operations Apply operations over multiple `DataTree` objects. | [`map_over_datasets`](../generated/xarray.map_over_datasets.md#xarray.map_over_datasets)(func, \*args[, kwargs]) | Applies a function to every dataset in one or more DataTree objects with the same structure (ie.., that are isomorphic), returning new trees which store the results. | |--------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [`group_subtrees`](../generated/xarray.group_subtrees.md#xarray.group_subtrees)(\*trees) | Iterate over subtrees grouped by relative paths in breadth-first order. | ## Comparisons Compare one `DataTree` object to another. | [`DataTree.isomorphic`](../generated/xarray.DataTree.isomorphic.md#xarray.DataTree.isomorphic)(other) | Two DataTrees are considered isomorphic if the set of paths to their descendent nodes are the same. | |---------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [`DataTree.equals`](../generated/xarray.DataTree.equals.md#xarray.DataTree.equals)(other) | Two DataTrees are equal if they have isomorphic node structures, with matching node names, and if they have matching variables and coordinates, all of which are equal. | | [`DataTree.identical`](../generated/xarray.DataTree.identical.md#xarray.DataTree.identical)(other) | Like equals, but also checks attributes on all datasets, variables and coordinates, and requires that any inherited coordinates at the tree root are also inherited on the other tree. | ## Indexing Index into all nodes in the subtree simultaneously. | [`DataTree.isel`](../generated/xarray.DataTree.isel.md#xarray.DataTree.isel)([indexers, drop, missing_dims]) | Returns a new data tree with each array indexed along the specified dimension(s). | |----------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------| | [`DataTree.sel`](../generated/xarray.DataTree.sel.md#xarray.DataTree.sel)([indexers, method, tolerance, drop]) | Returns a new data tree with each array indexed by tick labels along the specified dimension(s). | ## Aggregation Aggregate data in all nodes in the subtree simultaneously. | [`DataTree.all`](../generated/xarray.DataTree.all.md#xarray.DataTree.all)([dim, keep_attrs]) | Reduce this DataTree's data by applying `all` along some dimension(s). | |------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------| | [`DataTree.any`](../generated/xarray.DataTree.any.md#xarray.DataTree.any)([dim, keep_attrs]) | Reduce this DataTree's data by applying `any` along some dimension(s). | | [`DataTree.max`](../generated/xarray.DataTree.max.md#xarray.DataTree.max)([dim, skipna, keep_attrs]) | Reduce this DataTree's data by applying `max` along some dimension(s). | | [`DataTree.min`](../generated/xarray.DataTree.min.md#xarray.DataTree.min)([dim, skipna, keep_attrs]) | Reduce this DataTree's data by applying `min` along some dimension(s). | | [`DataTree.mean`](../generated/xarray.DataTree.mean.md#xarray.DataTree.mean)([dim, skipna, keep_attrs]) | Reduce this DataTree's data by applying `mean` along some dimension(s). | | [`DataTree.median`](../generated/xarray.DataTree.median.md#xarray.DataTree.median)([dim, skipna, keep_attrs]) | Reduce this DataTree's data by applying `median` along some dimension(s). | | [`DataTree.prod`](../generated/xarray.DataTree.prod.md#xarray.DataTree.prod)([dim, skipna, min_count, ...]) | Reduce this DataTree's data by applying `prod` along some dimension(s). | | [`DataTree.sum`](../generated/xarray.DataTree.sum.md#xarray.DataTree.sum)([dim, skipna, min_count, ...]) | Reduce this DataTree's data by applying `sum` along some dimension(s). | | [`DataTree.std`](../generated/xarray.DataTree.std.md#xarray.DataTree.std)([dim, skipna, ddof, keep_attrs]) | Reduce this DataTree's data by applying `std` along some dimension(s). | | [`DataTree.var`](../generated/xarray.DataTree.var.md#xarray.DataTree.var)([dim, skipna, ddof, keep_attrs]) | Reduce this DataTree's data by applying `var` along some dimension(s). | | [`DataTree.cumsum`](../generated/xarray.DataTree.cumsum.md#xarray.DataTree.cumsum)([dim, skipna, keep_attrs]) | Reduce this DataTree's data by applying `cumsum` along some dimension(s). | | [`DataTree.cumprod`](../generated/xarray.DataTree.cumprod.md#xarray.DataTree.cumprod)([dim, skipna, keep_attrs]) | Reduce this DataTree's data by applying `cumprod` along some dimension(s). | ## ndarray methods Methods copied from [`numpy.ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) objects, here applying to the data in all nodes in the subtree. | [`DataTree.argsort`](../generated/xarray.DataTree.argsort.md#xarray.DataTree.argsort)([axis, kind, order, stable]) | Returns the indices that would sort this array. | |----------------------------------------------------------------------------------------------------------------------|---------------------------------------------------| | [`DataTree.conj`](../generated/xarray.DataTree.conj.md#xarray.DataTree.conj)() | Complex-conjugate all elements. | | [`DataTree.conjugate`](../generated/xarray.DataTree.conjugate.md#xarray.DataTree.conjugate)(\*args, \*\*kwargs) | a.conj() | | [`DataTree.round`](../generated/xarray.DataTree.round.md#xarray.DataTree.round)(\*args, \*\*kwargs) | | # deprecated.html.md # Deprecated / Pending Deprecation | [`Dataset.drop`](../generated/xarray.Dataset.drop.md#xarray.Dataset.drop)([labels, dim, errors]) | Backward compatible method based on drop_vars and drop_sel | |-------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------| | [`DataArray.drop`](../generated/xarray.DataArray.drop.md#xarray.DataArray.drop)([labels, dim, errors]) | Backward compatible method based on drop_vars and drop_sel | | [`Dataset.apply`](../generated/xarray.Dataset.apply.md#xarray.Dataset.apply)(func[, keep_attrs, args]) | Backward compatible implementation of `map` | | [`core.groupby.DataArrayGroupBy.apply`](../generated/xarray.core.groupby.DataArrayGroupBy.apply.md#xarray.core.groupby.DataArrayGroupBy.apply)(func[, ...]) | Backward compatible implementation of `map` | | [`core.groupby.DatasetGroupBy.apply`](../generated/xarray.core.groupby.DatasetGroupBy.apply.md#xarray.core.groupby.DatasetGroupBy.apply)(func[, ...]) | Backward compatible implementation of `map` | | [`DataArray.dt.weekofyear`](../generated/xarray.DataArray.dt.weekofyear.md#xarray.DataArray.dt.weekofyear) | The week ordinal of the year | |--------------------------------------------------------------------------------------------------------------|--------------------------------| | [`DataArray.dt.week`](../generated/xarray.DataArray.dt.week.md#xarray.DataArray.dt.week) | The week ordinal of the year | # developers-meeting.html.md # Developers meeting Xarray developers meet bi-weekly every other Wednesday. The meeting occurs on [Zoom](https://us02web.zoom.us/j/87503265754?pwd=cEFJMzFqdTFaS3BMdkx4UkNZRk1QZz09). Find the [notes for the meeting here](https://hackmd.io/LFOk5e8BSnqjX3QiKWy5Mw/edit). There is a [GitHub issue for changes to the meeting](https://github.com/pydata/xarray/issues/4001). You can subscribe to this calendar to be notified of changes: * [Google Calendar](https://calendar.google.com/calendar/embed?src=59589f9634ab4ef304e8209be66cda9812dababca71eb8a01a6fa2d167f90d94%40group.calendar.google.com&ctz=America%2FLos_Angeles) * [iCal](https://calendar.google.com/calendar/ical/59589f9634ab4ef304e8209be66cda9812dababca71eb8a01a6fa2d167f90d94%40group.calendar.google.com/public/basic.ics) # duck-arrays-integration.html.md # Integrating with duck arrays #### WARNING This is an experimental feature. Please report any bugs or other difficulties on [xarray’s issue tracker](https://github.com/pydata/xarray/issues). Xarray can wrap custom numpy-like arrays (”[duck array](../user-guide/terminology.md#term-duck-array)s”) - see the [user guide documentation](../user-guide/duckarrays.md#userguide-duckarrays). This page is intended for developers who are interested in wrapping a new custom array type with xarray. ## Duck array requirements Xarray does not explicitly check that required methods are defined by the underlying duck array object before attempting to wrap the given array. However, a wrapped array type should at a minimum define these attributes: * `shape` property, * `dtype` property, * `ndim` property, * `__array__` method, * `__array_ufunc__` method, * `__array_function__` method. These need to be defined consistently with [`numpy.ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), for example the array `shape` property needs to obey [numpy’s broadcasting rules](https://numpy.org/doc/stable/user/basics.broadcasting.html) (see also the [Python Array API standard’s explanation](https://data-apis.org/array-api/latest/API_specification/broadcasting.html) of these same rules). ## Python Array API standard support As an integration library xarray benefits greatly from the standardization of duck-array libraries’ APIs, and so is a big supporter of the [Python Array API Standard](https://data-apis.org/array-api/latest/). We aim to support any array libraries that follow the Array API standard out-of-the-box. However, xarray does occasionally call some numpy functions which are not (yet) part of the standard (e.g. [`xarray.DataArray.pad()`](../generated/xarray.DataArray.pad.md#xarray.DataArray.pad) calls [`numpy.pad()`](https://numpy.org/doc/stable/reference/generated/numpy.pad.html#numpy.pad)). See [xarray issue #7848](https://github.com/pydata/xarray/issues/7848) for a list of such functions. We can still support dispatching on these functions through the array protocols above, it just means that if you exclusively implement the methods in the Python Array API standard then some features in xarray will not work. ## Custom inline reprs In certain situations (e.g. when printing the collapsed preview of variables of a `Dataset`), xarray will display the repr of a [duck array](../user-guide/terminology.md#term-duck-array) in a single line, truncating it to a certain number of characters. If that would drop too much information, the [duck array](../user-guide/terminology.md#term-duck-array) may define a `_repr_inline_` method that takes `max_width` (number of characters) as an argument ```python class MyDuckArray: ... def _repr_inline_(self, max_width): """format to a single line with at most max_width characters""" ... ... ``` To avoid duplicated information, this method must omit information about the shape and [dtype](https://numpy.org/doc/stable/glossary.html#term-dtype). For example, the string representation of a `dask` array or a `sparse` matrix would be: ```ipython3 import dask.array as da import xarray as xr import numpy as np import sparse ``` ```ipython3 a = da.linspace(0, 1, 20, chunks=2) a ``` ```none dask.array ```
Array Chunk
Bytes 160 B 16 B
Shape (20,) (2,)
Dask graph 10 chunks in 1 graph layer
Data type float64 numpy.ndarray
20 1
```ipython3 b = np.eye(10) b[[5, 7, 3, 0], [6, 8, 2, 9]] = 2 b = sparse.COO.from_numpy(b) b ``` ```none ```
Formatcoo
Data Typefloat64
Shape(10, 10)
nnz14
Density0.14
Read-onlyTrue
Size336
Storage ratio0.42
```ipython3 xr.Dataset(dict(a=("x", a), b=(("y", "z"), b))) ``` ```none Size: 496B Dimensions: (x: 20, y: 10, z: 10) Dimensions without coordinates: x, y, z Data variables: a (x) float64 160B dask.array b (y, z) float64 336B ```
<xarray.Dataset> Size: 496B
Dimensions:  (x: 20, y: 10, z: 10)
Dimensions without coordinates: x, y, z
Data variables:
    a        (x) float64 160B dask.array<chunksize=(2,), meta=np.ndarray>
    b        (y, z) float64 336B <COO: nnz=14, fill_value=0.0>
# duckarrays.html.md # Working with numpy-like arrays NumPy-like arrays (often known as [duck array](terminology.md#term-duck-array)s) are drop-in replacements for the [`numpy.ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) class but with different features, such as propagating physical units or a different layout in memory. Xarray can often wrap these array types, allowing you to use labelled dimensions and indexes whilst benefiting from the additional features of these array libraries. Some numpy-like array types that xarray already has some support for: * [Cupy](https://cupy.dev/) - GPU support (see [cupy-xarray](https://cupy-xarray.readthedocs.io)), * [Sparse](https://sparse.pydata.org/en/stable/) - for performant arrays with many zero elements, * [Pint](https://pint.readthedocs.io/en/latest/) - for tracking the physical units of your data (see [pint-xarray](https://pint-xarray.readthedocs.io)), * [Dask](https://docs.dask.org/en/stable/) - parallel computing on larger-than-memory arrays (see [using dask with xarray](dask.md#dask)), * [Cubed](https://github.com/cubed-dev/cubed/tree/main/cubed) - another parallel computing framework that emphasises reliability (see [cubed-xarray](https://github.com/cubed-dev/cubed-xarray)). #### WARNING This feature should be considered somewhat experimental. Please report any bugs you find on [xarray’s issue tracker](https://github.com/pydata/xarray/issues). #### NOTE For information on wrapping dask arrays see [Parallel Computing with Dask](dask.md#dask). Whilst xarray wraps dask arrays in a similar way to that described on this page, chunked array types like [`dask.array.Array`](https://docs.dask.org/en/latest/generated/dask.array.Array.html#dask.array.Array) implement additional methods that require slightly different user code (e.g. calling `.chunk` or `.compute`). See the docs on [wrapping chunked arrays](../internals/chunked-arrays.md#internals-chunkedarrays). ## Why “duck”? Why is it also called a “duck” array? This comes from a common statement of object-oriented programming - “If it walks like a duck, and quacks like a duck, treat it like a duck”. In other words, a library like xarray that is capable of using multiple different types of arrays does not have to explicitly check that each one it encounters is permitted (e.g. `if dask`, `if numpy`, `if sparse` etc.). Instead xarray can take the more permissive approach of simply treating the wrapped array as valid, attempting to call the relevant methods (e.g. `.mean()`) and only raising an error if a problem occurs (e.g. the method is not found on the wrapped class). This is much more flexible, and allows objects and classes from different libraries to work together more easily. ## What is a numpy-like array? A “numpy-like array” (also known as a “duck array”) is a class that contains array-like data, and implements key numpy-like functionality such as indexing, broadcasting, and computation methods. For example, the [sparse](https://sparse.pydata.org/en/stable/) library provides a sparse array type which is useful for representing nD array objects like sparse matrices in a memory-efficient manner. We can create a sparse array object (of the [`sparse.COO`](https://sparse.pydata.org/en/latest/api/COO/#sparse.COO) type) from a numpy array like this: ```ipython3 from sparse import COO import xarray as xr import numpy as np %xmode minimal ``` ```none Exception reporting mode: Minimal ``` ```ipython3 x = np.eye(4, dtype=np.uint8) # create diagonal identity matrix s = COO.from_numpy(x) s ``` ```none ```
Formatcoo
Data Typeuint8
Shape(4, 4)
nnz4
Density0.25
Read-onlyTrue
Size68
Storage ratio4.25
This sparse object does not attempt to explicitly store every element in the array, only the non-zero elements. This approach is much more efficient for large arrays with only a few non-zero elements (such as tri-diagonal matrices). Sparse array objects can be converted back to a “dense” numpy array by calling `sparse.COO.todense()`. Just like [`numpy.ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) objects, [`sparse.COO`](https://sparse.pydata.org/en/latest/api/COO/#sparse.COO) arrays support indexing ```ipython3 s[1, 1] # diagonal elements should be ones ``` ```none np.uint8(1) ``` ```ipython3 s[2, 3] # off-diagonal elements should be zero ``` ```none np.uint8(0) ``` broadcasting, ```ipython3 x2 = np.zeros( (4, 1), dtype=np.uint8 ) # create second sparse array of different shape s2 = COO.from_numpy(x2) (s * s2) # multiplication requires broadcasting ``` ```none ```
Formatcoo
Data Typeuint8
Shape(4, 4)
nnz0
Density0.0
Read-onlyTrue
Size0
Storage ratio0.00
and various computation methods ```ipython3 s.sum(axis=1) ``` ```none ```
Formatcoo
Data Typeuint64
Shape(4,)
nnz4
Density1.0
Read-onlyTrue
Size64
Storage ratio2.00
This numpy-like array also supports calling so-called [numpy ufuncs](https://numpy.org/doc/stable/reference/ufuncs.html#available-ufuncs) (“universal functions”) on it directly: ```ipython3 np.sum(s, axis=1) ``` ```none ```
Formatcoo
Data Typeuint64
Shape(4,)
nnz4
Density1.0
Read-onlyTrue
Size64
Storage ratio2.00
Notice that in each case the API for calling the operation on the sparse array is identical to that of calling it on the equivalent numpy array - this is the sense in which the sparse array is “numpy-like”. #### NOTE For discussion on exactly which methods a class needs to implement to be considered “numpy-like”, see [Integrating with duck arrays](../internals/duck-arrays-integration.md#internals-duckarrays). ## Wrapping numpy-like arrays in xarray [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray), [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset), and [`Variable`](../generated/xarray.Variable.md#xarray.Variable) objects can wrap these numpy-like arrays. ### Constructing xarray objects which wrap numpy-like arrays The primary way to create an xarray object which wraps a numpy-like array is to pass that numpy-like array instance directly to the constructor of the xarray class. The [page on xarray data structures](data-structures.md#data-structures) shows how [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) and [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) both accept data in various forms through their `data` argument, but in fact this data can also be any wrappable numpy-like array. For example, we can wrap the sparse array we created earlier inside a new DataArray object: ```ipython3 s_da = xr.DataArray(s, dims=["i", "j"]) s_da ``` ```none Size: 68B Dimensions without coordinates: i, j ```
<xarray.DataArray (i: 4, j: 4)> Size: 68B
<COO: shape=(4, 4), dtype=uint8, nnz=4, fill_value=0>
Dimensions without coordinates: i, j
We can see what’s inside - the printable representation of our xarray object (the repr) automatically uses the printable representation of the underlying wrapped array. Of course our sparse array object is still there underneath - it’s stored under the `.data` attribute of the dataarray: ```ipython3 s_da.data ``` ```none ```
Formatcoo
Data Typeuint8
Shape(4, 4)
nnz4
Density0.25
Read-onlyTrue
Size68
Storage ratio4.25
### Array methods We saw above that numpy-like arrays provide numpy methods. Xarray automatically uses these when you call the corresponding xarray method: ```ipython3 s_da.sum(dim="j") ``` ```none Size: 64B Dimensions without coordinates: i ```
<xarray.DataArray (i: 4)> Size: 64B
<COO: shape=(4,), dtype=uint64, nnz=4, fill_value=0>
Dimensions without coordinates: i
### Converting wrapped types If you want to change the type inside your xarray object you can use [`DataArray.as_numpy()`](../generated/xarray.DataArray.as_numpy.md#xarray.DataArray.as_numpy): ```ipython3 s_da.as_numpy() ``` ```none Size: 16B array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], dtype=uint8) Dimensions without coordinates: i, j ```
<xarray.DataArray (i: 4, j: 4)> Size: 16B
array([[1, 0, 0, 0],
       [0, 1, 0, 0],
       [0, 0, 1, 0],
       [0, 0, 0, 1]], dtype=uint8)
Dimensions without coordinates: i, j
This returns a new [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) object, but now wrapping a normal numpy array. If instead you want to convert to numpy and return that numpy array you can use either [`DataArray.to_numpy()`](../generated/xarray.DataArray.to_numpy.md#xarray.DataArray.to_numpy) or [`DataArray.values()`](../generated/xarray.DataArray.values.md#xarray.DataArray.values), where the former is strongly preferred. The difference is in the way they coerce to numpy - [`values()`](../generated/xarray.DataArray.values.md#xarray.DataArray.values) always uses [`numpy.asarray()`](https://numpy.org/doc/stable/reference/generated/numpy.asarray.html#numpy.asarray) which will fail for some array types (e.g. `cupy`), whereas [`to_numpy()`](../generated/xarray.DataArray.to_numpy.md#xarray.DataArray.to_numpy) uses the correct method depending on the array type. ```ipython3 s_da.to_numpy() ``` ```none array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], dtype=uint8) ``` ```ipython3 s_da.values ``` ```ipythontb RuntimeError: Cannot convert a sparse array to dense automatically. To manually densify, use the todense method. ``` This illustrates the difference between [`data()`](../generated/xarray.DataArray.data.md#xarray.DataArray.data) and [`values()`](../generated/xarray.DataArray.values.md#xarray.DataArray.values), which is sometimes a point of confusion for new xarray users. Explicitly: [`DataArray.data()`](../generated/xarray.DataArray.data.md#xarray.DataArray.data) returns the underlying numpy-like array, regardless of type, whereas [`DataArray.values()`](../generated/xarray.DataArray.values.md#xarray.DataArray.values) converts the underlying array to a numpy array before returning it. (This is another reason to use [`to_numpy()`](../generated/xarray.DataArray.to_numpy.md#xarray.DataArray.to_numpy) over [`values()`](../generated/xarray.DataArray.values.md#xarray.DataArray.values) - the intention is clearer.) ### Conversion to numpy as a fallback If a wrapped array does not implement the corresponding array method then xarray will often attempt to convert the underlying array to a numpy array so that the operation can be performed. You may want to watch out for this behavior, and report any instances in which it causes problems. Most of xarray’s API does support using [duck array](terminology.md#term-duck-array) objects, but there are a few areas where the code will still convert to `numpy` arrays: - Dimension coordinates, and thus all indexing operations: * [`Dataset.sel()`](../generated/xarray.Dataset.sel.md#xarray.Dataset.sel) and [`DataArray.sel()`](../generated/xarray.DataArray.sel.md#xarray.DataArray.sel) * [`Dataset.loc()`](../generated/xarray.Dataset.loc.md#xarray.Dataset.loc) and [`DataArray.loc()`](../generated/xarray.DataArray.loc.md#xarray.DataArray.loc) * [`Dataset.drop_sel()`](../generated/xarray.Dataset.drop_sel.md#xarray.Dataset.drop_sel) and [`DataArray.drop_sel()`](../generated/xarray.DataArray.drop_sel.md#xarray.DataArray.drop_sel) * [`Dataset.reindex()`](../generated/xarray.Dataset.reindex.md#xarray.Dataset.reindex), [`Dataset.reindex_like()`](../generated/xarray.Dataset.reindex_like.md#xarray.Dataset.reindex_like), [`DataArray.reindex()`](../generated/xarray.DataArray.reindex.md#xarray.DataArray.reindex) and [`DataArray.reindex_like()`](../generated/xarray.DataArray.reindex_like.md#xarray.DataArray.reindex_like): duck arrays in data variables and non-dimension coordinates won’t be casted - Functions and methods that depend on external libraries or features of `numpy` not covered by `__array_function__` / `__array_ufunc__`: * [`Dataset.ffill()`](../generated/xarray.Dataset.ffill.md#xarray.Dataset.ffill) and [`DataArray.ffill()`](../generated/xarray.DataArray.ffill.md#xarray.DataArray.ffill) (uses `bottleneck`) * [`Dataset.bfill()`](../generated/xarray.Dataset.bfill.md#xarray.Dataset.bfill) and [`DataArray.bfill()`](../generated/xarray.DataArray.bfill.md#xarray.DataArray.bfill) (uses `bottleneck`) * [`Dataset.interp()`](../generated/xarray.Dataset.interp.md#xarray.Dataset.interp), [`Dataset.interp_like()`](../generated/xarray.Dataset.interp_like.md#xarray.Dataset.interp_like), [`DataArray.interp()`](../generated/xarray.DataArray.interp.md#xarray.DataArray.interp) and [`DataArray.interp_like()`](../generated/xarray.DataArray.interp_like.md#xarray.DataArray.interp_like) (uses `scipy`): duck arrays in data variables and non-dimension coordinates will be casted in addition to not supporting duck arrays in dimension coordinates * [`Dataset.rolling()`](../generated/xarray.Dataset.rolling.md#xarray.Dataset.rolling) and [`DataArray.rolling()`](../generated/xarray.DataArray.rolling.md#xarray.DataArray.rolling) (requires `numpy>=1.20`) * [`Dataset.rolling_exp()`](../generated/xarray.Dataset.rolling_exp.md#xarray.Dataset.rolling_exp) and [`DataArray.rolling_exp()`](../generated/xarray.DataArray.rolling_exp.md#xarray.DataArray.rolling_exp) (uses `numbagg`) * [`Dataset.interpolate_na()`](../generated/xarray.Dataset.interpolate_na.md#xarray.Dataset.interpolate_na) and [`DataArray.interpolate_na()`](../generated/xarray.DataArray.interpolate_na.md#xarray.DataArray.interpolate_na) (uses [`numpy.vectorize`](https://numpy.org/doc/stable/reference/generated/numpy.vectorize.html#numpy.vectorize)) * [`apply_ufunc()`](../generated/xarray.apply_ufunc.md#xarray.apply_ufunc) with `vectorize=True` (uses [`numpy.vectorize`](https://numpy.org/doc/stable/reference/generated/numpy.vectorize.html#numpy.vectorize)) - Incompatibilities between different [duck array](terminology.md#term-duck-array) libraries: * [`Dataset.chunk()`](../generated/xarray.Dataset.chunk.md#xarray.Dataset.chunk) and [`DataArray.chunk()`](../generated/xarray.DataArray.chunk.md#xarray.DataArray.chunk): this fails if the data was not already chunked and the [duck array](terminology.md#term-duck-array) (e.g. a `pint` quantity) should wrap the new `dask` array; changing the chunk sizes works however. ## Extensions using duck arrays Whilst the features above allow many numpy-like array libraries to be used pretty seamlessly with xarray, it often also makes sense to use an interfacing package to make certain tasks easier. For example the [pint-xarray package](https://pint-xarray.readthedocs.io) offers a custom `.pint` accessor (see [Extending xarray using accessors](../internals/extending-xarray.md#internals-accessors)) which provides convenient access to information stored within the wrapped array (e.g. `.units` and `.magnitude`), and makes creating wrapped pint arrays (and especially xarray-wrapping-pint-wrapping-dask arrays) simpler for the user. We maintain a list of libraries extending `xarray` to make working with particular wrapped duck arrays easier. If you know of more that aren’t on this list please raise an issue to add them! - [pint-xarray](https://pint-xarray.readthedocs.io) - [cupy-xarray](https://cupy-xarray.readthedocs.io) - [cubed-xarray](https://github.com/cubed-dev/cubed-xarray) # ecosystem.html.md # Xarray related projects Below is a list of existing open source projects that build functionality upon xarray. See also section [Xarray Internals](../internals/index.md#internals) for more details on how to build xarray extensions. We also maintain the [xarray-contrib](https://github.com/xarray-contrib) GitHub organization as a place to curate projects that build upon xarray. ## Geosciences - [aospy](https://aospy.readthedocs.io): Automated analysis and management of gridded climate data. - [argopy](https://github.com/euroargodev/argopy): xarray-based Argo data access, manipulation and visualisation for standard users as well as Argo experts. - [cf_xarray](https://cf-xarray.readthedocs.io/en/latest/): Provides an accessor (DataArray.cf or Dataset.cf) that allows you to interpret Climate and Forecast metadata convention attributes present on xarray objects. - [climpred](https://climpred.readthedocs.io): Analysis of ensemble forecast models for climate prediction. - [geocube](https://corteva.github.io/geocube): Tool to convert geopandas vector data into rasterized xarray data. - [GeoWombat](https://github.com/jgrss/geowombat): Utilities for analysis of remotely sensed and gridded raster data at scale (easily tame Landsat, Sentinel, Quickbird, and PlanetScope). - [grib2io](https://github.com/NOAA-MDL/grib2io): Utility to work with GRIB2 files including an xarray backend, DASK support for parallel reading in open_mfdataset, lazy loading of data, editing of GRIB2 attributes and GRIB2IO DataArray attrs, and spatial interpolation and reprojection of GRIB2 messages and GRIB2IO Datasets/DataArrays for both grid to grid and grid to stations. - [gsw-xarray](https://github.com/DocOtak/gsw-xarray): a wrapper around [gsw](https://teos-10.github.io/GSW-Python) that adds CF compliant attributes when possible, units, name. - [infinite-diff](https://github.com/spencerahill/infinite-diff): xarray-based finite-differencing, focused on gridded climate/meteorology data - [marc_analysis](https://github.com/darothen/marc_analysis): Analysis package for CESM/MARC experiments and output. - [MetPy](https://unidata.github.io/MetPy/dev/index.html): A collection of tools in Python for reading, visualizing, and performing calculations with weather data. - [MPAS-Analysis](https://mpas-dev.github.io/MPAS-Analysis): Analysis for simulations produced with Model for Prediction Across Scales (MPAS) components and the Accelerated Climate Model for Energy (ACME). - [OGGM](https://oggm.org/): Open Global Glacier Model - [Oocgcm](https://oocgcm.readthedocs.io/): Analysis of large gridded geophysical datasets - [Open Data Cube](https://www.opendatacube.org/): Analysis toolkit of continental scale Earth Observation data from satellites. - [Pangaea](https://pangaea.readthedocs.io/en/latest/): xarray extension for gridded land surface & weather model output). - [Pangeo](https://pangeo.io): A community effort for big data geoscience in the cloud. - [PyGDX](https://pygdx.readthedocs.io/en/latest/): Python 3 package for accessing data stored in GAMS Data eXchange (GDX) files. Also uses a custom subclass. - [pyinterp](https://pangeo-pyinterp.readthedocs.io/en/latest/): Python 3 package for interpolating geo-referenced data used in the field of geosciences. - [pyXpcm](https://pyxpcm.readthedocs.io): xarray-based Profile Classification Modelling (PCM), mostly for ocean data. - [Regionmask](https://regionmask.readthedocs.io/): plotting and creation of masks of spatial regions - [rioxarray](https://corteva.github.io/rioxarray): geospatial xarray extension powered by rasterio - [salem](https://salem.readthedocs.io): Adds geolocalised subsetting, masking, and plotting operations to xarray’s data structures via accessors. - [SatPy](https://satpy.readthedocs.io/) : Library for reading and manipulating meteorological remote sensing data and writing it to various image and data file formats. - [SARXarray](https://tudelftgeodesy.github.io/sarxarray/): xarray extension for reading and processing large Synthetic Aperture Radar (SAR) data stacks. - [shxarray](https://shxarray.wobbly.earth/): Convert, filter,and map geodesy related spherical harmonic representations of gravity and terrestrial water storage through an xarray extension. - [Spyfit](https://spyfit.readthedocs.io/en/master/): FTIR spectroscopy of the atmosphere - [TOAD](https://github.com/tipmip-methods/toad/): TOAD (Tipping and Other Abrupt events Detector) detects and clusters abrupt shifts in gridded Earth system data and operates directly on xarray datasets. - [windspharm](https://ajdawson.github.io/windspharm/index.html): Spherical harmonic wind analysis in Python. - [wradlib](https://wradlib.org/): An Open Source Library for Weather Radar Data Processing. - [wrf-python](https://wrf-python.readthedocs.io/): A collection of diagnostic and interpolation routines for use with output of the Weather Research and Forecasting (WRF-ARW) Model. - [xarray-eopf](https://github.com/EOPF-Sample-Service/xarray-eopf): An xarray backend implementation for opening ESA EOPF data products in Zarr format. - [xarray-regrid](https://github.com/EXCITED-CO2/xarray-regrid): xarray extension for regridding rectilinear data. - [xarray-simlab](https://xarray-simlab.readthedocs.io): xarray extension for computer model simulations. - [xarray-spatial](https://xarray-spatial.org/): Numba-accelerated raster-based spatial processing tools (NDVI, curvature, zonal-statistics, proximity, hillshading, viewshed, etc.) - [xarray-topo](https://xarray-topo.readthedocs.io/): xarray extension for topographic analysis and modelling. - [xbpch](https://github.com/darothen/xbpch): xarray interface for bpch files. - [xCDAT](https://xcdat.readthedocs.io/): An extension of xarray for climate data analysis on structured grids. - [xclim](https://xclim.readthedocs.io/): A library for calculating climate science indices with unit handling built from xarray and dask. - [xESMF](https://pangeo-xesmf.readthedocs.io/): Universal regridder for geospatial data. - [xgcm](https://xgcm.readthedocs.io/): Extends the xarray data model to understand finite volume grid cells (common in General Circulation Models) and provides interpolation and difference operations for such grids. - [xmitgcm](https://xmitgcm.readthedocs.io/): a python package for reading [MITgcm](https://mitgcm.org/) binary MDS files into xarray data structures. - [xnemogcm](https://github.com/rcaneill/xnemogcm/): a package to read [NEMO](https://nemo-ocean.eu/) output files and add attributes to interface with xgcm. ## Machine Learning - [ArviZ](https://arviz-devs.github.io/arviz/): Exploratory analysis of Bayesian models, built on top of xarray. - [Darts](https://github.com/unit8co/darts/): User-friendly modern machine learning for time series in Python. - [Elm](https://ensemble-learning-models.readthedocs.io): Parallel machine learning on xarray data structures - [sklearn-xarray (1)](https://phausamann.github.io/sklearn-xarray): Combines scikit-learn and xarray (1). - [sklearn-xarray (2)](https://sklearn-xarray.readthedocs.io/en/latest/): Combines scikit-learn and xarray (2). - [xbatcher](https://xbatcher.readthedocs.io): Batch Generation from Xarray Datasets. ## Other domains - [ptsa](https://pennmem.github.io/ptsa/html/index.html): EEG Time Series Analysis - [pycalphad](https://pycalphad.org/docs/latest/): Computational Thermodynamics in Python - [pyomeca](https://pyomeca.github.io/): Python framework for biomechanical analysis - [movement](https://movement.neuroinformatics.dev/): A Python toolbox for analysing animal body movements ## Extend xarray capabilities - [Collocate](https://github.com/cistools/collocate): Collocate xarray trajectories in arbitrary physical dimensions - [eofs](https://ajdawson.github.io/eofs/): EOF analysis in Python. - [hypothesis-gufunc](https://hypothesis-gufunc.readthedocs.io/en/latest/): Extension to hypothesis. Makes it easy to write unit tests with xarray objects as input. - [ntv-pandas](https://github.com/loco-philippe/ntv-pandas) : A tabular analyzer and a semantic, compact and reversible converter for multidimensional and tabular data - [nxarray](https://github.com/nxarray/nxarray): NeXus input/output capability for xarray. - [xarray-compare](https://github.com/astropenguin/xarray-compare): xarray extension for data comparison. - [xarray-dataclasses](https://github.com/astropenguin/xarray-dataclasses): xarray extension for typed DataArray and Dataset creation. - [xarray_einstats](https://xarray-einstats.readthedocs.io): Statistics, linear algebra and einops for xarray - [xarray_extras](https://github.com/crusaderky/xarray_extras): Advanced algorithms for xarray objects (e.g. integrations/interpolations). - [xeofs](https://github.com/nicrie/xeofs): PCA/EOF analysis and related techniques, integrated with xarray and Dask for efficient handling of large-scale data. - [xpublish](https://xpublish.readthedocs.io/): Publish Xarray Datasets via a Zarr compatible REST API. - [xrft](https://github.com/rabernat/xrft): Fourier transforms for xarray data. - [xr-scipy](https://xr-scipy.readthedocs.io): A lightweight scipy wrapper for xarray. - [X-regression](https://github.com/kuchaale/X-regression): Multiple linear regression from Statsmodels library coupled with Xarray library. - [xskillscore](https://github.com/xarray-contrib/xskillscore): Metrics for verifying forecasts. - [xyzpy](https://xyzpy.readthedocs.io): Easily generate high dimensional data, including parallelization. - [xarray-lmfit](https://github.com/kmnhan/xarray-lmfit): xarray extension for curve fitting using [lmfit](https://lmfit.github.io/lmfit-py/). ## Visualization - [datashader](https://datashader.org), [geoviews](https://geoviews.org), [holoviews](https://holoviews.org/), : visualization packages for large data. - [hvplot](https://hvplot.pyviz.org/) : A high-level plotting API for the PyData ecosystem built on HoloViews. - [psyplot](https://psyplot.readthedocs.io): Interactive data visualization with python. - [xarray-leaflet](https://github.com/davidbrochart/xarray_leaflet): An xarray extension for tiled map plotting based on ipyleaflet. - [xtrude](https://github.com/davidbrochart/xtrude): An xarray extension for 3D terrain visualization based on pydeck. - [pyvista-xarray](https://github.com/pyvista/pyvista-xarray): xarray DataArray accessor for 3D visualization with [PyVista](https://github.com/pyvista/pyvista) and DataSet engines for reading VTK data formats. ## Non-Python projects - [xframe](https://github.com/xtensor-stack/xframe): C++ data structures inspired by xarray. - [AxisArrays](https://github.com/JuliaArrays/AxisArrays.jl), [NamedArrays](https://github.com/davidavdav/NamedArrays.jl) and [YAXArrays.jl](https://github.com/JuliaDataCubes/YAXArrays.jl): similar data structures for Julia. More projects can be found at the [“xarray” Github topic](https://github.com/topics/xarray). # encoding.html.md # Encoding/Decoding | [`decode_cf`](../generated/xarray.decode_cf.md#xarray.decode_cf)(obj[, concat_characters, ...]) | Decode the given Dataset or Datastore according to CF conventions into a new Dataset. | |---------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------| ## Coder objects | [`coders.CFDatetimeCoder`](../generated/xarray.coders.CFDatetimeCoder.md#xarray.coders.CFDatetimeCoder)([use_cftime, time_unit]) | Coder for CF Datetime coding. | |------------------------------------------------------------------------------------------------------------------------------------|---------------------------------| # exceptions.html.md # Exceptions | [`AlignmentError`](../generated/xarray.AlignmentError.md#xarray.AlignmentError) | Error class for alignment failures due to incompatible arguments. | |------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------| | [`CoordinateValidationError`](../generated/xarray.CoordinateValidationError.md#xarray.CoordinateValidationError) | Error class for Xarray coordinate validation failures. | | [`MergeError`](../generated/xarray.MergeError.md#xarray.MergeError) | Error class for merge failures due to incompatible arguments. | | [`SerializationWarning`](../generated/xarray.SerializationWarning.md#xarray.SerializationWarning) | Warnings about encoding/decoding issues in serialization. | ## DataTree Exceptions raised when manipulating trees. | [`TreeIsomorphismError`](../generated/xarray.TreeIsomorphismError.md#xarray.TreeIsomorphismError) | Error raised if two tree objects do not share the same node structure. | |-----------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| | [`InvalidTreeError`](../generated/xarray.InvalidTreeError.md#xarray.InvalidTreeError) | Raised when user attempts to create an invalid tree in some way. | | [`NotFoundInTreeError`](../generated/xarray.NotFoundInTreeError.md#xarray.NotFoundInTreeError) | Raised when operation can't be completed because one node is not part of the expected tree. | # extending-xarray.html.md # Extending xarray using accessors Xarray is designed as a general purpose library and hence tries to avoid including overly domain specific functionality. But inevitably, the need for more domain specific logic arises. ## Composition over Inheritance One potential solution to this problem is to subclass Dataset and/or DataArray to add domain specific functionality. However, inheritance is not very robust. It’s easy to inadvertently use internal APIs when subclassing, which means that your code may break when xarray upgrades. Furthermore, many builtin methods will only return native xarray objects. The standard advice is to use [composition over inheritance](https://github.com/pydata/xarray/issues/706), but reimplementing an API as large as xarray’s on your own objects can be an onerous task, even if most methods are only forwarding to xarray implementations. (For an example of a project which took this approach of subclassing see [UXarray](https://github.com/UXARRAY/uxarray)). If you simply want the ability to call a function with the syntax of a method call, then the builtin [`pipe()`](../generated/xarray.DataArray.pipe.md#xarray.DataArray.pipe) method (copied from pandas) may suffice. ## Writing Custom Accessors To resolve this issue for more complex cases, xarray has the [`register_dataset_accessor()`](../generated/xarray.register_dataset_accessor.md#xarray.register_dataset_accessor), [`register_dataarray_accessor()`](../generated/xarray.register_dataarray_accessor.md#xarray.register_dataarray_accessor) and [`register_datatree_accessor()`](../generated/xarray.register_datatree_accessor.md#xarray.register_datatree_accessor) decorators for adding custom “accessors” on xarray objects, thereby “extending” the functionality of your xarray object. Here’s how you might use these decorators to write a custom “geo” accessor implementing a geography specific extension to xarray: ```default import xarray as xr @xr.register_dataset_accessor("geo") class GeoAccessor: def __init__(self, xarray_obj): self._obj = xarray_obj self._center = None @property def center(self): """Return the geographic center point of this dataset.""" if self._center is None: # we can use a cache on our accessor objects, because accessors # themselves are cached on instances that access them. lon = self._obj.latitude lat = self._obj.longitude self._center = (float(lon.mean()), float(lat.mean())) return self._center def plot(self): """Plot data on a map.""" return "plotting!" ``` In general, the only restriction on the accessor class is that the `__init__` method must have a single parameter: the `Dataset` or `DataArray` object it is supposed to work on. This achieves the same result as if the `Dataset` class had a cached property defined that returns an instance of your class: ```python class Dataset: ... @property def geo(self): return GeoAccessor(self) ``` However, using the register accessor decorators is preferable to simply adding your own ad-hoc property (i.e., `Dataset.geo = property(...)`), for several reasons: 1. It ensures that the name of your property does not accidentally conflict with any other attributes or methods (including other accessors). 2. Instances of accessor object will be cached on the xarray object that creates them. This means you can save state on them (e.g., to cache computed properties). 3. Using an accessor provides an implicit namespace for your custom functionality that clearly identifies it as separate from built-in xarray methods. #### NOTE Accessors are created once per DataArray and Dataset instance. New instances, like those created from arithmetic operations or when accessing a DataArray from a Dataset (ex. `ds[var_name]`), will have new accessors created. Back in an interactive IPython session, we can use these properties: ```ipython3 ds = xr.Dataset({"longitude": np.linspace(0, 10), "latitude": np.linspace(0, 20)}) ds.geo.center ``` ```none (10.0, 5.0) ``` ```ipython3 ds.geo.plot() ``` ```none 'plotting!' ``` The intent here is that libraries that extend xarray could add such an accessor to implement subclass specific functionality rather than using actual subclasses or patching in a large number of domain specific methods. For further reading on ways to write new accessors and the philosophy behind the approach, see [https://github.com/pydata/xarray/issues/1080](https://github.com/pydata/xarray/issues/1080). To help users keep things straight, please [let us know](https://github.com/pydata/xarray/issues) if you plan to write a new accessor for an open source library. Existing open source accessors and the libraries that implement them are available in the list on the [Xarray related projects](../user-guide/ecosystem.md#ecosystem) page. To make documenting accessors with `sphinx` and `sphinx.ext.autosummary` easier, you can use [sphinx-autosummary-accessors](https://sphinx-autosummary-accessors.readthedocs.io/). # faq.html.md # Frequently Asked Questions ## Your documentation keeps mentioning pandas. What is pandas? [pandas](https://pandas.pydata.org) is a very popular data analysis package in Python with wide usage in many fields. Our API is heavily inspired by pandas — this is why there are so many references to pandas. ## Do I need to know pandas to use xarray? No! Our API is heavily inspired by pandas so while knowing pandas will let you become productive more quickly, knowledge of pandas is not necessary to use xarray. ## Should I use xarray instead of pandas? It’s not an either/or choice! xarray provides robust support for converting back and forth between the tabular data-structures of pandas and its own multi-dimensional data-structures. That said, you should only bother with xarray if some aspect of data is fundamentally multi-dimensional. If your data is unstructured or one-dimensional, pandas is usually the right choice: it has better performance for common operations such as `groupby` and you’ll find far more usage examples online. ## Why is pandas not enough? pandas is a fantastic library for analysis of low-dimensional labelled data - if it can be sensibly described as “rows and columns”, pandas is probably the right choice. However, sometimes we want to use higher dimensional arrays (ndim > 2), or arrays for which the order of dimensions (e.g., columns vs rows) shouldn’t really matter. For example, the images of a movie can be natively represented as an array with four dimensions: time, row, column and color. pandas has historically supported N-dimensional panels, but deprecated them in version 0.20 in favor of xarray data structures. There are now built-in methods on both sides to convert between pandas and xarray, allowing for more focused development effort. Xarray objects have a much richer model of dimensionality - if you were using Panels: - You need to create a new factory type for each dimensionality. - You can’t do math between NDPanels with different dimensionality. - Each dimension in an NDPanel has a name (e.g., ‘labels’, ‘items’, ‘major_axis’, etc.) but the dimension names refer to order, not their meaning. You can’t specify an operation as to be applied along the “time” axis. - You often have to manually convert collections of pandas arrays (Series, DataFrames, etc) to have the same number of dimensions. In contrast, this sort of data structure fits very naturally in an xarray `Dataset`. You can [read about switching from Panels to xarray here](../user-guide/pandas.md#panel-transition). pandas gets a lot of things right, but many science, engineering and complex analytics use cases need fully multi-dimensional data structures. ## How do xarray data structures differ from those found in pandas? The main distinguishing feature of xarray’s `DataArray` over labeled arrays in pandas is that dimensions can have names (e.g., “time”, “latitude”, “longitude”). Names are much easier to keep track of than axis numbers, and xarray uses dimension names for indexing, aggregation and broadcasting. Not only can you write `x.sel(time='2000-01-01')` and `x.mean(dim='time')`, but operations like `x - x.mean(dim='time')` always work, no matter the order of the “time” dimension. You never need to reshape arrays (e.g., with `np.newaxis`) to align them for arithmetic operations in xarray. ## Why don’t aggregations return Python scalars? Xarray tries hard to be self-consistent: operations on a `DataArray` (resp. `Dataset`) return another `DataArray` (resp. `Dataset`) object. In particular, operations returning scalar values (e.g. indexing or aggregations like `mean` or `sum` applied to all axes) will also return xarray objects. Unfortunately, this means we sometimes have to explicitly cast our results from xarray when using them in other libraries. As an illustration, the following code fragment ```ipython3 arr = xr.DataArray([1, 2, 3]) pd.Series({"x": arr[0], "mean": arr.mean(), "std": arr.std()}) ``` ```none x Size: 8B\narray(1) mean Size: 8B\narray(2.) std Size: 8B\narray(0.81649658) dtype: object ``` does not yield the pandas DataFrame we expected. We need to specify the type conversion ourselves: ```ipython3 pd.Series({"x": arr[0], "mean": arr.mean(), "std": arr.std()}, dtype=float) ``` ```none x 1.000000 mean 2.000000 std 0.816497 dtype: float64 ``` Alternatively, we could use the `item` method or the `float` constructor to convert values one at a time ```ipython3 pd.Series({"x": arr[0].item(), "mean": float(arr.mean())}) ``` ```none x 1.0 mean 2.0 dtype: float64 ``` ## What is your approach to metadata? We are firm believers in the power of labeled data! In addition to dimensions and coordinates, xarray supports arbitrary metadata in the form of global (Dataset) and variable specific (DataArray) attributes (`attrs`). Automatic interpretation of labels is powerful but also reduces flexibility. With xarray, we draw a firm line between labels that the library understands (`dims` and `coords`) and labels for users and user code (`attrs`). For example, we do not automatically interpret and enforce units or [CF conventions](https://cfconventions.org/latest.html). (An exception is serialization to and from netCDF files.) An implication of this choice is that we do not propagate `attrs` through most operations unless explicitly flagged (some methods have a `keep_attrs` option, and there is a global flag, accessible with [`xarray.set_options()`](../generated/xarray.set_options.md#xarray.set_options), for setting this to be always True or False). Similarly, xarray does not check for conflicts between `attrs` when combining arrays and datasets, unless explicitly requested with the option `compat='identical'`. The guiding principle is that metadata should not be allowed to get in the way. In general xarray uses the capabilities of the backends for reading and writing attributes. That has some implications on roundtripping. One example for such inconsistency is that size-1 lists will roundtrip as single element (for netcdf4 backends). ## What other netCDF related Python libraries should I know about? [netCDF4-python](https://unidata.github.io/netcdf4-python/) provides a lower level interface for working with netCDF and OpenDAP datasets in Python. We use netCDF4-python internally in xarray, and have contributed a number of improvements and fixes upstream. Xarray does not yet support all of netCDF4-python’s features, such as modifying files on-disk. [Iris](https://scitools-iris.readthedocs.io/en/stable/) (supported by the UK Met office) provides similar tools for in- memory manipulation of labeled arrays, aimed specifically at weather and climate data needs. Indeed, the Iris [`Cube`](https://scitools-iris.readthedocs.io/en/latest/generated/api/iris.cube.html#iris.cube.Cube) was direct inspiration for xarray’s [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray). Xarray and Iris take very different approaches to handling metadata: Iris strictly interprets [CF conventions](https://cfconventions.org/latest.html). Iris particularly shines at mapping, thanks to its integration with [Cartopy](https://cartopy.readthedocs.io/stable/). We think the design decisions we have made for xarray (namely, basing it on pandas) make it a faster and more flexible data analysis tool. That said, Iris has some great domain specific functionality, and there are dedicated methods for converting back and forth between xarray and Iris. See [Reading and Writing Iris data](../user-guide/io.md#io-iris) for more details. ## What other projects leverage xarray? See section [Xarray related projects](../user-guide/ecosystem.md#ecosystem). ## How do I open format X file as an xarray dataset? To open format X file in xarray, you need to know the [format of the data](https://docs.xarray.dev/en/stable/user-guide/io.html#csv-and-other-formats-supported-by-pandas/) you want to read. If the format is supported, you can use the appropriate function provided by xarray. The following table provides functions used for different file formats in xarray, as well as links to other packages that can be used: | File Format | Open via | > Related Packages | |--------------------------|----------------------------------------|---------------------------------------------------------------------------------------------------------| | NetCDF (.nc, .nc4, .cdf) | `open_dataset()` OR `open_mfdataset()` | [netCDF4](https://pypi.org/project/netCDF4/), [cdms2](https://cdms.readthedocs.io/en/latest/cdms2.html) | | HDF5 (.h5, .hdf5) | `open_dataset()` OR `open_mfdataset()` | [h5py](https://www.h5py.org/), [pytables](https://www.pytables.org/) | | GRIB (.grb, .grib) | `open_dataset()` | [cfgrib](https://pypi.org/project/cfgrib/), [pygrib](https://pypi.org/project/pygrib/) | | CSV (.csv) | `open_dataset()` | [pandas](https://pandas.pydata.org) , [dask](https://www.dask.org/) | | Zarr (.zarr) | `open_dataset()` OR `open_mfdataset()` | [zarr](https://pypi.org/project/zarr/) , [dask](https://www.dask.org/) | If you are unable to open a file in xarray: - You should check that you are having all necessary dependencies installed, including any optional dependencies (like scipy, h5netcdf, cfgrib etc as mentioned below) that may be required for the specific use case. - If all necessary dependencies are installed but the file still cannot be opened, you must check if there are any specialized backends available for the specific file format you are working with. You can consult the xarray documentation or the documentation for the file format to determine if a specialized backend is required, and if so, how to install and use it with xarray. - If the file format is not supported by xarray or any of its available backends, the user may need to use a different library or tool to work with the file. You can consult the documentation for the file format to determine which tools are recommended for working with it. Xarray provides a default engine to read files, which is usually determined by the file extension or type. If you don’t specify the engine, xarray will try to guess it based on the file extension or type, and may fall back to a different engine if it cannot determine the correct one. Therefore, it’s good practice to always specify the engine explicitly, to ensure that the correct backend is used and especially when working with complex data formats or non-standard file extensions. [`xarray.backends.list_engines()`](../generated/xarray.backends.list_engines.md#xarray.backends.list_engines) is a function in xarray that returns a dictionary of available engines and their BackendEntrypoint objects. You can use the `engine` argument to specify the backend when calling `open_dataset()` or other reading functions in xarray, as shown below: ### NetCDF If you are reading a netCDF file with a “.nc” extension, the default engine is `netcdf4`. However if you have files with non-standard extensions or if the file format is ambiguous. Specify the engine explicitly, to ensure that the correct backend is used. Use [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) to open a NetCDF file and return an xarray Dataset object. ```python import xarray as xr # use xarray to open the file and return an xarray.Dataset object using netcdf4 engine ds = xr.open_dataset("/path/to/my/file.nc", engine="netcdf4") # Print Dataset object print(ds) # use xarray to open the file and return an xarray.Dataset object using scipy engine ds = xr.open_dataset("/path/to/my/file.nc", engine="scipy") ``` We recommend installing `scipy` via conda using the below given code: ```default conda install scipy ``` ### HDF5 Use [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) to open an HDF5 file and return an xarray Dataset object. You should specify the `engine` keyword argument when reading HDF5 files with xarray, as there are multiple backends that can be used to read HDF5 files, and xarray may not always be able to automatically detect the correct one based on the file extension or file format. To read HDF5 files with xarray, you can use the [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) function from the `h5netcdf` backend, as follows: ```python import xarray as xr # Open HDF5 file as an xarray Dataset ds = xr.open_dataset("path/to/hdf5/file.hdf5", engine="h5netcdf") # Print Dataset object print(ds) ``` We recommend you to install `h5netcdf` library using the below given code: ```default conda install -c conda-forge h5netcdf ``` If you want to use the `netCDF4` backend to read a file with a “.h5” extension (which is typically associated with HDF5 file format), you can specify the engine argument as follows: ```python ds = xr.open_dataset("path/to/file.h5", engine="netcdf4") ``` ### GRIB You should specify the `engine` keyword argument when reading GRIB files with xarray, as there are multiple backends that can be used to read GRIB files, and xarray may not always be able to automatically detect the correct one based on the file extension or file format. Use the [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) function from the `cfgrib` package to open a GRIB file as an xarray Dataset. ```python import xarray as xr # define the path to your GRIB file and the engine you want to use to open the file # use ``open_dataset()`` to open the file with the specified engine and return an xarray.Dataset object ds = xr.open_dataset("path/to/your/file.grib", engine="cfgrib") # Print Dataset object print(ds) ``` We recommend installing `cfgrib` via conda using the below given code: ```default conda install -c conda-forge cfgrib ``` ### CSV By default, xarray uses the built-in `pandas` library to read CSV files. In general, you don’t need to specify the engine keyword argument when reading CSV files with xarray, as the default `pandas` engine is usually sufficient for most use cases. If you are working with very large CSV files or if you need to perform certain types of data processing that are not supported by the default `pandas` engine, you may want to use a different backend. In such cases, you can specify the engine argument when reading the CSV file with xarray. To read CSV files with xarray, use the [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) function and specify the path to the CSV file as follows: ```python import xarray as xr import pandas as pd # Load CSV file into pandas DataFrame using the "c" engine df = pd.read_csv("your_file.csv", engine="c") # Convert `:py:func:pandas` DataFrame to xarray.Dataset ds = xr.Dataset.from_dataframe(df) # Prints the resulting xarray dataset print(ds) ``` ### Zarr When opening a Zarr dataset with xarray, the `engine` is automatically detected based on the file extension or the type of input provided. If the dataset is stored in a directory with a “.zarr” extension, xarray will automatically use the “zarr” engine. To read zarr files with xarray, use the [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) function and specify the path to the zarr file as follows: ```python import xarray as xr # use xarray to open the file and return an xarray.Dataset object using zarr engine ds = xr.open_dataset("path/to/your/file.zarr", engine="zarr") # Print Dataset object print(ds) ``` We recommend installing `zarr` via conda using the below given code: ```default conda install -c conda-forge zarr ``` There may be situations where you need to specify the engine manually using the `engine` keyword argument. For example, if you have a Zarr dataset stored in a file with a different extension (e.g., “.npy”), you will need to specify the engine as “zarr” explicitly when opening the dataset. Some packages may have additional functionality beyond what is shown here. You can refer to the documentation for each package for more information. ## How does xarray handle missing values? **xarray can handle missing values using \`\`np.nan\`\`** - `np.nan` is used to represent missing values in labeled arrays and datasets. It is a commonly used standard for representing missing or undefined numerical data in scientific computing. `np.nan` is a constant value in NumPy that represents “Not a Number” or missing values. - Most of xarray’s computation methods are designed to automatically handle missing values appropriately. For example, when performing operations like addition or multiplication on arrays that contain missing values, xarray will automatically ignore the missing values and only perform the operation on the valid data. This makes it easy to work with data that may contain missing or undefined values without having to worry about handling them explicitly. - Many of xarray’s [aggregation methods](https://docs.xarray.dev/en/stable/user-guide/computation.html#aggregation), such as `sum()`, `mean()`, `min()`, `max()`, and others, have a skipna argument that controls whether missing values (represented by NaN) should be skipped (True) or treated as NaN (False) when performing the calculation. By default, `skipna` is set to `True`, so missing values are ignored when computing the result. However, you can set `skipna` to `False` if you want missing values to be treated as NaN and included in the calculation. - On [plotting](https://docs.xarray.dev/en/stable/user-guide/plotting.html#missing-values) an xarray dataset or array that contains missing values, xarray will simply leave the missing values as blank spaces in the plot. - We have a set of [methods](https://docs.xarray.dev/en/stable/user-guide/computation.html#missing-values) for manipulating missing and filling values. ## How should I cite xarray? If you are using xarray and would like to cite it in academic publication, we would certainly appreciate it. We recommend two citations. > 1. At a minimum, we recommend citing the xarray overview journal article, > published in the Journal of Open Research Software. > - Hoyer, S. & Hamman, J., (2017). xarray: N-D labeled Arrays and > Datasets in Python. Journal of Open Research Software. 5(1), p.10. > DOI: [https://doi.org/10.5334/jors.148](https://doi.org/10.5334/jors.148) > Here’s an example of a BibTeX entry: > ```default > @article{hoyer2017xarray, > title = {xarray: {N-D} labeled arrays and datasets in {Python}}, > author = {Hoyer, S. and J. Hamman}, > journal = {Journal of Open Research Software}, > volume = {5}, > number = {1}, > year = {2017}, > publisher = {Ubiquity Press}, > doi = {10.5334/jors.148}, > url = {https://doi.org/10.5334/jors.148} > } > ``` > 2. You may also want to cite a specific version of the xarray package. We > provide a [Zenodo citation and DOI](https://doi.org/10.5281/zenodo.598201) > for this purpose: > > > [![image](https://zenodo.org/badge/doi/10.5281/zenodo.598201.svg)](https://doi.org/10.5281/zenodo.598201) > > An example BibTeX entry: > > ```default > > @misc{xarray_v0_8_0, > > author = {Stephan Hoyer and Clark Fitzgerald and Joe Hamman and others}, > > title = {xarray: v0.8.0}, > > month = aug, > > year = 2016, > > doi = {10.5281/zenodo.59499}, > > url = {https://doi.org/10.5281/zenodo.59499} > > } > > ``` ## How stable is Xarray’s API? Xarray tries very hard to maintain backwards compatibility in our [API reference](../api.md#api) between released versions. Whilst we do occasionally make breaking changes in order to improve the library, we [signpost changes](https://docs.xarray.dev/en/stable/contributing.html#backwards-compatibility) with `FutureWarnings` for many releases in advance. (An exception is bugs - whose behaviour we try to fix as soon as we notice them.) Our [test-driven development practices](https://docs.xarray.dev/en/stable/contributing.html#test-driven-development-code-writing) helps to ensure any accidental regressions are caught. This philosophy applies to everything in the public API. ## What parts of xarray are considered public API? As a rule, only functions/methods documented in our [API reference](../api.md#api) are considered part of xarray’s public API. Everything else (in particular, everything in `xarray.core` that is not also exposed in the top level `xarray` namespace) is considered a private implementation detail that may change at any time. Objects that exist to facilitate xarray’s fluent interface on `DataArray` and `Dataset` objects are a special case. For convenience, we document them in the API docs, but only their methods and the `DataArray`/`Dataset` methods/properties to construct them (e.g., `.plot()`, `.groupby()`, `.str`) are considered public API. Constructors and other details of the internal classes used to implemented them (i.e., `xarray.plot.plotting._PlotMethods`, `xarray.core.groupby.DataArrayGroupBy`, `xarray.core.accessor_str.StringAccessor`) are not. # gallery.html.md # Gallery Here’s a list of examples on how to use xarray. We will be adding more examples soon. Contributions are highly welcomed and appreciated. So, if you are interested in contributing, please consult the [Contributing to xarray](contribute/contributing.md#contributing) guide. ## Notebook Examples ![Toy weather data](_static/thumbnails/toy-weather-data.png) Toy weather data ![Calculating Seasonal Averages from Timeseries of Monthly Means](_static/thumbnails/monthly-means.png) Calculating Seasonal Averages from Timeseries of Monthly Means ![Compare weighted and unweighted mean temperature](_static/thumbnails/area_weighted_temperature.png) Compare weighted and unweighted mean temperature ![Working with Multidimensional Coordinates](_static/thumbnails/multidimensional-coords.png) Working with Multidimensional Coordinates ![Visualization Gallery](_static/thumbnails/visualization_gallery.png) Visualization Gallery ![GRIB Data Example](_static/thumbnails/ERA5-GRIB-example.png) GRIB Data Example ![Applying unvectorized functions with apply_ufunc](_static/logos/Xarray_Logo_RGB_Final.svg) Applying unvectorized functions with apply_ufunc ## External Examples ![Managing raster data with rioxarray](_static/logos/Xarray_Logo_RGB_Final.svg) Managing raster data with rioxarray ![Xarray and dask on the cloud with Pangeo](https://avatars.githubusercontent.com/u/60833341?s=200&v=4) Xarray and dask on the cloud with Pangeo ![Xarray with Dask Arrays](_static/logos/Xarray_Logo_RGB_Final.svg) Xarray with Dask Arrays ![Project Pythia Foundations Book](https://raw.githubusercontent.com/ProjectPythia/projectpythia.github.io/main/portal/_static/images/logos/pythia_logo-blue-btext-twocolor.svg) Project Pythia Foundations Book # groupby.html.md # GroupBy: Group and Bin Data Often we want to bin or group data, produce statistics (mean, variance) on the groups, and then return a reduced data set. To do this, Xarray supports [“group by”](https://pandas.pydata.org/pandas-docs/stable/groupby.html) operations with the same API as pandas to implement the [split-apply-combine](https://www.jstatsoft.org/v40/i01/paper) strategy: - Split your data into multiple independent groups. - Apply some function to each group. - Combine your groups back into a single data object. Group by operations work on both [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) and [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) objects. Most of the examples focus on grouping by a single one-dimensional variable, although support for grouping over a multi-dimensional variable has recently been implemented. Note that for one-dimensional data, it is usually faster to rely on pandas’ implementation of the same pipeline. ## Split Let’s create a simple example dataset: ```ipython3 ds = xr.Dataset( {"foo": (("x", "y"), np.random.rand(4, 3))}, coords={"x": [10, 20, 30, 40], "letters": ("x", list("abba"))}, ) arr = ds["foo"] ds ``` ```none Size: 144B Dimensions: (x: 4, y: 3) Coordinates: * x (x) int64 32B 10 20 30 40 letters (x)
<xarray.Dataset> Size: 144B
Dimensions:  (x: 4, y: 3)
Coordinates:
  \* x        (x) int64 32B 10 20 30 40
    letters  (x) <U1 16B 'a' 'b' 'b' 'a'
Dimensions without coordinates: y
Data variables:
    foo      (x, y) float64 96B 0.127 0.9667 0.2605 0.8972 ... 0.543 0.373 0.448
If we groupby the name of a variable or coordinate in a dataset (we can also use a DataArray directly), we get back a `GroupBy` object: ```ipython3 ds.groupby("letters") ``` ```none ``` This object works very similarly to a pandas GroupBy object. You can view the group indices with the `groups` attribute: ```ipython3 ds.groupby("letters").groups ``` ```none {'a': [0, 3], 'b': [1, 2]} ``` You can also iterate over groups in `(label, group)` pairs: ```ipython3 list(ds.groupby("letters")) ``` ```none [('a', Size: 72B Dimensions: (x: 2, y: 3) Coordinates: * x (x) int64 16B 10 40 letters (x) Size: 72B Dimensions: (x: 2, y: 3) Coordinates: * x (x) int64 16B 20 30 letters (x) Size: 72B Dimensions: (x: 2, y: 3) Coordinates: * x (x) int64 16B 20 30 letters (x)
<xarray.Dataset> Size: 72B
Dimensions:  (x: 2, y: 3)
Coordinates:
  \* x        (x) int64 16B 20 30
    letters  (x) <U1 8B 'b' 'b'
Dimensions without coordinates: y
Data variables:
    foo      (x, y) float64 48B 0.8972 0.3767 0.3362 0.4514 0.8403 0.1231
To group by multiple variables, see [this section](#groupby-multiple). ## Binning Sometimes you don’t want to use all the unique values to determine the groups but instead want to “bin” the data into coarser groups. You could always create a customized coordinate, but xarray facilitates this via the [`Dataset.groupby_bins()`](../generated/xarray.Dataset.groupby_bins.md#xarray.Dataset.groupby_bins) method. ```ipython3 x_bins = [0, 25, 50] ds.groupby_bins("x", x_bins).groups ``` ```none {Interval(0, 25, closed='right'): [0, 1], Interval(25, 50, closed='right'): [2, 3]} ``` The binning is implemented via [`pandas.cut()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.cut.html#pandas.cut), whose documentation details how the bins are assigned. As seen in the example above, by default, the bins are labeled with strings using set notation to precisely identify the bin limits. To override this behavior, you can specify the bin labels explicitly. Here we choose `float` labels which identify the bin centers: ```ipython3 x_bin_labels = [12.5, 37.5] ds.groupby_bins("x", x_bins, labels=x_bin_labels).groups ``` ```none {np.float64(12.5): [0, 1], np.float64(37.5): [2, 3]} ``` ## Apply To apply a function to each group, you can use the flexible [`core.groupby.DatasetGroupBy.map()`](../generated/xarray.core.groupby.DatasetGroupBy.map.md#xarray.core.groupby.DatasetGroupBy.map) method. The resulting objects are automatically concatenated back together along the group axis: ```ipython3 def standardize(x): return (x - x.mean()) / x.std() arr.groupby("letters").map(standardize) ``` ```none Size: 96B array([[-1.22977845, 1.93741005, -0.72624738], [ 1.41979574, -0.46019243, -0.60657867], [-0.19064205, 1.21397989, -1.3763625 ], [ 0.33941723, -0.30180645, -0.01899499]]) Coordinates: * x (x) int64 32B 10 20 30 40 letters (x)
<xarray.DataArray 'foo' (x: 4, y: 3)> Size: 96B
array([[-1.22977845,  1.93741005, -0.72624738],
       [ 1.41979574, -0.46019243, -0.60657867],
       [-0.19064205,  1.21397989, -1.3763625 ],
       [ 0.33941723, -0.30180645, -0.01899499]])
Coordinates:
  \* x        (x) int64 32B 10 20 30 40
    letters  (x) <U1 16B 'a' 'b' 'b' 'a'
Dimensions without coordinates: y
GroupBy objects also have a [`core.groupby.DatasetGroupBy.reduce()`](../generated/xarray.core.groupby.DatasetGroupBy.reduce.md#xarray.core.groupby.DatasetGroupBy.reduce) method and methods like [`core.groupby.DatasetGroupBy.mean()`](../generated/xarray.core.groupby.DatasetGroupBy.mean.md#xarray.core.groupby.DatasetGroupBy.mean) as shortcuts for applying an aggregation function: ```ipython3 arr.groupby("letters").mean(dim="x") ``` ```none Size: 48B array([[0.33499802, 0.66986503, 0.35423642], [0.6743065 , 0.6085024 , 0.22966194]]) Coordinates: * letters (letters) object 16B 'a' 'b' Dimensions without coordinates: y ```
<xarray.DataArray 'foo' (letters: 2, y: 3)> Size: 48B
array([[0.33499802, 0.66986503, 0.35423642],
       [0.6743065 , 0.6085024 , 0.22966194]])
Coordinates:
  \* letters  (letters) object 16B 'a' 'b'
Dimensions without coordinates: y
Using a groupby is thus also a convenient shortcut for aggregating over all dimensions *other than* the provided one: ```ipython3 ds.groupby("x").std(...) ``` ```none Size: 64B Dimensions: (x: 4) Coordinates: * x (x) int64 32B 10 20 30 40 Data variables: foo (x) float64 32B 0.3684 0.2554 0.2931 0.06957 ```
<xarray.Dataset> Size: 64B
Dimensions:  (x: 4)
Coordinates:
  \* x        (x) int64 32B 10 20 30 40
Data variables:
    foo      (x) float64 32B 0.3684 0.2554 0.2931 0.06957
#### NOTE We use an ellipsis (…) here to indicate we want to reduce over all other dimensions ## First and last There are two special aggregation operations that are currently only found on groupby objects: first and last. These provide the first or last example of values for group along the grouped dimension: ```ipython3 ds.groupby("letters").first(...) ``` ```none Size: 64B Dimensions: (letters: 2, y: 3) Coordinates: * letters (letters) object 16B 'a' 'b' Dimensions without coordinates: y Data variables: foo (letters, y) float64 48B 0.127 0.9667 0.2605 0.8972 0.3767 0.3362 ```
<xarray.Dataset> Size: 64B
Dimensions:  (letters: 2, y: 3)
Coordinates:
  \* letters  (letters) object 16B 'a' 'b'
Dimensions without coordinates: y
Data variables:
    foo      (letters, y) float64 48B 0.127 0.9667 0.2605 0.8972 0.3767 0.3362
By default, they skip missing values (control this with `skipna`). ## Grouped arithmetic GroupBy objects also support a limited set of binary arithmetic operations, as a shortcut for mapping over all unique labels. Binary arithmetic is supported for `(GroupBy, Dataset)` and `(GroupBy, DataArray)` pairs, as long as the dataset or data array uses the unique grouped values as one of its index coordinates. For example: ```ipython3 alt = arr.groupby("letters").mean(...) alt ``` ```none Size: 16B array([0.45303315, 0.50415695]) Coordinates: * letters (letters) object 16B 'a' 'b' ```
<xarray.DataArray 'foo' (letters: 2)> Size: 16B
array([0.45303315, 0.50415695])
Coordinates:
  \* letters  (letters) object 16B 'a' 'b'
```ipython3 ds.groupby("letters") - alt ``` ```none Size: 144B Dimensions: (x: 4, y: 3) Coordinates: * x (x) int64 32B 10 20 30 40 letters (x)
<xarray.Dataset> Size: 144B
Dimensions:  (x: 4, y: 3)
Coordinates:
  \* x        (x) int64 32B 10 20 30 40
    letters  (x) <U1 16B 'a' 'b' 'b' 'a'
Dimensions without coordinates: y
Data variables:
    foo      (x, y) float64 96B -0.3261 0.5137 -0.1926 ... -0.08002 -0.005036
This last line is roughly equivalent to the following: ```default results = [] for label, group in ds.groupby('letters'): results.append(group - alt.sel(letters=label)) xr.concat(results, dim='x') ``` ## Multidimensional Grouping Many datasets have a multidimensional coordinate variable (e.g. longitude) which is different from the logical grid dimensions (e.g. nx, ny). Such variables are valid under the [CF conventions](https://cfconventions.org/cf-conventions/v1.6.0/cf-conventions.html#_two_dimensional_latitude_longitude_coordinate_variables). Xarray supports groupby operations over multidimensional coordinate variables: ```ipython3 da = xr.DataArray( [[0, 1], [2, 3]], coords={ "lon": (["ny", "nx"], [[30, 40], [40, 50]]), "lat": (["ny", "nx"], [[10, 10], [20, 20]]), }, dims=["ny", "nx"], ) da ``` ```none Size: 32B array([[0, 1], [2, 3]]) Coordinates: lon (ny, nx) int64 32B 30 40 40 50 lat (ny, nx) int64 32B 10 10 20 20 Dimensions without coordinates: ny, nx ```
<xarray.DataArray (ny: 2, nx: 2)> Size: 32B
array([[0, 1],
       [2, 3]])
Coordinates:
    lon      (ny, nx) int64 32B 30 40 40 50
    lat      (ny, nx) int64 32B 10 10 20 20
Dimensions without coordinates: ny, nx
```ipython3 da.groupby("lon").sum(...) ``` ```none Size: 24B array([0, 3, 3]) Coordinates: * lon (lon) int64 24B 30 40 50 ```
<xarray.DataArray (lon: 3)> Size: 24B
array([0, 3, 3])
Coordinates:
  \* lon      (lon) int64 24B 30 40 50
```ipython3 da.groupby("lon").map(lambda x: x - x.mean(), shortcut=False) ``` ```none Size: 32B array([[ 0. , -0.5], [ 0.5, 0. ]]) Coordinates: lon (ny, nx) int64 32B 30 40 40 50 lat (ny, nx) int64 32B 10 10 20 20 Dimensions without coordinates: ny, nx ```
<xarray.DataArray (ny: 2, nx: 2)> Size: 32B
array([[ 0. , -0.5],
       [ 0.5,  0. ]])
Coordinates:
    lon      (ny, nx) int64 32B 30 40 40 50
    lat      (ny, nx) int64 32B 10 10 20 20
Dimensions without coordinates: ny, nx
Because multidimensional groups have the ability to generate a very large number of bins, coarse-binning via [`Dataset.groupby_bins()`](../generated/xarray.Dataset.groupby_bins.md#xarray.Dataset.groupby_bins) may be desirable: ```ipython3 da.groupby_bins("lon", [0, 45, 50]).sum() ``` ```none Size: 16B array([3, 3]) Coordinates: * lon_bins (lon_bins) interval[int64, right] 32B (0, 45] (45, 50] ```
<xarray.DataArray (lon_bins: 2)> Size: 16B
array([3, 3])
Coordinates:
  \* lon_bins  (lon_bins) interval[int64, right] 32B (0, 45] (45, 50]
These methods group by `lon` values. It is also possible to groupby each cell in a grid, regardless of value, by stacking multiple dimensions, applying your function, and then unstacking the result: ```ipython3 stacked = da.stack(gridcell=["ny", "nx"]) stacked.groupby("gridcell").sum(...).unstack("gridcell") ``` ```none Size: 32B array([[0, 1], [2, 3]]) Coordinates: * ny (ny) int64 16B 0 1 * nx (nx) int64 16B 0 1 ```
<xarray.DataArray (ny: 2, nx: 2)> Size: 32B
array([[0, 1],
       [2, 3]])
Coordinates:
  \* ny       (ny) int64 16B 0 1
  \* nx       (nx) int64 16B 0 1
Alternatively, you can groupby both `lat` and `lon` at the [same time](#groupby-multiple). ## Grouper Objects Both `groupby_bins` and `resample` are specializations of the core `groupby` operation for binning, and time resampling. Many problems demand more complex GroupBy application: for example, grouping by multiple variables with a combination of categorical grouping, binning, and resampling; or more specializations like spatial resampling; or more complex time grouping like special handling of seasons, or the ability to specify custom seasons. To handle these use-cases and more, Xarray is evolving to providing an extension point using `Grouper` objects. For now Xarray provides three specialized Grouper objects: 1. [`groupers.UniqueGrouper`](../generated/xarray.groupers.UniqueGrouper.md#xarray.groupers.UniqueGrouper) for categorical grouping 2. [`groupers.BinGrouper`](../generated/xarray.groupers.BinGrouper.md#xarray.groupers.BinGrouper) for binned grouping 3. [`groupers.TimeResampler`](../generated/xarray.groupers.TimeResampler.md#xarray.groupers.TimeResampler) for resampling along a datetime coordinate These provide functionality identical to the existing `groupby`, `groupby_bins`, and `resample` methods. That is, ```python ds.groupby("x") ``` is identical to ```python from xarray.groupers import UniqueGrouper ds.groupby(x=UniqueGrouper()) ``` Similarly, ```python ds.groupby_bins("x", bins=bins) ``` is identical to ```python from xarray.groupers import BinGrouper ds.groupby(x=BinGrouper(bins)) ``` and ```python ds.resample(time="ME") ``` is identical to ```python from xarray.groupers import TimeResampler ds.resample(time=TimeResampler("ME")) ``` The [`groupers.UniqueGrouper`](../generated/xarray.groupers.UniqueGrouper.md#xarray.groupers.UniqueGrouper) accepts an optional `labels` kwarg that is not present in [`DataArray.groupby()`](../generated/xarray.DataArray.groupby.md#xarray.DataArray.groupby) or [`Dataset.groupby()`](../generated/xarray.Dataset.groupby.md#xarray.Dataset.groupby). Specifying `labels` is required when grouping by a lazy array type (e.g. dask or cubed). The `labels` are used to construct the output coordinate (say for a reduction), and aggregations will only be run over the specified labels. You may use `labels` to also specify the ordering of groups to be used during iteration. The order will be preserved in the output. ## Grouping by multiple variables Use grouper objects to group by multiple dimensions: ```ipython3 from xarray.groupers import UniqueGrouper da.groupby(["lat", "lon"]).sum() ``` ```none Size: 48B array([[ 0., 1., nan], [nan, 2., 3.]]) Coordinates: * lat (lat) int64 16B 10 20 * lon (lon) int64 24B 30 40 50 ```
<xarray.DataArray (lat: 2, lon: 3)> Size: 48B
array([[ 0.,  1., nan],
       [nan,  2.,  3.]])
Coordinates:
  \* lat      (lat) int64 16B 10 20
  \* lon      (lon) int64 24B 30 40 50
The above is sugar for using `UniqueGrouper` objects directly: ```ipython3 da.groupby(lat=UniqueGrouper(), lon=UniqueGrouper()).sum() ``` ```none Size: 48B array([[ 0., 1., nan], [nan, 2., 3.]]) Coordinates: * lat (lat) int64 16B 10 20 * lon (lon) int64 24B 30 40 50 ```
<xarray.DataArray (lat: 2, lon: 3)> Size: 48B
array([[ 0.,  1., nan],
       [nan,  2.,  3.]])
Coordinates:
  \* lat      (lat) int64 16B 10 20
  \* lon      (lon) int64 24B 30 40 50
Different groupers can be combined to construct sophisticated GroupBy operations. ```ipython3 from xarray.groupers import BinGrouper ds.groupby(x=BinGrouper(bins=[5, 15, 25]), letters=UniqueGrouper()).sum() ``` ```none Size: 144B Dimensions: (y: 3, x_bins: 2, letters: 2) Coordinates: * x_bins (x_bins) interval[int64, right] 32B (5, 15] (15, 25] * letters (letters) object 16B 'a' 'b' Dimensions without coordinates: y Data variables: foo (y, x_bins, letters) float64 96B 0.127 nan nan ... nan nan 0.3362 ```
<xarray.Dataset> Size: 144B
Dimensions:  (y: 3, x_bins: 2, letters: 2)
Coordinates:
  \* x_bins   (x_bins) interval[int64, right] 32B (5, 15] (15, 25]
  \* letters  (letters) object 16B 'a' 'b'
Dimensions without coordinates: y
Data variables:
    foo      (y, x_bins, letters) float64 96B 0.127 nan nan ... nan nan 0.3362
## Time Grouping and Resampling #### SEE ALSO See [Resampling and grouped operations](time-series.md#resampling). ## Shuffling Shuffling is a generalization of sorting a DataArray or Dataset by another DataArray, named `label` for example, that follows from the idea of grouping by `label`. Shuffling reorders the DataArray or the DataArrays in a Dataset such that all members of a group occur sequentially. For example, Shuffle the object using either `DatasetGroupBy` or `DataArrayGroupBy` as appropriate. ```ipython3 da = xr.DataArray( dims="x", data=[1, 2, 3, 4, 5, 6], coords={"label": ("x", "a b c a b c".split(" "))}, ) da.groupby("label").shuffle_to_chunks() ``` ```none Size: 48B array([1, 4, 2, 5, 3, 6]) Coordinates: label (x)
<xarray.DataArray (x: 6)> Size: 48B
array([1, 4, 2, 5, 3, 6])
Coordinates:
    label    (x) <U1 24B 'a' 'a' 'b' 'b' 'c' 'c'
Dimensions without coordinates: x
For chunked array types (e.g. dask or cubed), shuffle may result in a more optimized communication pattern when compared to direct indexing by the appropriate indexer. Shuffling also makes GroupBy operations on chunked arrays an embarrassingly parallel problem, and may significantly improve workloads that use `DatasetGroupBy.map()` or `DataArrayGroupBy.map()`. # groupby.html.md # GroupBy objects ## Dataset | [`DatasetGroupBy`](../generated/xarray.core.groupby.DatasetGroupBy.md#xarray.core.groupby.DatasetGroupBy)(obj, groupers[, ...]) | | |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------| | [`DatasetGroupBy.map`](../generated/xarray.core.groupby.DatasetGroupBy.map.md#xarray.core.groupby.DatasetGroupBy.map)(func[, args, shortcut]) | Apply a function to each Dataset in the group and concatenate them together into a new Dataset. | | [`DatasetGroupBy.reduce`](../generated/xarray.core.groupby.DatasetGroupBy.reduce.md#xarray.core.groupby.DatasetGroupBy.reduce)(func[, dim, axis, ...]) | Reduce the items in this group by applying func along some dimension(s). | | [`DatasetGroupBy.assign`](../generated/xarray.core.groupby.DatasetGroupBy.assign.md#xarray.core.groupby.DatasetGroupBy.assign)(\*\*kwargs) | Assign data variables by group. | | [`DatasetGroupBy.assign_coords`](../generated/xarray.core.groupby.DatasetGroupBy.assign_coords.md#xarray.core.groupby.DatasetGroupBy.assign_coords)([coords]) | Assign coordinates by group. | | [`DatasetGroupBy.first`](../generated/xarray.core.groupby.DatasetGroupBy.first.md#xarray.core.groupby.DatasetGroupBy.first)([skipna, keep_attrs]) | Return the first element of each group along the group dimension | | [`DatasetGroupBy.last`](../generated/xarray.core.groupby.DatasetGroupBy.last.md#xarray.core.groupby.DatasetGroupBy.last)([skipna, keep_attrs]) | Return the last element of each group along the group dimension | | [`DatasetGroupBy.fillna`](../generated/xarray.core.groupby.DatasetGroupBy.fillna.md#xarray.core.groupby.DatasetGroupBy.fillna)(value) | Fill missing values in this object by group. | | [`DatasetGroupBy.quantile`](../generated/xarray.core.groupby.DatasetGroupBy.quantile.md#xarray.core.groupby.DatasetGroupBy.quantile)(q[, dim, method, ...]) | Compute the qth quantile over each array in the groups and concatenate them together into a new array. | | [`DatasetGroupBy.where`](../generated/xarray.core.groupby.DatasetGroupBy.where.md#xarray.core.groupby.DatasetGroupBy.where)(cond[, other]) | Return elements from self or other depending on cond. | | [`DatasetGroupBy.all`](../generated/xarray.core.groupby.DatasetGroupBy.all.md#xarray.core.groupby.DatasetGroupBy.all)([dim, keep_attrs]) | Reduce this Dataset's data by applying `all` along some dimension(s). | | [`DatasetGroupBy.any`](../generated/xarray.core.groupby.DatasetGroupBy.any.md#xarray.core.groupby.DatasetGroupBy.any)([dim, keep_attrs]) | Reduce this Dataset's data by applying `any` along some dimension(s). | | [`DatasetGroupBy.count`](../generated/xarray.core.groupby.DatasetGroupBy.count.md#xarray.core.groupby.DatasetGroupBy.count)([dim, keep_attrs]) | Reduce this Dataset's data by applying `count` along some dimension(s). | | [`DatasetGroupBy.cumsum`](../generated/xarray.core.groupby.DatasetGroupBy.cumsum.md#xarray.core.groupby.DatasetGroupBy.cumsum)([dim, skipna, keep_attrs]) | Reduce this Dataset's data by applying `cumsum` along some dimension(s). | | [`DatasetGroupBy.cumprod`](../generated/xarray.core.groupby.DatasetGroupBy.cumprod.md#xarray.core.groupby.DatasetGroupBy.cumprod)([dim, skipna, keep_attrs]) | Reduce this Dataset's data by applying `cumprod` along some dimension(s). | | [`DatasetGroupBy.max`](../generated/xarray.core.groupby.DatasetGroupBy.max.md#xarray.core.groupby.DatasetGroupBy.max)([dim, skipna, keep_attrs]) | Reduce this Dataset's data by applying `max` along some dimension(s). | | [`DatasetGroupBy.mean`](../generated/xarray.core.groupby.DatasetGroupBy.mean.md#xarray.core.groupby.DatasetGroupBy.mean)([dim, skipna, keep_attrs]) | Reduce this Dataset's data by applying `mean` along some dimension(s). | | [`DatasetGroupBy.median`](../generated/xarray.core.groupby.DatasetGroupBy.median.md#xarray.core.groupby.DatasetGroupBy.median)([dim, skipna, keep_attrs]) | Reduce this Dataset's data by applying `median` along some dimension(s). | | [`DatasetGroupBy.min`](../generated/xarray.core.groupby.DatasetGroupBy.min.md#xarray.core.groupby.DatasetGroupBy.min)([dim, skipna, keep_attrs]) | Reduce this Dataset's data by applying `min` along some dimension(s). | | [`DatasetGroupBy.prod`](../generated/xarray.core.groupby.DatasetGroupBy.prod.md#xarray.core.groupby.DatasetGroupBy.prod)([dim, skipna, ...]) | Reduce this Dataset's data by applying `prod` along some dimension(s). | | [`DatasetGroupBy.std`](../generated/xarray.core.groupby.DatasetGroupBy.std.md#xarray.core.groupby.DatasetGroupBy.std)([dim, skipna, ddof, ...]) | Reduce this Dataset's data by applying `std` along some dimension(s). | | [`DatasetGroupBy.sum`](../generated/xarray.core.groupby.DatasetGroupBy.sum.md#xarray.core.groupby.DatasetGroupBy.sum)([dim, skipna, min_count, ...]) | Reduce this Dataset's data by applying `sum` along some dimension(s). | | [`DatasetGroupBy.var`](../generated/xarray.core.groupby.DatasetGroupBy.var.md#xarray.core.groupby.DatasetGroupBy.var)([dim, skipna, ddof, ...]) | Reduce this Dataset's data by applying `var` along some dimension(s). | | [`DatasetGroupBy.dims`](../generated/xarray.core.groupby.DatasetGroupBy.dims.md#xarray.core.groupby.DatasetGroupBy.dims) | | | [`DatasetGroupBy.groups`](../generated/xarray.core.groupby.DatasetGroupBy.groups.md#xarray.core.groupby.DatasetGroupBy.groups) | Mapping from group labels to indices. | | [`DatasetGroupBy.shuffle_to_chunks`](../generated/xarray.core.groupby.DatasetGroupBy.shuffle_to_chunks.md#xarray.core.groupby.DatasetGroupBy.shuffle_to_chunks)([chunks]) | Sort or "shuffle" the underlying object. | ## DataArray | [`DataArrayGroupBy`](../generated/xarray.core.groupby.DataArrayGroupBy.md#xarray.core.groupby.DataArrayGroupBy)(obj, groupers[, ...]) | | |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------| | [`DataArrayGroupBy.map`](../generated/xarray.core.groupby.DataArrayGroupBy.map.md#xarray.core.groupby.DataArrayGroupBy.map)(func[, args, shortcut]) | Apply a function to each array in the group and concatenate them together into a new array. | | [`DataArrayGroupBy.reduce`](../generated/xarray.core.groupby.DataArrayGroupBy.reduce.md#xarray.core.groupby.DataArrayGroupBy.reduce)(func[, dim, axis, ...]) | Reduce the items in this group by applying func along some dimension(s). | | [`DataArrayGroupBy.assign_coords`](../generated/xarray.core.groupby.DataArrayGroupBy.assign_coords.md#xarray.core.groupby.DataArrayGroupBy.assign_coords)([coords]) | Assign coordinates by group. | | [`DataArrayGroupBy.first`](../generated/xarray.core.groupby.DataArrayGroupBy.first.md#xarray.core.groupby.DataArrayGroupBy.first)([skipna, keep_attrs]) | Return the first element of each group along the group dimension | | [`DataArrayGroupBy.last`](../generated/xarray.core.groupby.DataArrayGroupBy.last.md#xarray.core.groupby.DataArrayGroupBy.last)([skipna, keep_attrs]) | Return the last element of each group along the group dimension | | [`DataArrayGroupBy.fillna`](../generated/xarray.core.groupby.DataArrayGroupBy.fillna.md#xarray.core.groupby.DataArrayGroupBy.fillna)(value) | Fill missing values in this object by group. | | [`DataArrayGroupBy.quantile`](../generated/xarray.core.groupby.DataArrayGroupBy.quantile.md#xarray.core.groupby.DataArrayGroupBy.quantile)(q[, dim, method, ...]) | Compute the qth quantile over each array in the groups and concatenate them together into a new array. | | [`DataArrayGroupBy.where`](../generated/xarray.core.groupby.DataArrayGroupBy.where.md#xarray.core.groupby.DataArrayGroupBy.where)(cond[, other]) | Return elements from self or other depending on cond. | | [`DataArrayGroupBy.all`](../generated/xarray.core.groupby.DataArrayGroupBy.all.md#xarray.core.groupby.DataArrayGroupBy.all)([dim, keep_attrs]) | Reduce this DataArray's data by applying `all` along some dimension(s). | | [`DataArrayGroupBy.any`](../generated/xarray.core.groupby.DataArrayGroupBy.any.md#xarray.core.groupby.DataArrayGroupBy.any)([dim, keep_attrs]) | Reduce this DataArray's data by applying `any` along some dimension(s). | | [`DataArrayGroupBy.count`](../generated/xarray.core.groupby.DataArrayGroupBy.count.md#xarray.core.groupby.DataArrayGroupBy.count)([dim, keep_attrs]) | Reduce this DataArray's data by applying `count` along some dimension(s). | | [`DataArrayGroupBy.cumsum`](../generated/xarray.core.groupby.DataArrayGroupBy.cumsum.md#xarray.core.groupby.DataArrayGroupBy.cumsum)([dim, skipna, ...]) | Reduce this DataArray's data by applying `cumsum` along some dimension(s). | | [`DataArrayGroupBy.cumprod`](../generated/xarray.core.groupby.DataArrayGroupBy.cumprod.md#xarray.core.groupby.DataArrayGroupBy.cumprod)([dim, skipna, ...]) | Reduce this DataArray's data by applying `cumprod` along some dimension(s). | | [`DataArrayGroupBy.max`](../generated/xarray.core.groupby.DataArrayGroupBy.max.md#xarray.core.groupby.DataArrayGroupBy.max)([dim, skipna, keep_attrs]) | Reduce this DataArray's data by applying `max` along some dimension(s). | | [`DataArrayGroupBy.mean`](../generated/xarray.core.groupby.DataArrayGroupBy.mean.md#xarray.core.groupby.DataArrayGroupBy.mean)([dim, skipna, keep_attrs]) | Reduce this DataArray's data by applying `mean` along some dimension(s). | | [`DataArrayGroupBy.median`](../generated/xarray.core.groupby.DataArrayGroupBy.median.md#xarray.core.groupby.DataArrayGroupBy.median)([dim, skipna, ...]) | Reduce this DataArray's data by applying `median` along some dimension(s). | | [`DataArrayGroupBy.min`](../generated/xarray.core.groupby.DataArrayGroupBy.min.md#xarray.core.groupby.DataArrayGroupBy.min)([dim, skipna, keep_attrs]) | Reduce this DataArray's data by applying `min` along some dimension(s). | | [`DataArrayGroupBy.prod`](../generated/xarray.core.groupby.DataArrayGroupBy.prod.md#xarray.core.groupby.DataArrayGroupBy.prod)([dim, skipna, ...]) | Reduce this DataArray's data by applying `prod` along some dimension(s). | | [`DataArrayGroupBy.std`](../generated/xarray.core.groupby.DataArrayGroupBy.std.md#xarray.core.groupby.DataArrayGroupBy.std)([dim, skipna, ddof, ...]) | Reduce this DataArray's data by applying `std` along some dimension(s). | | [`DataArrayGroupBy.sum`](../generated/xarray.core.groupby.DataArrayGroupBy.sum.md#xarray.core.groupby.DataArrayGroupBy.sum)([dim, skipna, ...]) | Reduce this DataArray's data by applying `sum` along some dimension(s). | | [`DataArrayGroupBy.var`](../generated/xarray.core.groupby.DataArrayGroupBy.var.md#xarray.core.groupby.DataArrayGroupBy.var)([dim, skipna, ddof, ...]) | Reduce this DataArray's data by applying `var` along some dimension(s). | | [`DataArrayGroupBy.dims`](../generated/xarray.core.groupby.DataArrayGroupBy.dims.md#xarray.core.groupby.DataArrayGroupBy.dims) | | | [`DataArrayGroupBy.groups`](../generated/xarray.core.groupby.DataArrayGroupBy.groups.md#xarray.core.groupby.DataArrayGroupBy.groups) | Mapping from group labels to indices. | | [`DataArrayGroupBy.shuffle_to_chunks`](../generated/xarray.core.groupby.DataArrayGroupBy.shuffle_to_chunks.md#xarray.core.groupby.DataArrayGroupBy.shuffle_to_chunks)([chunks]) | Sort or "shuffle" the underlying object. | ## Grouper Objects | [`groupers.BinGrouper`](../generated/xarray.groupers.BinGrouper.md#xarray.groupers.BinGrouper)(bins[, right, labels, ...]) | Grouper object for binning numeric data. | |------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------| | [`groupers.SeasonGrouper`](../generated/xarray.groupers.SeasonGrouper.md#xarray.groupers.SeasonGrouper)(seasons) | Allows grouping using a custom definition of seasons. | | [`groupers.UniqueGrouper`](../generated/xarray.groupers.UniqueGrouper.md#xarray.groupers.UniqueGrouper)([labels]) | Grouper object for grouping by a categorical variable. | ## Resampler Objects | [`groupers.SeasonResampler`](../generated/xarray.groupers.SeasonResampler.md#xarray.groupers.SeasonResampler)(seasons, \*[, ...]) | Allows grouping using a custom definition of seasons. | |-----------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------| | [`groupers.SeasonResampler.compute_chunks`](../generated/xarray.groupers.SeasonResampler.compute_chunks.md#xarray.groupers.SeasonResampler.compute_chunks)(...) | Compute chunk sizes for this season resampler. | | [`groupers.TimeResampler`](../generated/xarray.groupers.TimeResampler.md#xarray.groupers.TimeResampler)(freq[, closed, ...]) | Grouper object specialized to resampling the time coordinate. | | [`groupers.TimeResampler.compute_chunks`](../generated/xarray.groupers.TimeResampler.compute_chunks.md#xarray.groupers.TimeResampler.compute_chunks)(...) | Compute chunk sizes for this time resampler. | # help-diagram.html.md # Getting Help Navigating the wealth of resources available for Xarray can be overwhelming. We’ve created this flow chart to help guide you towards the best way to get help, depending on what you’re working towards. Also be sure to check out our [Frequently Asked Questions](faq.md#faq). and [How do I …](howdoi.md#howdoi) pages for solutions to common questions. A major strength of Xarray is in the user community. Sometimes you might not yet have a concrete question but would simply like to connect with other Xarray users. We have a few accounts on different social platforms for that! [Social Media](socials.md#socials). We look forward to hearing from you! ## Help Flowchart ## Flowchart links - [Xarray Tutorials](https://tutorial.xarray.dev/) - [Xarray Docs](https://docs.xarray.dev) - [Stack Exchange](https://stackoverflow.com/questions/tagged/python-xarray) - [Xarray Discussions](https://github.com/pydata/xarray/discussions) - [OSSci Zulip](https://ossci.zulipchat.com/#narrow/channel/582428-Xarray) - [Xarray Office Hours](https://github.com/pydata/xarray/discussions/categories/office-hours) - [Pangeo Discourse](https://discourse.pangeo.io/) - [Xarray Issues](https://github.com/pydata/xarray/issues) - [Contributing to xarray](../contribute/contributing.md#contributing) - [Developers meeting](../contribute/developers-meeting.md#developers-meeting) # hierarchical-data.html.md # Hierarchical data ## Why Hierarchical Data? Many real-world datasets are composed of multiple differing components, and it can often be useful to think of these in terms of a hierarchy of related groups of data. Examples of data which one might want organise in a grouped or hierarchical manner include: - Simulation data at multiple resolutions, - Observational data about the same system but from multiple different types of sensors, - Mixed experimental and theoretical data, - A systematic study recording the same experiment but with different parameters, - Heterogeneous data, such as demographic and metereological data, or even any combination of the above. Often datasets like this cannot easily fit into a single [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) object, or are more usefully thought of as groups of related [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) objects. For this purpose we provide the [`xarray.DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) class. This page explains in detail how to understand and use the different features of the [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) class for your own hierarchical data needs. ## Node Relationships ### Creating a Family Tree The three main ways of creating a [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) object are described briefly in [Creating a DataTree](data-structures.md#creating-a-datatree). Here we go into more detail about how to create a tree node-by-node, using a famous family tree from the Simpsons cartoon as an example. Let’s start by defining nodes representing the two siblings, Bart and Lisa Simpson: ```ipython3 bart = xr.DataTree(name="Bart") lisa = xr.DataTree(name="Lisa") ``` Each of these node objects knows their own [`name`](../generated/xarray.DataTree.name.md#xarray.DataTree.name), but they currently have no relationship to one another. We can connect them by creating another node representing a common parent, Homer Simpson: ```ipython3 homer = xr.DataTree(name="Homer", children={"Bart": bart, "Lisa": lisa}) ``` Here we set the children of Homer in the node’s constructor. We now have a small family tree where we can see how these individual Simpson family members are related to one another: ```ipython3 print(homer) ``` ```none Group: / ├── Group: /Bart └── Group: /Lisa ``` #### NOTE We use `print()` above to show the compact tree hierarchy. [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) objects also have an interactive HTML representation that is enabled by default in editors such as JupyterLab and VSCode. The HTML representation is especially helpful for larger trees and exploring new datasets, as it allows you to expand and collapse nodes. If you prefer the text representations you can also set `xr.set_options(display_style="text")`. The nodes representing Bart and Lisa are now connected - we can confirm their sibling rivalry by examining the [`siblings`](../generated/xarray.DataTree.siblings.md#xarray.DataTree.siblings) property: ```ipython3 list(homer["Bart"].siblings) ``` ```none ['Lisa'] ``` But oops, we forgot Homer’s third daughter, Maggie! Let’s add her by updating Homer’s [`children`](../generated/xarray.DataTree.children.md#xarray.DataTree.children) property to include her: ```ipython3 maggie = xr.DataTree(name="Maggie") homer.children = {"Bart": bart, "Lisa": lisa, "Maggie": maggie} print(homer) ``` ```none Group: / ├── Group: /Bart ├── Group: /Lisa └── Group: /Maggie ``` Let’s check that Maggie knows who her Dad is: ```ipython3 maggie.parent.name ``` ```none 'Homer' ``` That’s good - updating the properties of our nodes does not break the internal consistency of our tree, as changes of parentage are automatically reflected on both nodes. > These children obviously have another parent, Marge Simpson, but [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) nodes can only have a maximum of one parent. > Genealogical [family trees are not even technically trees](https://en.wikipedia.org/wiki/Family_tree#Graph_theory) in the mathematical sense - > the fact that distant relatives can mate makes them directed acyclic graphs. > Trees of [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) objects cannot represent this. Homer is currently listed as having no parent (the so-called “root node” of this tree), but we can update his [`parent`](../generated/xarray.DataTree.parent.md#xarray.DataTree.parent) property: ```ipython3 abe = xr.DataTree(name="Abe") abe.children = {"Homer": homer} ``` Abe is now the “root” of this tree, which we can see by examining the [`root`](../generated/xarray.DataTree.root.md#xarray.DataTree.root) property of any node in the tree ```ipython3 maggie.root.name ``` ```none 'Abe' ``` We can see the whole tree by printing Abe’s node or just part of the tree by printing Homer’s node: ```ipython3 print(abe) ``` ```none Group: / └── Group: /Homer ├── Group: /Homer/Bart ├── Group: /Homer/Lisa └── Group: /Homer/Maggie ``` ```ipython3 print(abe["Homer"]) ``` ```none Group: /Homer ├── Group: /Homer/Bart ├── Group: /Homer/Lisa └── Group: /Homer/Maggie ``` In episode 28, Abe Simpson reveals that he had another son, Herbert “Herb” Simpson. We can add Herbert to the family tree without displacing Homer by [`assign()`](../generated/xarray.DataTree.assign.md#xarray.DataTree.assign)-ing another child to Abe: ```ipython3 herbert = xr.DataTree(name="Herb") abe = abe.assign({"Herbert": herbert}) print(abe) ``` ```none Group: / ├── Group: /Homer │ ├── Group: /Homer/Bart │ ├── Group: /Homer/Lisa │ └── Group: /Homer/Maggie └── Group: /Herbert ``` ```ipython3 print(abe["Herbert"].name) print(herbert.name) ``` ```none Herbert Herb ``` #### NOTE This example shows a subtlety - the returned tree has Homer’s brother listed as `"Herbert"`, but the original node was named “Herb”. Not only are names overridden when stored as keys like this, but the new node is a copy, so that the original node that was referenced is unchanged (i.e. `herbert.name == "Herb"` still). In other words, nodes are copied into trees, not inserted into them. This is intentional, and mirrors the behaviour when storing named [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) objects inside datasets. Certain manipulations of our tree are forbidden, if they would create an inconsistent result. In episode 51 of the show Futurama, Philip J. Fry travels back in time and accidentally becomes his own Grandfather. If we try similar time-travelling hijinks with Homer, we get a [`InvalidTreeError`](../generated/xarray.InvalidTreeError.md#xarray.InvalidTreeError) raised: ```ipython3 abe["Homer"].children = {"Abe": abe} ``` ```ipythontb InvalidTreeError: Cannot set parent, as intended parent is already a descendant of this node. ``` ### Ancestry in an Evolutionary Tree Let’s use a different example of a tree to discuss more complex relationships between nodes - the phylogenetic tree, or tree of life. ```ipython3 vertebrates = xr.DataTree.from_dict( { "/Sharks": None, "/Bony Skeleton/Ray-finned Fish": None, "/Bony Skeleton/Four Limbs/Amphibians": None, "/Bony Skeleton/Four Limbs/Amniotic Egg/Hair/Primates": None, "/Bony Skeleton/Four Limbs/Amniotic Egg/Hair/Rodents & Rabbits": None, "/Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae/Dinosaurs": None, "/Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae/Birds": None, }, name="Vertebrae", ) primates = vertebrates["/Bony Skeleton/Four Limbs/Amniotic Egg/Hair/Primates"] dinosaurs = vertebrates[ "/Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae/Dinosaurs" ] ``` We have used the [`from_dict()`](../generated/xarray.DataTree.from_dict.md#xarray.DataTree.from_dict) constructor method as a preferred way to quickly create a whole tree, and [Filesystem-like Paths](#filesystem-paths) (to be explained shortly) to select two nodes of interest. ```ipython3 print(vertebrates) ``` ```none Group: / ├── Group: /Sharks └── Group: /Bony Skeleton ├── Group: /Bony Skeleton/Ray-finned Fish └── Group: /Bony Skeleton/Four Limbs ├── Group: /Bony Skeleton/Four Limbs/Amphibians └── Group: /Bony Skeleton/Four Limbs/Amniotic Egg ├── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Hair │ ├── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Hair/Primates │ └── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Hair/Rodents & Rabbits └── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae ├── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae/Dinosaurs └── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae/Birds ``` This tree shows various families of species, grouped by their common features (making it technically a [“Cladogram”](https://en.wikipedia.org/wiki/Cladogram), rather than an evolutionary tree). Here both the species and the features used to group them are represented by [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) node objects - there is no distinction in types of node. We can however get a list of only the nodes we used to represent species by using the fact that all those nodes have no children - they are “leaf nodes”. We can check if a node is a leaf with [`is_leaf()`](../generated/xarray.DataTree.is_leaf.md#xarray.DataTree.is_leaf), and get a list of all leaves with the [`leaves`](../generated/xarray.DataTree.leaves.md#xarray.DataTree.leaves) property: ```ipython3 print(primates.is_leaf) [node.name for node in vertebrates.leaves] ``` ```none True ``` ```none ['Sharks', 'Ray-finned Fish', 'Amphibians', 'Primates', 'Rodents & Rabbits', 'Dinosaurs', 'Birds'] ``` Pretending that this is a true evolutionary tree for a moment, we can find the features of the evolutionary ancestors (so-called “ancestor” nodes), the distinguishing feature of the common ancestor of all vertebrate life (the root node), and even the distinguishing feature of the common ancestor of any two species (the common ancestor of two nodes): ```ipython3 print([node.name for node in reversed(primates.parents)]) print(primates.root.name) print(primates.find_common_ancestor(dinosaurs).name) ``` ```none ['Vertebrae', 'Bony Skeleton', 'Four Limbs', 'Amniotic Egg', 'Hair'] Vertebrae Amniotic Egg ``` We can only find a common ancestor between two nodes that lie in the same tree. If we try to find the common evolutionary ancestor between primates and an Alien species that has no relationship to Earth’s evolutionary tree, an error will be raised. ```ipython3 alien = xr.DataTree(name="Xenomorph") primates.find_common_ancestor(alien) ``` ```ipythontb NotFoundInTreeError: Cannot find common ancestor because nodes do not lie within the same tree ``` ## Navigating Trees There are various ways to access the different nodes in a tree. ### Properties We can navigate trees using the [`parent`](../generated/xarray.DataTree.parent.md#xarray.DataTree.parent) and [`children`](../generated/xarray.DataTree.children.md#xarray.DataTree.children) properties of each node, for example: ```ipython3 lisa.parent.children["Bart"].name ``` ```none 'Bart' ``` but there are also more convenient ways to access nodes. ### Dictionary-like interface Children are stored on each node as a key-value mapping from name to child node. They can be accessed and altered via the [`__getitem__`](../generated/xarray.DataTree.__getitem__.md#xarray.DataTree.__getitem__) and [`__setitem__`](../generated/xarray.DataTree.__setitem__.md#xarray.DataTree.__setitem__) syntax. In general `DataTree` objects support almost the entire set of dict-like methods, including [`keys()`](../generated/xarray.DataTree.keys.md#xarray.DataTree.keys), [`values`](../generated/xarray.DataTree.values.md#xarray.DataTree.values), [`items`](../generated/xarray.DataTree.items.md#xarray.DataTree.items), [`__delitem__()`](../generated/xarray.DataTree.__delitem__.md#xarray.DataTree.__delitem__) and [`update()`](../generated/xarray.DataTree.update.md#xarray.DataTree.update). ```ipython3 print(vertebrates["Bony Skeleton"]["Ray-finned Fish"]) ``` ```none Group: /Bony Skeleton/Ray-finned Fish ``` Note that the dict-like interface combines access to child [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) nodes and stored `DataArrays`, so if we have a node that contains both children and data, calling [`keys()`](../generated/xarray.DataTree.keys.md#xarray.DataTree.keys) will list both names of child nodes and names of data variables: ```ipython3 dt = xr.DataTree( dataset=xr.Dataset({"foo": 0, "bar": 1}), children={"a": xr.DataTree(), "b": xr.DataTree()}, ) print(dt) list(dt.keys()) ``` ```none Group: / │ Dimensions: () │ Data variables: │ foo int64 8B 0 │ bar int64 8B 1 ├── Group: /a └── Group: /b ``` ```none ['foo', 'bar', 'a', 'b'] ``` This also means that the names of variables and of child nodes must be different to one another. ### Attribute-like access You can also select both variables and child nodes through dot indexing ```ipython3 print(dt.foo) print(dt.a) ``` ```none Size: 8B array(0) Group: /a ``` ### Filesystem-like Paths Hierarchical trees can be thought of as analogous to file systems. Each node is like a directory, and each directory can contain both more sub-directories and data. #### NOTE Future development will allow you to make the filesystem analogy concrete by using `open_mfdatatree()` or `save_mfdatatree()`. ([See related issue in GitHub](https://github.com/xarray-contrib/datatree/issues/55)) Datatree objects support a syntax inspired by unix-like filesystems, where the “path” to a node is specified by the keys of each intermediate node in sequence, separated by forward slashes. This is an extension of the conventional dictionary `__getitem__` syntax to allow navigation across multiple levels of the tree. Like with filepaths, paths within the tree can either be relative to the current node, e.g. ```ipython3 print(abe["Homer/Bart"].name) print(abe["./Homer/Bart"].name) # alternative syntax ``` ```none Bart Bart ``` or relative to the root node. A path specified from the root (as opposed to being specified relative to an arbitrary node in the tree) is sometimes also referred to as a [“fully qualified name”](https://www.unidata.ucar.edu/blogs/developer/en/entry/netcdf-zarr-data-model-specification#nczarr_fqn), or as an “absolute path”. The root node is referred to by `"/"`, so the path from the root node to its grand-child would be `"/child/grandchild"`, e.g. ```ipython3 # access lisa's sibling by a relative path. print(lisa["../Bart"]) # or from absolute path print(lisa["/Homer/Bart"]) ``` ```none Group: /Homer/Bart Group: /Homer/Bart ``` Relative paths between nodes also support the `"../"` syntax to mean the parent of the current node. We can use this with `__setitem__` to add a missing entry to our evolutionary tree, but add it relative to a more familiar node of interest: ```ipython3 primates["../../Two Fenestrae/Crocodiles"] = xr.DataTree() print(vertebrates) ``` ```none Group: / ├── Group: /Sharks └── Group: /Bony Skeleton ├── Group: /Bony Skeleton/Ray-finned Fish └── Group: /Bony Skeleton/Four Limbs ├── Group: /Bony Skeleton/Four Limbs/Amphibians └── Group: /Bony Skeleton/Four Limbs/Amniotic Egg ├── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Hair │ ├── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Hair/Primates │ └── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Hair/Rodents & Rabbits └── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae ├── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae/Dinosaurs ├── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae/Birds └── Group: /Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae/Crocodiles ``` Given two nodes in a tree, we can also find their relative path: ```ipython3 bart.relative_to(lisa) ``` ```none '../Bart' ``` You can use this filepath feature to build a nested tree from a dictionary of filesystem-like paths and corresponding [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) objects in a single step. If we have a dictionary where each key is a valid path, and each value is either valid data or `None`, we can construct a complex tree quickly using the alternative constructor [`from_dict()`](../generated/xarray.DataTree.from_dict.md#xarray.DataTree.from_dict): ```ipython3 d = { "/": xr.Dataset({"foo": "orange"}), "/a": xr.Dataset({"bar": 0}, coords={"y": ("y", [0, 1, 2])}), "/a/b": xr.Dataset({"zed": np.nan}), "a/c/d": None, } dt = xr.DataTree.from_dict(d) print(dt) ``` ```none Group: / │ Dimensions: () │ Data variables: │ foo ### Iterating over trees You can iterate over every node in a tree using the subtree [`subtree`](../generated/xarray.DataTree.subtree.md#xarray.DataTree.subtree) property. This returns an iterable of nodes, which yields them in depth-first order. ```ipython3 for node in vertebrates.subtree: print(node.path) ``` ```none / /Sharks /Bony Skeleton /Bony Skeleton/Ray-finned Fish /Bony Skeleton/Four Limbs /Bony Skeleton/Four Limbs/Amphibians /Bony Skeleton/Four Limbs/Amniotic Egg /Bony Skeleton/Four Limbs/Amniotic Egg/Hair /Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae /Bony Skeleton/Four Limbs/Amniotic Egg/Hair/Primates /Bony Skeleton/Four Limbs/Amniotic Egg/Hair/Rodents & Rabbits /Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae/Dinosaurs /Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae/Birds /Bony Skeleton/Four Limbs/Amniotic Egg/Two Fenestrae/Crocodiles ``` Similarly, [`subtree_with_keys`](../generated/xarray.DataTree.subtree_with_keys.md#xarray.DataTree.subtree_with_keys) returns an iterable of relative paths and corresponding nodes. A very useful pattern is to iterate over [`subtree_with_keys`](../generated/xarray.DataTree.subtree_with_keys.md#xarray.DataTree.subtree_with_keys) to manipulate nodes however you wish, then rebuild a new tree using [`xarray.DataTree.from_dict()`](../generated/xarray.DataTree.from_dict.md#xarray.DataTree.from_dict). For example, we could keep only the nodes containing data by looping over all nodes, checking if they contain any data using [`has_data`](../generated/xarray.DataTree.has_data.md#xarray.DataTree.has_data), then rebuilding a new tree using only the paths of those nodes: ```ipython3 non_empty_nodes = { path: node.dataset for path, node in dt.subtree_with_keys if node.has_data } print(xr.DataTree.from_dict(non_empty_nodes)) ``` ```none Group: / │ Dimensions: () │ Data variables: │ foo ## Manipulating Trees ### Subsetting Tree Nodes We can subset our tree to select only nodes of interest in various ways. Similarly to on a real filesystem, matching nodes by common patterns in their paths is often useful. We can use [`xarray.DataTree.match()`](../generated/xarray.DataTree.match.md#xarray.DataTree.match) for this: ```ipython3 dt = xr.DataTree.from_dict( { "/a/A": None, "/a/B": None, "/b/A": None, "/b/B": None, } ) result = dt.match("*/B") print(result) ``` ```none Group: / ├── Group: /a │ └── Group: /a/B └── Group: /b └── Group: /b/B ``` We can also subset trees by the contents of the nodes. [`xarray.DataTree.filter()`](../generated/xarray.DataTree.filter.md#xarray.DataTree.filter) retains only the nodes of a tree that meet a certain condition. For example, we could recreate the Simpson’s family tree with the ages of each individual, then filter for only the adults: First let’s recreate the tree but with an `age` data variable in every node: ```ipython3 simpsons = xr.DataTree.from_dict( { "/": xr.Dataset({"age": 83}), "/Herbert": xr.Dataset({"age": 40}), "/Homer": xr.Dataset({"age": 39}), "/Homer/Bart": xr.Dataset({"age": 10}), "/Homer/Lisa": xr.Dataset({"age": 8}), "/Homer/Maggie": xr.Dataset({"age": 1}), }, name="Abe", ) print(simpsons) ``` ```none Group: / │ Dimensions: () │ Data variables: │ age int64 8B 83 ├── Group: /Herbert │ Dimensions: () │ Data variables: │ age int64 8B 40 └── Group: /Homer │ Dimensions: () │ Data variables: │ age int64 8B 39 ├── Group: /Homer/Bart │ Dimensions: () │ Data variables: │ age int64 8B 10 ├── Group: /Homer/Lisa │ Dimensions: () │ Data variables: │ age int64 8B 8 └── Group: /Homer/Maggie Dimensions: () Data variables: age int64 8B 1 ``` Now let’s filter out the minors: ```ipython3 print(simpsons.filter(lambda node: node["age"] > 18)) ``` ```none Group: / │ Dimensions: () │ Data variables: │ age int64 8B 83 ├── Group: /Herbert │ Dimensions: () │ Data variables: │ age int64 8B 40 └── Group: /Homer Dimensions: () Data variables: age int64 8B 39 ``` The result is a new tree, containing only the nodes matching the condition. (Yes, under the hood [`filter()`](../generated/xarray.DataTree.filter.md#xarray.DataTree.filter) is just syntactic sugar for the pattern we showed you in [Iterating over trees](#iterating-over-trees) !) If you want to filter out empty nodes you can use `prune()`. ## Tree Contents ### Hollow Trees A concept that can sometimes be useful is that of a “Hollow Tree”, which means a tree with data stored only at the leaf nodes. This is useful because certain useful tree manipulation operations only make sense for hollow trees. You can check if a tree is a hollow tree by using the [`is_hollow`](../generated/xarray.DataTree.is_hollow.md#xarray.DataTree.is_hollow) property. We can see that the Simpson’s family is not hollow because the data variable `"age"` is present at some nodes which have children (i.e. Abe and Homer). ```ipython3 simpsons.is_hollow ``` ```none False ``` ## Computation [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) objects are also useful for performing computations, not just for organizing data. ### Operations and Methods on Trees To show how applying operations across a whole tree at once can be useful, let’s first create an example scientific dataset. ```ipython3 def time_stamps(n_samples, T): """Create an array of evenly-spaced time stamps""" return xr.DataArray( data=np.linspace(0, 2 * np.pi * T, n_samples), dims=["time"] ) def signal_generator(t, f, A, phase): """Generate an example electrical-like waveform""" return A * np.sin(f * t.data + phase) time_stamps1 = time_stamps(n_samples=15, T=1.5) time_stamps2 = time_stamps(n_samples=10, T=1.0) voltages = xr.DataTree.from_dict( { "/oscilloscope1": xr.Dataset( { "potential": ( "time", signal_generator(time_stamps1, f=2, A=1.2, phase=0.5), ), "current": ( "time", signal_generator(time_stamps1, f=2, A=1.2, phase=1), ), }, coords={"time": time_stamps1}, ), "/oscilloscope2": xr.Dataset( { "potential": ( "time", signal_generator(time_stamps2, f=1.6, A=1.6, phase=0.2), ), "current": ( "time", signal_generator(time_stamps2, f=1.6, A=1.6, phase=0.7), ), }, coords={"time": time_stamps2}, ), } ) print(voltages) ``` ```none Group: / ├── Group: /oscilloscope1 │ Dimensions: (time: 15) │ Coordinates: │ * time (time) float64 120B 0.0 0.6732 1.346 2.02 ... 8.078 8.752 9.425 │ Data variables: │ potential (time) float64 120B 0.5753 1.155 -0.06141 ... -0.8987 0.5753 │ current (time) float64 120B 1.01 0.8568 -0.6285 ... -1.191 -0.4074 1.01 └── Group: /oscilloscope2 Dimensions: (time: 10) Coordinates: * time (time) float64 80B 0.0 0.6981 1.396 2.094 ... 4.887 5.585 6.283 Data variables: potential (time) float64 80B 0.3179 1.549 1.04 ... 1.578 0.4555 -1.179 current (time) float64 80B 1.031 1.552 0.3297 ... 1.259 -0.3356 -1.553 ``` Most xarray computation methods also exist as methods on datatree objects, so you can for example take the mean value of these two timeseries at once: ```ipython3 print(voltages.mean(dim="time")) ``` ```none Group: / ├── Group: /oscilloscope1 │ Dimensions: () │ Data variables: │ potential float64 8B 0.03835 │ current float64 8B 0.06732 └── Group: /oscilloscope2 Dimensions: () Data variables: potential float64 8B 0.169 current float64 8B 0.1025 ``` This works by mapping the standard [`xarray.Dataset.mean()`](../generated/xarray.Dataset.mean.md#xarray.Dataset.mean) method over the dataset stored in each node of the tree one-by-one. The arguments passed to the method are used for every node, so the values of the arguments you pass might be valid for one node and invalid for another ```ipython3 voltages.isel(time=12) ``` ```ipythontb IndexError: index 12 is out of bounds for axis 0 with size 10 Raised whilst mapping function over node(s) with path 'oscilloscope2' ``` Notice that the error raised helpfully indicates which node of the tree the operation failed on. ### Arithmetic Methods on Trees Arithmetic methods are also implemented, so you can e.g. add a scalar to every dataset in the tree at once. For example, we can advance the timeline of the Simpsons by a decade just by ```ipython3 print(simpsons + 10) ``` ```none Group: / │ Dimensions: () │ Data variables: │ age int64 8B 93 ├── Group: /Herbert │ Dimensions: () │ Data variables: │ age int64 8B 50 └── Group: /Homer │ Dimensions: () │ Data variables: │ age int64 8B 49 ├── Group: /Homer/Bart │ Dimensions: () │ Data variables: │ age int64 8B 20 ├── Group: /Homer/Lisa │ Dimensions: () │ Data variables: │ age int64 8B 18 └── Group: /Homer/Maggie Dimensions: () Data variables: age int64 8B 11 ``` See that the same change (fast-forwarding by adding 10 years to the age of each character) has been applied to every node. ### Mapping Custom Functions Over Trees You can map custom computation over each node in a tree using [`xarray.DataTree.map_over_datasets()`](../generated/xarray.DataTree.map_over_datasets.md#xarray.DataTree.map_over_datasets). You can map any function, so long as it takes [`xarray.Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) objects as one (or more) of the input arguments, and returns one (or more) xarray datasets. #### NOTE Functions passed to [`map_over_datasets()`](../generated/xarray.DataTree.map_over_datasets.md#xarray.DataTree.map_over_datasets) cannot alter nodes in-place. Instead they must return new [`xarray.Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) objects. For example, we can define a function to calculate the Root Mean Square of a timeseries ```ipython3 def rms(signal): return np.sqrt(np.mean(signal**2)) ``` Then calculate the RMS value of these signals: ```ipython3 print(voltages.map_over_datasets(rms)) ``` ```none Group: / ├── Group: /oscilloscope1 │ Dimensions: () │ Data variables: │ potential float64 8B 0.8331 │ current float64 8B 0.8602 └── Group: /oscilloscope2 Dimensions: () Data variables: potential float64 8B 1.099 current float64 8B 1.158 ``` We can also use [`map_over_datasets()`](../generated/xarray.map_over_datasets.md#xarray.map_over_datasets) to apply a function over the data in multiple trees, by passing the trees as positional arguments. ## Operating on Multiple Trees The examples so far have involved mapping functions or methods over the nodes of a single tree, but we can generalize this to mapping functions over multiple trees at once. ### Iterating Over Multiple Trees To iterate over the corresponding nodes in multiple trees, use [`group_subtrees()`](../generated/xarray.group_subtrees.md#xarray.group_subtrees) instead of [`subtree_with_keys`](../generated/xarray.DataTree.subtree_with_keys.md#xarray.DataTree.subtree_with_keys). This combines well with [`xarray.DataTree.from_dict()`](../generated/xarray.DataTree.from_dict.md#xarray.DataTree.from_dict) to build a new tree: ```ipython3 dt1 = xr.DataTree.from_dict({"a": xr.Dataset({"x": 1}), "b": xr.Dataset({"x": 2})}) dt2 = xr.DataTree.from_dict( {"a": xr.Dataset({"x": 10}), "b": xr.Dataset({"x": 20})} ) result = {} for path, (node1, node2) in xr.group_subtrees(dt1, dt2): result[path] = node1.dataset + node2.dataset dt3 = xr.DataTree.from_dict(result) print(dt3) ``` ```none Group: / ├── Group: /a │ Dimensions: () │ Data variables: │ x int64 8B 11 └── Group: /b Dimensions: () Data variables: x int64 8B 22 ``` Alternatively, you apply a function directly to paired datasets at every node using [`xarray.map_over_datasets()`](../generated/xarray.map_over_datasets.md#xarray.map_over_datasets): ```ipython3 dt3 = xr.map_over_datasets(lambda x, y: x + y, dt1, dt2) print(dt3) ``` ```none Group: / ├── Group: /a │ Dimensions: () │ Data variables: │ x int64 8B 11 └── Group: /b Dimensions: () Data variables: x int64 8B 22 ``` ### Comparing Trees for Isomorphism For it to make sense to map a single non-unary function over the nodes of multiple trees at once, each tree needs to have the same structure. Specifically two trees can only be considered similar, or “isomorphic”, if the full paths to all of their descendent nodes are the same. Applying [`group_subtrees()`](../generated/xarray.group_subtrees.md#xarray.group_subtrees) to trees with different structures raises [`TreeIsomorphismError`](../generated/xarray.TreeIsomorphismError.md#xarray.TreeIsomorphismError): ```ipython3 tree = xr.DataTree.from_dict({"a": None, "a/b": None, "a/c": None}) simple_tree = xr.DataTree.from_dict({"a": None}) for _ in xr.group_subtrees(tree, simple_tree): ... ``` ```ipythontb TreeIsomorphismError: children at node 'a' do not match: ['b', 'c'] vs [] ``` We can explicitly also check if any two trees are isomorphic using the [`isomorphic()`](../generated/xarray.DataTree.isomorphic.md#xarray.DataTree.isomorphic) method: ```ipython3 tree.isomorphic(simple_tree) ``` ```none False ``` Corresponding tree nodes do not need to have the same data in order to be considered isomorphic: ```ipython3 tree_with_data = xr.DataTree.from_dict({"a": xr.Dataset({"foo": 1})}) simple_tree.isomorphic(tree_with_data) ``` ```none True ``` They also do not need to define child nodes in the same order: ```ipython3 reordered_tree = xr.DataTree.from_dict({"a": None, "a/c": None, "a/b": None}) tree.isomorphic(reordered_tree) ``` ```none True ``` ### Arithmetic Between Multiple Trees Arithmetic operations like multiplication are binary operations, so as long as we have two isomorphic trees, we can do arithmetic between them. ```ipython3 currents = xr.DataTree.from_dict( { "/oscilloscope1": xr.Dataset( { "current": ( "time", signal_generator(time_stamps1, f=2, A=1.2, phase=1), ), }, coords={"time": time_stamps1}, ), "/oscilloscope2": xr.Dataset( { "current": ( "time", signal_generator(time_stamps2, f=1.6, A=1.6, phase=0.7), ), }, coords={"time": time_stamps2}, ), } ) print(currents) ``` ```none Group: / ├── Group: /oscilloscope1 │ Dimensions: (time: 15) │ Coordinates: │ * time (time) float64 120B 0.0 0.6732 1.346 2.02 ... 8.078 8.752 9.425 │ Data variables: │ current (time) float64 120B 1.01 0.8568 -0.6285 ... -1.191 -0.4074 1.01 └── Group: /oscilloscope2 Dimensions: (time: 10) Coordinates: * time (time) float64 80B 0.0 0.6981 1.396 2.094 ... 4.887 5.585 6.283 Data variables: current (time) float64 80B 1.031 1.552 0.3297 ... 1.259 -0.3356 -1.553 ``` ```ipython3 currents.isomorphic(voltages) ``` ```none True ``` We could use this feature to quickly calculate the electrical power in our signal, P=IV. ```ipython3 power = currents * voltages print(power) ``` ```none Group: / ├── Group: /oscilloscope1 │ Dimensions: (time: 15) │ Coordinates: │ * time (time) float64 120B 0.0 0.6732 1.346 2.02 ... 8.078 8.752 9.425 │ Data variables: │ current (time) float64 120B 1.02 0.7341 0.395 1.292 ... 1.419 0.166 1.02 └── Group: /oscilloscope2 Dimensions: (time: 10) Coordinates: * time (time) float64 80B 0.0 0.6981 1.396 2.094 ... 4.887 5.585 6.283 Data variables: current (time) float64 80B 1.062 2.408 0.1087 1.594 ... 1.585 0.1126 2.412 ``` ## Alignment and Coordinate Inheritance ### Data Alignment The data in different datatree nodes are not totally independent. In particular dimensions (and indexes) in child nodes must be exactly aligned with those in their parent nodes. Exact alignment means that shared dimensions must be the same length, and indexes along those dimensions must be equal. #### NOTE If you were a previous user of the prototype [xarray-contrib/datatree](https://github.com/xarray-contrib/datatree) package, this is different from what you’re used to! In that package the data model was that the data stored in each node actually was completely unrelated. The data model is now slightly stricter. This allows us to provide features like [Coordinate Inheritance](#coordinate-inheritance). To demonstrate, let’s first generate some example datasets which are not aligned with one another: ```ipython3 # (drop the attributes just to make the printed representation shorter) ds = xr.tutorial.open_dataset("air_temperature").drop_attrs() ds_daily = ds.resample(time="D").mean("time") ds_weekly = ds.resample(time="W").mean("time") ds_monthly = ds.resample(time="ME").mean("time") ``` These datasets have different lengths along the `time` dimension, and are therefore not aligned along that dimension. ```ipython3 print(ds_daily.sizes) print(ds_weekly.sizes) print(ds_monthly.sizes) ``` ```none Frozen({'time': 730, 'lat': 25, 'lon': 53}) Frozen({'time': 105, 'lat': 25, 'lon': 53}) Frozen({'time': 24, 'lat': 25, 'lon': 53}) ``` We cannot store these non-alignable variables on a single [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) object, because they do not exactly align: ```ipython3 xr.align(ds_daily, ds_weekly, ds_monthly, join="exact") ``` ```ipythontb AlignmentError: cannot align objects with join='exact' where index/labels/sizes are not equal along these coordinates (dimensions): 'time' ('time',) ``` But we [previously said](#why) that multi-resolution data is a good use case for [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree), so surely we should be able to store these in a single [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree)? If we first try to create a [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) with these different-length time dimensions present in both parents and children, we will still get an alignment error: ```ipython3 xr.DataTree.from_dict({"daily": ds_daily, "daily/weekly": ds_weekly}) ``` ```ipythontb ValueError: group '/daily/weekly' is not aligned with its parents: Group: Dimensions: (time: 105, lat: 25, lon: 53) Coordinates: * time (time) datetime64[ns] 840B 2013-01-06 2013-01-13 ... 2015-01-04 * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 Data variables: air (time, lat, lon) float64 1MB 245.3 245.2 245.0 ... 296.6 296.2 From parents: Dimensions: (time: 730, lat: 25, lon: 53) Coordinates: * time (time) datetime64[ns] 6kB 2013-01-01 2013-01-02 ... 2014-12-31 * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 ``` This is because DataTree checks that data in child nodes align exactly with their parents. #### NOTE This requirement of aligned dimensions is similar to netCDF’s concept of [inherited dimensions](https://www.unidata.ucar.edu/software/netcdf/workshops/2007/groups-types/Introduction.html), as in netCDF-4 files dimensions are [visible to all child groups](https://docs.unidata.ucar.edu/netcdf-c/current/groups.html). This alignment check is performed up through the tree, all the way to the root, and so is therefore equivalent to requiring that this [`align()`](../generated/xarray.align.md#xarray.align) command succeeds: ```python xr.align(child.dataset, *(parent.dataset for parent in child.parents), join="exact") ``` To represent our unalignable data in a single [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree), we must instead place all variables which are a function of these different-length dimensions into nodes that are not direct descendents of one another, e.g. organize them as siblings. ```ipython3 dt = xr.DataTree.from_dict( {"daily": ds_daily, "weekly": ds_weekly, "monthly": ds_monthly} ) print(dt) ``` ```none Group: / ├── Group: /daily │ Dimensions: (time: 730, lat: 25, lon: 53) │ Coordinates: │ * time (time) datetime64[ns] 6kB 2013-01-01 2013-01-02 ... 2014-12-31 │ * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 │ * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 │ Data variables: │ air (time, lat, lon) float64 8MB 241.9 242.3 242.7 ... 295.9 295.5 ├── Group: /weekly │ Dimensions: (time: 105, lat: 25, lon: 53) │ Coordinates: │ * time (time) datetime64[ns] 840B 2013-01-06 2013-01-13 ... 2015-01-04 │ * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 │ * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 │ Data variables: │ air (time, lat, lon) float64 1MB 245.3 245.2 245.0 ... 296.6 296.2 └── Group: /monthly Dimensions: (time: 24, lat: 25, lon: 53) Coordinates: * time (time) datetime64[ns] 192B 2013-01-31 2013-02-28 ... 2014-12-31 * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 Data variables: air (time, lat, lon) float64 254kB 244.5 244.7 244.7 ... 297.7 297.7 ``` Now we have a valid [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) structure which contains all the data at each different time frequency, stored in a separate group. This is a useful way to organise our data because we can still operate on all the groups at once. For example we can extract all three timeseries at a specific lat-lon location: ```ipython3 dt_sel = dt.sel(lat=75, lon=300) print(dt_sel) ``` ```none Group: / ├── Group: /daily │ Dimensions: (time: 730) │ Coordinates: │ * time (time) datetime64[ns] 6kB 2013-01-01 2013-01-02 ... 2014-12-31 │ lat float32 4B 75.0 │ lon float32 4B 300.0 │ Data variables: │ air (time) float64 6kB 242.7 245.6 244.9 249.8 ... 254.8 255.6 256.8 ├── Group: /weekly │ Dimensions: (time: 105) │ Coordinates: │ * time (time) datetime64[ns] 840B 2013-01-06 2013-01-13 ... 2015-01-04 │ lat float32 4B 75.0 │ lon float32 4B 300.0 │ Data variables: │ air (time) float64 840B 247.2 251.7 256.2 261.4 ... 249.8 248.2 255.7 └── Group: /monthly Dimensions: (time: 24) Coordinates: * time (time) datetime64[ns] 192B 2013-01-31 2013-02-28 ... 2014-12-31 lat float32 4B 75.0 lon float32 4B 300.0 Data variables: air (time) float64 192B 254.0 252.8 256.9 258.7 ... 265.1 261.8 251.7 ``` or compute the standard deviation of each timeseries to find out how it varies with sampling frequency: ```ipython3 dt_std = dt.std(dim="time") print(dt_std) ``` ```none Group: / ├── Group: /daily │ Dimensions: (lat: 25, lon: 53) │ Coordinates: │ * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 │ * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 │ Data variables: │ air (lat, lon) float64 11kB 11.63 11.57 11.57 ... 1.715 1.82 1.899 ├── Group: /weekly │ Dimensions: (lat: 25, lon: 53) │ Coordinates: │ * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 │ * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 │ Data variables: │ air (lat, lon) float64 11kB 11.29 11.22 11.21 ... 1.651 1.744 1.818 └── Group: /monthly Dimensions: (lat: 25, lon: 53) Coordinates: * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 Data variables: air (lat, lon) float64 11kB 10.8 10.75 10.76 ... 1.608 1.693 1.763 ``` ### Coordinate Inheritance Notice that in the trees we constructed above there is some redundancy - the `lat` and `lon` variables appear in each sibling group, but are identical across the groups. ```ipython3 dt ``` ```none Group: / ├── Group: /daily │ Dimensions: (time: 730, lat: 25, lon: 53) │ Coordinates: │ * time (time) datetime64[ns] 6kB 2013-01-01 2013-01-02 ... 2014-12-31 │ * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 │ * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 │ Data variables: │ air (time, lat, lon) float64 8MB 241.9 242.3 242.7 ... 295.9 295.5 ├── Group: /weekly │ Dimensions: (time: 105, lat: 25, lon: 53) │ Coordinates: │ * time (time) datetime64[ns] 840B 2013-01-06 2013-01-13 ... 2015-01-04 │ * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 │ * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 │ Data variables: │ air (time, lat, lon) float64 1MB 245.3 245.2 245.0 ... 296.6 296.2 └── Group: /monthly Dimensions: (time: 24, lat: 25, lon: 53) Coordinates: * time (time) datetime64[ns] 192B 2013-01-31 2013-02-28 ... 2014-12-31 * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 Data variables: air (time, lat, lon) float64 254kB 244.5 244.7 244.7 ... 297.7 297.7 ```
<xarray.DataTree>
Group: /
├── Group: /daily
│       Dimensions:  (time: 730, lat: 25, lon: 53)
│       Coordinates:
│         \* time     (time) datetime64[ns] 6kB 2013-01-01 2013-01-02 ... 2014-12-31
│         \* lat      (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0
│         \* lon      (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0
│       Data variables:
│           air      (time, lat, lon) float64 8MB 241.9 242.3 242.7 ... 295.9 295.5
├── Group: /weekly
│       Dimensions:  (time: 105, lat: 25, lon: 53)
│       Coordinates:
│         \* time     (time) datetime64[ns] 840B 2013-01-06 2013-01-13 ... 2015-01-04
│         \* lat      (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0
│         \* lon      (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0
│       Data variables:
│           air      (time, lat, lon) float64 1MB 245.3 245.2 245.0 ... 296.6 296.2
└── Group: /monthly
        Dimensions:  (time: 24, lat: 25, lon: 53)
        Coordinates:
          \* time     (time) datetime64[ns] 192B 2013-01-31 2013-02-28 ... 2014-12-31
          \* lat      (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0
          \* lon      (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0
        Data variables:
            air      (time, lat, lon) float64 254kB 244.5 244.7 244.7 ... 297.7 297.7
We can use “Coordinate Inheritance” to define them only once in a parent group and remove this redundancy, whilst still being able to access those coordinate variables from the child groups. #### NOTE This is also a new feature relative to the prototype [xarray-contrib/datatree](https://github.com/xarray-contrib/datatree) package. Let’s instead place only the time-dependent variables in the child groups, and put the non-time-dependent `lat` and `lon` variables in the parent (root) group: ```ipython3 dt = xr.DataTree.from_dict( { "/": ds.drop_dims("time"), "daily": ds_daily.drop_vars(["lat", "lon"]), "weekly": ds_weekly.drop_vars(["lat", "lon"]), "monthly": ds_monthly.drop_vars(["lat", "lon"]), } ) dt ``` ```none Group: / │ Dimensions: (lat: 25, lon: 53) │ Coordinates: │ * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 │ * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 ├── Group: /daily │ Dimensions: (time: 730, lat: 25, lon: 53) │ Coordinates: │ * time (time) datetime64[ns] 6kB 2013-01-01 2013-01-02 ... 2014-12-31 │ Data variables: │ air (time, lat, lon) float64 8MB 241.9 242.3 242.7 ... 295.9 295.5 ├── Group: /weekly │ Dimensions: (time: 105, lat: 25, lon: 53) │ Coordinates: │ * time (time) datetime64[ns] 840B 2013-01-06 2013-01-13 ... 2015-01-04 │ Data variables: │ air (time, lat, lon) float64 1MB 245.3 245.2 245.0 ... 296.6 296.2 └── Group: /monthly Dimensions: (time: 24, lat: 25, lon: 53) Coordinates: * time (time) datetime64[ns] 192B 2013-01-31 2013-02-28 ... 2014-12-31 Data variables: air (time, lat, lon) float64 254kB 244.5 244.7 244.7 ... 297.7 297.7 ```
<xarray.DataTree>
Group: /
│   Dimensions:  (lat: 25, lon: 53)
│   Coordinates:
│     \* lat      (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0
│     \* lon      (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0
├── Group: /daily
│       Dimensions:  (time: 730, lat: 25, lon: 53)
│       Coordinates:
│         \* time     (time) datetime64[ns] 6kB 2013-01-01 2013-01-02 ... 2014-12-31
│       Data variables:
│           air      (time, lat, lon) float64 8MB 241.9 242.3 242.7 ... 295.9 295.5
├── Group: /weekly
│       Dimensions:  (time: 105, lat: 25, lon: 53)
│       Coordinates:
│         \* time     (time) datetime64[ns] 840B 2013-01-06 2013-01-13 ... 2015-01-04
│       Data variables:
│           air      (time, lat, lon) float64 1MB 245.3 245.2 245.0 ... 296.6 296.2
└── Group: /monthly
        Dimensions:  (time: 24, lat: 25, lon: 53)
        Coordinates:
          \* time     (time) datetime64[ns] 192B 2013-01-31 2013-02-28 ... 2014-12-31
        Data variables:
            air      (time, lat, lon) float64 254kB 244.5 244.7 244.7 ... 297.7 297.7
This is preferred to the previous representation because it now makes it clear that all of these datasets share common spatial grid coordinates. Defining the common coordinates just once also ensures that the spatial coordinates for each group cannot become out of sync with one another during operations. We can still access the coordinates defined in the parent groups from any of the child groups as if they were actually present on the child groups: ```ipython3 dt.daily.coords ``` ```none Coordinates: * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 * time (time) datetime64[ns] 6kB 2013-01-01 2013-01-02 ... 2014-12-31 ``` ```ipython3 dt["daily/lat"] ``` ```none Size: 100B array([75. , 72.5, 70. , 67.5, 65. , 62.5, 60. , 57.5, 55. , 52.5, 50. , 47.5, 45. , 42.5, 40. , 37.5, 35. , 32.5, 30. , 27.5, 25. , 22.5, 20. , 17.5, 15. ], dtype=float32) Coordinates: * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 ```
<xarray.DataArray 'lat' (lat: 25)> Size: 100B
array([75. , 72.5, 70. , 67.5, 65. , 62.5, 60. , 57.5, 55. , 52.5, 50. , 47.5,
       45. , 42.5, 40. , 37.5, 35. , 32.5, 30. , 27.5, 25. , 22.5, 20. , 17.5,
       15. ], dtype=float32)
Coordinates:
  \* lat      (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0
As we can still access them, we say that the `lat` and `lon` coordinates in the child groups have been “inherited” from their common parent group. If we print just one of the child nodes, it will still display inherited coordinates, but explicitly mark them as such: ```ipython3 dt["/daily"] ``` ```none Group: /daily Dimensions: (lat: 25, lon: 53, time: 730) Coordinates: * time (time) datetime64[ns] 6kB 2013-01-01 2013-01-02 ... 2014-12-31 Inherited coordinates: * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 Data variables: air (time, lat, lon) float64 8MB 241.9 242.3 242.7 ... 295.9 295.5 ```
<xarray.DataTree 'daily'>
Group: /daily
    Dimensions:  (lat: 25, lon: 53, time: 730)
    Coordinates:
      \* time     (time) datetime64[ns] 6kB 2013-01-01 2013-01-02 ... 2014-12-31
    Inherited coordinates:
      \* lat      (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0
      \* lon      (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0
    Data variables:
        air      (time, lat, lon) float64 8MB 241.9 242.3 242.7 ... 295.9 295.5
This helps to differentiate which variables are defined on the datatree node that you are currently looking at, and which were defined somewhere above it. We can also still perform all the same operations on the whole tree: ```ipython3 dt.sel(lat=[75], lon=[300]) ``` ```none Group: / │ Dimensions: (lat: 1, lon: 1) │ Coordinates: │ * lat (lat) float32 4B 75.0 │ * lon (lon) float32 4B 300.0 ├── Group: /daily │ Dimensions: (time: 730, lat: 1, lon: 1) │ Coordinates: │ * time (time) datetime64[ns] 6kB 2013-01-01 2013-01-02 ... 2014-12-31 │ Data variables: │ air (time, lat, lon) float64 6kB 242.7 245.6 244.9 ... 255.6 256.8 ├── Group: /weekly │ Dimensions: (time: 105, lat: 1, lon: 1) │ Coordinates: │ * time (time) datetime64[ns] 840B 2013-01-06 2013-01-13 ... 2015-01-04 │ Data variables: │ air (time, lat, lon) float64 840B 247.2 251.7 256.2 ... 248.2 255.7 └── Group: /monthly Dimensions: (time: 24, lat: 1, lon: 1) Coordinates: * time (time) datetime64[ns] 192B 2013-01-31 2013-02-28 ... 2014-12-31 Data variables: air (time, lat, lon) float64 192B 254.0 252.8 256.9 ... 261.8 251.7 ```
<xarray.DataTree>
Group: /
│   Dimensions:  (lat: 1, lon: 1)
│   Coordinates:
│     \* lat      (lat) float32 4B 75.0
│     \* lon      (lon) float32 4B 300.0
├── Group: /daily
│       Dimensions:  (time: 730, lat: 1, lon: 1)
│       Coordinates:
│         \* time     (time) datetime64[ns] 6kB 2013-01-01 2013-01-02 ... 2014-12-31
│       Data variables:
│           air      (time, lat, lon) float64 6kB 242.7 245.6 244.9 ... 255.6 256.8
├── Group: /weekly
│       Dimensions:  (time: 105, lat: 1, lon: 1)
│       Coordinates:
│         \* time     (time) datetime64[ns] 840B 2013-01-06 2013-01-13 ... 2015-01-04
│       Data variables:
│           air      (time, lat, lon) float64 840B 247.2 251.7 256.2 ... 248.2 255.7
└── Group: /monthly
        Dimensions:  (time: 24, lat: 1, lon: 1)
        Coordinates:
          \* time     (time) datetime64[ns] 192B 2013-01-31 2013-02-28 ... 2014-12-31
        Data variables:
            air      (time, lat, lon) float64 192B 254.0 252.8 256.9 ... 261.8 251.7
```ipython3 dt.std(dim="time") ``` ```none Group: / │ Dimensions: (lat: 25, lon: 53) │ Coordinates: │ * lat (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0 │ * lon (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0 ├── Group: /daily │ Dimensions: (lat: 25, lon: 53) │ Data variables: │ air (lat, lon) float64 11kB 11.63 11.57 11.57 ... 1.715 1.82 1.899 ├── Group: /weekly │ Dimensions: (lat: 25, lon: 53) │ Data variables: │ air (lat, lon) float64 11kB 11.29 11.22 11.21 ... 1.651 1.744 1.818 └── Group: /monthly Dimensions: (lat: 25, lon: 53) Data variables: air (lat, lon) float64 11kB 10.8 10.75 10.76 ... 1.608 1.693 1.763 ```
<xarray.DataTree>
Group: /
│   Dimensions:  (lat: 25, lon: 53)
│   Coordinates:
│     \* lat      (lat) float32 100B 75.0 72.5 70.0 67.5 65.0 ... 22.5 20.0 17.5 15.0
│     \* lon      (lon) float32 212B 200.0 202.5 205.0 207.5 ... 325.0 327.5 330.0
├── Group: /daily
│       Dimensions:  (lat: 25, lon: 53)
│       Data variables:
│           air      (lat, lon) float64 11kB 11.63 11.57 11.57 ... 1.715 1.82 1.899
├── Group: /weekly
│       Dimensions:  (lat: 25, lon: 53)
│       Data variables:
│           air      (lat, lon) float64 11kB 11.29 11.22 11.21 ... 1.651 1.744 1.818
└── Group: /monthly
        Dimensions:  (lat: 25, lon: 53)
        Data variables:
            air      (lat, lon) float64 11kB 10.8 10.75 10.76 ... 1.608 1.693 1.763
# how-to-add-new-backend.html.md # How to add a new backend Adding a new backend for read support to Xarray does not require one to integrate any code in Xarray; all you need to do is: - Create a class that inherits from Xarray [`BackendEntrypoint`](../generated/xarray.backends.BackendEntrypoint.md#xarray.backends.BackendEntrypoint) and implements the method `open_dataset` see [BackendEntrypoint subclassing](#rst-backend-entrypoint) - Declare this class as an external plugin in your project configuration, see [How to register a backend](#rst-backend-registration) If you also want to support lazy loading and dask see [How to support lazy loading](#rst-lazy-loading). Note that the new interface for backends is available from Xarray version >= 0.18 onwards. You can see what backends are currently available in your working environment with [`list_engines()`](../generated/xarray.backends.list_engines.md#xarray.backends.list_engines). ## BackendEntrypoint subclassing Your `BackendEntrypoint` sub-class is the primary interface with Xarray, and it should implement the following attributes and methods: - the `open_dataset` method (mandatory) - the `open_dataset_parameters` attribute (optional) - the `guess_can_open` method (optional) - the `description` attribute (optional) - the `url` attribute (optional). This is what a `BackendEntrypoint` subclass should look like: ```python from xarray.backends import BackendEntrypoint class MyBackendEntrypoint(BackendEntrypoint): def open_dataset( self, filename_or_obj, *, drop_variables=None, # other backend specific keyword arguments # `chunks` and `cache` DO NOT go here, they are handled by xarray ): return my_open_dataset(filename_or_obj, drop_variables=drop_variables) open_dataset_parameters = ["filename_or_obj", "drop_variables"] def guess_can_open(self, filename_or_obj): try: _, ext = os.path.splitext(filename_or_obj) except TypeError: return False return ext in {".my_format", ".my_fmt"} description = "Use .my_format files in Xarray" url = "https://link_to/your_backend/documentation" ``` `BackendEntrypoint` subclass methods and attributes are detailed in the following. ### open_dataset The backend `open_dataset` shall implement reading from file, the variables decoding and it shall instantiate the output Xarray class [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset). The following is an example of the high level processing steps: ```python def open_dataset( self, filename_or_obj, *, drop_variables=None, decode_times=True, decode_timedelta=True, decode_coords=True, my_backend_option=None, ): vars, attrs, coords = my_reader( filename_or_obj, drop_variables=drop_variables, my_backend_option=my_backend_option, ) vars, attrs, coords = my_decode_variables( vars, attrs, decode_times, decode_timedelta, decode_coords ) # see also conventions.decode_cf_variables ds = xr.Dataset(vars, attrs=attrs, coords=coords) ds.set_close(my_close_method) return ds ``` The output [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) shall implement the additional custom method `close`, used by Xarray to ensure the related files are eventually closed. This method shall be set by using [`set_close()`](../generated/xarray.Dataset.set_close.md#xarray.Dataset.set_close). The input of `open_dataset` method are one argument (`filename_or_obj`) and one keyword argument (`drop_variables`): - `filename_or_obj`: can be any object but usually it is a string containing a path or an instance of [`pathlib.Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path). - `drop_variables`: can be `None` or an iterable containing the variable names to be dropped when reading the data. If it makes sense for your backend, your `open_dataset` method should implement in its interface the following boolean keyword arguments, called **decoders**, which default to `None`: - `mask_and_scale` - `decode_times` - `decode_timedelta` - `use_cftime` - `concat_characters` - `decode_coords` Note: all the supported decoders shall be declared explicitly in backend `open_dataset` signature and adding a `**kwargs` is not allowed. These keyword arguments are explicitly defined in Xarray [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) signature. Xarray will pass them to the backend only if the User explicitly sets a value different from `None`. For more details on decoders see [Decoders](#rst-decoders). Your backend can also take as input a set of backend-specific keyword arguments. All these keyword arguments can be passed to [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) grouped either via the `backend_kwargs` parameter or explicitly using the syntax `**kwargs`. If you don’t want to support the lazy loading, then the [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) shall contain values as a [`numpy.ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) and your work is almost done. ### open_dataset_parameters `open_dataset_parameters` is the list of backend `open_dataset` parameters. It is not a mandatory parameter, and if the backend does not provide it explicitly, Xarray creates a list of them automatically by inspecting the backend signature. If `open_dataset_parameters` is not defined, but `**kwargs` and `*args` are in the backend `open_dataset` signature, Xarray raises an error. On the other hand, if the backend provides the `open_dataset_parameters`, then `**kwargs` and `*args` can be used in the signature. However, this practice is discouraged unless there is a good reasons for using `**kwargs` or `*args`. ### guess_can_open `guess_can_open` is used to identify the proper engine to open your data file automatically in case the engine is not specified explicitly. If you are not interested in supporting this feature, you can skip this step since [`BackendEntrypoint`](../generated/xarray.backends.BackendEntrypoint.md#xarray.backends.BackendEntrypoint) already provides a default [`guess_can_open()`](../generated/xarray.backends.BackendEntrypoint.guess_can_open.md#xarray.backends.BackendEntrypoint.guess_can_open) that always returns `False`. Backend `guess_can_open` takes as input the `filename_or_obj` parameter of Xarray [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset), and returns a boolean. ### description and url `description` is used to provide a short text description of the backend. `url` is used to include a link to the backend’s documentation or code. These attributes are surfaced when a user prints [`BackendEntrypoint`](../generated/xarray.backends.BackendEntrypoint.md#xarray.backends.BackendEntrypoint). If `description` or `url` are not defined, an empty string is returned. ### Decoders The decoders implement specific operations to transform data from on-disk representation to Xarray representation. A classic example is the “time” variable decoding operation. In NetCDF, the elements of the “time” variable are stored as integers, and the unit contains an origin (for example: “seconds since 1970-1-1”). In this case, Xarray transforms the pair integer-unit in a [`numpy.datetime64`](https://numpy.org/doc/stable/reference/arrays.scalars.html#numpy.datetime64). The standard coders implemented in Xarray are: - [`xarray.coding.strings.CharacterArrayCoder()`](../generated/xarray.coding.strings.CharacterArrayCoder.md#xarray.coding.strings.CharacterArrayCoder) - [`xarray.coding.strings.EncodedStringCoder()`](../generated/xarray.coding.strings.EncodedStringCoder.md#xarray.coding.strings.EncodedStringCoder) - `xarray.coding.variables.UnsignedIntegerCoder()` - [`xarray.coding.variables.CFMaskCoder()`](../generated/xarray.coding.variables.CFMaskCoder.md#xarray.coding.variables.CFMaskCoder) - [`xarray.coding.variables.CFScaleOffsetCoder()`](../generated/xarray.coding.variables.CFScaleOffsetCoder.md#xarray.coding.variables.CFScaleOffsetCoder) - [`xarray.coding.times.CFTimedeltaCoder()`](../generated/xarray.coding.times.CFTimedeltaCoder.md#xarray.coding.times.CFTimedeltaCoder) - [`xarray.coding.times.CFDatetimeCoder()`](../generated/xarray.coding.times.CFDatetimeCoder.md#xarray.coding.times.CFDatetimeCoder) Xarray coders all have the same interface. They have two methods: `decode` and `encode`. The method `decode` takes a `Variable` in on-disk format and returns a `Variable` in Xarray format. Variable attributes no more applicable after the decoding, are dropped and stored in the `Variable.encoding` to make them available to the `encode` method, which performs the inverse transformation. In the following an example on how to use the coders `decode` method: ```ipython3 var = xr.Variable( dims=("x",), data=np.arange(10.0), attrs={"scale_factor": 10, "add_offset": 2} ) var ``` ```none Size: 80B array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]) Attributes: scale_factor: 10 add_offset: 2 ```
<xarray.Variable (x: 10)> Size: 80B
array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
Attributes:
    scale_factor:  10
    add_offset:    2
```ipython3 coder = xr.coding.variables.CFScaleOffsetCoder() decoded_var = coder.decode(var) decoded_var ``` ```none Size: 80B [10 values with dtype=float64] ```
<xarray.Variable (x: 10)> Size: 80B
[10 values with dtype=float64]
```ipython3 decoded_var.encoding ``` ```none {'scale_factor': 10, 'add_offset': 2} ``` Some of the transformations can be common to more backends, so before implementing a new decoder, be sure Xarray does not already implement that one. The backends can reuse Xarray’s decoders, either instantiating the coders and using the method `decode` directly or using the higher-level function [`decode_cf_variables()`](../generated/xarray.conventions.decode_cf_variables.md#xarray.conventions.decode_cf_variables) that groups Xarray decoders. In some cases, the transformation to apply strongly depends on the on-disk data format. Therefore, you may need to implement your own decoder. An example of such a case is when you have to deal with the time format of a grib file. grib format is very different from the NetCDF one: in grib, the time is stored in two attributes dataDate and dataTime as strings. Therefore, it is not possible to reuse the Xarray time decoder, and implementing a new one is mandatory. Decoders can be activated or deactivated using the boolean keywords of Xarray [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) signature: `mask_and_scale`, `decode_times`, `decode_timedelta`, `use_cftime`, `concat_characters`, `decode_coords`. Such keywords are passed to the backend only if the User sets a value different from `None`. Note that the backend does not necessarily have to implement all the decoders, but it shall declare in its `open_dataset` interface only the boolean keywords related to the supported decoders. ## How to register a backend Define a new entrypoint in your `pyproject.toml` (or `setup.cfg/setup.py` for older configurations), with: - group: `xarray.backends` - name: the name to be passed to [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) as `engine` - object reference: the reference of the class that you have implemented. You can declare the entrypoint in your project configuration like so: ```toml [project.entry-points."xarray.backends"] my_engine = "my_package.my_module:MyBackendEntrypoint" ``` ```toml [tool.poetry.plugins."xarray.backends"] my_engine = "my_package.my_module:MyBackendEntrypoint" ``` ```cfg [options.entry_points] xarray.backends = my_engine = my_package.my_module:MyBackendEntrypoint ``` ```default setuptools.setup( entry_points={ "xarray.backends": [ "my_engine=my_package.my_module:MyBackendEntrypoint" ], }, ) ``` See the [Python Packaging User Guide](https://packaging.python.org/specifications/entry-points/#data-model) for more information on entrypoints and details of the syntax. If you’re using Poetry, note that table name in `pyproject.toml` is slightly different. See [the Poetry docs](https://python-poetry.org/docs/pyproject/#plugins) for more information on plugins. ## How to support lazy loading If you want to make your backend effective with big datasets, then you should take advantage of xarray’s support for lazy loading and indexing. Basically, when your backend constructs the `Variable` objects, you need to replace the [`numpy.ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) inside the variables with a custom [`BackendArray`](../generated/xarray.backends.BackendArray.md#xarray.backends.BackendArray) subclass that supports lazy loading and indexing. See the example below: ```python backend_array = MyBackendArray() data = indexing.LazilyIndexedArray(backend_array) var = xr.Variable(dims, data, attrs=attrs, encoding=encoding) ``` Where: - [`LazilyIndexedArray`](../generated/xarray.core.indexing.LazilyIndexedArray.md#xarray.core.indexing.LazilyIndexedArray) is a wrapper class provided by Xarray that manages the lazy loading and indexing. - `MyBackendArray` should be implemented by the backend and must inherit from [`BackendArray`](../generated/xarray.backends.BackendArray.md#xarray.backends.BackendArray). ### BackendArray subclassing The BackendArray subclass must implement the following method and attributes: - the `__getitem__` method that takes an index as an input and returns a [NumPy](https://numpy.org/) array, - the `shape` attribute, - the `dtype` attribute. It may also optionally implement an additional `async_getitem` method. Xarray supports different types of [Indexing and selecting data](../user-guide/indexing.md), that can be grouped in three types of indexes: [`BasicIndexer`](../generated/xarray.core.indexing.BasicIndexer.md#xarray.core.indexing.BasicIndexer), [`OuterIndexer`](../generated/xarray.core.indexing.OuterIndexer.md#xarray.core.indexing.OuterIndexer), and [`VectorizedIndexer`](../generated/xarray.core.indexing.VectorizedIndexer.md#xarray.core.indexing.VectorizedIndexer). This implies that the implementation of the method `__getitem__` can be tricky. In order to simplify this task, Xarray provides a helper function, [`explicit_indexing_adapter()`](../generated/xarray.core.indexing.explicit_indexing_adapter.md#xarray.core.indexing.explicit_indexing_adapter), that transforms all the input indexer types (basic, outer, vectorized) in a tuple which is interpreted correctly by your backend. This is an example `BackendArray` subclass implementation: ```python from xarray.backends import BackendArray class MyBackendArray(BackendArray): def __init__( self, shape, dtype, lock, # other backend specific keyword arguments ): self.shape = shape self.dtype = dtype self.lock = lock def __getitem__( self, key: xarray.core.indexing.ExplicitIndexer ) -> np.typing.ArrayLike: return indexing.explicit_indexing_adapter( key, self.shape, indexing.IndexingSupport.BASIC, self._raw_indexing_method, ) def _raw_indexing_method(self, key: tuple) -> np.typing.ArrayLike: # thread safe method that access to data on disk with self.lock: ... return item ``` Note that `BackendArray.__getitem__` must be thread safe to support multi-thread processing. The [`explicit_indexing_adapter()`](../generated/xarray.core.indexing.explicit_indexing_adapter.md#xarray.core.indexing.explicit_indexing_adapter) method takes in input the `key`, the array `shape` and the following parameters: - `indexing_support`: the type of index supported by `raw_indexing_method` - `raw_indexing_method`: a method that shall take in input a key in the form of a tuple and return an indexed [`numpy.ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray). For more details see [`IndexingSupport`](../generated/xarray.core.indexing.IndexingSupport.md#xarray.core.indexing.IndexingSupport) and [Indexing examples](#rst-indexing). ### Async support Backends can also optionally support loading data asynchronously via xarray’s asynchronous loading methods (e.g. `~xarray.Dataset.load_async`). To support async loading the `BackendArray` subclass must additionally implement the `BackendArray.async_getitem` method. Note that implementing this method is only necessary if you want to be able to load data from different xarray objects concurrently. Even without this method your `BackendArray` implementation is still free to concurrently load chunks of data for a single `Variable` itself, so long as it does so behind the synchronous `__getitem__` interface. ### Dask support In order to support [Dask Distributed](https://distributed.dask.org/) and [`multiprocessing`](https://docs.python.org/3/library/multiprocessing.html#module-multiprocessing), the `BackendArray` subclass should be serializable either with [Pickle](../user-guide/io.md#io-pickle) or [cloudpickle](https://github.com/cloudpipe/cloudpickle). That implies that all the reference to open files should be dropped. For opening files, we therefore suggest to use the helper class provided by Xarray [`CachingFileManager`](../generated/xarray.backends.CachingFileManager.md#xarray.backends.CachingFileManager). ### Indexing examples **BASIC** In the `BASIC` indexing support, numbers and slices are supported. Example: ```ipython3 # () shall return the full array backend_array._raw_indexing_method(()) ``` ```none array([[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]) ``` ```ipython3 # shall support integers backend_array._raw_indexing_method(1, 1) ``` ```none 5 ``` ```ipython3 # shall support slices backend_array._raw_indexing_method(slice(0, 3), slice(2, 4)) ``` ```none array([[2, 3], [6, 7], [10, 11]]) ``` **OUTER** The `OUTER` indexing shall support number, slices and in addition it shall support also lists of integers. The outer indexing is equivalent to combining multiple input list with `itertools.product()`: ```ipython3 backend_array._raw_indexing_method([0, 1], [0, 1, 2]) ``` ```none array([[0, 1, 2], [4, 5, 6]]) ``` ```ipython3 # shall support integers backend_array._raw_indexing_method(1, 1) ``` ```none 5 ``` **OUTER_1VECTOR** The `OUTER_1VECTOR` indexing shall supports number, slices and at most one list. The behaviour with the list shall be the same as `OUTER` indexing. If you support more complex indexing as explicit indexing or numpy indexing, you can have a look to the implementation of Zarr backend and Scipy backend, currently available in `backends` module. ### Preferred chunk sizes To potentially improve performance with lazy loading, the backend may define for each variable the chunk sizes that it prefers—that is, sizes that align with how the variable is stored. (Note that the backend is not directly involved in [Dask](https://dask.org/) chunking, because Xarray internally manages chunking.) To define the preferred chunk sizes, store a mapping within the variable’s encoding under the key `"preferred_chunks"` (that is, `var.encoding["preferred_chunks"]`). The mapping’s keys shall be the names of dimensions with preferred chunk sizes, and each value shall be the corresponding dimension’s preferred chunk sizes expressed as either an integer (such as `{"dim1": 1000, "dim2": 2000}`) or a tuple of integers (such as `{"dim1": (1000, 100), "dim2": (2000, 2000, 2000)}`). Xarray uses the preferred chunk sizes in some special cases of the `chunks` argument of the [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) and [`open_mfdataset()`](../generated/xarray.open_mfdataset.md#xarray.open_mfdataset) functions. If `chunks` is a `dict`, then for any dimensions missing from the keys or whose value is `None`, Xarray sets the chunk sizes to the preferred sizes. If `chunks` equals `"auto"`, then Xarray seeks ideal chunk sizes informed by the preferred chunk sizes. Specifically, it determines the chunk sizes using [`dask.array.core.normalize_chunks()`](https://docs.dask.org/en/latest/generated/dask.array.core.normalize_chunks.html#dask.array.core.normalize_chunks) with the `previous_chunks` argument set according to the preferred chunk sizes. # how-to-create-custom-index.html.md # How to create a custom index #### WARNING This feature is highly experimental. Support for custom indexes has been introduced in v2022.06.0 and is still incomplete. API is subject to change without deprecation notice. However we encourage you to experiment and report issues that arise. Xarray’s built-in support for label-based indexing (e.g. `ds.sel(latitude=40, method="nearest")`) and alignment operations relies on [`pandas.Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index) objects. Pandas Indexes are powerful and suitable for many applications but also have some limitations: - it only works with 1-dimensional coordinates where explicit labels are fully loaded in memory - it is hard to reuse it with irregular data for which there exist more efficient, tree-based structures to perform data selection - it doesn’t support extra metadata that may be required for indexing and alignment (e.g., a coordinate reference system) Fortunately, Xarray now allows extending this functionality with custom indexes, which can be implemented in 3rd-party libraries. ## The Index base class Every Xarray index must inherit from the [`Index`](../generated/xarray.Index.md#xarray.Index) base class. It is for example the case of Xarray built-in `PandasIndex` and `PandasMultiIndex` subclasses, which wrap [`pandas.Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index) and [`pandas.MultiIndex`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.MultiIndex.html#pandas.MultiIndex) respectively. The `Index` API closely follows the [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) and [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) API, e.g., for an index to support [`DataArray.sel()`](../generated/xarray.DataArray.sel.md#xarray.DataArray.sel) it needs to implement [`Index.sel()`](../generated/xarray.Index.sel.md#xarray.Index.sel), to support [`DataArray.stack()`](../generated/xarray.DataArray.stack.md#xarray.DataArray.stack) and [`DataArray.unstack()`](../generated/xarray.DataArray.unstack.md#xarray.DataArray.unstack) it needs to implement [`Index.stack()`](../generated/xarray.Index.stack.md#xarray.Index.stack) and [`Index.unstack()`](../generated/xarray.Index.unstack.md#xarray.Index.unstack), etc. Some guidelines and examples are given below. More details can be found in the documented [`Index`](../generated/xarray.Index.md#xarray.Index) API. ## Minimal requirements Every index must at least implement the [`Index.from_variables()`](../generated/xarray.Index.from_variables.md#xarray.Index.from_variables) class method, which is used by Xarray to build a new index instance from one or more existing coordinates in a Dataset or DataArray. Since any collection of coordinates can be passed to that method (i.e., the number, order and dimensions of the coordinates are all arbitrary), it is the responsibility of the index to check the consistency and validity of those input coordinates. For example, [`PandasIndex`](../generated/xarray.indexes.PandasIndex.md#xarray.indexes.PandasIndex) accepts only one coordinate and [`PandasMultiIndex`](../generated/xarray.indexes.PandasMultiIndex.md#xarray.indexes.PandasMultiIndex) accepts one or more 1-dimensional coordinates that must all share the same dimension. Other, custom indexes need not have the same constraints, e.g., - a georeferenced raster index which only accepts two 1-d coordinates with distinct dimensions - a staggered grid index which takes coordinates with different dimension name suffixes (e.g., “_c” and “_l” for center and left) ## Optional requirements Pretty much everything else is optional. Depending on the method, in the absence of a (re)implementation, an index will either raise a `NotImplementedError` or won’t do anything specific (just drop, pass or copy itself from/to the resulting Dataset or DataArray). For example, you can just skip re-implementing [`Index.rename()`](../generated/xarray.Index.rename.md#xarray.Index.rename) if there is no internal attribute or object to rename according to the new desired coordinate or dimension names. In the case of `PandasIndex`, we rename the underlying `pandas.Index` object and/or update the `PandasIndex.dim` attribute since the associated dimension name has been changed. ## Wrap index data as coordinate data In some cases it is possible to reuse the index’s underlying object or structure as coordinate data and hence avoid data duplication. For `PandasIndex` and `PandasMultiIndex`, we leverage the fact that `pandas.Index` objects expose some array-like API. In Xarray we use some wrappers around those underlying objects as a thin compatibility layer to preserve dtypes, handle explicit and n-dimensional indexing, etc. Other structures like tree-based indexes (e.g., kd-tree) may differ too much from arrays to reuse it as coordinate data. If the index data can be reused as coordinate data, the `Index` subclass should implement [`Index.create_variables()`](../generated/xarray.Index.create_variables.md#xarray.Index.create_variables). This method accepts a dictionary of variable names as keys and [`Variable`](../generated/xarray.Variable.md#xarray.Variable) objects as values (used for propagating variable metadata) and should return a dictionary of new [`Variable`](../generated/xarray.Variable.md#xarray.Variable) or [`IndexVariable`](../generated/xarray.IndexVariable.md#xarray.IndexVariable) objects. ## Data selection For an index to support label-based selection, it needs to at least implement [`Index.sel()`](../generated/xarray.Index.sel.md#xarray.Index.sel). This method accepts a dictionary of labels where the keys are coordinate names (already filtered for the current index) and the values can be pretty much anything (e.g., a slice, a tuple, a list, a numpy array, a [`Variable`](../generated/xarray.Variable.md#xarray.Variable) or a [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray)). It is the responsibility of the index to properly handle those input labels. [`Index.sel()`](../generated/xarray.Index.sel.md#xarray.Index.sel) must return an instance of [`IndexSelResult`](../generated/xarray.IndexSelResult.md#xarray.IndexSelResult). The latter is a small data class that holds positional indexers (indices) and that may also hold new variables, new indexes, names of variables or indexes to drop, names of dimensions to rename, etc. For example, this is useful in the case of `PandasMultiIndex` as it allows Xarray to convert it into a single `PandasIndex` when only one level remains after the selection. The [`IndexSelResult`](../generated/xarray.IndexSelResult.md#xarray.IndexSelResult) class is also used to merge results from label-based selection performed by different indexes. Note that it is now possible to have two distinct indexes for two 1-d coordinates sharing the same dimension, but it is not currently possible to use those two indexes in the same call to [`Dataset.sel()`](../generated/xarray.Dataset.sel.md#xarray.Dataset.sel). Optionally, the index may also implement [`Index.isel()`](../generated/xarray.Index.isel.md#xarray.Index.isel). In the case of `PandasIndex` we use it to create a new index object by just indexing the underlying `pandas.Index` object. In other cases this may not be possible, e.g., a kd-tree object may not be easily indexed. If `Index.isel()` is not implemented, the index in just dropped in the DataArray or Dataset resulting from the selection. ## Alignment For an index to support alignment, it needs to implement: - [`Index.equals()`](../generated/xarray.Index.equals.md#xarray.Index.equals), which compares the index with another index and returns either `True` or `False` - [`Index.join()`](../generated/xarray.Index.join.md#xarray.Index.join), which combines the index with another index and returns a new Index object - [`Index.reindex_like()`](../generated/xarray.Index.reindex_like.md#xarray.Index.reindex_like), which queries the index with another index and returns positional indexers that are used to re-index Dataset or DataArray variables along one or more dimensions Xarray ensures that those three methods are called with an index of the same type as argument. ## Meta-indexes Nothing prevents writing a custom Xarray index that itself encapsulates other Xarray index(es). We call such index a “meta-index”. Here is a small example of a meta-index for geospatial, raster datasets (i.e., regularly spaced 2-dimensional data) that internally relies on two `PandasIndex` instances for the x and y dimensions respectively: ```ipython3 from xarray import Index from xarray.core.indexes import PandasIndex from xarray.core.indexing import merge_sel_results class RasterIndex(Index): def __init__(self, xy_indexes): assert len(xy_indexes) == 2 # must have two distinct dimensions dim = [idx.dim for idx in xy_indexes.values()] assert dim[0] != dim[1] self._xy_indexes = xy_indexes @classmethod def from_variables(cls, variables, *, options): assert len(variables) == 2 xy_indexes = { k: PandasIndex.from_variables({k: v}, options=options) for k, v in variables.items() } return cls(xy_indexes) def create_variables(self, variables): idx_variables = {} for index in self._xy_indexes.values(): idx_variables.update(index.create_variables(variables)) return idx_variables def sel(self, labels): results = [] for k, index in self._xy_indexes.items(): if k in labels: results.append(index.sel({k: labels[k]})) return merge_sel_results(results) ``` This basic index only supports label-based selection. Providing a full-featured index by implementing the other `Index` methods should be pretty straightforward for this example, though. This example is also not very useful unless we add some extra functionality on top of the two encapsulated `PandasIndex` objects, such as a coordinate reference system. ## How to use a custom index You can use [`Dataset.set_xindex()`](../generated/xarray.Dataset.set_xindex.md#xarray.Dataset.set_xindex) or [`DataArray.set_xindex()`](../generated/xarray.DataArray.set_xindex.md#xarray.DataArray.set_xindex) to assign a custom index to a Dataset or DataArray, e.g., using the `RasterIndex` above: ```ipython3 import numpy as np import xarray as xr da = xr.DataArray( np.random.uniform(size=(100, 50)), coords={"x": ("x", np.arange(50)), "y": ("y", np.arange(100))}, dims=("y", "x"), ) # Build a RasterIndex from the 'x' and 'y' coordinates # Xarray creates default indexes for the 'x' and 'y' coordinates # this will automatically drop those indexes da_raster = da.set_xindex(["x", "y"], RasterIndex) # RasterIndex now takes care of label-based selection selected = da_raster.sel(x=10, y=slice(20, 50)) selected ``` ```none Size: 248B array([0.73896724, 0.16676071, 0.27294435, 0.31156105, 0.61813214, 0.46129975, 0.80095943, 0.84171057, 0.15536804, 0.40278696, 0.77158219, 0.67610414, 0.46140659, 0.05339299, 0.82293825, 0.4545841 , 0.78942283, 0.30940154, 0.10112574, 0.79627955, 0.00901582, 0.56157695, 0.30336343, 0.40387357, 0.66337058, 0.0106193 , 0.29703627, 0.95584982, 0.60461075, 0.64122512, 0.15596854]) Coordinates: y (y) int64 248B 20 21 22 23 24 25 26 27 ... 43 44 45 46 47 48 49 50 x int64 8B 10 ```
<xarray.DataArray (y: 31)> Size: 248B
array([0.73896724, 0.16676071, 0.27294435, 0.31156105, 0.61813214,
       0.46129975, 0.80095943, 0.84171057, 0.15536804, 0.40278696,
       0.77158219, 0.67610414, 0.46140659, 0.05339299, 0.82293825,
       0.4545841 , 0.78942283, 0.30940154, 0.10112574, 0.79627955,
       0.00901582, 0.56157695, 0.30336343, 0.40387357, 0.66337058,
       0.0106193 , 0.29703627, 0.95584982, 0.60461075, 0.64122512,
       0.15596854])
Coordinates:
    y        (y) int64 248B 20 21 22 23 24 25 26 27 ... 43 44 45 46 47 48 49 50
    x        int64 8B 10
# howdoi.html.md # How do I … | How do I… | Solution | |-------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | add a DataArray to my dataset as a new variable | `my_dataset[varname] = my_dataArray` or [`Dataset.assign()`](../generated/xarray.Dataset.assign.md#xarray.Dataset.assign) (see also [Dictionary like methods](../user-guide/data-structures.md#dictionary-like-methods)) | | add variables from other datasets to my dataset | [`Dataset.merge()`](../generated/xarray.Dataset.merge.md#xarray.Dataset.merge) | | add a new dimension and/or coordinate | [`DataArray.expand_dims()`](../generated/xarray.DataArray.expand_dims.md#xarray.DataArray.expand_dims), [`Dataset.expand_dims()`](../generated/xarray.Dataset.expand_dims.md#xarray.Dataset.expand_dims) | | add a new coordinate variable | [`DataArray.assign_coords()`](../generated/xarray.DataArray.assign_coords.md#xarray.DataArray.assign_coords) | | change a data variable to a coordinate variable | [`Dataset.set_coords()`](../generated/xarray.Dataset.set_coords.md#xarray.Dataset.set_coords) | | change the order of dimensions | [`DataArray.transpose()`](../generated/xarray.DataArray.transpose.md#xarray.DataArray.transpose), [`Dataset.transpose()`](../generated/xarray.Dataset.transpose.md#xarray.Dataset.transpose) | | reshape dimensions | [`DataArray.stack()`](../generated/xarray.DataArray.stack.md#xarray.DataArray.stack), [`Dataset.stack()`](../generated/xarray.Dataset.stack.md#xarray.Dataset.stack), `Dataset.coarsen.construct()`, `DataArray.coarsen.construct()` | | remove a variable from my object | [`Dataset.drop_vars()`](../generated/xarray.Dataset.drop_vars.md#xarray.Dataset.drop_vars), [`DataArray.drop_vars()`](../generated/xarray.DataArray.drop_vars.md#xarray.DataArray.drop_vars) | | remove dimensions of length 1 or 0 | [`DataArray.squeeze()`](../generated/xarray.DataArray.squeeze.md#xarray.DataArray.squeeze), [`Dataset.squeeze()`](../generated/xarray.Dataset.squeeze.md#xarray.Dataset.squeeze) | | remove all variables with a particular dimension | [`Dataset.drop_dims()`](../generated/xarray.Dataset.drop_dims.md#xarray.Dataset.drop_dims) | | convert non-dimension coordinates to data variables or remove them | [`DataArray.reset_coords()`](../generated/xarray.DataArray.reset_coords.md#xarray.DataArray.reset_coords), [`Dataset.reset_coords()`](../generated/xarray.Dataset.reset_coords.md#xarray.Dataset.reset_coords) | | rename a variable, dimension or coordinate | [`Dataset.rename()`](../generated/xarray.Dataset.rename.md#xarray.Dataset.rename), [`DataArray.rename()`](../generated/xarray.DataArray.rename.md#xarray.DataArray.rename), [`Dataset.rename_vars()`](../generated/xarray.Dataset.rename_vars.md#xarray.Dataset.rename_vars), [`Dataset.rename_dims()`](../generated/xarray.Dataset.rename_dims.md#xarray.Dataset.rename_dims), | | convert a DataArray to Dataset or vice versa | [`DataArray.to_dataset()`](../generated/xarray.DataArray.to_dataset.md#xarray.DataArray.to_dataset), [`Dataset.to_dataarray()`](../generated/xarray.Dataset.to_dataarray.md#xarray.Dataset.to_dataarray), [`Dataset.to_stacked_array()`](../generated/xarray.Dataset.to_stacked_array.md#xarray.Dataset.to_stacked_array), [`DataArray.to_unstacked_dataset()`](../generated/xarray.DataArray.to_unstacked_dataset.md#xarray.DataArray.to_unstacked_dataset) | | extract variables that have certain attributes | [`Dataset.filter_by_attrs()`](../generated/xarray.Dataset.filter_by_attrs.md#xarray.Dataset.filter_by_attrs) | | extract the underlying array (e.g. NumPy or Dask arrays) | [`DataArray.data`](../generated/xarray.DataArray.data.md#xarray.DataArray.data) | | convert to and extract the underlying NumPy array | [`DataArray.to_numpy`](../generated/xarray.DataArray.to_numpy.md#xarray.DataArray.to_numpy) | | convert to a pandas DataFrame | [`Dataset.to_dataframe`](../generated/xarray.Dataset.to_dataframe.md#xarray.Dataset.to_dataframe) | | sort values | [`Dataset.sortby`](../generated/xarray.Dataset.sortby.md#xarray.Dataset.sortby) | | find out if my xarray object is wrapping a Dask Array | [`dask.is_dask_collection()`](https://docs.dask.org/en/latest/api.html#dask.is_dask_collection) | | know how much memory my object requires | [`DataArray.nbytes`](../generated/xarray.DataArray.nbytes.md#xarray.DataArray.nbytes), [`Dataset.nbytes`](../generated/xarray.Dataset.nbytes.md#xarray.Dataset.nbytes) | | Get axis number for a dimension | [`DataArray.get_axis_num()`](../generated/xarray.DataArray.get_axis_num.md#xarray.DataArray.get_axis_num) | | convert a possibly irregularly sampled timeseries to a regularly sampled timeseries | [`DataArray.resample()`](../generated/xarray.DataArray.resample.md#xarray.DataArray.resample), [`Dataset.resample()`](../generated/xarray.Dataset.resample.md#xarray.Dataset.resample) (see [Resampling and grouped operations](../user-guide/time-series.md#resampling) for more) | | apply a function on all data variables in a Dataset | [`Dataset.map()`](../generated/xarray.Dataset.map.md#xarray.Dataset.map) | | write xarray objects with complex values to a netCDF file | [`Dataset.to_netcdf()`](../generated/xarray.Dataset.to_netcdf.md#xarray.Dataset.to_netcdf), [`DataArray.to_netcdf()`](../generated/xarray.DataArray.to_netcdf.md#xarray.DataArray.to_netcdf) specifying `engine="h5netcdf"` or [`Dataset.to_netcdf()`](../generated/xarray.Dataset.to_netcdf.md#xarray.Dataset.to_netcdf), [`DataArray.to_netcdf()`](../generated/xarray.DataArray.to_netcdf.md#xarray.DataArray.to_netcdf) specifying `engine="netCDF4", auto_complex=True` | | make xarray objects look like other xarray objects | [`ones_like()`](../generated/xarray.ones_like.md#xarray.ones_like), [`zeros_like()`](../generated/xarray.zeros_like.md#xarray.zeros_like), [`full_like()`](../generated/xarray.full_like.md#xarray.full_like), [`Dataset.reindex_like()`](../generated/xarray.Dataset.reindex_like.md#xarray.Dataset.reindex_like), [`Dataset.interp_like()`](../generated/xarray.Dataset.interp_like.md#xarray.Dataset.interp_like), [`Dataset.broadcast_like()`](../generated/xarray.Dataset.broadcast_like.md#xarray.Dataset.broadcast_like), [`DataArray.reindex_like()`](../generated/xarray.DataArray.reindex_like.md#xarray.DataArray.reindex_like), [`DataArray.interp_like()`](../generated/xarray.DataArray.interp_like.md#xarray.DataArray.interp_like), [`DataArray.broadcast_like()`](../generated/xarray.DataArray.broadcast_like.md#xarray.DataArray.broadcast_like) | | Make sure my datasets have values at the same coordinate locations | `xr.align(dataset_1, dataset_2, join="exact")` | | replace NaNs with other values | [`Dataset.fillna()`](../generated/xarray.Dataset.fillna.md#xarray.Dataset.fillna), [`Dataset.ffill()`](../generated/xarray.Dataset.ffill.md#xarray.Dataset.ffill), [`Dataset.bfill()`](../generated/xarray.Dataset.bfill.md#xarray.Dataset.bfill), [`Dataset.interpolate_na()`](../generated/xarray.Dataset.interpolate_na.md#xarray.Dataset.interpolate_na), [`DataArray.fillna()`](../generated/xarray.DataArray.fillna.md#xarray.DataArray.fillna), [`DataArray.ffill()`](../generated/xarray.DataArray.ffill.md#xarray.DataArray.ffill), [`DataArray.bfill()`](../generated/xarray.DataArray.bfill.md#xarray.DataArray.bfill), [`DataArray.interpolate_na()`](../generated/xarray.DataArray.interpolate_na.md#xarray.DataArray.interpolate_na) | | extract the year, month, day or similar from a DataArray of time values | `obj.dt.month` for example where `obj` is a [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) containing `datetime64` or `cftime` values. See [Datetime components](../user-guide/time-series.md#dt-accessor) for more. | | round off time values to a specified frequency | `obj.dt.ceil`, `obj.dt.floor`, `obj.dt.round`. See [Datetime components](../user-guide/time-series.md#dt-accessor) for more. | | make a mask that is `True` where an object contains any of the values in an array | [`Dataset.isin()`](../generated/xarray.Dataset.isin.md#xarray.Dataset.isin), [`DataArray.isin()`](../generated/xarray.DataArray.isin.md#xarray.DataArray.isin) | | Index using a boolean mask | [`Dataset.query()`](../generated/xarray.Dataset.query.md#xarray.Dataset.query), [`DataArray.query()`](../generated/xarray.DataArray.query.md#xarray.DataArray.query), [`Dataset.where()`](../generated/xarray.Dataset.where.md#xarray.Dataset.where), [`DataArray.where()`](../generated/xarray.DataArray.where.md#xarray.DataArray.where) | | preserve `attrs` during (most) xarray operations | `xr.set_options(keep_attrs=True)` | # indexes.html.md # Indexes #### SEE ALSO See the Xarray gallery on [custom indexes](https://xarray-indexes.readthedocs.io/) for more examples. ## Creating indexes | [`cftime_range`](../generated/xarray.cftime_range.md#xarray.cftime_range)([start, end, periods, freq, ...]) | Return a fixed frequency CFTimeIndex. | |--------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------| | [`date_range`](../generated/xarray.date_range.md#xarray.date_range)([start, end, periods, freq, tz, ...]) | Return a fixed frequency datetime index. | | [`date_range_like`](../generated/xarray.date_range_like.md#xarray.date_range_like)(source, calendar[, use_cftime]) | Generate a datetime array with the same frequency, start and end as another one, but in a different calendar. | | [`indexes.RangeIndex.arange`](../generated/xarray.indexes.RangeIndex.arange.md#xarray.indexes.RangeIndex.arange)([start, stop, ...]) | Create a new RangeIndex from given start, stop and step values. | | [`indexes.RangeIndex.linspace`](../generated/xarray.indexes.RangeIndex.linspace.md#xarray.indexes.RangeIndex.linspace)(start, stop[, ...]) | Create a new RangeIndex from given start / stop values and number of values. | ## Built-in Indexes Default, pandas-backed indexes built-in to Xarray: | [`indexes.PandasIndex`](../generated/xarray.indexes.PandasIndex.md#xarray.indexes.PandasIndex)(array, dim[, ...]) | Wrap a pandas.Index as an xarray compatible index. | |----------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------| | [`indexes.PandasMultiIndex`](../generated/xarray.indexes.PandasMultiIndex.md#xarray.indexes.PandasMultiIndex)(array, dim[, ...]) | Wrap a pandas.MultiIndex as an xarray compatible index. | More complex indexes built-in to Xarray: | [`CFTimeIndex`](../generated/xarray.CFTimeIndex.md#xarray.CFTimeIndex)(data[, name]) | Custom Index for working with CF calendars and dates | |--------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------| | [`indexes.RangeIndex`](../generated/xarray.indexes.RangeIndex.md#xarray.indexes.RangeIndex)(transform) | Xarray index implementing a simple bounded 1-dimension interval with evenly spaced, monotonic floating-point values. | | [`indexes.NDPointIndex`](../generated/xarray.indexes.NDPointIndex.md#xarray.indexes.NDPointIndex)(tree_obj, \*, ...) | Xarray index for irregular, n-dimensional data. | | [`indexes.CoordinateTransformIndex`](../generated/xarray.indexes.CoordinateTransformIndex.md#xarray.indexes.CoordinateTransformIndex)(transform) | Helper class for creating Xarray indexes based on coordinate transforms. | ## Building custom indexes These classes are building blocks for more complex Indexes: | [`indexes.CoordinateTransform`](../generated/xarray.indexes.CoordinateTransform.md#xarray.indexes.CoordinateTransform)(coord_names, ...) | Abstract coordinate transform with dimension & coordinate names. | |--------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [`indexes.CoordinateTransformIndex`](../generated/xarray.indexes.CoordinateTransformIndex.md#xarray.indexes.CoordinateTransformIndex)(transform) | Helper class for creating Xarray indexes based on coordinate transforms. | | [`indexes.NDPointIndex`](../generated/xarray.indexes.NDPointIndex.md#xarray.indexes.NDPointIndex)(tree_obj, \*, ...) | Xarray index for irregular, n-dimensional data. | | [`indexes.TreeAdapter`](../generated/xarray.indexes.TreeAdapter.md#xarray.indexes.TreeAdapter)(points, \*, options) | Lightweight adapter abstract class for plugging in 3rd-party structures like [`scipy.spatial.KDTree`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.KDTree.html#scipy.spatial.KDTree) or `sklearn.neighbors.KDTree` into [`NDPointIndex`](../generated/xarray.indexes.NDPointIndex.md#xarray.indexes.NDPointIndex). | The Index base class for building custom indexes: | [`Index`](../generated/xarray.Index.md#xarray.Index)() | Base class inherited by all xarray-compatible indexes. | |-----------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------| | [`Index.from_variables`](../generated/xarray.Index.from_variables.md#xarray.Index.from_variables)(variables, \*, options) | Create a new index object from one or more coordinate variables. | | [`Index.concat`](../generated/xarray.Index.concat.md#xarray.Index.concat)(indexes, dim[, positions]) | Create a new index by concatenating one or more indexes of the same type. | | [`Index.stack`](../generated/xarray.Index.stack.md#xarray.Index.stack)(variables, dim) | Create a new index by stacking coordinate variables into a single new dimension. | | [`Index.unstack`](../generated/xarray.Index.unstack.md#xarray.Index.unstack)() | Unstack a (multi-)index into multiple (single) indexes. | | [`Index.create_variables`](../generated/xarray.Index.create_variables.md#xarray.Index.create_variables)([variables]) | Maybe create new coordinate variables from this index. | | [`Index.should_add_coord_to_array`](../generated/xarray.Index.should_add_coord_to_array.md#xarray.Index.should_add_coord_to_array)(name, var, dims) | Define whether or not an index coordinate variable should be added to a new DataArray. | | [`Index.to_pandas_index`](../generated/xarray.Index.to_pandas_index.md#xarray.Index.to_pandas_index)() | Cast this xarray index to a pandas.Index object or raise a `TypeError` if this is not supported. | | [`Index.isel`](../generated/xarray.Index.isel.md#xarray.Index.isel)(indexers) | Maybe returns a new index from the current index itself indexed by positional indexers. | | [`Index.sel`](../generated/xarray.Index.sel.md#xarray.Index.sel)(labels) | Query the index with arbitrary coordinate label indexers. | | [`Index.join`](../generated/xarray.Index.join.md#xarray.Index.join)(other[, how]) | Return a new index from the combination of this index with another index of the same type. | | [`Index.reindex_like`](../generated/xarray.Index.reindex_like.md#xarray.Index.reindex_like)(other) | Query the index with another index of the same type. | | [`Index.equals`](../generated/xarray.Index.equals.md#xarray.Index.equals)(other, \*\*kwargs) | Compare this index with another index of the same type. | | [`Index.roll`](../generated/xarray.Index.roll.md#xarray.Index.roll)(shifts) | Roll this index by an offset along one or more dimensions. | | [`Index.rename`](../generated/xarray.Index.rename.md#xarray.Index.rename)(name_dict, dims_dict) | Maybe update the index with new coordinate and dimension names. | | [`Index.copy`](../generated/xarray.Index.copy.md#xarray.Index.copy)([deep]) | Return a (deep) copy of this index. | The following are useful when building custom Indexes | [`IndexSelResult`](../generated/xarray.IndexSelResult.md#xarray.IndexSelResult)(dim_indexers[, indexes, ...]) | Index query results. | |-----------------------------------------------------------------------------------------------------------------|------------------------| # indexing.html.md # Indexing and selecting data Xarray offers extremely flexible indexing routines that combine the best features of NumPy and pandas for data selection. The most basic way to access elements of a [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) object is to use Python’s `[]` syntax, such as `array[i, j]`, where `i` and `j` are both integers. As xarray objects can store coordinates corresponding to each dimension of an array, label-based indexing similar to `pandas.DataFrame.loc` is also possible. In label-based indexing, the element position `i` is automatically looked-up from the coordinate values. Dimensions of xarray objects have names, so you can also lookup the dimensions by name, instead of remembering their positional order. ## Quick overview In total, xarray supports four different kinds of indexing, as described below and summarized in this table: | Dimension lookup | Index lookup | `DataArray` syntax | `Dataset` syntax | |--------------------|----------------|---------------------------------------------------------------|---------------------------------------------------------------| | Positional | By integer | `da[:, 0]` | *not available* | | Positional | By label | `da.loc[:, 'IA']` | *not available* | | By name | By integer | `da.isel(space=0)` or

`da[dict(space=0)]` | `ds.isel(space=0)` or

`ds[dict(space=0)]` | | By name | By label | `da.sel(space='IA')` or

`da.loc[dict(space='IA')]` | `ds.sel(space='IA')` or

`ds.loc[dict(space='IA')]` | More advanced indexing is also possible for all the methods by supplying [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) objects as indexer. See [Vectorized Indexing](#vectorized-indexing) for the details. ## Positional indexing Indexing a [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) directly works (mostly) just like it does for numpy arrays, except that the returned object is always another DataArray: ```ipython3 da = xr.DataArray( np.random.rand(4, 3), [ ("time", pd.date_range("2000-01-01", periods=4)), ("space", ["IA", "IL", "IN"]), ], ) da[:2] ``` ```none Size: 48B array([[0.12696983, 0.96671784, 0.26047601], [0.89723652, 0.37674972, 0.33622174]]) Coordinates: * time (time) datetime64[us] 16B 2000-01-01 2000-01-02 * space (space)
<xarray.DataArray (time: 2, space: 3)> Size: 48B
array([[0.12696983, 0.96671784, 0.26047601],
       [0.89723652, 0.37674972, 0.33622174]])
Coordinates:
  \* time     (time) datetime64[us] 16B 2000-01-01 2000-01-02
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
```ipython3 da[0, 0] ``` ```none Size: 8B array(0.12696983) Coordinates: time datetime64[us] 8B 2000-01-01 space
<xarray.DataArray ()> Size: 8B
array(0.12696983)
Coordinates:
    time     datetime64[us] 8B 2000-01-01
    space    <U2 8B 'IA'
```ipython3 da[:, [2, 1]] ``` ```none Size: 64B array([[0.26047601, 0.96671784], [0.33622174, 0.37674972], [0.12310214, 0.84025508], [0.44799682, 0.37301223]]) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.DataArray (time: 4, space: 2)> Size: 64B
array([[0.26047601, 0.96671784],
       [0.33622174, 0.37674972],
       [0.12310214, 0.84025508],
       [0.44799682, 0.37301223]])
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 16B 'IN' 'IL'
Attributes are persisted in all indexing operations. #### WARNING Positional indexing deviates from the NumPy when indexing with multiple arrays like `da[[0, 1], [0, 1]]`, as described in [Vectorized Indexing](#vectorized-indexing). Xarray also supports label-based indexing, just like pandas. Because we use a [`pandas.Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index) under the hood, label based indexing is very fast. To do label based indexing, use the [`loc`](../generated/xarray.DataArray.loc.md#xarray.DataArray.loc) attribute: ```ipython3 da.loc["2000-01-01":"2000-01-02", "IA"] ``` ```none Size: 16B array([0.12696983, 0.89723652]) Coordinates: * time (time) datetime64[us] 16B 2000-01-01 2000-01-02 space
<xarray.DataArray (time: 2)> Size: 16B
array([0.12696983, 0.89723652])
Coordinates:
  \* time     (time) datetime64[us] 16B 2000-01-01 2000-01-02
    space    <U2 8B 'IA'
In this example, the selected is a subpart of the array in the range ‘2000-01-01’:’2000-01-02’ along the first coordinate `time` and with ‘IA’ value from the second coordinate `space`. You can perform any of the [label indexing operations supported by pandas](https://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-label), including indexing with individual, slices and lists/arrays of labels, as well as indexing with boolean arrays. Like pandas, label based indexing in xarray is *inclusive* of both the start and stop bounds. Setting values with label based indexing is also supported: ```ipython3 da.loc["2000-01-01", ["IL", "IN"]] = -10 da ``` ```none Size: 96B array([[ 0.12696983, -10. , -10. ], [ 0.89723652, 0.37674972, 0.33622174], [ 0.45137647, 0.84025508, 0.12310214], [ 0.5430262 , 0.37301223, 0.44799682]]) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.DataArray (time: 4, space: 3)> Size: 96B
array([[  0.12696983, -10.        , -10.        ],
       [  0.89723652,   0.37674972,   0.33622174],
       [  0.45137647,   0.84025508,   0.12310214],
       [  0.5430262 ,   0.37301223,   0.44799682]])
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
## Indexing with dimension names With the dimension names, we do not have to rely on dimension order and can use them explicitly to slice data. There are two ways to do this: 1. Use the [`sel()`](../generated/xarray.DataArray.sel.md#xarray.DataArray.sel) and [`isel()`](../generated/xarray.DataArray.isel.md#xarray.DataArray.isel) convenience methods: > ```ipython3 > # index by integer array indices > da.isel(space=0, time=slice(None, 2)) > ``` > ```none > Size: 16B > array([0.12696983, 0.89723652]) > Coordinates: > * time (time) datetime64[us] 16B 2000-01-01 2000-01-02 > space ``` >
> > > > > > > > > > > > > > >
<xarray.DataArray (time: 2)> Size: 16B
   > array([0.12696983, 0.89723652])
   > Coordinates:
   >   \* time     (time) datetime64[us] 16B 2000-01-01 2000-01-02
   >     space    <U2 8B 'IA'
> ```ipython3 > # index by dimension coordinate labels > da.sel(time=slice("2000-01-01", "2000-01-02")) > ``` > ```none > Size: 48B > array([[ 0.12696983, -10. , -10. ], > [ 0.89723652, 0.37674972, 0.33622174]]) > Coordinates: > * time (time) datetime64[us] 16B 2000-01-01 2000-01-02 > * space (space) ``` >
> > > > > > > > > > > > > > >
<xarray.DataArray (time: 2, space: 3)> Size: 48B
   > array([[  0.12696983, -10.        , -10.        ],
   >        [  0.89723652,   0.37674972,   0.33622174]])
   > Coordinates:
   >   \* time     (time) datetime64[us] 16B 2000-01-01 2000-01-02
   >   \* space    (space) <U2 24B 'IA' 'IL' 'IN'
2. Use a dictionary as the argument for array positional or label based array indexing: > ```ipython3 > # index by integer array indices > da[dict(space=0, time=slice(None, 2))] > ``` > ```none > Size: 16B > array([0.12696983, 0.89723652]) > Coordinates: > * time (time) datetime64[us] 16B 2000-01-01 2000-01-02 > space ``` >
> > > > > > > > > > > > > > >
<xarray.DataArray (time: 2)> Size: 16B
   > array([0.12696983, 0.89723652])
   > Coordinates:
   >   \* time     (time) datetime64[us] 16B 2000-01-01 2000-01-02
   >     space    <U2 8B 'IA'
> ```ipython3 > # index by dimension coordinate labels > da.loc[dict(time=slice("2000-01-01", "2000-01-02"))] > ``` > ```none > Size: 48B > array([[ 0.12696983, -10. , -10. ], > [ 0.89723652, 0.37674972, 0.33622174]]) > Coordinates: > * time (time) datetime64[us] 16B 2000-01-01 2000-01-02 > * space (space) ``` >
> > > > > > > > > > > > > > >
<xarray.DataArray (time: 2, space: 3)> Size: 48B
   > array([[  0.12696983, -10.        , -10.        ],
   >        [  0.89723652,   0.37674972,   0.33622174]])
   > Coordinates:
   >   \* time     (time) datetime64[us] 16B 2000-01-01 2000-01-02
   >   \* space    (space) <U2 24B 'IA' 'IL' 'IN'
The arguments to these methods can be any objects that could index the array along the dimension given by the keyword, e.g., labels for an individual value, `Python slice` objects or 1-dimensional arrays. #### NOTE We would love to be able to do indexing with labeled dimension names inside brackets, but unfortunately, [Python does not yet support indexing with keyword arguments](https://legacy.python.org/dev/peps/pep-0472/) like `da[space=0]` ## Nearest neighbor lookups The label based selection methods [`sel()`](../generated/xarray.Dataset.sel.md#xarray.Dataset.sel), [`reindex()`](../generated/xarray.Dataset.reindex.md#xarray.Dataset.reindex) and [`reindex_like()`](../generated/xarray.Dataset.reindex_like.md#xarray.Dataset.reindex_like) all support `method` and `tolerance` keyword argument. The method parameter allows for enabling nearest neighbor (inexact) lookups by use of the methods `'pad'`, `'backfill'` or `'nearest'`: ```ipython3 da = xr.DataArray([1, 2, 3], [("x", [0, 1, 2])]) da.sel(x=[1.1, 1.9], method="nearest") ``` ```none Size: 16B array([2, 3]) Coordinates: * x (x) int64 16B 1 2 ```
<xarray.DataArray (x: 2)> Size: 16B
array([2, 3])
Coordinates:
  \* x        (x) int64 16B 1 2
```ipython3 da.sel(x=0.1, method="backfill") ``` ```none Size: 8B array(2) Coordinates: x int64 8B 1 ```
<xarray.DataArray ()> Size: 8B
array(2)
Coordinates:
    x        int64 8B 1
```ipython3 da.reindex(x=[0.5, 1, 1.5, 2, 2.5], method="pad") ``` ```none Size: 40B array([1, 2, 2, 3, 3]) Coordinates: * x (x) float64 40B 0.5 1.0 1.5 2.0 2.5 ```
<xarray.DataArray (x: 5)> Size: 40B
array([1, 2, 2, 3, 3])
Coordinates:
  \* x        (x) float64 40B 0.5 1.0 1.5 2.0 2.5
Tolerance limits the maximum distance for valid matches with an inexact lookup: ```ipython3 da.reindex(x=[1.1, 1.5], method="nearest", tolerance=0.2) ``` ```none Size: 16B array([ 2., nan]) Coordinates: * x (x) float64 16B 1.1 1.5 ```
<xarray.DataArray (x: 2)> Size: 16B
array([ 2., nan])
Coordinates:
  \* x        (x) float64 16B 1.1 1.5
The method parameter is not yet supported if any of the arguments to `.sel()` is a `slice` object: ```ipython3 da.sel(x=slice(1, 3), method="nearest") ``` ```ipythontb NotImplementedError: cannot use ``method`` argument if any indexers are slice objects ``` However, you don’t need to use `method` to do inexact slicing. Slicing already returns all values inside the range (inclusive), as long as the index labels are monotonic increasing: ```ipython3 da.sel(x=slice(0.9, 3.1)) ``` ```none Size: 16B array([2, 3]) Coordinates: * x (x) int64 16B 1 2 ```
<xarray.DataArray (x: 2)> Size: 16B
array([2, 3])
Coordinates:
  \* x        (x) int64 16B 1 2
Indexing axes with monotonic decreasing labels also works, as long as the `slice` or `.loc` arguments are also decreasing: ```ipython3 reversed_da = da[::-1] reversed_da.loc[3.1:0.9] ``` ```none Size: 16B array([3, 2]) Coordinates: * x (x) int64 16B 2 1 ```
<xarray.DataArray (x: 2)> Size: 16B
array([3, 2])
Coordinates:
  \* x        (x) int64 16B 2 1
#### NOTE If you want to interpolate along coordinates rather than looking up the nearest neighbors, use [`interp()`](../generated/xarray.Dataset.interp.md#xarray.Dataset.interp) and [`interp_like()`](../generated/xarray.Dataset.interp_like.md#xarray.Dataset.interp_like). See [interpolation](interpolation.md#interp) for the details. ## Dataset indexing We can also use these methods to index all variables in a dataset simultaneously, returning a new dataset: ```ipython3 da = xr.DataArray( np.random.rand(4, 3), [ ("time", pd.date_range("2000-01-01", periods=4)), ("space", ["IA", "IL", "IN"]), ], ) ds = da.to_dataset(name="foo") ds.isel(space=[0], time=[0]) ``` ```none Size: 24B Dimensions: (time: 1, space: 1) Coordinates: * time (time) datetime64[us] 8B 2000-01-01 * space (space)
<xarray.Dataset> Size: 24B
Dimensions:  (time: 1, space: 1)
Coordinates:
  \* time     (time) datetime64[us] 8B 2000-01-01
  \* space    (space) <U2 8B 'IA'
Data variables:
    foo      (time, space) float64 8B 0.1294
```ipython3 ds.sel(time="2000-01-01") ``` ```none Size: 56B Dimensions: (space: 3) Coordinates: * space (space)
<xarray.Dataset> Size: 56B
Dimensions:  (space: 3)
Coordinates:
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
    time     datetime64[us] 8B 2000-01-01
Data variables:
    foo      (space) float64 24B 0.1294 0.8599 0.8204
Positional indexing on a dataset is not supported because the ordering of dimensions in a dataset is somewhat ambiguous (it can vary between different arrays). However, you can do normal indexing with dimension names: ```ipython3 ds[dict(space=[0], time=[0])] ``` ```none Size: 24B Dimensions: (time: 1, space: 1) Coordinates: * time (time) datetime64[us] 8B 2000-01-01 * space (space)
<xarray.Dataset> Size: 24B
Dimensions:  (time: 1, space: 1)
Coordinates:
  \* time     (time) datetime64[us] 8B 2000-01-01
  \* space    (space) <U2 8B 'IA'
Data variables:
    foo      (time, space) float64 8B 0.1294
```ipython3 ds.loc[dict(time="2000-01-01")] ``` ```none Size: 56B Dimensions: (space: 3) Coordinates: * space (space)
<xarray.Dataset> Size: 56B
Dimensions:  (space: 3)
Coordinates:
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
    time     datetime64[us] 8B 2000-01-01
Data variables:
    foo      (space) float64 24B 0.1294 0.8599 0.8204
## Dropping labels and dimensions The [`drop_sel()`](../generated/xarray.Dataset.drop_sel.md#xarray.Dataset.drop_sel) method returns a new object with the listed index labels along a dimension dropped: ```ipython3 ds.drop_sel(space=["IN", "IL"]) ``` ```none Size: 72B Dimensions: (time: 4, space: 1) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.Dataset> Size: 72B
Dimensions:  (time: 4, space: 1)
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 8B 'IA'
Data variables:
    foo      (time, space) float64 32B 0.1294 0.3521 0.5948 0.2355
`drop_sel` is both a `Dataset` and `DataArray` method. Use [`drop_dims()`](../generated/xarray.Dataset.drop_dims.md#xarray.Dataset.drop_dims) to drop a full dimension from a Dataset. Any variables with these dimensions are also dropped: ```ipython3 ds.drop_dims("time") ``` ```none Size: 24B Dimensions: (space: 3) Coordinates: * space (space)
<xarray.Dataset> Size: 24B
Dimensions:  (space: 3)
Coordinates:
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
Data variables:
    \*empty\*
## Masking with `where` Indexing methods on xarray objects generally return a subset of the original data. However, it is sometimes useful to select an object with the same shape as the original data, but with some elements masked. To do this type of selection in xarray, use [`where()`](../generated/xarray.DataArray.where.md#xarray.DataArray.where): ```ipython3 da = xr.DataArray(np.arange(16).reshape(4, 4), dims=["x", "y"]) da.where(da.x + da.y < 4) ``` ```none Size: 128B array([[ 0., 1., 2., 3.], [ 4., 5., 6., nan], [ 8., 9., nan, nan], [12., nan, nan, nan]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 4, y: 4)> Size: 128B
array([[ 0.,  1.,  2.,  3.],
       [ 4.,  5.,  6., nan],
       [ 8.,  9., nan, nan],
       [12., nan, nan, nan]])
Dimensions without coordinates: x, y
This is particularly useful for ragged indexing of multi-dimensional data, e.g., to apply a 2D mask to an image. Note that `where` follows all the usual xarray broadcasting and alignment rules for binary operations (e.g., `+`) between the object being indexed and the condition, as described in [Computation](computation.md#compute): ```ipython3 da.where(da.y < 2) ``` ```none Size: 128B array([[ 0., 1., nan, nan], [ 4., 5., nan, nan], [ 8., 9., nan, nan], [12., 13., nan, nan]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 4, y: 4)> Size: 128B
array([[ 0.,  1., nan, nan],
       [ 4.,  5., nan, nan],
       [ 8.,  9., nan, nan],
       [12., 13., nan, nan]])
Dimensions without coordinates: x, y
By default `where` maintains the original size of the data. For cases where the selected data size is much smaller than the original data, use of the option `drop=True` clips coordinate elements that are fully masked: ```ipython3 da.where(da.y < 2, drop=True) ``` ```none Size: 64B array([[ 0., 1.], [ 4., 5.], [ 8., 9.], [12., 13.]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 4, y: 2)> Size: 64B
array([[ 0.,  1.],
       [ 4.,  5.],
       [ 8.,  9.],
       [12., 13.]])
Dimensions without coordinates: x, y
## Selecting values with `isin` To check whether elements of an xarray object contain a single object, you can compare with the equality operator `==` (e.g., `arr == 3`). To check multiple values, use [`isin()`](../generated/xarray.DataArray.isin.md#xarray.DataArray.isin): ```ipython3 da = xr.DataArray([1, 2, 3, 4, 5], dims=["x"]) da.isin([2, 4]) ``` ```none Size: 5B array([False, True, False, True, False]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 5)> Size: 5B
array([False,  True, False,  True, False])
Dimensions without coordinates: x
[`isin()`](../generated/xarray.DataArray.isin.md#xarray.DataArray.isin) works particularly well with [`where()`](../generated/xarray.DataArray.where.md#xarray.DataArray.where) to support indexing by arrays that are not already labels of an array: ```ipython3 lookup = xr.DataArray([-1, -2, -3, -4, -5], dims=["x"]) da.where(lookup.isin([-2, -4]), drop=True) ``` ```none Size: 16B array([2., 4.]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 2)> Size: 16B
array([2., 4.])
Dimensions without coordinates: x
However, some caution is in order: when done repeatedly, this type of indexing is significantly slower than using [`sel()`](../generated/xarray.DataArray.sel.md#xarray.DataArray.sel). ## Vectorized Indexing Like numpy and pandas, xarray supports indexing many array elements at once in a vectorized manner. If you only provide integers, slices, or unlabeled arrays (array without dimension names, such as `np.ndarray`, `list`, but not [`DataArray()`](../generated/xarray.DataArray.md#xarray.DataArray) or [`Variable()`](../generated/xarray.Variable.md#xarray.Variable)) indexing can be understood as orthogonally. Each indexer component selects independently along the corresponding dimension, similar to how vector indexing works in Fortran or MATLAB, or after using the [`numpy.ix_()`](https://numpy.org/doc/stable/reference/generated/numpy.ix_.html#numpy.ix_) helper: ```ipython3 da = xr.DataArray( np.arange(12).reshape((3, 4)), dims=["x", "y"], coords={"x": [0, 1, 2], "y": ["a", "b", "c", "d"]}, ) da ``` ```none Size: 96B array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) Coordinates: * x (x) int64 24B 0 1 2 * y (y)
<xarray.DataArray (x: 3, y: 4)> Size: 96B
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
Coordinates:
  \* x        (x) int64 24B 0 1 2
  \* y        (y) <U1 16B 'a' 'b' 'c' 'd'
```ipython3 da[[0, 2, 2], [1, 3]] ``` ```none Size: 48B array([[ 1, 3], [ 9, 11], [ 9, 11]]) Coordinates: * x (x) int64 24B 0 2 2 * y (y)
<xarray.DataArray (x: 3, y: 2)> Size: 48B
array([[ 1,  3],
       [ 9, 11],
       [ 9, 11]])
Coordinates:
  \* x        (x) int64 24B 0 2 2
  \* y        (y) <U1 8B 'b' 'd'
For more flexibility, you can supply [`DataArray()`](../generated/xarray.DataArray.md#xarray.DataArray) objects as indexers. Dimensions on resultant arrays are given by the ordered union of the indexers’ dimensions: ```ipython3 ind_x = xr.DataArray([0, 1], dims=["x"]) ind_y = xr.DataArray([0, 1], dims=["y"]) da[ind_x, ind_y] # orthogonal indexing ``` ```none Size: 32B array([[0, 1], [4, 5]]) Coordinates: * x (x) int64 16B 0 1 * y (y)
<xarray.DataArray (x: 2, y: 2)> Size: 32B
array([[0, 1],
       [4, 5]])
Coordinates:
  \* x        (x) int64 16B 0 1
  \* y        (y) <U1 8B 'a' 'b'
Slices or sequences/arrays without named-dimensions are treated as if they have the same dimension which is indexed along: ```ipython3 # Because [0, 1] is used to index along dimension 'x', # it is assumed to have dimension 'x' da[[0, 1], ind_x] ``` ```none Size: 16B array([0, 5]) Coordinates: * x (x) int64 16B 0 1 y (x)
<xarray.DataArray (x: 2)> Size: 16B
array([0, 5])
Coordinates:
  \* x        (x) int64 16B 0 1
    y        (x) <U1 8B 'a' 'b'
Furthermore, you can use multi-dimensional [`DataArray()`](../generated/xarray.DataArray.md#xarray.DataArray) as indexers, where the resultant array dimension is also determined by indexers’ dimension: ```ipython3 ind = xr.DataArray([[0, 1], [0, 1]], dims=["a", "b"]) da[ind] ``` ```none Size: 128B array([[[0, 1, 2, 3], [4, 5, 6, 7]], [[0, 1, 2, 3], [4, 5, 6, 7]]]) Coordinates: x (a, b) int64 32B 0 1 0 1 * y (y)
<xarray.DataArray (a: 2, b: 2, y: 4)> Size: 128B
array([[[0, 1, 2, 3],
        [4, 5, 6, 7]],

       [[0, 1, 2, 3],
        [4, 5, 6, 7]]])
Coordinates:
    x        (a, b) int64 32B 0 1 0 1
  \* y        (y) <U1 16B 'a' 'b' 'c' 'd'
Dimensions without coordinates: a, b
Similar to how [NumPy’s advanced indexing](https://numpy.org/doc/stable/user/basics.indexing.html#advanced-indexing) works, vectorized indexing for xarray is based on our [broadcasting rules](computation.md#compute-broadcasting). See [Indexing rules](#indexing-rules) for the complete specification. Vectorized indexing also works with `isel`, `loc`, and `sel`: ```ipython3 ind = xr.DataArray([[0, 1], [0, 1]], dims=["a", "b"]) da.isel(y=ind) # same as da[:, ind] ``` ```none Size: 96B array([[[0, 1], [0, 1]], [[4, 5], [4, 5]], [[8, 9], [8, 9]]]) Coordinates: * x (x) int64 24B 0 1 2 y (a, b)
<xarray.DataArray (x: 3, a: 2, b: 2)> Size: 96B
array([[[0, 1],
        [0, 1]],

       [[4, 5],
        [4, 5]],

       [[8, 9],
        [8, 9]]])
Coordinates:
  \* x        (x) int64 24B 0 1 2
    y        (a, b) <U1 16B 'a' 'b' 'a' 'b'
Dimensions without coordinates: a, b
```ipython3 ind = xr.DataArray([["a", "b"], ["b", "a"]], dims=["a", "b"]) da.loc[:, ind] # same as da.sel(y=ind) ``` ```none Size: 96B array([[[0, 1], [1, 0]], [[4, 5], [5, 4]], [[8, 9], [9, 8]]]) Coordinates: * x (x) int64 24B 0 1 2 y (a, b)
<xarray.DataArray (x: 3, a: 2, b: 2)> Size: 96B
array([[[0, 1],
        [1, 0]],

       [[4, 5],
        [5, 4]],

       [[8, 9],
        [9, 8]]])
Coordinates:
  \* x        (x) int64 24B 0 1 2
    y        (a, b) <U1 16B 'a' 'b' 'b' 'a'
Dimensions without coordinates: a, b
These methods may also be applied to `Dataset` objects ```ipython3 ds = da.to_dataset(name="bar") ds.isel(x=xr.DataArray([0, 1, 2], dims=["points"])) ``` ```none Size: 136B Dimensions: (points: 3, y: 4) Coordinates: x (points) int64 24B 0 1 2 * y (y)
<xarray.Dataset> Size: 136B
Dimensions:  (points: 3, y: 4)
Coordinates:
    x        (points) int64 24B 0 1 2
  \* y        (y) <U1 16B 'a' 'b' 'c' 'd'
Dimensions without coordinates: points
Data variables:
    bar      (points, y) int64 96B 0 1 2 3 4 5 6 7 8 9 10 11
Vectorized indexing may be used to extract information from the nearest grid cells of interest, for example, the nearest climate model grid cells to a collection specified weather station latitudes and longitudes. To trigger vectorized indexing behavior you will need to provide the selection dimensions with a new shared output dimension name. In the example below, the selections of the closest latitude and longitude are renamed to an output dimension named “points”: ```ipython3 ds = xr.tutorial.open_dataset("air_temperature") # Define target latitude and longitude (where weather stations might be) target_lon = xr.DataArray([200, 201, 202, 205], dims="points") target_lat = xr.DataArray([31, 41, 42, 42], dims="points") # Retrieve data at the grid cells nearest to the target latitudes and longitudes da = ds["air"].sel(lon=target_lon, lat=target_lat, method="nearest") da ``` ```none Size: 93kB [11680 values with dtype=float64] Coordinates: * time (time) datetime64[ns] 23kB 2013-01-01 ... 2014-12-31T18:00:00 lat (points) float32 16B 30.0 40.0 42.5 42.5 lon (points) float32 16B 200.0 200.0 202.5 205.0 Dimensions without coordinates: points Attributes: long_name: 4xDaily Air temperature at sigma level 995 units: degK precision: 2 GRIB_id: 11 GRIB_name: TMP var_desc: Air temperature dataset: NMC Reanalysis level_desc: Surface statistic: Individual Obs parent_stat: Other actual_range: [185.16 322.1 ] ```
<xarray.DataArray 'air' (time: 2920, points: 4)> Size: 93kB
[11680 values with dtype=float64]
Coordinates:
  \* time     (time) datetime64[ns] 23kB 2013-01-01 ... 2014-12-31T18:00:00
    lat      (points) float32 16B 30.0 40.0 42.5 42.5
    lon      (points) float32 16B 200.0 200.0 202.5 205.0
Dimensions without coordinates: points
Attributes:
    long_name:     4xDaily Air temperature at sigma level 995
    units:         degK
    precision:     2
    GRIB_id:       11
    GRIB_name:     TMP
    var_desc:      Air temperature
    dataset:       NMC Reanalysis
    level_desc:    Surface
    statistic:     Individual Obs
    parent_stat:   Other
    actual_range:  [185.16 322.1 ]
#### NOTE If an indexer is a [`DataArray()`](../generated/xarray.DataArray.md#xarray.DataArray), its coordinates should not conflict with the selected subpart of the target array (except for the explicitly indexed dimensions with `.loc`/`.sel`). Otherwise, `IndexError` will be raised. ## Assigning values with indexing To select and assign values to a portion of a [`DataArray()`](../generated/xarray.DataArray.md#xarray.DataArray) you can use indexing with `.loc` : ```ipython3 ds = xr.tutorial.open_dataset("air_temperature") # add an empty 2D dataarray ds["empty"] = xr.full_like(ds.air.mean("time"), fill_value=0) # modify one grid point using loc() ds["empty"].loc[dict(lon=260, lat=30)] = 100 # modify a 2D region using loc() lc = ds.coords["lon"] la = ds.coords["lat"] ds["empty"].loc[ dict(lon=lc[(lc > 220) & (lc < 260)], lat=la[(la > 20) & (la < 60)]) ] = 100 ``` or [`where()`](../generated/xarray.where.md#xarray.where): ```ipython3 # modify one grid point using xr.where() ds["empty"] = xr.where( (ds.coords["lat"] == 20) & (ds.coords["lon"] == 260), 100, ds["empty"] ) # or modify a 2D region using xr.where() mask = ( (ds.coords["lat"] > 20) & (ds.coords["lat"] < 60) & (ds.coords["lon"] > 220) & (ds.coords["lon"] < 260) ) ds["empty"] = xr.where(mask, 100, ds["empty"]) ``` Vectorized indexing can also be used to assign values to xarray object. ```ipython3 da = xr.DataArray( np.arange(12).reshape((3, 4)), dims=["x", "y"], coords={"x": [0, 1, 2], "y": ["a", "b", "c", "d"]}, ) da ``` ```none Size: 96B array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) Coordinates: * x (x) int64 24B 0 1 2 * y (y)
<xarray.DataArray (x: 3, y: 4)> Size: 96B
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
Coordinates:
  \* x        (x) int64 24B 0 1 2
  \* y        (y) <U1 16B 'a' 'b' 'c' 'd'
```ipython3 da[0] = -1 # assignment with broadcasting da ``` ```none Size: 96B array([[-1, -1, -1, -1], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) Coordinates: * x (x) int64 24B 0 1 2 * y (y)
<xarray.DataArray (x: 3, y: 4)> Size: 96B
array([[-1, -1, -1, -1],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
Coordinates:
  \* x        (x) int64 24B 0 1 2
  \* y        (y) <U1 16B 'a' 'b' 'c' 'd'
```ipython3 ind_x = xr.DataArray([0, 1], dims=["x"]) ind_y = xr.DataArray([0, 1], dims=["y"]) da[ind_x, ind_y] = -2 # assign -2 to (ix, iy) = (0, 0) and (1, 1) da ``` ```none Size: 96B array([[-2, -2, -1, -1], [-2, -2, 6, 7], [ 8, 9, 10, 11]]) Coordinates: * x (x) int64 24B 0 1 2 * y (y)
<xarray.DataArray (x: 3, y: 4)> Size: 96B
array([[-2, -2, -1, -1],
       [-2, -2,  6,  7],
       [ 8,  9, 10, 11]])
Coordinates:
  \* x        (x) int64 24B 0 1 2
  \* y        (y) <U1 16B 'a' 'b' 'c' 'd'
```ipython3 da[ind_x, ind_y] += 100 # increment is also possible da ``` ```none Size: 96B array([[98, 98, -1, -1], [98, 98, 6, 7], [ 8, 9, 10, 11]]) Coordinates: * x (x) int64 24B 0 1 2 * y (y)
<xarray.DataArray (x: 3, y: 4)> Size: 96B
array([[98, 98, -1, -1],
       [98, 98,  6,  7],
       [ 8,  9, 10, 11]])
Coordinates:
  \* x        (x) int64 24B 0 1 2
  \* y        (y) <U1 16B 'a' 'b' 'c' 'd'
Like `numpy.ndarray`, value assignment sometimes works differently from what one may expect. ```ipython3 da = xr.DataArray([0, 1, 2, 3], dims=["x"]) ind = xr.DataArray([0, 0, 0], dims=["x"]) da[ind] -= 1 da ``` ```none Size: 32B array([-1, 1, 2, 3]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 4)> Size: 32B
array([-1,  1,  2,  3])
Dimensions without coordinates: x
Where the 0th element will be subtracted 1 only once. This is because `v[0] = v[0] - 1` is called three times, rather than `v[0] = v[0] - 1 - 1 - 1`. See [Assigning values to indexed arrays](https://numpy.org/doc/stable/user/basics.indexing.html#assigning-values-to-indexed-arrays) for the details. #### NOTE Dask array does not support value assignment (see [Parallel Computing with Dask](dask.md#dask) for the details). #### NOTE Coordinates in both the left- and right-hand-side arrays should not conflict with each other. Otherwise, `IndexError` will be raised. #### WARNING Do not try to assign values when using any of the indexing methods `isel` or `sel`: ```default # DO NOT do this da.isel(space=0) = 0 ``` Instead, values can be assigned using dictionary-based indexing: ```default da[dict(space=0)] = 0 ``` Assigning values with the chained indexing using `.sel` or `.isel` fails silently. ```ipython3 da = xr.DataArray([0, 1, 2, 3], dims=["x"]) # DO NOT do this da.isel(x=[0, 1, 2])[1] = -1 da ``` ```none Size: 32B array([0, 1, 2, 3]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 4)> Size: 32B
array([0, 1, 2, 3])
Dimensions without coordinates: x
You can also assign values to all variables of a `Dataset` at once: ```ipython3 ds_org = xr.tutorial.open_dataset("eraint_uvz").isel( latitude=slice(56, 59), longitude=slice(255, 258), level=0 ) # set all values to 0 ds = xr.zeros_like(ds_org) ds ``` ```none /home/docs/checkouts/readthedocs.org/user_builds/xray/checkouts/stable/xarray/conventions.py:205: SerializationWarning: variable 'z' has non-conforming '_FillValue' np.float64(nan) defined, dropping '_FillValue' entirely. var = coder.decode(var, name=name) /home/docs/checkouts/readthedocs.org/user_builds/xray/checkouts/stable/xarray/conventions.py:205: SerializationWarning: variable 'u' has non-conforming '_FillValue' np.float64(nan) defined, dropping '_FillValue' entirely. var = coder.decode(var, name=name) /home/docs/checkouts/readthedocs.org/user_builds/xray/checkouts/stable/xarray/conventions.py:205: SerializationWarning: variable 'v' has non-conforming '_FillValue' np.float64(nan) defined, dropping '_FillValue' entirely. var = coder.decode(var, name=name) ``` ```none Size: 468B Dimensions: (month: 2, latitude: 3, longitude: 3) Coordinates: * month (month) int32 8B 1 7 * latitude (latitude) float32 12B 48.0 47.25 46.5 * longitude (longitude) float32 12B 11.25 12.0 12.75 level int32 4B 200 Data variables: z (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 0.0 u (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 0.0 v (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 0.0 Attributes: Conventions: CF-1.0 Info: Monthly ERA-Interim data. Downloaded and edited by fabien.m... ```
<xarray.Dataset> Size: 468B
Dimensions:    (month: 2, latitude: 3, longitude: 3)
Coordinates:
  \* month      (month) int32 8B 1 7
  \* latitude   (latitude) float32 12B 48.0 47.25 46.5
  \* longitude  (longitude) float32 12B 11.25 12.0 12.75
    level      int32 4B 200
Data variables:
    z          (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 0.0
    u          (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 0.0
    v          (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 0.0
Attributes:
    Conventions:  CF-1.0
    Info:         Monthly ERA-Interim data. Downloaded and edited by fabien.m...
```ipython3 # by integer ds[dict(latitude=2, longitude=2)] = 1 ds["u"] ``` ```none Size: 144B array([[[0., 0., 0.], [0., 0., 0.], [0., 0., 1.]], [[0., 0., 0.], [0., 0., 0.], [0., 0., 1.]]]) Coordinates: * month (month) int32 8B 1 7 * latitude (latitude) float32 12B 48.0 47.25 46.5 * longitude (longitude) float32 12B 11.25 12.0 12.75 level int32 4B 200 Attributes: number_of_significant_digits: 2 units: m s**-1 long_name: U component of wind standard_name: eastward_wind ```
<xarray.DataArray 'u' (month: 2, latitude: 3, longitude: 3)> Size: 144B
array([[[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 1.]],

       [[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 1.]]])
Coordinates:
  \* month      (month) int32 8B 1 7
  \* latitude   (latitude) float32 12B 48.0 47.25 46.5
  \* longitude  (longitude) float32 12B 11.25 12.0 12.75
    level      int32 4B 200
Attributes:
    number_of_significant_digits:  2
    units:                         m s\*\*-1
    long_name:                     U component of wind
    standard_name:                 eastward_wind
```ipython3 ds["v"] ``` ```none Size: 144B array([[[0., 0., 0.], [0., 0., 0.], [0., 0., 1.]], [[0., 0., 0.], [0., 0., 0.], [0., 0., 1.]]]) Coordinates: * month (month) int32 8B 1 7 * latitude (latitude) float32 12B 48.0 47.25 46.5 * longitude (longitude) float32 12B 11.25 12.0 12.75 level int32 4B 200 Attributes: number_of_significant_digits: 2 units: m s**-1 long_name: V component of wind standard_name: northward_wind ```
<xarray.DataArray 'v' (month: 2, latitude: 3, longitude: 3)> Size: 144B
array([[[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 1.]],

       [[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 1.]]])
Coordinates:
  \* month      (month) int32 8B 1 7
  \* latitude   (latitude) float32 12B 48.0 47.25 46.5
  \* longitude  (longitude) float32 12B 11.25 12.0 12.75
    level      int32 4B 200
Attributes:
    number_of_significant_digits:  2
    units:                         m s\*\*-1
    long_name:                     V component of wind
    standard_name:                 northward_wind
```ipython3 # by label ds.loc[dict(latitude=47.25, longitude=[11.25, 12])] = 100 ds["u"] ``` ```none Size: 144B array([[[ 0., 0., 0.], [100., 100., 0.], [ 0., 0., 1.]], [[ 0., 0., 0.], [100., 100., 0.], [ 0., 0., 1.]]]) Coordinates: * month (month) int32 8B 1 7 * latitude (latitude) float32 12B 48.0 47.25 46.5 * longitude (longitude) float32 12B 11.25 12.0 12.75 level int32 4B 200 Attributes: number_of_significant_digits: 2 units: m s**-1 long_name: U component of wind standard_name: eastward_wind ```
<xarray.DataArray 'u' (month: 2, latitude: 3, longitude: 3)> Size: 144B
array([[[  0.,   0.,   0.],
        [100., 100.,   0.],
        [  0.,   0.,   1.]],

       [[  0.,   0.,   0.],
        [100., 100.,   0.],
        [  0.,   0.,   1.]]])
Coordinates:
  \* month      (month) int32 8B 1 7
  \* latitude   (latitude) float32 12B 48.0 47.25 46.5
  \* longitude  (longitude) float32 12B 11.25 12.0 12.75
    level      int32 4B 200
Attributes:
    number_of_significant_digits:  2
    units:                         m s\*\*-1
    long_name:                     U component of wind
    standard_name:                 eastward_wind
```ipython3 # dataset as new values new_dat = ds_org.loc[dict(latitude=48, longitude=[11.25, 12])] new_dat ``` ```none Size: 120B Dimensions: (month: 2, longitude: 2) Coordinates: * month (month) int32 8B 1 7 * longitude (longitude) float32 8B 11.25 12.0 latitude float32 4B 48.0 level int32 4B 200 Data variables: z (month, longitude) float64 32B 1.136e+05 1.136e+05 ... 1.187e+05 u (month, longitude) float64 32B 12.75 12.69 14.87 14.62 v (month, longitude) float64 32B -7.891 -7.781 -1.875 -1.984 Attributes: Conventions: CF-1.0 Info: Monthly ERA-Interim data. Downloaded and edited by fabien.m... ```
<xarray.Dataset> Size: 120B
Dimensions:    (month: 2, longitude: 2)
Coordinates:
  \* month      (month) int32 8B 1 7
  \* longitude  (longitude) float32 8B 11.25 12.0
    latitude   float32 4B 48.0
    level      int32 4B 200
Data variables:
    z          (month, longitude) float64 32B 1.136e+05 1.136e+05 ... 1.187e+05
    u          (month, longitude) float64 32B 12.75 12.69 14.87 14.62
    v          (month, longitude) float64 32B -7.891 -7.781 -1.875 -1.984
Attributes:
    Conventions:  CF-1.0
    Info:         Monthly ERA-Interim data. Downloaded and edited by fabien.m...
```ipython3 ds.loc[dict(latitude=47.25, longitude=[11.25, 12])] = new_dat ds["u"] ``` ```none Size: 144B array([[[ 0. , 0. , 0. ], [12.74992466, 12.68701646, 0. ], [ 0. , 0. , 1. ]], [[ 0. , 0. , 0. ], [14.87464903, 14.62458894, 0. ], [ 0. , 0. , 1. ]]]) Coordinates: * month (month) int32 8B 1 7 * latitude (latitude) float32 12B 48.0 47.25 46.5 * longitude (longitude) float32 12B 11.25 12.0 12.75 level int32 4B 200 Attributes: number_of_significant_digits: 2 units: m s**-1 long_name: U component of wind standard_name: eastward_wind ```
<xarray.DataArray 'u' (month: 2, latitude: 3, longitude: 3)> Size: 144B
array([[[ 0.        ,  0.        ,  0.        ],
        [12.74992466, 12.68701646,  0.        ],
        [ 0.        ,  0.        ,  1.        ]],

       [[ 0.        ,  0.        ,  0.        ],
        [14.87464903, 14.62458894,  0.        ],
        [ 0.        ,  0.        ,  1.        ]]])
Coordinates:
  \* month      (month) int32 8B 1 7
  \* latitude   (latitude) float32 12B 48.0 47.25 46.5
  \* longitude  (longitude) float32 12B 11.25 12.0 12.75
    level      int32 4B 200
Attributes:
    number_of_significant_digits:  2
    units:                         m s\*\*-1
    long_name:                     U component of wind
    standard_name:                 eastward_wind
The dimensions can differ between the variables in the dataset, but all variables need to have at least the dimensions specified in the indexer dictionary. The new values must be either a scalar, a `DataArray` or a `Dataset` itself that contains all variables that also appear in the dataset to be modified. ## More advanced indexing The use of [`DataArray()`](../generated/xarray.DataArray.md#xarray.DataArray) objects as indexers enables very flexible indexing. The following is an example of the pointwise indexing: ```ipython3 da = xr.DataArray(np.arange(56).reshape((7, 8)), dims=["x", "y"]) da ``` ```none Size: 448B array([[ 0, 1, 2, 3, 4, 5, 6, 7], [ 8, 9, 10, 11, 12, 13, 14, 15], [16, 17, 18, 19, 20, 21, 22, 23], [24, 25, 26, 27, 28, 29, 30, 31], [32, 33, 34, 35, 36, 37, 38, 39], [40, 41, 42, 43, 44, 45, 46, 47], [48, 49, 50, 51, 52, 53, 54, 55]]) Dimensions without coordinates: x, y ```
<xarray.DataArray (x: 7, y: 8)> Size: 448B
array([[ 0,  1,  2,  3,  4,  5,  6,  7],
       [ 8,  9, 10, 11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29, 30, 31],
       [32, 33, 34, 35, 36, 37, 38, 39],
       [40, 41, 42, 43, 44, 45, 46, 47],
       [48, 49, 50, 51, 52, 53, 54, 55]])
Dimensions without coordinates: x, y
```ipython3 da.isel(x=xr.DataArray([0, 1, 6], dims="z"), y=xr.DataArray([0, 1, 0], dims="z")) ``` ```none Size: 24B array([ 0, 9, 48]) Dimensions without coordinates: z ```
<xarray.DataArray (z: 3)> Size: 24B
array([ 0,  9, 48])
Dimensions without coordinates: z
where three elements at `(ix, iy) = ((0, 0), (1, 1), (6, 0))` are selected and mapped along a new dimension `z`. If you want to add a coordinate to the new dimension `z`, you can supply a [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) with a coordinate, ```ipython3 da.isel( x=xr.DataArray([0, 1, 6], dims="z", coords={"z": ["a", "b", "c"]}), y=xr.DataArray([0, 1, 0], dims="z"), ) ``` ```none Size: 24B array([ 0, 9, 48]) Coordinates: * z (z)
<xarray.DataArray (z: 3)> Size: 24B
array([ 0,  9, 48])
Coordinates:
  \* z        (z) <U1 12B 'a' 'b' 'c'
Analogously, label-based pointwise-indexing is also possible by the `.sel` method: ```ipython3 da = xr.DataArray( np.random.rand(4, 3), [ ("time", pd.date_range("2000-01-01", periods=4)), ("space", ["IA", "IL", "IN"]), ], ) times = xr.DataArray( pd.to_datetime(["2000-01-03", "2000-01-02", "2000-01-01"]), dims="new_time" ) da.sel(space=xr.DataArray(["IA", "IL", "IN"], dims=["new_time"]), time=times) ``` ```none Size: 24B array([0.9195404 , 0.34044494, 0.590426 ]) Coordinates: * new_time (new_time) datetime64[us] 24B 2000-01-03 2000-01-02 2000-01-01 time (new_time) datetime64[us] 24B 2000-01-03 2000-01-02 2000-01-01 space (new_time)
<xarray.DataArray (new_time: 3)> Size: 24B
array([0.9195404 , 0.34044494, 0.590426  ])
Coordinates:
  \* new_time  (new_time) datetime64[us] 24B 2000-01-03 2000-01-02 2000-01-01
    time      (new_time) datetime64[us] 24B 2000-01-03 2000-01-02 2000-01-01
    space     (new_time) <U2 24B 'IA' 'IL' 'IN'
## Align and reindex Xarray’s `reindex`, `reindex_like` and `align` impose a `DataArray` or `Dataset` onto a new set of coordinates corresponding to dimensions. The original values are subset to the index labels still found in the new labels, and values corresponding to new labels not found in the original object are in-filled with `NaN`. Xarray operations that combine multiple objects generally automatically align their arguments to share the same indexes. However, manual alignment can be useful for greater control and for increased performance. To reindex a particular dimension, use [`reindex()`](../generated/xarray.DataArray.reindex.md#xarray.DataArray.reindex): ```ipython3 da.reindex(space=["IA", "CA"]) ``` ```none Size: 64B array([[0.57401177, nan], [0.24534982, nan], [0.9195404 , nan], [0.75356885, nan]]) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.DataArray (time: 4, space: 2)> Size: 64B
array([[0.57401177,        nan],
       [0.24534982,        nan],
       [0.9195404 ,        nan],
       [0.75356885,        nan]])
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 16B 'IA' 'CA'
The [`reindex_like()`](../generated/xarray.DataArray.reindex_like.md#xarray.DataArray.reindex_like) method is a useful shortcut. To demonstrate, we will make a subset DataArray with new values: ```ipython3 foo = da.rename("foo") baz = (10 * da[:2, :2]).rename("baz") baz ``` ```none Size: 32B array([[5.74011775, 0.61269962], [2.45349819, 3.40444937]]) Coordinates: * time (time) datetime64[us] 16B 2000-01-01 2000-01-02 * space (space)
<xarray.DataArray 'baz' (time: 2, space: 2)> Size: 32B
array([[5.74011775, 0.61269962],
       [2.45349819, 3.40444937]])
Coordinates:
  \* time     (time) datetime64[us] 16B 2000-01-01 2000-01-02
  \* space    (space) <U2 16B 'IA' 'IL'
Reindexing `foo` with `baz` selects out the first two values along each dimension: ```ipython3 foo.reindex_like(baz) ``` ```none Size: 32B array([[0.57401177, 0.06126996], [0.24534982, 0.34044494]]) Coordinates: * time (time) datetime64[us] 16B 2000-01-01 2000-01-02 * space (space)
<xarray.DataArray 'foo' (time: 2, space: 2)> Size: 32B
array([[0.57401177, 0.06126996],
       [0.24534982, 0.34044494]])
Coordinates:
  \* time     (time) datetime64[us] 16B 2000-01-01 2000-01-02
  \* space    (space) <U2 16B 'IA' 'IL'
The opposite operation asks us to reindex to a larger shape, so we fill in the missing values with `NaN`: ```ipython3 baz.reindex_like(foo) ``` ```none Size: 96B array([[5.74011775, 0.61269962, nan], [2.45349819, 3.40444937, nan], [ nan, nan, nan], [ nan, nan, nan]]) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.DataArray 'baz' (time: 4, space: 3)> Size: 96B
array([[5.74011775, 0.61269962,        nan],
       [2.45349819, 3.40444937,        nan],
       [       nan,        nan,        nan],
       [       nan,        nan,        nan]])
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
The [`align()`](../generated/xarray.align.md#xarray.align) function lets us perform more flexible database-like `'inner'`, `'outer'`, `'left'` and `'right'` joins: ```ipython3 xr.align(foo, baz, join="inner") ``` ```none ( Size: 32B array([[0.57401177, 0.06126996], [0.24534982, 0.34044494]]) Coordinates: * time (time) datetime64[us] 16B 2000-01-01 2000-01-02 * space (space) Size: 32B array([[5.74011775, 0.61269962], [2.45349819, 3.40444937]]) Coordinates: * time (time) datetime64[us] 16B 2000-01-01 2000-01-02 * space (space) Size: 96B array([[0.57401177, 0.06126996, 0.590426 ], [0.24534982, 0.34044494, 0.98472874], [0.9195404 , 0.03777169, 0.86154929], [0.75356885, 0.40517876, 0.34352588]]) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space) Size: 96B array([[5.74011775, 0.61269962, nan], [2.45349819, 3.40444937, nan], [ nan, nan, nan], [ nan, nan, nan]]) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space) Size: 468B Dimensions: (month: 2, latitude: 3, longitude: 3) Coordinates: * month (month) int32 8B 1 7 * latitude (latitude) float32 12B 48.0 47.25 46.5 * longitude (longitude) float32 12B 11.25 12.0 12.75 level int32 4B 200 Data variables: z (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0 u (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0 v (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0 Attributes: Conventions: CF-1.0 Info: Monthly ERA-Interim data. Downloaded and edited by fabien.m... ```
<xarray.Dataset> Size: 468B
Dimensions:    (month: 2, latitude: 3, longitude: 3)
Coordinates:
  \* month      (month) int32 8B 1 7
  \* latitude   (latitude) float32 12B 48.0 47.25 46.5
  \* longitude  (longitude) float32 12B 11.25 12.0 12.75
    level      int32 4B 200
Data variables:
    z          (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0
    u          (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0
    v          (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0
Attributes:
    Conventions:  CF-1.0
    Info:         Monthly ERA-Interim data. Downloaded and edited by fabien.m...
```ipython3 ds.reindex_like(baz) ``` ```none Size: 468B Dimensions: (month: 2, latitude: 3, longitude: 3) Coordinates: * month (month) int32 8B 1 7 * latitude (latitude) float32 12B 48.0 47.25 46.5 * longitude (longitude) float32 12B 11.25 12.0 12.75 level int32 4B 200 Data variables: z (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0 u (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0 v (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0 Attributes: Conventions: CF-1.0 Info: Monthly ERA-Interim data. Downloaded and edited by fabien.m... ```
<xarray.Dataset> Size: 468B
Dimensions:    (month: 2, latitude: 3, longitude: 3)
Coordinates:
  \* month      (month) int32 8B 1 7
  \* latitude   (latitude) float32 12B 48.0 47.25 46.5
  \* longitude  (longitude) float32 12B 11.25 12.0 12.75
    level      int32 4B 200
Data variables:
    z          (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0
    u          (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0
    v          (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0
Attributes:
    Conventions:  CF-1.0
    Info:         Monthly ERA-Interim data. Downloaded and edited by fabien.m...
```ipython3 other = xr.DataArray(["a", "b", "c"], dims="other") # this is a no-op, because there are no shared dimension names ds.reindex_like(other) ``` ```none Size: 468B Dimensions: (month: 2, latitude: 3, longitude: 3) Coordinates: * month (month) int32 8B 1 7 * latitude (latitude) float32 12B 48.0 47.25 46.5 * longitude (longitude) float32 12B 11.25 12.0 12.75 level int32 4B 200 Data variables: z (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0 u (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0 v (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0 Attributes: Conventions: CF-1.0 Info: Monthly ERA-Interim data. Downloaded and edited by fabien.m... ```
<xarray.Dataset> Size: 468B
Dimensions:    (month: 2, latitude: 3, longitude: 3)
Coordinates:
  \* month      (month) int32 8B 1 7
  \* latitude   (latitude) float32 12B 48.0 47.25 46.5
  \* longitude  (longitude) float32 12B 11.25 12.0 12.75
    level      int32 4B 200
Data variables:
    z          (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0
    u          (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0
    v          (month, latitude, longitude) float64 144B 0.0 0.0 0.0 ... 0.0 1.0
Attributes:
    Conventions:  CF-1.0
    Info:         Monthly ERA-Interim data. Downloaded and edited by fabien.m...
## Missing coordinate labels Coordinate labels for each dimension are optional (as of xarray v0.9). Label based indexing with `.sel` and `.loc` uses standard positional, integer-based indexing as a fallback for dimensions without a coordinate label: ```ipython3 da = xr.DataArray([1, 2, 3], dims="x") da.sel(x=[0, -1]) ``` ```none Size: 16B array([1, 3]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 2)> Size: 16B
array([1, 3])
Dimensions without coordinates: x
Alignment between xarray objects where one or both do not have coordinate labels succeeds only if all dimensions of the same name have the same length. Otherwise, it raises an informative error: ```ipython3 xr.align(da, da[:2]) ``` ```ipythontb AlignmentError: cannot reindex or align along dimension 'x' because of conflicting dimension sizes: {2, 3} ``` ## Underlying Indexes Xarray uses the [`pandas.Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index) internally to perform indexing operations. If you need to access the underlying indexes, they are available through the [`indexes`](../generated/xarray.DataArray.indexes.md#xarray.DataArray.indexes) attribute. ```ipython3 da = xr.DataArray( np.random.rand(4, 3), [ ("time", pd.date_range("2000-01-01", periods=4)), ("space", ["IA", "IL", "IN"]), ], ) da ``` ```none Size: 96B array([[0.17091717, 0.39465901, 0.64166617], [0.27459243, 0.46235433, 0.87137165], [0.40113122, 0.61058827, 0.11796713], [0.70218436, 0.41403366, 0.34234521]]) Coordinates: * time (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04 * space (space)
<xarray.DataArray (time: 4, space: 3)> Size: 96B
array([[0.17091717, 0.39465901, 0.64166617],
       [0.27459243, 0.46235433, 0.87137165],
       [0.40113122, 0.61058827, 0.11796713],
       [0.70218436, 0.41403366, 0.34234521]])
Coordinates:
  \* time     (time) datetime64[us] 32B 2000-01-01 2000-01-02 ... 2000-01-04
  \* space    (space) <U2 24B 'IA' 'IL' 'IN'
```ipython3 da.indexes ``` ```none Indexes: time DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04'], dtype='datetime64[us]', name='time', freq='D') space Index(['IA', 'IL', 'IN'], dtype='str', name='space') ``` ```ipython3 da.indexes["time"] ``` ```none DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04'], dtype='datetime64[us]', name='time', freq='D') ``` Use [`get_index()`](../generated/xarray.DataArray.get_index.md#xarray.DataArray.get_index) to get an index for a dimension, falling back to a default [`pandas.RangeIndex`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.RangeIndex.html#pandas.RangeIndex) if it has no coordinate labels: ```ipython3 da = xr.DataArray([1, 2, 3], dims="x") da ``` ```none Size: 24B array([1, 2, 3]) Dimensions without coordinates: x ```
<xarray.DataArray (x: 3)> Size: 24B
array([1, 2, 3])
Dimensions without coordinates: x
```ipython3 da.get_index("x") ``` ```none RangeIndex(start=0, stop=3, step=1, name='x') ``` ## Copies vs. Views Whether array indexing returns a view or a copy of the underlying data depends on the nature of the labels. For positional (integer) indexing, xarray follows the same [rules](https://numpy.org/doc/stable/user/basics.copies.html) as NumPy: * Positional indexing with only integers and slices returns a view. * Positional indexing with arrays or lists returns a copy. The rules for label based indexing are more complex: * Label-based indexing with only slices returns a view. * Label-based indexing with arrays returns a copy. * Label-based indexing with scalars returns a view or a copy, depending upon if the corresponding positional indexer can be represented as an integer or a slice object. The exact rules are determined by pandas. Whether data is a copy or a view is more predictable in xarray than in pandas, so unlike pandas, xarray does not produce [SettingWithCopy warnings](https://pandas.pydata.org/pandas-docs/stable/indexing.html#returning-a-view-versus-a-copy). However, you should still avoid assignment with chained indexing. Note that other operations (such as [`values()`](../generated/xarray.DataArray.values.md#xarray.DataArray.values)) may also return views rather than copies. ## Multi-level indexing Just like pandas, advanced indexing on multi-level indexes is possible with `loc` and `sel`. You can slice a multi-index by providing multiple indexers, i.e., a tuple of slices, labels, list of labels, or any selector allowed by pandas: ```ipython3 midx = pd.MultiIndex.from_product([list("abc"), [0, 1]], names=("one", "two")) mda = xr.DataArray(np.random.rand(6, 3), [("x", midx), ("y", range(3))]) mda ``` ```none Size: 144B array([[0.59592532, 0.19986426, 0.09973676], [0.73459622, 0.01654451, 0.4813845 ], [0.09593887, 0.49730633, 0.83879627], [0.89733326, 0.73259152, 0.75872436], [0.56065718, 0.47147793, 0.13876812], [0.09446113, 0.94225634, 0.13409924]]) Coordinates: * x (x) object 48B MultiIndex * one (x) object 48B 'a' 'a' 'b' 'b' 'c' 'c' * two (x) int64 48B 0 1 0 1 0 1 * y (y) int64 24B 0 1 2 ```
<xarray.DataArray (x: 6, y: 3)> Size: 144B
array([[0.59592532, 0.19986426, 0.09973676],
       [0.73459622, 0.01654451, 0.4813845 ],
       [0.09593887, 0.49730633, 0.83879627],
       [0.89733326, 0.73259152, 0.75872436],
       [0.56065718, 0.47147793, 0.13876812],
       [0.09446113, 0.94225634, 0.13409924]])
Coordinates:
  \* x        (x) object 48B MultiIndex
  \* one      (x) object 48B 'a' 'a' 'b' 'b' 'c' 'c'
  \* two      (x) int64 48B 0 1 0 1 0 1
  \* y        (y) int64 24B 0 1 2
```ipython3 mda.sel(x=(list("ab"), [0])) ``` ```none Size: 48B array([[0.59592532, 0.19986426, 0.09973676], [0.09593887, 0.49730633, 0.83879627]]) Coordinates: * x (x) object 16B MultiIndex * one (x) object 16B 'a' 'b' * two (x) int64 16B 0 0 * y (y) int64 24B 0 1 2 ```
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[0.59592532, 0.19986426, 0.09973676],
       [0.09593887, 0.49730633, 0.83879627]])
Coordinates:
  \* x        (x) object 16B MultiIndex
  \* one      (x) object 16B 'a' 'b'
  \* two      (x) int64 16B 0 0
  \* y        (y) int64 24B 0 1 2
You can also select multiple elements by providing a list of labels or tuples or a slice of tuples: ```ipython3 mda.sel(x=[("a", 0), ("b", 1)]) ``` ```none Size: 48B array([[0.59592532, 0.19986426, 0.09973676], [0.89733326, 0.73259152, 0.75872436]]) Coordinates: * x (x) object 16B MultiIndex * one (x) object 16B 'a' 'b' * two (x) int64 16B 0 1 * y (y) int64 24B 0 1 2 ```
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[0.59592532, 0.19986426, 0.09973676],
       [0.89733326, 0.73259152, 0.75872436]])
Coordinates:
  \* x        (x) object 16B MultiIndex
  \* one      (x) object 16B 'a' 'b'
  \* two      (x) int64 16B 0 1
  \* y        (y) int64 24B 0 1 2
Additionally, xarray supports dictionaries: ```ipython3 mda.sel(x={"one": "a", "two": 0}) ``` ```none Size: 24B array([0.59592532, 0.19986426, 0.09973676]) Coordinates: * y (y) int64 24B 0 1 2 x object 8B ('a', np.int64(0)) one
<xarray.DataArray (y: 3)> Size: 24B
array([0.59592532, 0.19986426, 0.09973676])
Coordinates:
  \* y        (y) int64 24B 0 1 2
    x        object 8B ('a', np.int64(0))
    one      <U1 4B 'a'
    two      int64 8B 0
For convenience, `sel` also accepts multi-index levels directly as keyword arguments: ```ipython3 mda.sel(one="a", two=0) ``` ```none Size: 24B array([0.59592532, 0.19986426, 0.09973676]) Coordinates: * y (y) int64 24B 0 1 2 x object 8B ('a', np.int64(0)) one
<xarray.DataArray (y: 3)> Size: 24B
array([0.59592532, 0.19986426, 0.09973676])
Coordinates:
  \* y        (y) int64 24B 0 1 2
    x        object 8B ('a', np.int64(0))
    one      <U1 4B 'a'
    two      int64 8B 0
Note that using `sel` it is not possible to mix a dimension indexer with level indexers for that dimension (e.g., `mda.sel(x={'one': 'a'}, two=0)` will raise a `ValueError`). Like pandas, xarray handles partial selection on multi-index (level drop). As shown below, it also renames the dimension / coordinate when the multi-index is reduced to a single index. ```ipython3 mda.loc[{"one": "a"}, ...] ``` ```none Size: 48B array([[0.59592532, 0.19986426, 0.09973676], [0.73459622, 0.01654451, 0.4813845 ]]) Coordinates: * two (two) int64 16B 0 1 * y (y) int64 24B 0 1 2 one
<xarray.DataArray (two: 2, y: 3)> Size: 48B
array([[0.59592532, 0.19986426, 0.09973676],
       [0.73459622, 0.01654451, 0.4813845 ]])
Coordinates:
  \* two      (two) int64 16B 0 1
  \* y        (y) int64 24B 0 1 2
    one      <U1 4B 'a'
Unlike pandas, xarray does not guess whether you provide index levels or dimensions when using `loc` in some ambiguous cases. For example, for `mda.loc[{'one': 'a', 'two': 0}]` and `mda.loc['a', 0]` xarray always interprets (‘one’, ‘two’) and (‘a’, 0) as the names and labels of the 1st and 2nd dimension, respectively. You must specify all dimensions or use the ellipsis in the `loc` specifier, e.g. in the example above, `mda.loc[{'one': 'a', 'two': 0}, :]` or `mda.loc[('a', 0), ...]`. ## Indexing rules Here we describe the full rules xarray uses for vectorized indexing. Note that this is for the purposes of explanation: for the sake of efficiency and to support various backends, the actual implementation is different. 1. (Only for label based indexing.) Look up positional indexes along each dimension from the corresponding [`pandas.Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index). 2. A full slice object `:` is inserted for each dimension without an indexer. 3. `slice` objects are converted into arrays, given by `np.arange(*slice.indices(...))`. 4. Assume dimension names for array indexers without dimensions, such as `np.ndarray` and `list`, from the dimensions to be indexed along. For example, `v.isel(x=[0, 1])` is understood as `v.isel(x=xr.DataArray([0, 1], dims=['x']))`. 5. For each variable in a `Dataset` or `DataArray` (the array and its coordinates): 1. Broadcast all relevant indexers based on their dimension names (see [Broadcasting by dimension name](computation.md#compute-broadcasting) for full details). 2. Index the underling array by the broadcast indexers, using NumPy’s advanced indexing rules. 6. If any indexer DataArray has coordinates and no coordinate with the same name exists, attach them to the indexed object. #### NOTE Only 1-dimensional boolean arrays can be used as indexers. # installing.html.md # Installation ## Required dependencies - Python (3.11 or later) - [numpy](https://www.numpy.org/) (1.26 or later) - [packaging](https://packaging.pypa.io/en/latest/#) (24.1 or later) - [pandas](https://pandas.pydata.org/) (2.2 or later) ## Optional dependencies #### NOTE If you are using pip to install xarray, optional dependencies can be installed by specifying *extras*. [Instructions](#installation-instructions) for both pip and conda are given below. ### For netCDF and IO - [netCDF4](https://github.com/Unidata/netcdf4-python): recommended if you want to use xarray for reading or writing netCDF files - [scipy](https://scipy.org): used as a fallback for reading/writing netCDF3 - [pydap](https://pydap.github.io/pydap/en/intro.html): used as a fallback for accessing OPeNDAP - [h5netcdf](https://github.com/h5netcdf/h5netcdf): an alternative library for reading and writing netCDF4 files that does not use the netCDF-C libraries - [zarr](https://zarr.readthedocs.io): for chunked, compressed, N-dimensional arrays. - [cftime](https://unidata.github.io/cftime): recommended if you want to encode/decode datetimes for non-standard calendars or dates before year 1678 or after year 2262. - [iris](https://github.com/scitools/iris): for conversion to and from iris’ Cube objects ### For accelerating xarray - [scipy](https://scipy.org/): necessary to enable the interpolation features for xarray objects - [bottleneck](https://github.com/pydata/bottleneck): speeds up NaN-skipping and rolling window aggregations by a large factor - [numbagg](https://github.com/numbagg/numbagg): for exponential rolling window operations ### For parallel computing - [dask.array](https://docs.dask.org): required for [Parallel Computing with Dask](../user-guide/dask.md#dask). ### For plotting - [matplotlib](https://matplotlib.org): required for [Plotting](../user-guide/plotting.md#plotting) - [cartopy](https://cartopy.readthedocs.io): recommended for [Maps](../user-guide/plotting.md#plot-maps) - [seaborn](https://seaborn.pydata.org): for better color palettes - [nc-time-axis](https://nc-time-axis.readthedocs.io): for plotting cftime.datetime objects ### Alternative data containers - [sparse](https://sparse.pydata.org/): for sparse arrays - [pint](https://pint.readthedocs.io/): for units of measure - Any numpy-like objects that support [NEP-18](https://numpy.org/neps/nep-0018-array-function-protocol.html). Note that while such libraries theoretically should work, they are untested. Integration tests are in the process of being written for individual libraries. ## Minimum dependency versions Xarray adopts a rolling policy regarding the minimum supported version of its dependencies: - **Python:** 30 months ([NEP-29](https://numpy.org/neps/nep-0029-deprecation_policy.html)) - **numpy:** 18 months ([NEP-29](https://numpy.org/neps/nep-0029-deprecation_policy.html)) - **all other libraries:** 12 months This means the latest minor (X.Y) version from N months prior. Patch versions (x.y.Z) are not pinned, and only the latest available at the moment of publishing the xarray release is guaranteed to work. You can see the actual minimum tested versions: [https://github.com/pydata/xarray/blob/main/ci/requirements/min-all-deps.yml](https://github.com/pydata/xarray/blob/main/ci/requirements/min-all-deps.yml) ## Instructions Xarray itself is a pure Python package, but its dependencies are not. The easiest way to get everything installed is to use [conda](https://docs.conda.io). To install xarray with its recommended dependencies using the conda command line tool: ```default $ conda install -c conda-forge xarray dask netCDF4 bottleneck ``` If you require other [Optional dependencies](#optional-dependencies) add them to the line above. We recommend using the community maintained [conda-forge](https://conda-forge.org) channel, as some of the dependencies are difficult to build. New releases may also appear in conda-forge before being updated in the default channel. If you don’t use conda, be sure you have the required dependencies (numpy and pandas) installed first. Then, install xarray with pip: ```default $ python -m pip install xarray ``` We also maintain other dependency sets for different subsets of functionality: ```default $ python -m pip install "xarray[io]" # Install optional dependencies for handling I/O $ python -m pip install "xarray[accel]" # Install optional dependencies for accelerating xarray $ python -m pip install "xarray[parallel]" # Install optional dependencies for dask arrays $ python -m pip install "xarray[viz]" # Install optional dependencies for visualization $ python -m pip install "xarray[complete]" # Install all the above ``` The above commands should install most of the [optional dependencies](). However, some packages which are either not listed on PyPI or require extra installation steps are excluded. To know which dependencies would be installed, take a look at the `[project.optional-dependencies]` section in `pyproject.toml`: ```toml [project.optional-dependencies] accel = [ "scipy>=1.15", "bottleneck", "numbagg>=0.9", "numba>=0.62", # numba 0.62 added support for numpy 2.3 "flox>=0.10", "opt_einsum", ] complete = ["xarray[accel,etc,io,parallel,viz]"] io = [ "netCDF4>=1.6.0", "h5netcdf[h5py]>=1.5.0", "pydap", "scipy>=1.15", "zarr>=3.0", "fsspec", "cftime", "pooch", ] etc = ["sparse>=0.15"] parallel = ["dask[complete]"] viz = ["cartopy>=0.24", "matplotlib>=3.10", "nc-time-axis", "seaborn"] types = [ "pandas-stubs", "scipy-stubs", "types-colorama", "types-decorator", "types-defusedxml", "types-docutils", "types-networkx", "types-openpyxl", "types-pexpect", "types-psutil", "types-pycurl", "types-Pygments", "types-python-dateutil", "types-pytz", "types-PyYAML", "types-requests", "types-setuptools", "types-xlrd", ] [dependency-groups] dev = [ "hypothesis", "jinja2", "mypy==1.19.1", "pre-commit", "pytest", "pytest-cov", "pytest-env", "pytest-mypy-plugins>=4.0.0", "pytest-timeout", "pytest-xdist", "pytest-asyncio", "pytz", "ruff>=0.15.0", "sphinx", "sphinx_autosummary_accessors", "xarray[complete,types]", ] [project.urls] Documentation = "https://docs.xarray.dev" SciPy2015-talk = "https://www.youtube.com/watch?v=X0pAhJgySxk" homepage = "https://xarray.dev/" issue-tracker = "https://github.com/pydata/xarray/issues" source-code = "https://github.com/pydata/xarray" [project.entry-points."xarray.chunkmanagers"] dask = "xarray.namedarray.daskmanager:DaskManager" ``` ## Development versions To install the most recent development version, install from github: ```default $ python -m pip install git+https://github.com/pydata/xarray.git ``` or from TestPyPI: ```default $ python -m pip install --index-url https://test.pypi.org/simple --extra-index-url https://pypi.org/simple --pre xarray ``` ## Testing To run the test suite after installing xarray, install (via pypi or conda) [py.test](https://pytest.org) and run `pytest` in the root directory of the xarray repository. ### Performance Monitoring To run these benchmark tests in a local machine, first install - [airspeed-velocity](https://asv.readthedocs.io/en/latest/): a tool for benchmarking Python packages over their lifetime. and run `asv run # this will install some conda environments in ./.asv/envs` # internal-design.html.md # Internal Design This page gives an overview of the internal design of xarray. In totality, the Xarray project defines 4 key data structures. In order of increasing complexity, they are: - [`xarray.Variable`](../generated/xarray.Variable.md#xarray.Variable), - [`xarray.DataArray`](../generated/xarray.DataArray.md#xarray.DataArray), - [`xarray.Dataset`](../generated/xarray.Dataset.md#xarray.Dataset), - [`xarray.DataTree`](../generated/xarray.DataTree.md#xarray.DataTree). The user guide lists only [`xarray.DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) and [`xarray.Dataset`](../generated/xarray.Dataset.md#xarray.Dataset), but [`Variable`](../generated/xarray.Variable.md#xarray.Variable) is the fundamental object internally, and [`DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) is a natural generalisation of [`xarray.Dataset`](../generated/xarray.Dataset.md#xarray.Dataset). #### NOTE Our [Development roadmap](../roadmap.md#roadmap) includes plans to document [`Variable`](../generated/xarray.Variable.md#xarray.Variable) as fully public API. Internally private [lazy indexing classes](#internal-design-lazy-indexing) are used to avoid loading more data than necessary, and flexible indexes classes (derived from `Index`) provide performant label-based lookups. ## Data Structures The [Data Structures](../user-guide/data-structures.md#data-structures) page in the user guide explains the basics and concentrates on user-facing behavior, whereas this section explains how xarray’s data structure classes actually work internally. ### Variable Objects The core internal data structure in xarray is the [`Variable`](../generated/xarray.Variable.md#xarray.Variable), which is used as the basic building block behind xarray’s [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset), [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) types. A [`Variable`](../generated/xarray.Variable.md#xarray.Variable) consists of: - `dims`: A tuple of dimension names. - `data`: The N-dimensional array (typically a NumPy or Dask array) storing the Variable’s data. It must have the same number of dimensions as the length of `dims`. - `attrs`: A dictionary of metadata associated with this array. By convention, xarray’s built-in operations never use this metadata. - `encoding`: Another dictionary used to store information about how these variable’s data is represented on disk. See [Reading encoded data](../user-guide/io.md#io-encoding) for more details. [`Variable`](../generated/xarray.Variable.md#xarray.Variable) has an interface similar to NumPy arrays, but extended to make use of named dimensions. For example, it uses `dim` in preference to an `axis` argument for methods like `mean`, and supports [Broadcasting by dimension name](../user-guide/computation.md#compute-broadcasting). However, unlike `Dataset` and `DataArray`, the basic `Variable` does not include coordinate labels along each axis. [`Variable`](../generated/xarray.Variable.md#xarray.Variable) is public API, but because of its incomplete support for labeled data, it is mostly intended for advanced uses, such as in xarray itself, for writing new backends, or when creating custom indexes. You can access the variable objects that correspond to xarray objects via the (readonly) [`Dataset.variables`](../generated/xarray.Dataset.variables.md#xarray.Dataset.variables) and [`DataArray.variable`](../generated/xarray.DataArray.variable.md#xarray.DataArray.variable) attributes. ### DataArray Objects The simplest data structure used by most users is [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray). A [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) is a composite object consisting of multiple [`Variable`](../generated/xarray.Variable.md#xarray.Variable) objects which store related data. A single [`Variable`](../generated/xarray.Variable.md#xarray.Variable) is referred to as the “data variable”, and stored under the `variable`` attribute. A [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) inherits all of the properties of this data variable, i.e. `dims`, `data`, `attrs` and `encoding`, all of which are implemented by forwarding on to the underlying `Variable` object. In addition, a [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) stores additional `Variable` objects stored in a dict under the private `_coords` attribute, each of which is referred to as a “Coordinate Variable”. These coordinate variable objects are only allowed to have `dims` that are a subset of the data variable’s `dims`, and each dim has a specific length. This means that the full [`size`](../generated/xarray.DataArray.size.md#xarray.DataArray.size) of the dataarray can be represented by a dictionary mapping dimension names to integer sizes. The underlying data variable has this exact same size, and the attached coordinate variables have sizes which are some subset of the size of the data variable. Another way of saying this is that all coordinate variables must be “alignable” with the data variable. When a coordinate is accessed by the user (e.g. via the dict-like [`__getitem__`](../generated/xarray.DataArray.__getitem__.md#xarray.DataArray.__getitem__) syntax), then a new `DataArray` is constructed by finding all coordinate variables that have compatible dimensions and re-attaching them before the result is returned. This is why most users never see the `Variable` class underlying each coordinate variable - it is always promoted to a `DataArray` before returning. Lookups are performed by special `Index` objects, which are stored in a dict under the private `_indexes` attribute. Indexes must be associated with one or more coordinates, and essentially act by translating a query given in physical coordinate space (typically via the [`sel()`](../generated/xarray.DataArray.sel.md#xarray.DataArray.sel) method) into a set of integer indices in array index space that can be used to index the underlying n-dimensional array-like `data`. Indexing in array index space (typically performed via the [`isel()`](../generated/xarray.DataArray.isel.md#xarray.DataArray.isel) method) does not require consulting an `Index` object. Finally a [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) defines a [`name`](../generated/xarray.DataArray.name.md#xarray.DataArray.name) attribute, which refers to its data variable but is stored on the wrapping `DataArray` class. The `name` attribute is primarily used when one or more [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) objects are promoted into a [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) (e.g. via [`to_dataset()`](../generated/xarray.DataArray.to_dataset.md#xarray.DataArray.to_dataset)). Note that the underlying [`Variable`](../generated/xarray.Variable.md#xarray.Variable) objects are all unnamed, so they can always be referred to uniquely via a dict-like mapping. ### Dataset Objects The [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) class is a generalization of the [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) class that can hold multiple data variables. Internally all data variables and coordinate variables are stored under a single `variables` dict, and coordinates are specified by storing their names in a private `_coord_names` dict. The dataset’s `dims` are the set of all dims present across any variable, but (similar to in dataarrays) coordinate variables cannot have a dimension that is not present on any data variable. When a data variable or coordinate variable is accessed, a new `DataArray` is again constructed from all compatible coordinates before returning. #### NOTE The way that selecting a variable from a `DataArray` or `Dataset` actually involves internally wrapping the `Variable` object back up into a `DataArray`/`Dataset` is the primary reason [we recommend against subclassing](extending-xarray.md#internals-accessors-composition) Xarray objects. The main problem it creates is that we currently cannot easily guarantee that for example selecting a coordinate variable from your `SubclassedDataArray` would return an instance of `SubclassedDataArray` instead of just an [`xarray.DataArray`](../generated/xarray.DataArray.md#xarray.DataArray). See [GH issue](https://github.com/pydata/xarray/issues/3980) for more details. ## Lazy Indexing Classes ### Lazy Loading If we open a `Variable` object from disk using [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset) we can see that the actual values of the array wrapped by the data variable are not displayed. ```ipython3 da = xr.tutorial.open_dataset("air_temperature")["air"] var = da.variable var ``` ```none Size: 31MB [3869000 values with dtype=float64] Attributes: long_name: 4xDaily Air temperature at sigma level 995 units: degK precision: 2 GRIB_id: 11 GRIB_name: TMP var_desc: Air temperature dataset: NMC Reanalysis level_desc: Surface statistic: Individual Obs parent_stat: Other actual_range: [185.16 322.1 ] ```
<xarray.Variable (time: 2920, lat: 25, lon: 53)> Size: 31MB
[3869000 values with dtype=float64]
Attributes:
    long_name:     4xDaily Air temperature at sigma level 995
    units:         degK
    precision:     2
    GRIB_id:       11
    GRIB_name:     TMP
    var_desc:      Air temperature
    dataset:       NMC Reanalysis
    level_desc:    Surface
    statistic:     Individual Obs
    parent_stat:   Other
    actual_range:  [185.16 322.1 ]
We can see the size, and the dtype of the underlying array, but not the actual values. This is because the values have not yet been loaded. If we look at the private attribute `_data()` containing the underlying array object, we see something interesting: ```ipython3 var._data ``` ```none MemoryCachedArray(array=CopyOnWriteArray(array=_ElementwiseFunctionArray(LazilyIndexedArray(array=, key=BasicIndexer((slice(None, None, None), slice(None, None, None), slice(None, None, None)))), func=functools.partial(, scale_factor=np.float64(0.01), add_offset=None, dtype=), dtype=dtype('float64')))) ``` You’re looking at one of xarray’s internal Lazy Indexing Classes. These powerful classes are hidden from the user, but provide important functionality. Calling the public [`data`](../generated/xarray.Variable.data.md#xarray.Variable.data) property loads the underlying array into memory. ```ipython3 var.data ``` ```none array([[[241.2 , 242.5 , ..., 235.5 , 238.6 ], [243.8 , 244.5 , ..., 235.3 , 239.3 ], ..., [295.9 , 296.2 , ..., 295.9 , 295.2 ], [296.29, 296.79, ..., 296.79, 296.6 ]], [[242.1 , 242.7 , ..., 233.6 , 235.8 ], [243.6 , 244.1 , ..., 232.5 , 235.7 ], ..., [296.2 , 296.7 , ..., 295.5 , 295.1 ], [296.29, 297.2 , ..., 296.4 , 296.6 ]], ..., [[245.79, 244.79, ..., 243.99, 244.79], [249.89, 249.29, ..., 242.49, 244.29], ..., [296.29, 297.19, ..., 295.09, 294.39], [297.79, 298.39, ..., 295.49, 295.19]], [[245.09, 244.29, ..., 241.49, 241.79], [249.89, 249.29, ..., 240.29, 241.69], ..., [296.09, 296.89, ..., 295.69, 295.19], [297.69, 298.09, ..., 296.19, 295.69]]], shape=(2920, 25, 53)) ``` This array is now cached, which we can see by accessing the private attribute again: ```ipython3 var._data ``` ```none MemoryCachedArray(array=NumpyIndexingAdapter(array=array([[[241.2 , 242.5 , ..., 235.5 , 238.6 ], [243.8 , 244.5 , ..., 235.3 , 239.3 ], ..., [295.9 , 296.2 , ..., 295.9 , 295.2 ], [296.29, 296.79, ..., 296.79, 296.6 ]], [[242.1 , 242.7 , ..., 233.6 , 235.8 ], [243.6 , 244.1 , ..., 232.5 , 235.7 ], ..., [296.2 , 296.7 , ..., 295.5 , 295.1 ], [296.29, 297.2 , ..., 296.4 , 296.6 ]], ..., [[245.79, 244.79, ..., 243.99, 244.79], [249.89, 249.29, ..., 242.49, 244.29], ..., [296.29, 297.19, ..., 295.09, 294.39], [297.79, 298.39, ..., 295.49, 295.19]], [[245.09, 244.29, ..., 241.49, 241.79], [249.89, 249.29, ..., 240.29, 241.69], ..., [296.09, 296.89, ..., 295.69, 295.19], [297.69, 298.09, ..., 296.19, 295.69]]], shape=(2920, 25, 53)))) ``` ### Lazy Indexing The purpose of these lazy indexing classes is to prevent more data being loaded into memory than is necessary for the subsequent analysis, by deferring loading data until after indexing is performed. Let’s open the data from disk again. ```ipython3 da = xr.tutorial.open_dataset("air_temperature")["air"] var = da.variable ``` Now, notice how even after subsetting the data has does not get loaded: ```ipython3 var.isel(time=0) ``` ```none Size: 11kB [1325 values with dtype=float64] Attributes: long_name: 4xDaily Air temperature at sigma level 995 units: degK precision: 2 GRIB_id: 11 GRIB_name: TMP var_desc: Air temperature dataset: NMC Reanalysis level_desc: Surface statistic: Individual Obs parent_stat: Other actual_range: [185.16 322.1 ] ```
<xarray.Variable (lat: 25, lon: 53)> Size: 11kB
[1325 values with dtype=float64]
Attributes:
    long_name:     4xDaily Air temperature at sigma level 995
    units:         degK
    precision:     2
    GRIB_id:       11
    GRIB_name:     TMP
    var_desc:      Air temperature
    dataset:       NMC Reanalysis
    level_desc:    Surface
    statistic:     Individual Obs
    parent_stat:   Other
    actual_range:  [185.16 322.1 ]
The shape has changed, but the values are still not shown. Looking at the private attribute again shows how this indexing information was propagated via the hidden lazy indexing classes: ```ipython3 var.isel(time=0)._data ``` ```none MemoryCachedArray(array=CopyOnWriteArray(array=_ElementwiseFunctionArray(LazilyIndexedArray(array=, key=BasicIndexer((0, slice(None, None, None), slice(None, None, None)))), func=functools.partial(, scale_factor=np.float64(0.01), add_offset=None, dtype=), dtype=dtype('float64')))) ``` #### NOTE Currently only certain indexing operations are lazy, not all array operations. For discussion of making all array operations lazy see [GH issue #5081](https://github.com/pydata/xarray/issues/5081). ### Lazy Dask Arrays Note that xarray’s implementation of Lazy Indexing classes is completely separate from how [`dask.array.Array`](https://docs.dask.org/en/latest/generated/dask.array.Array.html#dask.array.Array) objects evaluate lazily. Dask-backed xarray objects delay almost all operations until [`compute()`](../generated/xarray.DataArray.compute.md#xarray.DataArray.compute) is called (either explicitly or implicitly via [`plot()`](../generated/xarray.DataArray.plot.md#xarray.DataArray.plot) for example). The exceptions to this laziness are operations whose output shape is data-dependent, such as when calling [`where()`](../generated/xarray.DataArray.where.md#xarray.DataArray.where). # interoperability.html.md # Interoperability of Xarray Xarray is designed to be extremely interoperable, in many orthogonal ways. Making xarray as flexible as possible is the common theme of most of the goals on our [Development roadmap](../roadmap.md#roadmap). This interoperability comes via a set of flexible abstractions into which the user can plug in. The current full list is: - [Custom file backends](how-to-add-new-backend.md#add-a-backend) via the [`BackendEntrypoint`](../generated/xarray.backends.BackendEntrypoint.md#xarray.backends.BackendEntrypoint) system, - Numpy-like [“duck” array wrapping](duck-arrays-integration.md#internals-duckarrays), which supports the [Python Array API Standard](https://data-apis.org/array-api/latest/), - [Chunked distributed array computation](chunked-arrays.md#internals-chunkedarrays) via the [`ChunkManagerEntrypoint`](chunked-arrays.md#xarray.namedarray.parallelcompat.ChunkManagerEntrypoint) system, - Custom [`Index`](../generated/xarray.Index.md#xarray.Index) objects for [flexible label-based lookups](how-to-create-custom-index.md#internals-custom-indexes), - Extending xarray objects with domain-specific methods via [custom accessors](extending-xarray.md#internals-accessors). #### WARNING One obvious way in which xarray could be more flexible is that whilst subclassing xarray objects is possible, we currently don’t support it in most transformations, instead recommending composition over inheritance. See the [internal design page](internal-design.md#internal-design-subclassing) for the rationale and look at the corresponding [GH issue](https://github.com/pydata/xarray/issues/3980) if you’re interested in improving support for subclassing! #### NOTE If you think there is another way in which xarray could become more generically flexible then please tell us your ideas by [raising an issue to request the feature](https://github.com/pydata/xarray/issues/new/choose)! Whilst xarray was originally designed specifically to open `netCDF4` files as [`numpy.ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) objects labelled by [`pandas.Index`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html#pandas.Index) objects, it is entirely possible today to: - lazily open an xarray object directly from a custom binary file format (e.g. using `xarray.open_dataset(path, engine='my_custom_format')`, - handle the data as any API-compliant numpy-like array type (e.g. sparse or GPU-backed), - distribute out-of-core computation across that array type in parallel (e.g. via [Parallel Computing with Dask](../user-guide/dask.md#dask)), - track the physical units of the data through computations (e.g via [pint-xarray](https://pint-xarray.readthedocs.io/en/stable/)), - query the data via custom index logic optimized for specific applications (e.g. an [`Index`](../generated/xarray.Index.md#xarray.Index) object backed by a KDTree structure), - attach domain-specific logic via accessor methods (e.g. to understand geographic Coordinate Reference System metadata), - organize hierarchical groups of xarray data in a [`xarray.DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) (e.g. to treat heterogeneous simulation and observational data together during analysis). All of these features can be provided simultaneously, using libraries compatible with the rest of the scientific python ecosystem. In this situation xarray would be essentially a thin wrapper acting as pure-python framework, providing a common interface and separation of concerns via various domain-agnostic abstractions. Most of the remaining pages in the documentation of xarray’s internals describe these various types of interoperability in more detail. # interpolation.html.md # Interpolating data Xarray offers flexible interpolation routines, which have a similar interface to our [indexing](indexing.md#indexing). #### NOTE `interp` requires `scipy` installed. ## Scalar and 1-dimensional interpolation Interpolating a [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) works mostly like labeled indexing of a [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray), ```ipython3 da = xr.DataArray( np.sin(0.3 * np.arange(12).reshape(4, 3)), [("time", np.arange(4)), ("space", [0.1, 0.2, 0.3])], ) # label lookup da.sel(time=3) ``` ```none Size: 24B array([ 0.42737988, 0.14112001, -0.15774569]) Coordinates: * space (space) float64 24B 0.1 0.2 0.3 time int64 8B 3 ```
<xarray.DataArray (space: 3)> Size: 24B
array([ 0.42737988,  0.14112001, -0.15774569])
Coordinates:
  \* space    (space) float64 24B 0.1 0.2 0.3
    time     int64 8B 3
```ipython3 # interpolation da.interp(time=2.5) ``` ```none Size: 24B array([0.70061376, 0.50216469, 0.25885874]) Coordinates: * space (space) float64 24B 0.1 0.2 0.3 time float64 8B 2.5 ```
<xarray.DataArray (space: 3)> Size: 24B
array([0.70061376, 0.50216469, 0.25885874])
Coordinates:
  \* space    (space) float64 24B 0.1 0.2 0.3
    time     float64 8B 2.5
Similar to the indexing, [`interp()`](../generated/xarray.DataArray.interp.md#xarray.DataArray.interp) also accepts an array-like, which gives the interpolated result as an array. ```ipython3 # label lookup da.sel(time=[2, 3]) ``` ```none Size: 48B array([[ 0.97384763, 0.86320937, 0.67546318], [ 0.42737988, 0.14112001, -0.15774569]]) Coordinates: * time (time) int64 16B 2 3 * space (space) float64 24B 0.1 0.2 0.3 ```
<xarray.DataArray (time: 2, space: 3)> Size: 48B
array([[ 0.97384763,  0.86320937,  0.67546318],
       [ 0.42737988,  0.14112001, -0.15774569]])
Coordinates:
  \* time     (time) int64 16B 2 3
  \* space    (space) float64 24B 0.1 0.2 0.3
```ipython3 # interpolation da.interp(time=[2.5, 3.5]) ``` ```none Size: 48B array([[0.70061376, 0.50216469, 0.25885874], [ nan, nan, nan]]) Coordinates: * time (time) float64 16B 2.5 3.5 * space (space) float64 24B 0.1 0.2 0.3 ```
<xarray.DataArray (time: 2, space: 3)> Size: 48B
array([[0.70061376, 0.50216469, 0.25885874],
       [       nan,        nan,        nan]])
Coordinates:
  \* time     (time) float64 16B 2.5 3.5
  \* space    (space) float64 24B 0.1 0.2 0.3
To interpolate data with a [numpy.datetime64](https://numpy.org/doc/stable/reference/arrays.datetime.html) coordinate you can pass a string. ```ipython3 da_dt64 = xr.DataArray( [1, 3], [("time", pd.date_range("1/1/2000", "1/3/2000", periods=2))] ) da_dt64.interp(time="2000-01-02") ``` ```none Size: 8B array(nan) Coordinates: time datetime64[ns] 8B 2000-01-02 ```
<xarray.DataArray ()> Size: 8B
array(nan)
Coordinates:
    time     datetime64[ns] 8B 2000-01-02
The interpolated data can be merged into the original [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) by specifying the time periods required. ```ipython3 da_dt64.interp(time=pd.date_range("1/1/2000", "1/3/2000", periods=3)) ``` ```none Size: 24B array([1., 2., 3.]) Coordinates: * time (time) datetime64[us] 24B 2000-01-01 2000-01-02 2000-01-03 ```
<xarray.DataArray (time: 3)> Size: 24B
array([1., 2., 3.])
Coordinates:
  \* time     (time) datetime64[us] 24B 2000-01-01 2000-01-02 2000-01-03
Interpolation of data indexed by a [`CFTimeIndex`](../generated/xarray.CFTimeIndex.md#xarray.CFTimeIndex) is also allowed. See [Non-standard calendars and dates outside the precision range](weather-climate.md#cftimeindex) for examples. #### NOTE Currently, our interpolation only works for regular grids. Therefore, similarly to [`sel()`](../generated/xarray.DataArray.sel.md#xarray.DataArray.sel), only 1D coordinates along a dimension can be used as the original coordinate to be interpolated. ## Multi-dimensional Interpolation Like [`sel()`](../generated/xarray.DataArray.sel.md#xarray.DataArray.sel), [`interp()`](../generated/xarray.DataArray.interp.md#xarray.DataArray.interp) accepts multiple coordinates. In this case, multidimensional interpolation is carried out. ```ipython3 # label lookup da.sel(time=2, space=0.1) ``` ```none Size: 8B array(0.97384763) Coordinates: time int64 8B 2 space float64 8B 0.1 ```
<xarray.DataArray ()> Size: 8B
array(0.97384763)
Coordinates:
    time     int64 8B 2
    space    float64 8B 0.1
```ipython3 # interpolation da.interp(time=2.5, space=0.15) ``` ```none Size: 8B array(0.60138922) Coordinates: time float64 8B 2.5 space float64 8B 0.15 ```
<xarray.DataArray ()> Size: 8B
array(0.60138922)
Coordinates:
    time     float64 8B 2.5
    space    float64 8B 0.15
Array-like coordinates are also accepted: ```ipython3 # label lookup da.sel(time=[2, 3], space=[0.1, 0.2]) ``` ```none Size: 32B array([[0.97384763, 0.86320937], [0.42737988, 0.14112001]]) Coordinates: * time (time) int64 16B 2 3 * space (space) float64 16B 0.1 0.2 ```
<xarray.DataArray (time: 2, space: 2)> Size: 32B
array([[0.97384763, 0.86320937],
       [0.42737988, 0.14112001]])
Coordinates:
  \* time     (time) int64 16B 2 3
  \* space    (space) float64 16B 0.1 0.2
```ipython3 # interpolation da.interp(time=[1.5, 2.5], space=[0.15, 0.25]) ``` ```none Size: 32B array([[0.88810575, 0.86705165], [0.60138922, 0.38051172]]) Coordinates: * time (time) float64 16B 1.5 2.5 * space (space) float64 16B 0.15 0.25 ```
<xarray.DataArray (time: 2, space: 2)> Size: 32B
array([[0.88810575, 0.86705165],
       [0.60138922, 0.38051172]])
Coordinates:
  \* time     (time) float64 16B 1.5 2.5
  \* space    (space) float64 16B 0.15 0.25
[`interp_like()`](../generated/xarray.DataArray.interp_like.md#xarray.DataArray.interp_like) method is a useful shortcut. This method interpolates an xarray object onto the coordinates of another xarray object. For example, if we want to compute the difference between two [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) s (`da` and `other`) staying on slightly different coordinates, ```ipython3 other = xr.DataArray( np.sin(0.4 * np.arange(9).reshape(3, 3)), [("time", [0.9, 1.9, 2.9]), ("space", [0.15, 0.25, 0.35])], ) ``` it might be a good idea to first interpolate `da` so that it will stay on the same coordinates of `other`, and then subtract it. [`interp_like()`](../generated/xarray.DataArray.interp_like.md#xarray.DataArray.interp_like) can be used for such a case, ```ipython3 # interpolate da along other's coordinates interpolated = da.interp_like(other) interpolated ``` ```none Size: 72B array([[0.78669071, 0.91129847, nan], [0.91244395, 0.78887935, nan], [0.3476778 , 0.06945207, nan]]) Coordinates: * time (time) float64 24B 0.9 1.9 2.9 * space (space) float64 24B 0.15 0.25 0.35 ```
<xarray.DataArray (time: 3, space: 3)> Size: 72B
array([[0.78669071, 0.91129847,        nan],
       [0.91244395, 0.78887935,        nan],
       [0.3476778 , 0.06945207,        nan]])
Coordinates:
  \* time     (time) float64 24B 0.9 1.9 2.9
  \* space    (space) float64 24B 0.15 0.25 0.35
It is now possible to safely compute the difference `other - interpolated`. ## Interpolation methods We use either [`scipy.interpolate.interp1d`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html#scipy.interpolate.interp1d) or special interpolants from `scipy.interpolate` for 1-dimensional interpolation (see [`interp()`](../generated/xarray.Dataset.interp.md#xarray.Dataset.interp)). For multi-dimensional interpolation, an attempt is first made to decompose the interpolation in a series of 1-dimensional interpolations, in which case the relevant 1-dimensional interpolator is used. If a decomposition cannot be made (e.g. with advanced interpolation), [`scipy.interpolate.interpn()`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interpn.html#scipy.interpolate.interpn) is used. The interpolation method can be specified by the optional `method` argument. ```ipython3 da = xr.DataArray( np.sin(np.linspace(0, 2 * np.pi, 10)), dims="x", coords={"x": np.linspace(0, 1, 10)}, ) da.plot.line("o", label="original") da.interp(x=np.linspace(0, 1, 100)).plot.line(label="linear (default)") da.interp(x=np.linspace(0, 1, 100), method="cubic").plot.line(label="cubic") plt.legend(); ``` ```none
``` ![image](../_readthedocs/html/jupyter_execute/user-guide/interpolation_13_0.png) Additional keyword arguments can be passed to scipy’s functions. ```ipython3 # fill 0 for the outside of the original coordinates. da.interp(x=np.linspace(-0.5, 1.5, 10), kwargs={"fill_value": 0.0}) ``` ```none Size: 80B array([ 0. , 0. , 0. , 0.81379768, 0.60402277, -0.60402277, -0.81379768, 0. , 0. , 0. ]) Coordinates: * x (x) float64 80B -0.5 -0.2778 -0.05556 0.1667 ... 1.056 1.278 1.5 ```
<xarray.DataArray (x: 10)> Size: 80B
array([ 0.        ,  0.        ,  0.        ,  0.81379768,  0.60402277,
       -0.60402277, -0.81379768,  0.        ,  0.        ,  0.        ])
Coordinates:
  \* x        (x) float64 80B -0.5 -0.2778 -0.05556 0.1667 ... 1.056 1.278 1.5
```ipython3 # 1-dimensional extrapolation da.interp(x=np.linspace(-0.5, 1.5, 10), kwargs={"fill_value": "extrapolate"}) ``` ```none Size: 80B array([-2.89254424, -1.60696902, -0.3213938 , 0.81379768, 0.60402277, -0.60402277, -0.81379768, 0.3213938 , 1.60696902, 2.89254424]) Coordinates: * x (x) float64 80B -0.5 -0.2778 -0.05556 0.1667 ... 1.056 1.278 1.5 ```
<xarray.DataArray (x: 10)> Size: 80B
array([-2.89254424, -1.60696902, -0.3213938 ,  0.81379768,  0.60402277,
       -0.60402277, -0.81379768,  0.3213938 ,  1.60696902,  2.89254424])
Coordinates:
  \* x        (x) float64 80B -0.5 -0.2778 -0.05556 0.1667 ... 1.056 1.278 1.5
```ipython3 # multi-dimensional extrapolation da = xr.DataArray( np.sin(0.3 * np.arange(12).reshape(4, 3)), [("time", np.arange(4)), ("space", [0.1, 0.2, 0.3])], ) da.interp( time=4, space=np.linspace(-0.1, 0.5, 10), kwargs={"fill_value": "extrapolate"} ) ``` ```none Size: 80B array([ 0.80467509, 0.4967541 , 0.18883312, -0.11908787, -0.42700886, -0.71763109, -0.99095457, -1.26427805, -1.53760153, -1.81092501]) Coordinates: * space (space) float64 80B -0.1 -0.03333 0.03333 0.1 ... 0.3667 0.4333 0.5 time int64 8B 4 ```
<xarray.DataArray (space: 10)> Size: 80B
array([ 0.80467509,  0.4967541 ,  0.18883312, -0.11908787, -0.42700886,
       -0.71763109, -0.99095457, -1.26427805, -1.53760153, -1.81092501])
Coordinates:
  \* space    (space) float64 80B -0.1 -0.03333 0.03333 0.1 ... 0.3667 0.4333 0.5
    time     int64 8B 4
## Advanced Interpolation [`interp()`](../generated/xarray.DataArray.interp.md#xarray.DataArray.interp) accepts [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) as similar to [`sel()`](../generated/xarray.DataArray.sel.md#xarray.DataArray.sel), which enables us more advanced interpolation. Based on the dimension of the new coordinate passed to [`interp()`](../generated/xarray.DataArray.interp.md#xarray.DataArray.interp), the dimension of the result are determined. For example, if you want to interpolate a two dimensional array along a particular dimension, as illustrated below, you can pass two 1-dimensional [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) s with a common dimension as new coordinate. ![advanced indexing and interpolation](_static/advanced_selection_interpolation.svg) For example: ```ipython3 da = xr.DataArray( np.sin(0.3 * np.arange(20).reshape(5, 4)), [("x", np.arange(5)), ("y", [0.1, 0.2, 0.3, 0.4])], ) # advanced indexing x = xr.DataArray([0, 2, 4], dims="z") y = xr.DataArray([0.1, 0.2, 0.3], dims="z") da.sel(x=x, y=y) ``` ```none Size: 24B array([ 0. , 0.42737988, -0.77276449]) Coordinates: x (z) int64 24B 0 2 4 y (z) float64 24B 0.1 0.2 0.3 Dimensions without coordinates: z ```
<xarray.DataArray (z: 3)> Size: 24B
array([ 0.        ,  0.42737988, -0.77276449])
Coordinates:
    x        (z) int64 24B 0 2 4
    y        (z) float64 24B 0.1 0.2 0.3
Dimensions without coordinates: z
```ipython3 # advanced interpolation, without extrapolation x = xr.DataArray([0.5, 1.5, 2.5, 3.5], dims="z") y = xr.DataArray([0.15, 0.25, 0.35, 0.45], dims="z") da.interp(x=x, y=y) ``` ```none Size: 32B array([ 0.55626357, 0.63496063, -0.46643289, nan]) Coordinates: x (z) float64 32B 0.5 1.5 2.5 3.5 y (z) float64 32B 0.15 0.25 0.35 0.45 Dimensions without coordinates: z ```
<xarray.DataArray (z: 4)> Size: 32B
array([ 0.55626357,  0.63496063, -0.46643289,         nan])
Coordinates:
    x        (z) float64 32B 0.5 1.5 2.5 3.5
    y        (z) float64 32B 0.15 0.25 0.35 0.45
Dimensions without coordinates: z
where values on the original coordinates `(x, y) = ((0.5, 0.15), (1.5, 0.25), (2.5, 0.35), (3.5, 0.45))` are obtained by the 2-dimensional interpolation and mapped along a new dimension `z`. Since no keyword arguments are passed to the interpolation routine, no extrapolation is performed resulting in a `nan` value. If you want to add a coordinate to the new dimension `z`, you can supply [`DataArray`](../generated/xarray.DataArray.md#xarray.DataArray) s with a coordinate. Extrapolation can be achieved by passing additional arguments to SciPy’s `interpnd` function, ```ipython3 x = xr.DataArray([0.5, 1.5, 2.5, 3.5], dims="z", coords={"z": ["a", "b", "c", "d"]}) y = xr.DataArray( [0.15, 0.25, 0.35, 0.45], dims="z", coords={"z": ["a", "b", "c", "d"]} ) da.interp(x=x, y=y, kwargs={"fill_value": None}) ``` ```none Size: 32B array([ 0.55626357, 0.63496063, -0.46643289, -0.73507668]) Coordinates: * z (z)
<xarray.DataArray (z: 4)> Size: 32B
array([ 0.55626357,  0.63496063, -0.46643289, -0.73507668])
Coordinates:
  \* z        (z) <U1 16B 'a' 'b' 'c' 'd'
    x        (z) float64 32B 0.5 1.5 2.5 3.5
    y        (z) float64 32B 0.15 0.25 0.35 0.45
For the details of the advanced indexing, see [more advanced indexing](indexing.md#more-advanced-indexing). ## Interpolating arrays with NaN Our [`interp()`](../generated/xarray.DataArray.interp.md#xarray.DataArray.interp) works with arrays with NaN the same way that [scipy.interpolate.interp1d](https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html) and [scipy.interpolate.interpn](https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interpn.html) do. `linear` and `nearest` methods return arrays including NaN, while other methods such as `cubic` or `quadratic` return all NaN arrays. ```ipython3 da = xr.DataArray([0, 2, np.nan, 3, 3.25], dims="x", coords={"x": range(5)}) da.interp(x=[0.5, 1.5, 2.5]) ``` ```none Size: 24B array([ 1., nan, nan]) Coordinates: * x (x) float64 24B 0.5 1.5 2.5 ```
<xarray.DataArray (x: 3)> Size: 24B
array([ 1., nan, nan])
Coordinates:
  \* x        (x) float64 24B 0.5 1.5 2.5
```ipython3 da.interp(x=[0.5, 1.5, 2.5], method="cubic") ``` ```none Size: 24B array([nan, nan, nan]) Coordinates: * x (x) float64 24B 0.5 1.5 2.5 ```
<xarray.DataArray (x: 3)> Size: 24B
array([nan, nan, nan])
Coordinates:
  \* x        (x) float64 24B 0.5 1.5 2.5
To avoid this, you can drop NaN by [`dropna()`](../generated/xarray.DataArray.dropna.md#xarray.DataArray.dropna), and then make the interpolation ```ipython3 dropped = da.dropna("x") dropped ``` ```none Size: 32B array([0. , 2. , 3. , 3.25]) Coordinates: * x (x) int64 32B 0 1 3 4 ```
<xarray.DataArray (x: 4)> Size: 32B
array([0.  , 2.  , 3.  , 3.25])
Coordinates:
  \* x        (x) int64 32B 0 1 3 4
```ipython3 dropped.interp(x=[0.5, 1.5, 2.5], method="cubic") ``` ```none Size: 24B array([1.19010417, 2.5078125 , 2.9296875 ]) Coordinates: * x (x) float64 24B 0.5 1.5 2.5 ```
<xarray.DataArray (x: 3)> Size: 24B
array([1.19010417, 2.5078125 , 2.9296875 ])
Coordinates:
  \* x        (x) float64 24B 0.5 1.5 2.5
If NaNs are distributed randomly in your multidimensional array, dropping all the columns containing more than one NaNs by [`dropna()`](../generated/xarray.DataArray.dropna.md#xarray.DataArray.dropna) may lose a significant amount of information. In such a case, you can fill NaN by [`interpolate_na()`](../generated/xarray.DataArray.interpolate_na.md#xarray.DataArray.interpolate_na), which is similar to [`pandas.Series.interpolate()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.interpolate.html#pandas.Series.interpolate). ```ipython3 filled = da.interpolate_na(dim="x") filled ``` ```none Size: 40B array([0. , 2. , 2.5 , 3. , 3.25]) Coordinates: * x (x) int64 40B 0 1 2 3 4 ```
<xarray.DataArray (x: 5)> Size: 40B
array([0.  , 2.  , 2.5 , 3.  , 3.25])
Coordinates:
  \* x        (x) int64 40B 0 1 2 3 4
This fills NaN by interpolating along the specified dimension. After filling NaNs, you can interpolate: ```ipython3 filled.interp(x=[0.5, 1.5, 2.5], method="cubic") ``` ```none Size: 24B array([1.30859375, 2.31640625, 2.73828125]) Coordinates: * x (x) float64 24B 0.5 1.5 2.5 ```
<xarray.DataArray (x: 3)> Size: 24B
array([1.30859375, 2.31640625, 2.73828125])
Coordinates:
  \* x        (x) float64 24B 0.5 1.5 2.5
For the details of [`interpolate_na()`](../generated/xarray.DataArray.interpolate_na.md#xarray.DataArray.interpolate_na), see [Missing values](computation.md#missing-values). ## Example Let’s see how [`interp()`](../generated/xarray.DataArray.interp.md#xarray.DataArray.interp) works on real data. ```ipython3 # Raw data ds = xr.tutorial.open_dataset("air_temperature").isel(time=0) fig, axes = plt.subplots(ncols=2, figsize=(10, 4)) ds.air.plot(ax=axes[0]) axes[0].set_title("Raw data") # Interpolated data new_lon = np.linspace(ds.lon[0].item(), ds.lon[-1].item(), ds.sizes["lon"] * 4) new_lat = np.linspace(ds.lat[0].item(), ds.lat[-1].item(), ds.sizes["lat"] * 4) dsi = ds.interp(lat=new_lat, lon=new_lon) dsi.air.plot(ax=axes[1]) axes[1].set_title("Interpolated data"); ``` ```none
``` ![image](../_readthedocs/html/jupyter_execute/user-guide/interpolation_26_0.png) Our advanced interpolation can be used to remap the data to the new coordinate. Consider the new coordinates x and z on the two dimensional plane. The remapping can be done as follows ```ipython3 # new coordinate x = np.linspace(240, 300, 100) z = np.linspace(20, 70, 100) # relation between new and original coordinates lat = xr.DataArray(z, dims=["z"], coords={"z": z}) lon = xr.DataArray( (x[:, np.newaxis] - 270) / np.cos(z * np.pi / 180) + 270, dims=["x", "z"], coords={"x": x, "z": z}, ) fig, axes = plt.subplots(ncols=2, figsize=(10, 4)) ds.air.plot(ax=axes[0]) # draw the new coordinate on the original coordinates. for idx in [0, 33, 66, 99]: axes[0].plot(lon.isel(x=idx), lat, "--k") for idx in [0, 33, 66, 99]: axes[0].plot(*xr.broadcast(lon.isel(z=idx), lat.isel(z=idx)), "--k") axes[0].set_title("Raw data") dsi = ds.interp(lon=lon, lat=lat) dsi.air.plot(ax=axes[1]) axes[1].set_title("Remapped data"); ``` ```none
``` ![image](../_readthedocs/html/jupyter_execute/user-guide/interpolation_27_0.png) # io.html.md # Reading and writing files Xarray supports direct serialization and IO to several file formats, from simple [Pickle](#io-pickle) files to the more flexible [netCDF](#io-netcdf) format (recommended). You can read different types of files in `xr.open_dataset` by specifying the engine to be used: ```python xr.open_dataset("example.nc", engine="netcdf4") ``` The “engine” provides a set of instructions that tells xarray how to read the data and pack them into a `Dataset` (or `Dataarray`). These instructions are stored in an underlying “backend”. Xarray comes with several backends that cover many common data formats. Many more backends are available via external libraries, or you can [write your own](https://docs.xarray.dev/en/stable/internals/how-to-add-new-backend.html). This diagram aims to help you determine - based on the format of the file you’d like to read - which type of backend you’re using and how to use it. Text and boxes are clickable for more information. Following the diagram is detailed information on many popular backends. You can learn more about using and developing backends in the [Xarray tutorial JupyterBook](https://tutorial.xarray.dev/advanced/backends/backends.html). ## Backend Selection When opening a file or URL without explicitly specifying the `engine` parameter, xarray automatically selects an appropriate backend based on the file path or URL. The backends are tried in order: **netcdf4 → h5netcdf → scipy → pydap → zarr**. #### NOTE You can customize the order in which netCDF backends are tried using the `netcdf_engine_order` option in [`set_options()`](../generated/xarray.set_options.md#xarray.set_options): ```python # Prefer h5netcdf over netcdf4 xr.set_options(netcdf_engine_order=["h5netcdf", "netcdf4", "scipy"]) ``` See [Configuration](options.md#options) for more details on configuration options. The following tables show which backend will be selected for different types of URLs and files. #### IMPORTANT ✅ means the backend will **guess it can open** the URL or file based on its path, extension, or magic number, but this doesn’t guarantee success. For example, not all Zarr stores are xarray-compatible. ❌ means the backend will not attempt to open it. ### Remote URL Resolution | URL | [netcdf4](#io-netcdf) | [h5netcdf](#io-hdf5) | [scipy](#io-netcdf) | [pydap](#io-opendap) | [zarr](#io-zarr) | |-----------------------------------------|-------------------------|------------------------|-----------------------|------------------------|--------------------| | `https://example.com/store.zarr` | ❌ | ❌ | ❌ | ❌ | ✅ | | `https://example.com/data.nc` | ✅ | ✅ | ❌ | ❌ | ❌ | | `http://example.com/data.nc?var=temp` | ✅ | ❌ | ❌ | ❌ | ❌ | | `http://example.com/dap4/data.nc?var=x` | ✅ | ❌ | ❌ | ✅ | ❌ | | `dap2://opendap.nasa.gov/dataset` | ❌ | ❌ | ❌ | ✅ | ❌ | | `https://example.com/DAP4/data` | ❌ | ❌ | ❌ | ✅ | ❌ | | `http://test.opendap.org/dap4/file.nc4` | ✅ | ✅ | ❌ | ✅ | ❌ | | `https://example.com/DAP4/data.nc` | ✅ | ✅ | ❌ | ✅ | ❌ | ### Local File Resolution For local files, backends first try to read the file’s **magic number** (first few bytes). If the magic number **cannot be read** (e.g., file doesn’t exist, no permissions), they fall back to checking the file **extension**. If the magic number is readable but invalid, the backend returns False (does not fall back to extension). | File Path | Magic Number | [netcdf4](#io-netcdf) | [h5netcdf](#io-hdf5) | [scipy](#io-netcdf) | [zarr](#io-zarr) | |------------------------|------------------------------------|-------------------------|------------------------|-----------------------|--------------------| | `/path/to/file.nc` | `CDF\x01` (netCDF3) | ✅ | ❌ | ✅ | ❌ | | `/path/to/file.nc4` | `\x89HDF\r\n\x1a\n` (HDF5/netCDF4) | ✅ | ✅ | ❌ | ❌ | | `/path/to/file.nc.gz` | `\x1f\x8b` + `CDF` inside | ❌ | ❌ | ✅ | ❌ | | `/path/to/store.zarr/` | (directory) | ❌ | ❌ | ❌ | ✅ | | `/path/to/file.nc` | *(no magic number)* | ✅ | ✅ | ✅ | ❌ | | `/path/to/file.xyz` | `CDF\x01` (netCDF3) | ✅ | ❌ | ✅ | ❌ | | `/path/to/file.xyz` | `\x89HDF\r\n\x1a\n` (HDF5/netCDF4) | ✅ | ✅ | ❌ | ❌ | | `/path/to/file.xyz` | *(no magic number)* | ❌ | ❌ | ❌ | ❌ | #### NOTE Remote URLs ending in `.nc` are **ambiguous**: - They could be netCDF files stored on a remote HTTP server (readable by `netcdf4` or `h5netcdf`) - They could be OPeNDAP/DAP endpoints (readable by `netcdf4` with DAP support or `pydap`) These interpretations are fundamentally incompatible. If xarray’s automatic selection chooses the wrong backend, you must explicitly specify the `engine` parameter: ```python # Force interpretation as a DAP endpoint ds = xr.open_dataset("http://example.com/data.nc", engine="pydap") # Force interpretation as a remote netCDF file ds = xr.open_dataset("https://example.com/data.nc", engine="netcdf4") ``` ## netCDF The recommended way to store xarray data structures is [netCDF](https://www.unidata.ucar.edu/software/netcdf/), which is a binary file format for self-described datasets that originated in the geosciences. Xarray is based on the netCDF data model, so netCDF files on disk directly correspond to [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) objects (more accurately, a group in a netCDF file directly corresponds to a [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) object. See [Groups](#io-netcdf-groups) for more.) NetCDF is supported on almost all platforms, and parsers exist for the vast majority of scientific programming languages. Recent versions of netCDF are based on the even more widely used HDF5 file-format. Reading and writing netCDF files with xarray requires scipy, h5netcdf, or the [netCDF4-Python](https://github.com/Unidata/netcdf4-python) library to be installed. SciPy only supports reading and writing of netCDF V3 files. We can save a Dataset to disk using the [`Dataset.to_netcdf()`](../generated/xarray.Dataset.to_netcdf.md#xarray.Dataset.to_netcdf) method: ```ipython3 nc_filename = "saved_on_disk.nc" ``` ```ipython3 ds = xr.Dataset( {"foo": (("x", "y"), np.random.rand(4, 5))}, coords={ "x": [10, 20, 30, 40], "y": pd.date_range("2000-01-01", periods=5), "z": ("x", list("abcd")), }, ) ds.to_netcdf(nc_filename) ``` By default, the file is saved as netCDF4 (assuming netCDF4-Python is installed). You can control the format and engine used to write the file with the `format` and `engine` arguments. We can load netCDF files to create a new Dataset using [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset): ```ipython3 ds_disk = xr.open_dataset(nc_filename) ds_disk ``` ```none Size: 248B Dimensions: (x: 4, y: 5) Coordinates: * x (x) int64 32B 10 20 30 40 z (x)
<xarray.Dataset> Size: 248B
Dimensions:  (x: 4, y: 5)
Coordinates:
  \* x        (x) int64 32B 10 20 30 40
    z        (x) <U1 16B ...
  \* y        (y) datetime64[ns] 40B 2000-01-01 2000-01-02 ... 2000-01-05
Data variables:
    foo      (x, y) float64 160B ...
Similarly, a DataArray can be saved to disk using the [`DataArray.to_netcdf()`](../generated/xarray.DataArray.to_netcdf.md#xarray.DataArray.to_netcdf) method, and loaded from disk using the [`open_dataarray()`](../generated/xarray.open_dataarray.md#xarray.open_dataarray) function. As netCDF files correspond to [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) objects, these functions internally convert the `DataArray` to a `Dataset` before saving, and then convert back when loading, ensuring that the `DataArray` that is loaded is always exactly the same as the one that was saved. A dataset can also be loaded or written to a specific group within a netCDF file. To load from a group, pass a `group` keyword argument to the `open_dataset` function. The group can be specified as a path-like string, e.g., to access subgroup ‘bar’ within group ‘foo’ pass ‘/foo/bar’ as the `group` argument. When writing multiple groups in one file, pass `mode='a'` to `to_netcdf` to ensure that each call does not delete the file. Data is *always* loaded lazily from netCDF files. You can manipulate, slice and subset Dataset and DataArray objects, and no array values are loaded into memory until you try to perform some sort of actual computation. For an example of how these lazy arrays work, see the OPeNDAP section below. There may be minor differences in the [`Dataset`](../generated/xarray.Dataset.md#xarray.Dataset) object returned when reading a NetCDF file with different engines. It is important to note that when you modify values of a Dataset, even one linked to files on disk, only the in-memory copy you are manipulating in xarray is modified: the original file on disk is never touched. Datasets have a [`Dataset.close()`](../generated/xarray.Dataset.close.md#xarray.Dataset.close) method to close the associated netCDF file. However, it’s often cleaner to use a `with` statement: ```ipython3 # this automatically closes the dataset after use with xr.open_dataset(nc_filename) as ds: print(ds.keys()) ``` ```none KeysView( Size: 248B Dimensions: (x: 4, y: 5) Coordinates: * x (x) int64 32B 10 20 30 40 z (x) ### Groups Whilst netCDF groups can only be loaded individually as `Dataset` objects, a whole file of many nested groups can be loaded as a single [`xarray.DataTree`](../generated/xarray.DataTree.md#xarray.DataTree) object. To open a whole netCDF file as a tree of groups use the [`xarray.open_datatree()`](../generated/xarray.open_datatree.md#xarray.open_datatree) function. To save a DataTree object as a netCDF file containing many groups, use the [`xarray.DataTree.to_netcdf()`](../generated/xarray.DataTree.to_netcdf.md#xarray.DataTree.to_netcdf) method. #### NOTE Due to file format specifications the on-disk root group name is always `"/"`, overriding any given `DataTree` root node name. #### WARNING `DataTree` objects do not follow the exact same data model as netCDF files, which means that perfect round-tripping is not always possible. In particular in the netCDF data model dimensions are entities that can exist regardless of whether any variable possesses them. This is in contrast to [xarray’s data model](https://docs.xarray.dev/en/stable/user-guide/data-structures.html) (and hence [DataTree’s data model](data-structures.md#data-structures)) in which the dimensions of a (Dataset/Tree) object are simply the set of dimensions present across all variables in that dataset. This means that if a netCDF file contains dimensions but no variables which possess those dimensions, these dimensions will not be present when that file is opened as a DataTree object. Saving this DataTree object to file will therefore not preserve these “unused” dimensions. ### Reading encoded data NetCDF files follow some conventions for encoding datetime arrays (as numbers with a “units” attribute) and for packing and unpacking data (as described by the “scale_factor” and “add_offset” attributes). If the argument `decode_cf=True` (default) is given to [`open_dataset()`](../generated/xarray.open_dataset.md#xarray.open_dataset), xarray will attempt to automatically decode the values in the netCDF objects according to [CF conventions](https://cfconventions.org/). Sometimes this will fail, for example, if a variable has an invalid “units” or “calendar” attribute. For these cases, you can turn this decoding off manually. You can view this encoding information (among others) in the [`DataArray.encoding`](../generated/xarray.DataArray.encoding.md#xarray.DataArray.encoding) and [`DataArray.encoding`](../generated/xarray.DataArray.encoding.md#xarray.DataArray.encoding) attributes: ```ipython3 ds_disk["y"].encoding ``` ```none {'dtype': dtype('int64'), 'zlib': False, 'szip': False, 'zstd': False, 'bzip2': False, 'blosc': False, 'shuffle': False, 'complevel': 0, 'fletcher32': False, 'contiguous': True, 'chunksizes': None, 'source': '/tmp/tmpxz1cg9y2/saved_on_disk.nc', 'original_shape': (5,), 'units': 'days since 2000-01-01 00:00:00', 'calendar': 'proleptic_gregorian'} ``` ```ipython3 ds_disk.encoding ``` ```none {'unlimited_dims': set(), 'source': '/tmp/tmpxz1cg9y2/saved_on_disk.nc'} ``` Note that all operations that manipulate variables other than indexing will remove encoding information. In some cases it is useful to intentionally reset a dataset’s original encoding values. This can be done with either the [`Dataset.drop_encoding()`](../generated/xarray.Dataset.drop_encoding.md#xarray.Dataset.drop_encoding) or [`DataArray.drop_encoding()`](../generated/xarray.DataArray.drop_encoding.md#xarray.DataArray.drop_encoding) methods. ```ipython3 ds_no_encoding = ds_disk.drop_encoding() ds_no_encoding.encoding ``` ```none {} ``` #### Reading multi-file datasets NetCDF files are often encountered in collections, e.g., with different files corresponding to different model runs or one file per timestamp. Xarray can straightforwardly combine such files into a single Dataset by making use of [`concat()`](../generated/xarray.concat.md#xarray.concat), [`merge()`](../generated/xarray.merge.md#xarray.merge), [`combine_nested()`](../generated/xarray.combine_nested.md#xarray.combine_nested) and [`combine_by_coords()`](../generated/xarray.combine_by_coords.md#xarray.combine_by_coords). For details on the difference between these functions see [Combining data](combining.md#combining-data). Xarray includes support for manipulating datasets that don’t fit into memory with [dask](https://www.dask.org). If you have dask installed, you can open multiple files simultaneously in parallel using [`open_mfdataset()`](../generated/xarray.open_mfdataset.md#xarray.open_mfdataset): ```default xr.open_mfdataset('my/files/*.nc', parallel=True) ``` This function automatically concatenates and merges multiple files into a single xarray dataset. It is the recommended way to open multiple files with xarray. For more details on parallel reading, see [Combining along multiple dimensions](combining.md#combining-multi), [Reading and writing data](dask.md#dask-io) and a [blog post](https://stephanhoyer.com/2015/06/11/xray-dask-out-of-core-labeled-arrays/) by Stephan Hoyer. [`open_mfdataset()`](../generated/xarray.open_mfdataset.md#xarray.open_mfdataset) takes many kwargs that allow you to control its behaviour (for e.g. `parallel`, `combine`, `compat`, `join`, `concat_dim`). See its docstring for more details. #### NOTE A common use-case involves a dataset distributed across a large number of files with each file containing a large number of variables. Commonly, a few of these variables need to be concatenated along a dimension (say `"time"`), while the rest are equal across the datasets (ignoring floating point differences). The following command with suitable modifications (such as `parallel=True`) works well with such datasets: ```default xr.open_mfdataset('my/files/*.nc', concat_dim="time", combine="nested", data_vars='minimal', coords='minimal', compat='override') ``` This command concatenates variables along the `"time"` dimension, but only those that already contain the `"time"` dimension (`data_vars='minimal', coords='minimal'`). Variables that lack the `"time"` dimension are taken from the first dataset (`compat='override'`). Sometimes multi-file datasets are not conveniently organized for easy use of [`open_mfdataset()`](../generated/xarray.open_mfdataset.md#xarray.open_mfdataset). One can use the `preprocess` argument to provide a function that takes a dataset and returns a modified Dataset. [`open_mfdataset()`](../generated/xarray.open_mfdataset.md#xarray.open_mfdataset) will call `preprocess` on every dataset (corresponding to each file) prior to combining them. If [`open_mfdataset()`](../generated/xarray.open_mfdataset.md#xarray.open_mfdataset) does not meet your needs, other approaches are possible. The general pattern for parallel reading of multiple files using dask, modifying those datasets and then combining into a single `Dataset` is: ```default def modify(ds): # modify ds here return ds # this is basically what open_mfdataset does open_kwargs = dict(decode_cf=True, decode_times=False) open_tasks = [dask.delayed(xr.open_dataset)(f, **open_kwargs) for f in file_names] tasks = [dask.delayed(modify)(task) for task in open_tasks] datasets = dask.compute(tasks) # get a list of xarray.Datasets combined = xr.combine_nested(datasets) # or some combination of concat, merge ``` As an example, here’s how we could approximate `MFDataset` from the netCDF4 library: ```default from glob import glob import xarray as xr def read_netcdfs(files, dim): # glob expands paths with * to a list of files, like the unix shell paths = sorted(glob(files)) datasets = [xr.open_dataset(p) for p in paths] combined = xr.concat(datasets, dim) return combined combined = read_netcdfs('/all/my/files/*.nc', dim='time') ``` This function will work in many cases, but it’s not very robust. First, it never closes files, which means it will fail if you need to load more than a few thousand files. Second, it assumes that you want all the data from each file and that it can all fit into memory. In many situations, you only need a small subset or an aggregated summary of the data from each file. Here’s a slightly more sophisticated example of how to remedy these deficiencies: ```default def read_netcdfs(files, dim, transform_func=None): def process_one_path(path): # use a context manager, to ensure the file gets closed after use with xr.open_dataset(path) as ds: # transform_func should do some sort of selection or # aggregation if transform_func is not None: ds = transform_func(ds) # load all data from the transformed dataset, to ensure we can # use it after closing each original file ds.load() return ds paths = sorted(glob(files)) datasets = [process_one_path(p) for p in paths] combined = xr.concat(datasets, dim) return combined # here we suppose we only care about the combined mean of each file; # you might also use indexing operations like .sel to subset datasets combined = read_netcdfs('/all/my/files/*.nc', dim='time', transform_func=lambda ds: ds.mean()) ``` This pattern works well and is very robust. We’ve used similar code to process tens of thousands of files constituting 100s of GB of data. ### Writing encoded data Conversely, you can customize how xarray writes netCDF files on disk by providing explicit encodings for each dataset variable. The `encoding` argument takes a dictionary with variable names as keys and variable specific encodings as values. These encodings are saved as attributes on the netCDF variables on disk, which allows xarray to faithfully read encoded data back into memory. It is important to note that using encodings is entirely optional: if you do not supply any of these encoding options, xarray will write data to disk using a default encoding, or the options in the `encoding` attribute, if set. This works perfectly fine in most cases, but encoding can be useful for additional control, especially for enabling compression. In the file on disk, these encodings are saved as attributes on each variable, which allow xarray and other CF-compliant tools for working with netCDF files to correctly read the data. #### Scaling and type conversions These encoding options (based on [CF Conventions on packed data](https://cfconventions.org/cf-conventions/cf-conventions.html#packed-data)) work on any version of the netCDF file format: - `dtype`: Any valid NumPy dtype or string convertible to a dtype, e.g., `'int16'` or `'float32'`. This controls the type of the data written on disk. - `_FillValue`: Values of `NaN` in xarray variables are remapped to this value when saved on disk. This is important when converting floating point with missing values to integers on disk, because `NaN` is not a valid value for integer dtypes. By default, variables with float types are attributed a `_FillValue` of `NaN` in the output file, unless explicitly disabled with an encoding `{'_FillValue': None}`. - `scale_factor` and `add_offset`: Used to convert from encoded data on disk to to the decoded data in memory, according to the formula `decoded = scale_factor * encoded + add_offset`. Please note that `scale_factor` and `add_offset` must be of same type and determine the type of the decoded data. These parameters can be fruitfully combined to compress discretized data on disk. For example, to save the variable `foo` with a precision of 0.1 in 16-bit integers while converting `NaN` to `-9999`, we would use `encoding={'foo': {'dtype': 'int16', 'scale_factor': 0.1, '_FillValue': -9999}}`. Compression and decompression with such discretization is extremely fast. #### String encoding Xarray can write unicode strings to netCDF files in two ways: - As variable length strings. This is only supported on netCDF4 (HDF5) files. - By encoding strings into bytes, and writing encoded bytes as a character array. The default encoding is UTF-8. By default, we use variable length strings for compatible files and fall-back to using encoded character arrays. Character arrays can be selected even for netCDF4 files by setting the `dtype` field in `encoding` to `S1` (corresponding to NumPy’s single-character bytes dtype). If character arrays are used: - The string encoding that was used is stored on disk in the `_Encoding` attribute, which matches an ad-hoc convention [adopted by the netCDF4-Python library](https://github.com/Unidata/netcdf4-python/pull/665). At the time of this writing (October 2017), a standard convention for indicating string encoding for character arrays in netCDF files was [still under discussion](https://github.com/Unidata/netcdf-c/issues/402). Technically, you can use [any string encoding recognized by Python](https://docs.python.org/3/library/codecs.html#standard-encodings) if you feel the need to deviate from UTF-8, by setting the `_Encoding` field in `encoding`. But [we don’t recommend it](https://utf8everywhere.org/). - The character dimension name can be specified by the `char_dim_name` field of a variable’s `encoding`. If the name of the character dimension is not specified, the default is `f'string{data.shape[-1]}'`. When decoding character arrays from existing files, the `char_dim_name` is added to the variables `encoding` to preserve if encoding happens, but the field can be edited by the user. #### WARNING Missing values in bytes or unicode string arrays (represented by `NaN` in xarray) are currently written to disk as empty strings `''`. This means missing values will not be restored when data is loaded from disk. This behavior is likely to change in the future ([GH1647](https://github.com/pydata/xarray/issues/1647)). Unfortunately, explicitly setting a `_FillValue` for string arrays to handle missing values doesn’t work yet either, though we also hope to fix this in the future. #### Chunk based compression `zlib`, `complevel`, `fletcher32`, `contiguous` and `chunksizes` can be used for enabling netCDF4/HDF5’s chunk based compression, as described in the [documentation for createVariable](https://unidata.github.io/netcdf4-python/#netCDF4.Dataset.createVariable) for netCDF4-Python. This only works for netCDF4 files and thus requires using `format='netCDF4'` and either `engine='netcdf4'` or `engine='h5netcdf'`. Chunk based gzip compression can yield impressive space savings, especially for sparse data, but it comes with significant performance overhead. HDF5 libraries can only read complete chunks back into memory, and maximum decompression speed is in the range of 50-100 MB/s. Worse, HDF5’s compression and decompression currently cannot be parallelized with dask. For these reasons, we recommend trying discretization based compression (described above) first. #### Time units The `units` and `calendar` attributes control how xarray serializes `datetime64` and `timedelta64` arrays to datasets on disk as numeric values. The `units` encoding should be a string like `'days since 1900-01-01'` for `datetime64` data or a string like `'days'` for `timedelta64` data. `calendar` should be one of the calendar types supported by netCDF4-python: `'standard'`, `'gregorian'`, `'proleptic_gregorian'`, `'noleap'`, `'365_day'`, `'360_day'`, `'julian'`, `'all_leap'`, `'366_day'`. By default, xarray uses the `'proleptic_gregorian'` calendar and units of the smallest time difference between values, with a reference time of the first time value. #### Coordinates You can control the `coordinates` attribute written to disk by specifying `DataArray.encoding["coordinates"]`. If not specified, xarray automatically sets `DataArray.encoding["coordinates"]` to a space-delimited list of names of coordinate variables that share dimensions with the `DataArray` being written. This allows perfect roundtripping of xarray datasets but may not be desirable. When an xarray `Dataset` contains non-dimensional coordinates that do not share dimensions with any of the variables, these coordinate variable names are saved under a “global” `"coordinates"` attribute. This is not CF-compliant but again facilitates roundtripping of xarray datasets. ### Invalid netCDF files The library `h5netcdf` allows writing some dtypes that aren’t allowed in netCDF4 (see [h5netcdf documentation](https://github.com/h5netcdf/h5netcdf#invalid-netcdf-files)). This feature is available through [`DataArray.to_netcdf()`](../generated/xarray.DataArray.to_netcdf.md#xarray.DataArray.to_netcdf) and [`Dataset.to_netcdf()`](../generated/xarray.Dataset.to_netcdf.md#xarray.Dataset.to_netcdf) when used with `engine="h5netcdf"`, only if `invalid_netcdf=True` is explicitly set. #### WARNING Note that this produces a file that is likely to be not readable by other netCDF libraries! ## HDF5 [HDF5](https://www.hdfgroup.org/solutions/hdf5/) is both a file format and a data model for storing information. HDF5 stores data hierarchically, using groups to create a nested structure. HDF5 is a more general version of the netCDF4 data model, so the nested structure is one of many similarities between the two data formats. Reading HDF5 files in xarray requires the `h5netcdf` engine, which can be installed with `conda install h5netcdf`. Once installed we can use xarray to open HDF5 files: ```python xr.open_dataset("/path/to/my/file.h5") ``` The similarities between HDF5 and netCDF4 mean that HDF5 data can be written with the same [`Dataset.to_netcdf()`](../generated/xarray.Dataset.to_netcdf.md#xarray.Dataset.to_netcdf) method as used for netCDF4 data: ```ipython3 ds = xr.Dataset( {"foo": (("x", "y"), np.random.rand(4, 5))}, coords={ "x": [10, 20, 30, 40], "y": pd.date_range("2000-01-01", periods=5), "z": ("x", list("abcd")), }, ) ``` ```python ds.to_netcdf("saved_on_disk.h5") ``` ### Groups If you have multiple or highly nested groups, xarray by default may not read the group that you want. A particular group of an HDF5 file can be specified using the `group` argument: ```python xr.open_dataset("/path/to/my/file.h5", group="/my/group") ``` While xarray cannot interrogate an HDF5 file to determine which groups are available, the HDF5 Python reader [h5py](https://www.h5py.org/) can be used instead. Natively the xarray data structures can only handle one level of nesting, organized as DataArrays inside of Datasets. If your HDF5 file has additional levels of hierarchy you can only access one group and a time and will need to specify group names. ## Zarr [Zarr](https://zarr.readthedocs.io/) is a Python package that provides an implementation of chunked, compressed, N-dimensional arrays. Zarr has the ability to store arrays in a range of ways, including in memory, in files, and in cloud-based object storage such as [Amazon S3](https://aws.amazon.com/s3/) and [Google Cloud Storage](https://cloud.google.com/storage/). Xarray’s Zarr backend allows xarray to leverage these capabilities, including the ability to store and analyze datasets far too large fit onto disk (particularly [in combination with dask](dask.md#dask)). Xarray can’t open just any zarr dataset, because xarray requires special metadata (attributes) describing the dataset dimensions and coordinates. At this time, xarray can only open zarr datasets with these special attributes, such as zarr datasets written by xarray, [netCDF](https://docs.unidata.ucar.edu/nug/current/nczarr_head.html), or [GDAL](https://gdal.org/drivers/raster/zarr.html). For implementation details, see [Zarr Encoding Specification](../internals/zarr-encoding-spec.md#zarr-encoding). To write a dataset with zarr, we use the [`Dataset.to_zarr()`](../generated/xarray.Dataset.to_zarr.md#xarray.Dataset.to_zarr) method. To write to a local directory, we pass a path to a directory: ```ipython3 zarr_filename = "example.zarr" ``` ```ipython3 ds = xr.Dataset( {"foo": (("x", "y"), np.random.rand(4, 5))}, coords={ "x": [10, 20, 30, 40], "y": pd.date_range("2000-01-01", periods=5), "z": ("x", list("abcd")), }, ) ds.to_zarr(zarr_filename, zarr_format=2, consolidated=False) ``` ```none ``` (The suffix `.zarr` is optional–just a reminder that a zarr store lives there.) If the directory does not exist, it will be created. If a zarr store is already present at that path, an error will be raised, preventing it from being overwritten. To override this behavior and overwrite an existing store, add `mode='w'` when invoking [`to_zarr()`](../generated/xarray.Dataset.to_zarr.md#xarray.Dataset.to_zarr). DataArrays can also be saved to disk using the [`DataArray.to_zarr()`](../generated/xarray.DataArray.to_zarr.md#xarray.DataArray.to_zarr) method, and loaded from disk using the [`open_dataarray()`](../generated/xarray.open_dataarray.md#xarray.open_dataarray) function with `engine='zarr'`. Similar to [`DataArray.to_netcdf()`](../generated/xarray.DataArray.to_netcdf.md#xarray.DataArray.to_netcdf), [`DataArray.to_zarr()`](../generated/xarray.DataArray.to_zarr.md#xarray.DataArray.to_zarr) will convert the `DataArray` to a `Dataset` before saving, and then convert back when loading, ensuring that the `DataArray` that is loaded is always exactly the same as the one that was saved. #### NOTE xarray does not write [NCZarr](https://docs.unidata.ucar.edu/nug/current/nczarr_head.html) attributes. Therefore, NCZarr data must be opened in read-only mode. To store variable length strings, convert them to object arrays first with `dtype=object`. To read back a zarr dataset that has been created this way, we use the [`open_zarr()`](../generated/xarray.open_zarr.md#xarray.open_zarr) method: ```ipython3 ds_zarr = xr.open_zarr(zarr_filename, consolidated=False) ds_zarr ``` ```none Size: 248B Dimensions: (x: 4, y: 5) Coordinates: * x (x) int64 32B 10 20 30 40 z (x) * y (y) datetime64[ns] 40B 2000-01-01 2000-01-02 ... 2000-01-05 Data variables: foo (x, y) float64 160B dask.array ```
<xarray.Dataset> Size: 248B
Dimensions:  (x: 4, y: 5)
Coordinates:
  \* x        (x) int64 32B 10 20 30 40
    z        (x) <U1 16B dask.array<chunksize=(4,), meta=np.ndarray>
  \* y        (y) datetime64[ns] 40B 2000-01-01 2000-01-02 ... 2000-01-05
Data variables:
    foo      (x, y) float64 160B dask.array<chunksize=(4, 5), meta=np.ndarray>
### Cloud Storage Buckets It is possible to read and write xarray datasets directly from / to cloud storage buckets using zarr. This example uses the [gcsfs](https://github.com/fsspec/gcsfs) package to provide an interface to [Google Cloud Storage](https://cloud.google.com/storage/). General [fsspec](https://filesystem-spec.readthedocs.io/en/latest/) URLs, those that begin with `s3://` or `gcs://` for example, are parsed and the store set up for you automatically when reading. You should include any arguments to the storage backend as the key ``storage_options`, part of `backend_kwargs`. ```python ds_gcs = xr.open_dataset( "gcs:///path.zarr", backend_kwargs={ "storage_options": {"project": "", "token": None} }, engine="zarr", ) ``` This also works with `open_mfdataset`, allowing you to pass a list of paths or a URL to be interpreted as a glob string. For writing, you may either specify a bucket URL or explicitly set up a `zarr.abc.store.Store` instance, as follows: ```python # write to the bucket via GCS URL ds.to_zarr("gs://") # read it back ds_gcs = xr.open_zarr("gs://") ``` ```python import gcsfs import zarr # manually manage the cloud filesystem connection -- useful, for example, # when you need to manage permissions to cloud resources fs = gcsfs.GCSFileSystem(project="", token=None) zstore = zarr.storage.FsspecStore(fs, path="") # write to the bucket ds.to_zarr(store=zstore) # read it back ds_gcs = xr.open_zarr(zstore) ``` ```python import obstore import zarr # alternatively, obstore offers a modern, performant interface for # cloud buckets gcsstore = obstore.store.GCSStore( "", prefix="", skip_signature=True ) zstore = zarr.store.ObjectStore(gcsstore) # write to the bucket ds.to_zarr(store=zstore) # read it back ds_gcs = xr.open_zarr(zstore) ``` ### Distributed writes Xarray will natively use dask to write in parallel to a zarr store, which should satisfy most moderately sized datasets. For more flexible parallelization, we can use `region` to write to limited regions of arrays in an existing Zarr store. To scale this up to writing large datasets, first create an initial Zarr store without writing all of its array data. This can be done by first creating a `Dataset` with dummy values stored in [dask](dask.md#dask), and then calling `to_zarr` with `compute=False` to write only metadata (including `attrs`) to Zarr: ```ipython3 import dask.array # The values of this dask array are entirely irrelevant; only the dtype, # shape and chunks are used dummies = dask.array.zeros(30, chunks=10) ds = xr.Dataset({"foo": ("x", dummies)}, coords={"x": np.arange(30)}) # Now we write the metadata without computing any array values ds.to_zarr(zarr_filename, compute=False, consolidated=False) ``` ```none Delayed('_finalize_store-8f24a2ab-ef6c-4107-836b-d0a855abc377') ``` Now, a Zarr store with the correct variable shapes and attributes exists that can be filled out by subsequent calls to `to_zarr`. Setting `region="auto"` will open the existing store and determine the correct alignment of the new data with the existing dimensions, or as an explicit mapping from dimension names to Python `slice` objects indicating where the data should be written (in index space, not label space), e.g., ```ipython3 # For convenience, we'll slice a single dataset, but in the real use-case # we would create them separately possibly even from separate processes. ds = xr.Dataset({"foo": ("x", np.arange(30))}, coords={"x": np.arange(30)}) # Any of the following region specifications are valid ds.isel(x=slice(0, 10)).to_zarr(zarr_filename, region="auto", consolidated=False) ds.isel(x=slice(10, 20)).to_zarr(zarr_filename, region={"x": "auto"}, consolidated=False) ds.isel(x=slice(20, 30)).to_zarr(zarr_filename, region={"x": slice(20, 30)}, consolidated=False) ``` ```none ``` Concurrent writes with `region` are safe as long as they modify distinct chunks in the underlying Zarr arrays (or use an appropriate `lock`). As a safety check to make it harder to inadvertently override existing values, if you set `region` then *all* variables included in a Dataset must have dimensions included in `region`. Other variables (typically coordinates) need to be explicitly dropped and/or written in a separate calls to `to_zarr` with `mode='a'`. ### Zarr Compressors and Filters There are many different [options for compression and filtering possible with zarr](https://zarr.readthedocs.io/en/stable/user-guide/arrays.html#compressors). These options can be passed to the `to_zarr` method as variable encoding. For example: ```ipython3 zarr_filename = "foo.zarr" ``` ```ipython3 import zarr from zarr.codecs import BloscCodec compressor = BloscCodec(cname="zstd", clevel=3, shuffle="shuffle") ds.to_zarr(zarr_filename, consolidated=False, encoding={"foo": {"compressors": [compressor]}}) ``` ```none ``` #### NOTE Not all native zarr compression and filtering options have been tested with xarray. ### Modifying existing Zarr stores Xarray supports several ways of incrementally writing variables to a Zarr store. These options are useful for scenarios when it is infeasible or undesirable to write your entire dataset at once. 1. Use `mode='a'` to add or overwrite entire variables, 2. Use `append_dim` to resize and append to existing variables, and 3. Use `region` to write to limited regions of existing arrays. #### WARNING Alignment of coordinates is currently not checked when modifying an existing Zarr store. It is up to the user to ensure that coordinates are consistent. To add or overwrite entire variables, simply call [`to_zarr()`](../generated/xarray.Dataset.to_zarr.md#xarray.Dataset.to_zarr) with `mode='a'` on a Dataset containing the new variables, passing in an existing Zarr store or path to a Zarr store. To resize and then append values along an existing dimension in a store, set `append_dim`. This is a good option if data always arrives in a particular order, e.g., for time-stepping a simulation: ```ipython3 ds1 = xr.Dataset( {"foo": (("x", "y", "t"), np.random.rand(4, 5, 2))}, coords={ "x": [10, 20, 30, 40], "y": [1, 2, 3, 4, 5], "t": pd.date_range("2001-01-01", periods=2), }, ) ds1.to_zarr(zarr_filename, consolidated=False) ``` ```none ``` ```ipython3 ds2 = xr.Dataset( {"foo": (("x", "y", "t"), np.random.rand(4, 5, 2))}, coords={ "x": [10, 20, 30, 40], "y": [1, 2, 3, 4, 5], "t": pd.date_range("2001-01-03", periods=2), }, ) ds2.to_zarr(zarr_filename, append_dim="t", consolidated=False) ``` ```none ``` ### Specifying chunks in a zarr store Chunk sizes may be specified in one of three ways when writing to a zarr store: 1. Manual chunk sizing through the use of the `encoding` argument in [`Dataset.to_zarr()`](../generated/xarray.Dataset.to_zarr.md#xarray.Dataset.to_zarr): 2. Automatic chunking based on chunks in dask arrays 3. Default chunk behavior determined by the zarr library The resulting chunks will be determined based on the order of the above list; dask chunks will be overridden by manually-specified chunks in the encoding argument, and the presence of either dask chunks or chunks in the `encoding` attribute will supersede the default chunking heuristics in zarr. Importantly, this logic applies to every array in the zarr store individually, including coordinate arrays. Therefore, if a dataset contains one or more dask arrays, it may still be desirable to specify a chunk size for the coordinate arrays (for example, with a chunk size of `-1` to include the full coordinate). To specify chunks manually using the `encoding` argument, provide a nested dictionary with the structure `{'variable_or_coord_name': {'chunks': chunks_tuple}}`. #### NOTE The positional ordering of the chunks in the encoding argument must match the positional ordering of the dimensions in each array. Watch out for arrays with differently-ordered dimensions within a single Dataset. For example, let’s say we’re working with a dataset with dimensions `('time', 'x', 'y')`, a variable `Tair` which is chunked in `x` and `y`, and two multi-dimensional coordinates `xc` and `yc`: ```ipython3 ds = xr.tutorial.open_dataset("rasm") ds["Tair"] = ds["Tair"].chunk({"x": 100, "y": 100}) ds ``` ```none Size: 17MB Dimensions: (time: 36, y: 205, x: 275) Coordinates: * time (time) object 288B 1980-09-16 12:00:00 ... 1983-08-17 00:00:00 xc (y, x) float64 451kB ... yc (y, x) float64 451kB ... Dimensions without coordinates: y, x Data variables: Tair (time, y, x) float64 16MB dask.array Attributes: title: /workspace/jhamman/processed/R1002RBRxaaa01a/l... institution: U.W. source: RACM R1002RBRxaaa01a output_frequency: daily output_mode: averaged convention: CF-1.4 references: Based on the initial model of Liang et al., 19... comment: Output from the Variable Infiltration Capacity... nco_openmp_thread_number: 1 NCO: netCDF Operators version 4.7.9 (Homepage = htt... history: Fri Aug 7 17:57:38 2020: ncatted -a bounds,,d... ```
<xarray.Dataset> Size: 17MB
Dimensions:  (time: 36, y: 205, x: 275)
Coordinates:
  \* time     (time) object 288B 1980-09-16 12:00:00 ... 1983-08-17 00:00:00
    xc       (y, x) float64 451kB ...
    yc       (y, x) float64 451kB ...
Dimensions without coordinates: y, x
Data variables:
    Tair     (time, y, x) float64 16MB dask.array<chunksize=(36, 100, 100), meta=np.ndarray>
Attributes:
    title:                     /workspace/jhamman/processed/R1002RBRxaaa01a/l...
    institution:               U.W.
    source:                    RACM R1002RBRxaaa01a
    output_frequency:          daily
    output_mode:               averaged
    convention:                CF-1.4
    references:                Based on the initial model of Liang et al., 19...
    comment:                   Output from the Variable Infiltration Capacity...
    nco_openmp_thread_number:  1
    NCO:                       netCDF Operators version 4.7.9 (Homepage = htt...
    history:                   Fri Aug  7 17:57:38 2020: ncatted -a bounds,,d...
These multi-dimensional coordinates are only two-dimensional and take up very little space on disk or in memory, yet when writing to disk the default zarr behavior is to split them into chunks: ```ipython3 ds.to_zarr(zarr_filename, consolidated=False, mode="w") !tree -I zarr.json $zarr_filename ``` ```none /usr/bin/sh: 1: tree: not found ``` This may cause unwanted overhead on some systems, such as when reading from a cloud storage provider. To disable this chunking, we can specify a chunk size equal to the shape of each coordinate array in the `encoding` argument: ```ipython3 ds.to_zarr( zarr_filename, encoding={"xc": {"chunks": ds.xc.shape}, "yc": {"chunks": ds.yc.shape}}, consolidated=False, mode="w", ) !tree -I