From df745a57b62e39bd1a67a06244d57d5d34e68689 Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Tue, 11 Jul 2023 02:48:10 -0600 Subject: [PATCH 01/27] adding the links to all indexing materials --- workshops/scipy2023/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/workshops/scipy2023/README.md b/workshops/scipy2023/README.md index 552c5c9f..cd0868be 100644 --- a/workshops/scipy2023/README.md +++ b/workshops/scipy2023/README.md @@ -63,7 +63,11 @@ Once your codespace is launched, the following happens: ``` ```{dropdown} Indexing +{doc}`../../fundamentals/02.1_indexing_Basic` + {doc}`../../intermediate/indexing/advanced-indexing` + +{doc}`../../intermediate/indexing/boolean-masking-indexing` ``` ```{dropdown} Computational Patterns From 155c810ba5568b4d566b96da2c66bf9daf067b2c Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Tue, 11 Jul 2023 02:55:33 -0600 Subject: [PATCH 02/27] typo fix + remove a redundant example. --- intermediate/indexing/advanced-indexing.ipynb | 51 ++++++++----------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 804af21c..efaf6556 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -17,7 +17,7 @@ "source": [ "## Overview\n", "\n", - "In the previous notebooks, we learned basic forms of indexing with xarray (positional and name based dimensions, integer and label based indexing), Datetime Indexing, and nearest neighbor lookups. In this tutorial, we will lean how Xarray indexing is different from Numpy and how to do vectorized/pointwise indexing using Xarray. \n", + "In the previous notebooks, we learned basic forms of indexing with xarray (positional and name based dimensions, integer and label based indexing), Datetime Indexing, and nearest neighbor lookups. In this tutorial, we will learn how Xarray indexing is different from Numpy and how to do vectorized/pointwise indexing using Xarray. \n", "First, let's import packages needed for this repository: " ] }, @@ -107,6 +107,18 @@ "da.sel(lat=target_lat, lon=target_lon, method=\"nearest\") # -- orthogonal indexing" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "target_lat = xr.DataArray([31, 41, 42, 42], dims=\"degrees_north\")\n", + "target_lon = xr.DataArray([200, 201, 202, 205], dims=\"degrees_east\")\n", + "\n", + "da.sel(lat=target_lat, lon=target_lon, method=\"nearest\") # -- orthogonal indexing" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -229,35 +241,6 @@ "```" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Analogously, label-based pointwise-indexing is also possible by the `.sel()` method:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "da = xr.DataArray(\n", - " np.random.rand(4, 3),\n", - " [\n", - " (\"time\", pd.date_range(\"2000-01-01\", periods=4)),\n", - " (\"space\", [\"IA\", \"IL\", \"IN\"]),\n", - " ],\n", - ")\n", - "times = xr.DataArray(pd.to_datetime([\"2000-01-03\", \"2000-01-02\", \"2000-01-01\"]), dims=\"new_time\")\n", - "\n", - "\n", - "# -- get data for each state and each time:\n", - "da.sel(space=xr.DataArray([\"IA\", \"IL\", \"IN\"], dims=[\"new_time\"]), time=times)" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -269,6 +252,11 @@ } ], "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, "language_info": { "codemirror_mode": { "name": "ipython", @@ -278,7 +266,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.11.4" }, "toc": { "base_numbering": 1, From 3300d69db28149cff08c2261f93bb7c23e2b67e1 Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Thu, 6 Jun 2024 13:06:41 -0600 Subject: [PATCH 03/27] updates to indexing --- images/orthogonal_vs_vectorized.png | Bin 0 -> 172020 bytes intermediate/indexing/advanced-indexing.ipynb | 3922 ++++++++++++++++- 2 files changed, 3875 insertions(+), 47 deletions(-) create mode 100644 images/orthogonal_vs_vectorized.png diff --git a/images/orthogonal_vs_vectorized.png b/images/orthogonal_vs_vectorized.png new file mode 100644 index 0000000000000000000000000000000000000000..e2033b876f7178eb62f9f7334e86b42df1532810 GIT binary patch literal 172020 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%0D=3v?Bh-JMGZS<6Sd)&{@Er~2kJW%L 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\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (dim_0: 5, dim_1: 5)>\n",
+       "array([[ 1,  2, ...,  4,  5],\n",
+       "       [ 6,  7, ...,  9, 10],\n",
+       "       ...,\n",
+       "       [16, 17, ..., 19, 20],\n",
+       "       [21, 22, ..., 24, 25]])\n",
+       "Dimensions without coordinates: dim_0, dim_1
" + ], + "text/plain": [ + "\n", + "array([[ 1, 2, ..., 4, 5],\n", + " [ 6, 7, ..., 9, 10],\n", + " ...,\n", + " [16, 17, ..., 19, 20],\n", + " [21, 22, ..., 24, 25]])\n", + "Dimensions without coordinates: dim_0, dim_1" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "ds = xr.tutorial.load_dataset(\"air_temperature\")\n", - "da = ds.air\n", - "ds" + "import xarray as xr\n", + "da = xr.DataArray(np_array)\n", + "da" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 1, 13, 25])" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np_array [[0,2,4],[0,2,4]]" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (dim_0: 3, dim_1: 3)>\n",
+       "array([[ 1,  3,  5],\n",
+       "       [11, 13, 15],\n",
+       "       [21, 23, 25]])\n",
+       "Dimensions without coordinates: dim_0, dim_1
" + ], + "text/plain": [ + "\n", + "array([[ 1, 3, 5],\n", + " [11, 13, 15],\n", + " [21, 23, 25]])\n", + "Dimensions without coordinates: dim_0, dim_1" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "da [[0,2,4],[0,2,4]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Orthogonal Indexing \n", + "The image below shows the difference between orthogonal and vectorized indexing for a 2D 5x5 array. \n", "\n", - "As we learned in the previous tutorial, positional indexing deviates from the behavior exhibited by NumPy when indexing with multiple arrays. However, Xarray pointwise indexing supports the indexing along multiple labeled dimensions using list-like objects similar to NumPy indexing behavior.\n", + "![Orthogonal vs. Vectorized Indexing](../../images/orthogonal_vs_vectorized.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " Point-wise indexing, shown on the left, selects specific elements at given coordinates, resulting in an array of those individual elements. In the example shown, the indices `[0, 2, 4]`, `[0, 2, 4]` select the elements at positions (0, 0), (2, 2), and (4, 4), resulting in the values `[1, 13, 25]`. This is shown in NumPy indexing example. \n", "\n", - "If you only provide integers, slices, or unlabeled arrays (array without dimension names, such as `np.ndarray`, `list`, but not `DataArray()`) indexing can be understood as orthogonally (i.e. along independent axes, instead of using NumPy’s broadcasting rules to vectorize indexers). \n", "\n", - "*Orthogonal* or *outer* indexing considers one-dimensional arrays in the same way as slices when deciding the output shapes. The principle of outer or orthogonal indexing is that the result mirrors the effect of independently indexing along each dimension with integer or boolean arrays, treating both the indexed and indexing arrays as one-dimensional. This method of indexing is analogous to vector indexing in programming languages like MATLAB, Fortran, and R, where each indexer component *independently* selects along its corresponding dimension. \n", + " In contrast, **orthogonal indexing** uses the same indices to select entire rows and columns, forming a cross-product of the specified indices. This method results in subarrays that include all combinations of the selected rows and columns. The example demonstrates this by selecting rows 0, 2, and 4 and columns 0, 2, and 4, resulting in a subarray containing `[[1, 3, 5], [11, 13, 15], [21, 23, 25]]`. This is shown in Xarray indexing example.\n", + " \n", + " The output of orthogonal indexing is a 3x3 array, while the output of vectorized indexing is a 1D array." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The principle of outer or orthogonal indexing is that the result mirrors the effect of independently indexing along each dimension with integer or boolean arrays, treating both the indexed and indexing arrays as one-dimensional." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Orthogonal Indexing in Xarray\n", "\n", - "For example : " + "If you only provide integers, slices, or unlabeled arrays (array without dimension names, such as `np.ndarray`, `list`, but not `DataArray()`) indexing can be understood as orthogonally (i.e. along independent axes, instead of using NumPy’s broadcasting rules to vectorize indexers). In the example above we saw this behavior, but let's see it in action with a real dataset." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 46, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset>\n",
+       "Dimensions:  (lat: 25, time: 2920, lon: 53)\n",
+       "Coordinates:\n",
+       "  * lat      (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
+       "  * lon      (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n",
+       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
+       "Data variables:\n",
+       "    air      (time, lat, lon) float32 241.2 242.5 243.5 ... 296.5 296.2 295.7\n",
+       "Attributes: (5)
" + ], + "text/plain": [ + "\n", + "Dimensions: (lat: 25, time: 2920, lon: 53)\n", + "Coordinates:\n", + " * lat (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n", + " * lon (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n", + " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", + "Data variables:\n", + " air (time, lat, lon) float32 241.2 242.5 243.5 ... 296.5 296.2 295.7\n", + "Attributes: (5)" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "da.isel(time=0, lat=[2, 4, 10, 13], lon=[1, 6, 7]).plot(); # -- orthogonal indexing" + "import numpy as np\n", + "import pandas as pd\n", + "import xarray as xr\n", + "\n", + "\n", + "xr.set_options(display_expand_attrs=False)\n", + "np.set_printoptions(threshold=10, edgeitems=2)\n", + "\n", + "ds = xr.tutorial.load_dataset(\"air_temperature\")\n", + "da_air = ds.air\n", + "ds\n" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'air' (lat: 4, lon: 3)>\n",
+       "array([[249.79999, 243.09999, 242.39   ],\n",
+       "       [274.29   , 271.79   , 270.6    ],\n",
+       "       [277.4    , 280.6    , 280.9    ],\n",
+       "       [283.19998, 285.5    , 285.9    ]], dtype=float32)\n",
+       "Coordinates:\n",
+       "  * lat      (lat) float32 70.0 65.0 50.0 42.5\n",
+       "  * lon      (lon) float32 202.5 215.0 217.5\n",
+       "    time     datetime64[ns] 2013-01-01\n",
+       "Attributes: (11)
" + ], + "text/plain": [ + "\n", + "array([[249.79999, 243.09999, 242.39 ],\n", + " [274.29 , 271.79 , 270.6 ],\n", + " [277.4 , 280.6 , 280.9 ],\n", + " [283.19998, 285.5 , 285.9 ]], dtype=float32)\n", + "Coordinates:\n", + " * lat (lat) float32 70.0 65.0 50.0 42.5\n", + " * lon (lon) float32 202.5 215.0 217.5\n", + " time datetime64[ns] 2013-01-01\n", + "Attributes: (11)" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "selected_da = da_air.isel(time=0, lat=[2, 4, 10, 13], lon=[1, 6, 7]) # -- orthogonal indexing\n", + "selected_da" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "For more flexibility, you can supply `DataArray()` objects as indexers. Dimensions on resultant arrays are given by the ordered union of the indexers’ dimensions:\n", + "👆 please notice how the ouput if the indexing example above resulted in an array of 3x4. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For more flexibility, you can supply `DataArray()` objects as indexers. Dimensions on resultant arrays are given by the ordered union of the indexers’ dimensions.\n", "\n", "For example, in the example below we do orthogonal indexing using `DataArray()` objects. " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 41, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'air' (time: 2920, degrees_north: 4, degrees_east: 4)>\n",
+       "array([[[293.1    , 293.1    , 293.29   , 293.29   ],\n",
+       "        [284.6    , 284.6    , 284.9    , 284.19998],\n",
+       "        [282.79   , 282.79   , 283.19998, 282.6    ],\n",
+       "        [282.79   , 282.79   , 283.19998, 282.6    ]],\n",
+       "\n",
+       "       [[293.19998, 293.19998, 293.9    , 294.19998],\n",
+       "        [283.29   , 283.29   , 285.19998, 285.19998],\n",
+       "        [281.4    , 281.4    , 282.79   , 283.5    ],\n",
+       "        [281.4    , 281.4    , 282.79   , 283.5    ]],\n",
+       "\n",
+       "       ...,\n",
+       "\n",
+       "       [[288.29   , 288.29   , 289.19   , 290.79   ],\n",
+       "        [282.09   , 282.09   , 281.59   , 282.38998],\n",
+       "        [280.99   , 280.99   , 280.38998, 280.59   ],\n",
+       "        [280.99   , 280.99   , 280.38998, 280.59   ]],\n",
+       "\n",
+       "       [[289.49   , 289.49   , 290.38998, 291.59   ],\n",
+       "        [282.09   , 282.09   , 281.99   , 283.09   ],\n",
+       "        [281.38998, 281.38998, 280.59   , 280.99   ],\n",
+       "        [281.38998, 281.38998, 280.59   , 280.99   ]]], dtype=float32)\n",
+       "Coordinates:\n",
+       "    lat      (degrees_north) float32 30.0 40.0 42.5 42.5\n",
+       "    lon      (degrees_east) float32 200.0 200.0 202.5 205.0\n",
+       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
+       "Dimensions without coordinates: degrees_north, degrees_east\n",
+       "Attributes: (11)
" + ], + "text/plain": [ + "\n", + "array([[[293.1 , 293.1 , 293.29 , 293.29 ],\n", + " [284.6 , 284.6 , 284.9 , 284.19998],\n", + " [282.79 , 282.79 , 283.19998, 282.6 ],\n", + " [282.79 , 282.79 , 283.19998, 282.6 ]],\n", + "\n", + " [[293.19998, 293.19998, 293.9 , 294.19998],\n", + " [283.29 , 283.29 , 285.19998, 285.19998],\n", + " [281.4 , 281.4 , 282.79 , 283.5 ],\n", + " [281.4 , 281.4 , 282.79 , 283.5 ]],\n", + "\n", + " ...,\n", + "\n", + " [[288.29 , 288.29 , 289.19 , 290.79 ],\n", + " [282.09 , 282.09 , 281.59 , 282.38998],\n", + " [280.99 , 280.99 , 280.38998, 280.59 ],\n", + " [280.99 , 280.99 , 280.38998, 280.59 ]],\n", + "\n", + " [[289.49 , 289.49 , 290.38998, 291.59 ],\n", + " [282.09 , 282.09 , 281.99 , 283.09 ],\n", + " [281.38998, 281.38998, 280.59 , 280.99 ],\n", + " [281.38998, 281.38998, 280.59 , 280.99 ]]], dtype=float32)\n", + "Coordinates:\n", + " lat (degrees_north) float32 30.0 40.0 42.5 42.5\n", + " lon (degrees_east) float32 200.0 200.0 202.5 205.0\n", + " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", + "Dimensions without coordinates: degrees_north, degrees_east\n", + "Attributes: (11)" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "target_lat = xr.DataArray([31, 41, 42, 42], dims=\"degrees_north\")\n", "target_lon = xr.DataArray([200, 201, 202, 205], dims=\"degrees_east\")\n", "\n", - "da.sel(lat=target_lat, lon=target_lon, method=\"nearest\") # -- orthogonal indexing" + "da_air.sel(lat=target_lat, lon=target_lon, method=\"nearest\") # -- orthogonal indexing" ] }, { @@ -137,13 +2323,12 @@ "\n", "## Vectorized or Pointwise Indexing\n", "\n", - "Like NumPy and pandas, Xarray supports indexing many array elements at once in a\n", - "*vectorized* manner. \n", + "Like NumPy and pandas, Xarray supports indexing many array elements at once in a *vectorized* manner. \n", "\n", "**Vectorized indexing** or **Pointwise Indexing** using `DataArrays()` can be used to extract information from the nearest grid cells of interest, for example, the nearest climate model grid cells to a collection of specified weather station latitudes and longitudes.\n", "\n", "```{hint}\n", - "To trigger vectorized indexing behavior, you will need to provide the selection dimensions with a new shared output dimension name. \n", + "To trigger vectorized indexing behavior, you will need to provide the selection dimensions with a different name than the original dimensions. This dimension name will be used in the output array.\n", "```\n", "\n", "In the example below, the selections of the closest latitude and longitude are renamed to an output dimension named `points`:" @@ -151,26 +2336,788 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (points: 4)>\n",
+       "array([31, 41, 42, 42])\n",
+       "Dimensions without coordinates: points
" + ], + "text/plain": [ + "\n", + "array([31, 41, 42, 42])\n", + "Dimensions without coordinates: points" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Define target latitude and longitude (where weather stations might be)\n", "lat_points = xr.DataArray([31, 41, 42, 42], dims=\"points\")\n", - "lon_points = xr.DataArray([200, 201, 202, 205], dims=\"points\")\n", "lat_points" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (points: 4)>\n",
+       "array([200, 201, 202, 205])\n",
+       "Dimensions without coordinates: points
" + ], + "text/plain": [ + "\n", + "array([200, 201, 202, 205])\n", + "Dimensions without coordinates: points" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ + "lon_points = xr.DataArray([200, 201, 202, 205], dims=\"points\")\n", "lon_points" ] }, @@ -183,11 +3130,428 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'air' (time: 2920, points: 4)>\n",
+       "array([[293.1    , 284.6    , 283.19998, 282.6    ],\n",
+       "       [293.19998, 283.29   , 282.79   , 283.5    ],\n",
+       "       ...,\n",
+       "       [288.29   , 282.09   , 280.38998, 280.59   ],\n",
+       "       [289.49   , 282.09   , 280.59   , 280.99   ]], dtype=float32)\n",
+       "Coordinates:\n",
+       "    lat      (points) float32 30.0 40.0 42.5 42.5\n",
+       "    lon      (points) float32 200.0 200.0 202.5 205.0\n",
+       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
+       "Dimensions without coordinates: points\n",
+       "Attributes: (11)
" + ], + "text/plain": [ + "\n", + "array([[293.1 , 284.6 , 283.19998, 282.6 ],\n", + " [293.19998, 283.29 , 282.79 , 283.5 ],\n", + " ...,\n", + " [288.29 , 282.09 , 280.38998, 280.59 ],\n", + " [289.49 , 282.09 , 280.59 , 280.99 ]], dtype=float32)\n", + "Coordinates:\n", + " lat (points) float32 30.0 40.0 42.5 42.5\n", + " lon (points) float32 200.0 200.0 202.5 205.0\n", + " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", + "Dimensions without coordinates: points\n", + "Attributes: (11)" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "da.sel(lat=lat_points, lon=lon_points, method=\"nearest\")" ] @@ -201,11 +3565,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 28, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "('time', 'points')" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "da.sel(lat=lat_points, lon=lon_points, method=\"nearest\").dims" ] @@ -223,11 +3598,464 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 29, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'air' (time: 2920, lat: 3, points: 4)>\n",
+       "array([[[296.6    , 296.6    , 296.19998, 296.4    ],\n",
+       "        [293.1    , 293.1    , 293.29   , 293.29   ],\n",
+       "        [284.6    , 284.6    , 284.9    , 284.19998]],\n",
+       "\n",
+       "       [[296.4    , 296.4    , 295.9    , 296.19998],\n",
+       "        [293.19998, 293.19998, 293.9    , 294.19998],\n",
+       "        [283.29   , 283.29   , 285.19998, 285.19998]],\n",
+       "\n",
+       "       ...,\n",
+       "\n",
+       "       [[293.69   , 293.69   , 293.88998, 295.38998],\n",
+       "        [288.29   , 288.29   , 289.19   , 290.79   ],\n",
+       "        [282.09   , 282.09   , 281.59   , 282.38998]],\n",
+       "\n",
+       "       [[293.79   , 293.79   , 293.69   , 295.09   ],\n",
+       "        [289.49   , 289.49   , 290.38998, 291.59   ],\n",
+       "        [282.09   , 282.09   , 281.99   , 283.09   ]]], dtype=float32)\n",
+       "Coordinates:\n",
+       "  * lat      (lat) float32 20.0 30.0 40.0\n",
+       "    lon      (points) float32 200.0 200.0 202.5 205.0\n",
+       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
+       "Dimensions without coordinates: points\n",
+       "Attributes: (11)
" + ], + "text/plain": [ + "\n", + "array([[[296.6 , 296.6 , 296.19998, 296.4 ],\n", + " [293.1 , 293.1 , 293.29 , 293.29 ],\n", + " [284.6 , 284.6 , 284.9 , 284.19998]],\n", + "\n", + " [[296.4 , 296.4 , 295.9 , 296.19998],\n", + " [293.19998, 293.19998, 293.9 , 294.19998],\n", + " [283.29 , 283.29 , 285.19998, 285.19998]],\n", + "\n", + " ...,\n", + "\n", + " [[293.69 , 293.69 , 293.88998, 295.38998],\n", + " [288.29 , 288.29 , 289.19 , 290.79 ],\n", + " [282.09 , 282.09 , 281.59 , 282.38998]],\n", + "\n", + " [[293.79 , 293.79 , 293.69 , 295.09 ],\n", + " [289.49 , 289.49 , 290.38998, 291.59 ],\n", + " [282.09 , 282.09 , 281.99 , 283.09 ]]], dtype=float32)\n", + "Coordinates:\n", + " * lat (lat) float32 20.0 30.0 40.0\n", + " lon (points) float32 200.0 200.0 202.5 205.0\n", + " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", + "Dimensions without coordinates: points\n", + "Attributes: (11)" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "da.sel(lat=[20, 30, 40], lon=lon_points, method=\"nearest\")" ] From 19c97f4818ea93ca6c91eb3e3c57ceeaeeb77aad Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Thu, 6 Jun 2024 13:10:09 -0600 Subject: [PATCH 04/27] updating advanced indexing --- intermediate/indexing/advanced-indexing.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index d6a06b3f..16b14d68 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -8,7 +8,7 @@ "\n", "## Learning Objectives\n", "\n", - "* Orthogonal vs. Vectorized and Pointwise Indexing" + "* Orthogonal vs. Pointwise Indexing" ] }, { @@ -17,7 +17,7 @@ "source": [ "## Overview\n", "\n", - "In the previous notebooks, we learned basic forms of indexing with Xarray (positional and name based dimensions, integer and label based indexing), datetime Indexing, and nearest neighbor lookups. Xarray positional indexing deviates from the NumPy when indexing with multiple arrays like arr[[0, 1], [0, 1]]. In this tutorial we learn about this difference and how to do vectorized/pointwise indexing using Xarray.\n", + "In the previous notebooks, we learned basic forms of indexing with Xarray (positional and name based dimensions, integer and label based indexing), datetime Indexing, and nearest neighbor lookups. Xarray positional indexing deviates from the NumPy when indexing with multiple arrays like `arr[[0, 1], [0, 1]]`. In this tutorial we learn about this difference and how to do vectorized/pointwise indexing using Xarray.\n", "\n", "For this notebook, first, we should learn about orthogonal (i.e. outer) and vectorized (i.e. pointwise) indexing concepts. \n", "\n", From f25af4c130254dfe423fac44cce2b867ef15da3e Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Thu, 6 Jun 2024 13:28:43 -0600 Subject: [PATCH 05/27] advanced indexing --- intermediate/indexing/advanced-indexing.ipynb | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 16b14d68..43380b14 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -17,7 +17,9 @@ "source": [ "## Overview\n", "\n", - "In the previous notebooks, we learned basic forms of indexing with Xarray (positional and name based dimensions, integer and label based indexing), datetime Indexing, and nearest neighbor lookups. Xarray positional indexing deviates from the NumPy when indexing with multiple arrays like `arr[[0, 1], [0, 1]]`. In this tutorial we learn about this difference and how to do vectorized/pointwise indexing using Xarray.\n", + "In the previous notebooks, we learned basic forms of indexing with Xarray (positional and name based dimensions, integer and label based indexing), datetime Indexing, and nearest neighbor lookups. Xarray positional indexing deviates from the NumPy when indexing with multiple arrays like `arr[[0, 1], [0, 1]]`.\n", + "\n", + "In this tutorial we learn about this difference and how to do vectorized/pointwise indexing using Xarray.\n", "\n", "For this notebook, first, we should learn about orthogonal (i.e. outer) and vectorized (i.e. pointwise) indexing concepts. \n", "\n", @@ -31,7 +33,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 47, "metadata": {}, "outputs": [ { @@ -44,7 +46,7 @@ " [21, 22, ..., 24, 25]])" ] }, - "execution_count": 42, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -66,7 +68,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 48, "metadata": {}, "outputs": [ { @@ -441,11 +443,11 @@ " ...,\n", " [16, 17, ..., 19, 20],\n", " [21, 22, ..., 24, 25]])\n", - "Dimensions without coordinates: dim_0, dim_1
      • " ], "text/plain": [ "\n", @@ -457,7 +459,7 @@ "Dimensions without coordinates: dim_0, dim_1" ] }, - "execution_count": 43, + "execution_count": 48, "metadata": {}, "output_type": "execute_result" } @@ -470,7 +472,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 49, "metadata": {}, "outputs": [ { @@ -479,7 +481,7 @@ "array([ 1, 13, 25])" ] }, - "execution_count": 44, + "execution_count": 49, "metadata": {}, "output_type": "execute_result" } @@ -490,7 +492,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 50, "metadata": {}, "outputs": [ { @@ -863,9 +865,9 @@ "array([[ 1, 3, 5],\n", " [11, 13, 15],\n", " [21, 23, 25]])\n", - "Dimensions without coordinates: dim_0, dim_1
          • " ], "text/plain": [ "\n", @@ -875,7 +877,7 @@ "Dimensions without coordinates: dim_0, dim_1" ] }, - "execution_count": 45, + "execution_count": 50, "metadata": {}, "output_type": "execute_result" } @@ -888,7 +890,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The image below shows the difference between orthogonal and vectorized indexing for a 2D 5x5 array. \n", + "The image below summarizes the difference between orthogonal and vectorized indexing for a 2D 5x5 array. \n", "\n", "![Orthogonal vs. Vectorized Indexing](../../images/orthogonal_vs_vectorized.png)" ] From 9ff571abfb0801b1bcc56b7ed437fc3f155c5d16 Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Thu, 6 Jun 2024 13:41:06 -0600 Subject: [PATCH 06/27] update indexing redundancies --- intermediate/indexing/advanced-indexing.ipynb | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 43380b14..2ede75cd 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -907,13 +907,6 @@ " The output of orthogonal indexing is a 3x3 array, while the output of vectorized indexing is a 1D array." ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The principle of outer or orthogonal indexing is that the result mirrors the effect of independently indexing along each dimension with integer or boolean arrays, treating both the indexed and indexing arrays as one-dimensional." - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -1818,7 +1811,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 51, "metadata": { "tags": [] }, @@ -2216,7 +2209,7 @@ " lon (degrees_east) float32 200.0 200.0 202.5 205.0\n", " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", "Dimensions without coordinates: degrees_north, degrees_east\n", - "Attributes: (11)
          • 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 ]
          • " ], "text/plain": [ "\n", @@ -2283,7 +2276,7 @@ "Attributes: (11)" ] }, - "execution_count": 41, + "execution_count": 51, "metadata": {}, "output_type": "execute_result" } @@ -2295,18 +2288,6 @@ "da_air.sel(lat=target_lat, lon=target_lon, method=\"nearest\") # -- orthogonal indexing" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "target_lat = xr.DataArray([31, 41, 42, 42], dims=\"degrees_north\")\n", - "target_lon = xr.DataArray([200, 201, 202, 205], dims=\"degrees_east\")\n", - "\n", - "da.sel(lat=target_lat, lon=target_lon, method=\"nearest\") # -- orthogonal indexing" - ] - }, { "cell_type": "markdown", "metadata": {}, From 64d714c328518deb6072445c1c48da02e1de9fdc Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Thu, 6 Jun 2024 14:39:59 -0600 Subject: [PATCH 07/27] adding excercise --- intermediate/indexing/advanced-indexing.ipynb | 156 ++++++++++-------- 1 file changed, 88 insertions(+), 68 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 2ede75cd..a5a8095e 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -33,20 +33,20 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([[ 1, 2, ..., 4, 5],\n", - " [ 6, 7, ..., 9, 10],\n", - " ...,\n", - " [16, 17, ..., 19, 20],\n", - " [21, 22, ..., 24, 25]])" + "array([[ 1, 2, 3, 4, 5],\n", + " [ 6, 7, 8, 9, 10],\n", + " [11, 12, 13, 14, 15],\n", + " [16, 17, 18, 19, 20],\n", + " [21, 22, 23, 24, 25]])" ] }, - "execution_count": 47, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -68,7 +68,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 54, "metadata": {}, "outputs": [ { @@ -437,42 +437,42 @@ " stroke: currentColor;\n", " fill: currentColor;\n", "}\n", - "
            <xarray.DataArray (dim_0: 5, dim_1: 5)>\n",
            +       "
            <xarray.DataArray (x: 5, y: 5)>\n",
                    "array([[ 1,  2, ...,  4,  5],\n",
                    "       [ 6,  7, ...,  9, 10],\n",
                    "       ...,\n",
                    "       [16, 17, ..., 19, 20],\n",
                    "       [21, 22, ..., 24, 25]])\n",
            -       "Dimensions without coordinates: dim_0, dim_1
              • " ], "text/plain": [ - "\n", + "\n", "array([[ 1, 2, ..., 4, 5],\n", " [ 6, 7, ..., 9, 10],\n", " ...,\n", " [16, 17, ..., 19, 20],\n", " [21, 22, ..., 24, 25]])\n", - "Dimensions without coordinates: dim_0, dim_1" + "Dimensions without coordinates: x, y" ] }, - "execution_count": 48, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import xarray as xr\n", - "da = xr.DataArray(np_array)\n", + "da = xr.DataArray(np_array, dims=[\"x\", \"y\"])\n", "da" ] }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -481,7 +481,7 @@ "array([ 1, 13, 25])" ] }, - "execution_count": 49, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -492,7 +492,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -865,9 +865,9 @@ "array([[ 1, 3, 5],\n", " [11, 13, 15],\n", " [21, 23, 25]])\n", - "Dimensions without coordinates: dim_0, dim_1
                  • " ], "text/plain": [ "\n", @@ -877,7 +877,7 @@ "Dimensions without coordinates: dim_0, dim_1" ] }, - "execution_count": 50, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -918,7 +918,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 5, "metadata": { "tags": [] }, @@ -1297,17 +1297,17 @@ " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", "Data variables:\n", " air (time, lat, lon) float32 241.2 242.5 243.5 ... 296.5 296.2 295.7\n", - "Attributes: (5)" ], "text/plain": [ @@ -1366,7 +1366,7 @@ "Attributes: (5)" ] }, - "execution_count": 46, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -1387,7 +1387,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -1765,10 +1765,10 @@ " * lat (lat) float32 70.0 65.0 50.0 42.5\n", " * lon (lon) float32 202.5 215.0 217.5\n", " time datetime64[ns] 2013-01-01\n", - "Attributes: (11)
                    • lat
                      (lat)
                      float32
                      70.0 65.0 50.0 42.5
                      standard_name :
                      latitude
                      long_name :
                      Latitude
                      units :
                      degrees_north
                      axis :
                      Y
                      array([70. , 65. , 50. , 42.5], dtype=float32)
                    • lon
                      (lon)
                      float32
                      202.5 215.0 217.5
                      standard_name :
                      longitude
                      long_name :
                      Longitude
                      units :
                      degrees_east
                      axis :
                      X
                      array([202.5, 215. , 217.5], dtype=float32)
                    • time
                      ()
                      datetime64[ns]
                      2013-01-01
                      standard_name :
                      time
                      long_name :
                      Time
                      array('2013-01-01T00:00:00.000000000', dtype='datetime64[ns]')
                    • lat
                      PandasIndex
                      PandasIndex(Index([70.0, 65.0, 50.0, 42.5], dtype='float32', name='lat'))
                    • lon
                      PandasIndex
                      PandasIndex(Index([202.5, 215.0, 217.5], dtype='float32', name='lon'))
                  • 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 ]
                  • " ], "text/plain": [ "\n", @@ -1783,7 +1783,7 @@ "Attributes: (11)" ] }, - "execution_count": 39, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -1811,7 +1811,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 7, "metadata": { "tags": [] }, @@ -2209,7 +2209,7 @@ " lon (degrees_east) float32 200.0 200.0 202.5 205.0\n", " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", "Dimensions without coordinates: degrees_north, degrees_east\n", - "Attributes: (11)
                  • 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 ]
                  • " ], "text/plain": [ "\n", @@ -2276,7 +2276,7 @@ "Attributes: (11)" ] }, - "execution_count": 51, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -2304,7 +2304,7 @@ "\n", "But what if we would like to find the information from the nearest grid cell to a collection of specified points (for example, weather stations or tower data)?\n", "\n", - "## Vectorized or Pointwise Indexing\n", + "## Vectorized or Pointwise Indexing in Xarray\n", "\n", "Like NumPy and pandas, Xarray supports indexing many array elements at once in a *vectorized* manner. \n", "\n", @@ -2319,7 +2319,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 44, "metadata": { "tags": [] }, @@ -2692,7 +2692,7 @@ "}\n", "
                    <xarray.DataArray (points: 4)>\n",
                            "array([31, 41, 42, 42])\n",
                    -       "Dimensions without coordinates: points
                    " + "Dimensions without coordinates: points" ], "text/plain": [ "\n", @@ -2700,7 +2700,7 @@ "Dimensions without coordinates: points" ] }, - "execution_count": 22, + "execution_count": 44, "metadata": {}, "output_type": "execute_result" } @@ -2713,7 +2713,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 45, "metadata": { "tags": [] }, @@ -3086,7 +3086,7 @@ "}\n", "
                    <xarray.DataArray (points: 4)>\n",
                            "array([200, 201, 202, 205])\n",
                    -       "Dimensions without coordinates: points
                    " + "Dimensions without coordinates: points" ], "text/plain": [ "\n", @@ -3094,7 +3094,7 @@ "Dimensions without coordinates: points" ] }, - "execution_count": 26, + "execution_count": 45, "metadata": {}, "output_type": "execute_result" } @@ -3113,7 +3113,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 23, "metadata": { "tags": [] }, @@ -3495,14 +3495,14 @@ " lon (points) float32 200.0 200.0 202.5 205.0\n", " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", "Dimensions without coordinates: points\n", - "Attributes: (11)
                  • 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 ]
                  • " ], "text/plain": [ "\n", @@ -3530,13 +3530,13 @@ "Attributes: (11)" ] }, - "execution_count": 27, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "da.sel(lat=lat_points, lon=lon_points, method=\"nearest\")" + "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\")" ] }, { @@ -3548,7 +3548,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 24, "metadata": { "tags": [] }, @@ -3559,13 +3559,13 @@ "('time', 'points')" ] }, - "execution_count": 28, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "da.sel(lat=lat_points, lon=lon_points, method=\"nearest\").dims" + "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\").dims" ] }, { @@ -3581,7 +3581,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 43, "metadata": { "tags": [] }, @@ -3975,7 +3975,7 @@ " lon (points) float32 200.0 200.0 202.5 205.0\n", " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", "Dimensions without coordinates: points\n", - "Attributes: (11)
                  • 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 ]
                  • " ], "text/plain": [ "\n", @@ -4034,22 +4034,42 @@ "Attributes: (11)" ] }, - "execution_count": 29, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "da.sel(lat=[20, 30, 40], lon=lon_points, method=\"nearest\")" + "da_air.sel(lat=[20, 30, 40], lon=lon_points, method=\"nearest\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "```{warning}\n", - "If an indexer is a `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!\n", - "```" + "## Excersises\n", + "\n", + "```{exercise}\n", + ":label: indexing-1\n", + "\n", + "In the simple 2D 5x5 Xarray data array above, select the sub-array containing (0,0),(2,2),(4,4) : \n", + "```\n", + "\n", + "\n", + "\n", + "````{solution} indexing-1\n", + ":class: dropdown\n", + "```python\n", + "\n", + "indices = np.array([0, 2, 4])\n", + "\n", + "xs_da = xr.DataArray(indices, dims=\"points\")\n", + "ys_da = xr.DataArray(indices, dims=\"points\")\n", + "\n", + "subset_da = da.sel(x=xs_da, y=xs_da)\n", + "subset_da\n", + "```\n", + "````\n" ] }, { From 8999e25372168f943d9d81d8cdd37a750445a803 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:43:55 +0000 Subject: [PATCH 08/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- intermediate/indexing/advanced-indexing.ipynb | 3823 +---------------- 1 file changed, 29 insertions(+), 3794 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index a5a8095e..9950e621 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -33,24 +33,9 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[ 1, 2, 3, 4, 5],\n", - " [ 6, 7, 8, 9, 10],\n", - " [11, 12, 13, 14, 15],\n", - " [16, 17, 18, 19, 20],\n", - " [21, 22, 23, 24, 25]])" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import numpy as np\n", "\n", @@ -68,822 +53,32 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray (x: 5, y: 5)>\n",
                    -       "array([[ 1,  2, ...,  4,  5],\n",
                    -       "       [ 6,  7, ...,  9, 10],\n",
                    -       "       ...,\n",
                    -       "       [16, 17, ..., 19, 20],\n",
                    -       "       [21, 22, ..., 24, 25]])\n",
                    -       "Dimensions without coordinates: x, y
                    " - ], - "text/plain": [ - "\n", - "array([[ 1, 2, ..., 4, 5],\n", - " [ 6, 7, ..., 9, 10],\n", - " ...,\n", - " [16, 17, ..., 19, 20],\n", - " [21, 22, ..., 24, 25]])\n", - "Dimensions without coordinates: x, y" - ] - }, - "execution_count": 54, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import xarray as xr\n", + "\n", "da = xr.DataArray(np_array, dims=[\"x\", \"y\"])\n", "da" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 1, 13, 25])" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "np_array [[0,2,4],[0,2,4]]" + "np_array[[0, 2, 4], [0, 2, 4]]" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray (dim_0: 3, dim_1: 3)>\n",
                    -       "array([[ 1,  3,  5],\n",
                    -       "       [11, 13, 15],\n",
                    -       "       [21, 23, 25]])\n",
                    -       "Dimensions without coordinates: dim_0, dim_1
                    " - ], - "text/plain": [ - "\n", - "array([[ 1, 3, 5],\n", - " [11, 13, 15],\n", - " [21, 23, 25]])\n", - "Dimensions without coordinates: dim_0, dim_1" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "da [[0,2,4],[0,2,4]]" + "da[[0, 2, 4], [0, 2, 4]]" ] }, { @@ -918,459 +113,11 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.Dataset>\n",
                    -       "Dimensions:  (lat: 25, time: 2920, lon: 53)\n",
                    -       "Coordinates:\n",
                    -       "  * lat      (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
                    -       "  * lon      (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n",
                    -       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    -       "Data variables:\n",
                    -       "    air      (time, lat, lon) float32 241.2 242.5 243.5 ... 296.5 296.2 295.7\n",
                    -       "Attributes: (5)
                    " - ], - "text/plain": [ - "\n", - "Dimensions: (lat: 25, time: 2920, lon: 53)\n", - "Coordinates:\n", - " * lat (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n", - " * lon (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n", - " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", - "Data variables:\n", - " air (time, lat, lon) float32 241.2 242.5 243.5 ... 296.5 296.2 295.7\n", - "Attributes: (5)" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", @@ -1382,412 +129,14 @@ "\n", "ds = xr.tutorial.load_dataset(\"air_temperature\")\n", "da_air = ds.air\n", - "ds\n" + "ds" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray 'air' (lat: 4, lon: 3)>\n",
                    -       "array([[249.79999, 243.09999, 242.39   ],\n",
                    -       "       [274.29   , 271.79   , 270.6    ],\n",
                    -       "       [277.4    , 280.6    , 280.9    ],\n",
                    -       "       [283.19998, 285.5    , 285.9    ]], dtype=float32)\n",
                    -       "Coordinates:\n",
                    -       "  * lat      (lat) float32 70.0 65.0 50.0 42.5\n",
                    -       "  * lon      (lon) float32 202.5 215.0 217.5\n",
                    -       "    time     datetime64[ns] 2013-01-01\n",
                    -       "Attributes: (11)
                    " - ], - "text/plain": [ - "\n", - "array([[249.79999, 243.09999, 242.39 ],\n", - " [274.29 , 271.79 , 270.6 ],\n", - " [277.4 , 280.6 , 280.9 ],\n", - " [283.19998, 285.5 , 285.9 ]], dtype=float32)\n", - "Coordinates:\n", - " * lat (lat) float32 70.0 65.0 50.0 42.5\n", - " * lon (lon) float32 202.5 215.0 217.5\n", - " time datetime64[ns] 2013-01-01\n", - "Attributes: (11)" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "selected_da = da_air.isel(time=0, lat=[2, 4, 10, 13], lon=[1, 6, 7]) # -- orthogonal indexing\n", "selected_da" @@ -1811,476 +160,11 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray 'air' (time: 2920, degrees_north: 4, degrees_east: 4)>\n",
                    -       "array([[[293.1    , 293.1    , 293.29   , 293.29   ],\n",
                    -       "        [284.6    , 284.6    , 284.9    , 284.19998],\n",
                    -       "        [282.79   , 282.79   , 283.19998, 282.6    ],\n",
                    -       "        [282.79   , 282.79   , 283.19998, 282.6    ]],\n",
                    -       "\n",
                    -       "       [[293.19998, 293.19998, 293.9    , 294.19998],\n",
                    -       "        [283.29   , 283.29   , 285.19998, 285.19998],\n",
                    -       "        [281.4    , 281.4    , 282.79   , 283.5    ],\n",
                    -       "        [281.4    , 281.4    , 282.79   , 283.5    ]],\n",
                    -       "\n",
                    -       "       ...,\n",
                    -       "\n",
                    -       "       [[288.29   , 288.29   , 289.19   , 290.79   ],\n",
                    -       "        [282.09   , 282.09   , 281.59   , 282.38998],\n",
                    -       "        [280.99   , 280.99   , 280.38998, 280.59   ],\n",
                    -       "        [280.99   , 280.99   , 280.38998, 280.59   ]],\n",
                    -       "\n",
                    -       "       [[289.49   , 289.49   , 290.38998, 291.59   ],\n",
                    -       "        [282.09   , 282.09   , 281.99   , 283.09   ],\n",
                    -       "        [281.38998, 281.38998, 280.59   , 280.99   ],\n",
                    -       "        [281.38998, 281.38998, 280.59   , 280.99   ]]], dtype=float32)\n",
                    -       "Coordinates:\n",
                    -       "    lat      (degrees_north) float32 30.0 40.0 42.5 42.5\n",
                    -       "    lon      (degrees_east) float32 200.0 200.0 202.5 205.0\n",
                    -       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    -       "Dimensions without coordinates: degrees_north, degrees_east\n",
                    -       "Attributes: (11)
                    " - ], - "text/plain": [ - "\n", - "array([[[293.1 , 293.1 , 293.29 , 293.29 ],\n", - " [284.6 , 284.6 , 284.9 , 284.19998],\n", - " [282.79 , 282.79 , 283.19998, 282.6 ],\n", - " [282.79 , 282.79 , 283.19998, 282.6 ]],\n", - "\n", - " [[293.19998, 293.19998, 293.9 , 294.19998],\n", - " [283.29 , 283.29 , 285.19998, 285.19998],\n", - " [281.4 , 281.4 , 282.79 , 283.5 ],\n", - " [281.4 , 281.4 , 282.79 , 283.5 ]],\n", - "\n", - " ...,\n", - "\n", - " [[288.29 , 288.29 , 289.19 , 290.79 ],\n", - " [282.09 , 282.09 , 281.59 , 282.38998],\n", - " [280.99 , 280.99 , 280.38998, 280.59 ],\n", - " [280.99 , 280.99 , 280.38998, 280.59 ]],\n", - "\n", - " [[289.49 , 289.49 , 290.38998, 291.59 ],\n", - " [282.09 , 282.09 , 281.99 , 283.09 ],\n", - " [281.38998, 281.38998, 280.59 , 280.99 ],\n", - " [281.38998, 281.38998, 280.59 , 280.99 ]]], dtype=float32)\n", - "Coordinates:\n", - " lat (degrees_north) float32 30.0 40.0 42.5 42.5\n", - " lon (degrees_east) float32 200.0 200.0 202.5 205.0\n", - " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", - "Dimensions without coordinates: degrees_north, degrees_east\n", - "Attributes: (11)" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "target_lat = xr.DataArray([31, 41, 42, 42], dims=\"degrees_north\")\n", "target_lon = xr.DataArray([200, 201, 202, 205], dims=\"degrees_east\")\n", @@ -2319,392 +203,11 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray (points: 4)>\n",
                    -       "array([31, 41, 42, 42])\n",
                    -       "Dimensions without coordinates: points
                    " - ], - "text/plain": [ - "\n", - "array([31, 41, 42, 42])\n", - "Dimensions without coordinates: points" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Define target latitude and longitude (where weather stations might be)\n", "lat_points = xr.DataArray([31, 41, 42, 42], dims=\"points\")\n", @@ -2713,392 +216,11 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray (points: 4)>\n",
                    -       "array([200, 201, 202, 205])\n",
                    -       "Dimensions without coordinates: points
                    " - ], - "text/plain": [ - "\n", - "array([200, 201, 202, 205])\n", - "Dimensions without coordinates: points" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "lon_points = xr.DataArray([200, 201, 202, 205], dims=\"points\")\n", "lon_points" @@ -3113,428 +235,11 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray 'air' (time: 2920, points: 4)>\n",
                    -       "array([[293.1    , 284.6    , 283.19998, 282.6    ],\n",
                    -       "       [293.19998, 283.29   , 282.79   , 283.5    ],\n",
                    -       "       ...,\n",
                    -       "       [288.29   , 282.09   , 280.38998, 280.59   ],\n",
                    -       "       [289.49   , 282.09   , 280.59   , 280.99   ]], dtype=float32)\n",
                    -       "Coordinates:\n",
                    -       "    lat      (points) float32 30.0 40.0 42.5 42.5\n",
                    -       "    lon      (points) float32 200.0 200.0 202.5 205.0\n",
                    -       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    -       "Dimensions without coordinates: points\n",
                    -       "Attributes: (11)
                    " - ], - "text/plain": [ - "\n", - "array([[293.1 , 284.6 , 283.19998, 282.6 ],\n", - " [293.19998, 283.29 , 282.79 , 283.5 ],\n", - " ...,\n", - " [288.29 , 282.09 , 280.38998, 280.59 ],\n", - " [289.49 , 282.09 , 280.59 , 280.99 ]], dtype=float32)\n", - "Coordinates:\n", - " lat (points) float32 30.0 40.0 42.5 42.5\n", - " lon (points) float32 200.0 200.0 202.5 205.0\n", - " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", - "Dimensions without coordinates: points\n", - "Attributes: (11)" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\")" ] @@ -3548,22 +253,11 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/plain": [ - "('time', 'points')" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\").dims" ] @@ -3581,464 +275,11 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray 'air' (time: 2920, lat: 3, points: 4)>\n",
                    -       "array([[[296.6    , 296.6    , 296.19998, 296.4    ],\n",
                    -       "        [293.1    , 293.1    , 293.29   , 293.29   ],\n",
                    -       "        [284.6    , 284.6    , 284.9    , 284.19998]],\n",
                    -       "\n",
                    -       "       [[296.4    , 296.4    , 295.9    , 296.19998],\n",
                    -       "        [293.19998, 293.19998, 293.9    , 294.19998],\n",
                    -       "        [283.29   , 283.29   , 285.19998, 285.19998]],\n",
                    -       "\n",
                    -       "       ...,\n",
                    -       "\n",
                    -       "       [[293.69   , 293.69   , 293.88998, 295.38998],\n",
                    -       "        [288.29   , 288.29   , 289.19   , 290.79   ],\n",
                    -       "        [282.09   , 282.09   , 281.59   , 282.38998]],\n",
                    -       "\n",
                    -       "       [[293.79   , 293.79   , 293.69   , 295.09   ],\n",
                    -       "        [289.49   , 289.49   , 290.38998, 291.59   ],\n",
                    -       "        [282.09   , 282.09   , 281.99   , 283.09   ]]], dtype=float32)\n",
                    -       "Coordinates:\n",
                    -       "  * lat      (lat) float32 20.0 30.0 40.0\n",
                    -       "    lon      (points) float32 200.0 200.0 202.5 205.0\n",
                    -       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    -       "Dimensions without coordinates: points\n",
                    -       "Attributes: (11)
                    " - ], - "text/plain": [ - "\n", - "array([[[296.6 , 296.6 , 296.19998, 296.4 ],\n", - " [293.1 , 293.1 , 293.29 , 293.29 ],\n", - " [284.6 , 284.6 , 284.9 , 284.19998]],\n", - "\n", - " [[296.4 , 296.4 , 295.9 , 296.19998],\n", - " [293.19998, 293.19998, 293.9 , 294.19998],\n", - " [283.29 , 283.29 , 285.19998, 285.19998]],\n", - "\n", - " ...,\n", - "\n", - " [[293.69 , 293.69 , 293.88998, 295.38998],\n", - " [288.29 , 288.29 , 289.19 , 290.79 ],\n", - " [282.09 , 282.09 , 281.59 , 282.38998]],\n", - "\n", - " [[293.79 , 293.79 , 293.69 , 295.09 ],\n", - " [289.49 , 289.49 , 290.38998, 291.59 ],\n", - " [282.09 , 282.09 , 281.99 , 283.09 ]]], dtype=float32)\n", - "Coordinates:\n", - " * lat (lat) float32 20.0 30.0 40.0\n", - " lon (points) float32 200.0 200.0 202.5 205.0\n", - " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", - "Dimensions without coordinates: points\n", - "Attributes: (11)" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "da_air.sel(lat=[20, 30, 40], lon=lon_points, method=\"nearest\")" ] @@ -4083,11 +324,6 @@ } ], "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, "language_info": { "codemirror_mode": { "name": "ipython", @@ -4097,8 +333,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" + "pygments_lexer": "ipython3" }, "toc": { "base_numbering": 1, From 3287085a21e7cc82cc40457f0cd55c2f835d60ad Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Thu, 6 Jun 2024 14:49:58 -0600 Subject: [PATCH 09/27] few fixes for build fail --- intermediate/indexing/advanced-indexing.ipynb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 9950e621..1d0fecfb 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -87,6 +87,8 @@ "source": [ "The image below summarizes the difference between orthogonal and vectorized indexing for a 2D 5x5 array. \n", "\n", + "\n", + "\n", "![Orthogonal vs. Vectorized Indexing](../../images/orthogonal_vs_vectorized.png)" ] }, @@ -146,7 +148,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "👆 please notice how the ouput if the indexing example above resulted in an array of 3x4. " + "👆 please notice how the output if the indexing example above resulted in an array of 3x4. " ] }, { From 5b686307d5b323c645cefe5389c5503e510196ab Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Thu, 6 Jun 2024 14:56:21 -0600 Subject: [PATCH 10/27] updating header --- intermediate/indexing/advanced-indexing.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 1d0fecfb..1dd3bebf 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -190,7 +190,7 @@ "\n", "But what if we would like to find the information from the nearest grid cell to a collection of specified points (for example, weather stations or tower data)?\n", "\n", - "## Vectorized or Pointwise Indexing in Xarray\n", + "## Pointwise Indexing in Xarray\n", "\n", "Like NumPy and pandas, Xarray supports indexing many array elements at once in a *vectorized* manner. \n", "\n", From e7bd5c3bf9a08a17514c54d98f38c4464bcfbce8 Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Thu, 6 Jun 2024 14:57:53 -0600 Subject: [PATCH 11/27] updating header --- intermediate/indexing/advanced-indexing.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 1dd3bebf..0ad3a9cd 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -190,7 +190,7 @@ "\n", "But what if we would like to find the information from the nearest grid cell to a collection of specified points (for example, weather stations or tower data)?\n", "\n", - "## Pointwise Indexing in Xarray\n", + "## Vectorized or Pointwise Indexing in Xarray\n", "\n", "Like NumPy and pandas, Xarray supports indexing many array elements at once in a *vectorized* manner. \n", "\n", @@ -293,14 +293,14 @@ "## Excersises\n", "\n", "```{exercise}\n", - ":label: indexing-1\n", + ":label: indexing-advanced-1\n", "\n", "In the simple 2D 5x5 Xarray data array above, select the sub-array containing (0,0),(2,2),(4,4) : \n", "```\n", "\n", "\n", "\n", - "````{solution} indexing-1\n", + "````{solution} indexing-advanced-1\n", ":class: dropdown\n", "```python\n", "\n", From fd4e2401910074ec92ef54ac19a61e506f63b728 Mon Sep 17 00:00:00 2001 From: Scott Henderson Date: Mon, 24 Jun 2024 19:43:35 -0700 Subject: [PATCH 12/27] align with new exercise syntax --- intermediate/indexing/advanced-indexing.ipynb | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 0ad3a9cd..89c17773 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -292,15 +292,12 @@ "source": [ "## Excersises\n", "\n", - "```{exercise}\n", - ":label: indexing-advanced-1\n", + "::::{admonition} Exercise\n", + ":class: tip\n", "\n", "In the simple 2D 5x5 Xarray data array above, select the sub-array containing (0,0),(2,2),(4,4) : \n", - "```\n", - "\n", - "\n", "\n", - "````{solution} indexing-advanced-1\n", + ":::{admonition} Solution\n", ":class: dropdown\n", "```python\n", "\n", @@ -312,7 +309,8 @@ "subset_da = da.sel(x=xs_da, y=xs_da)\n", "subset_da\n", "```\n", - "````\n" + ":::\n", + "::::" ] }, { From 473ac50bfbc6bc4503d9b6d82c0de8dba2041d3a Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Mon, 1 Jul 2024 17:46:03 -0600 Subject: [PATCH 13/27] adding advanced indexing --- intermediate/indexing/advanced-indexing.ipynb | 161 +++++++++++++----- 1 file changed, 119 insertions(+), 42 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 89c17773..b6e8af62 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -8,7 +8,8 @@ "\n", "## Learning Objectives\n", "\n", - "* Orthogonal vs. Pointwise Indexing" + "* Orthogonal vs. Pointwise (Vectorized) Indexing\n", + "* Pointwise indexing in Xarray to extract data at a collection of points." ] }, { @@ -17,18 +18,9 @@ "source": [ "## Overview\n", "\n", - "In the previous notebooks, we learned basic forms of indexing with Xarray (positional and name based dimensions, integer and label based indexing), datetime Indexing, and nearest neighbor lookups. Xarray positional indexing deviates from the NumPy when indexing with multiple arrays like `arr[[0, 1], [0, 1]]`.\n", + "In the previous notebooks, we learned basic forms of indexing with Xarray, including positional and label-based indexing, datetime indexing, and nearest neighbor lookups. We also learned that indexing an Xarray DataArray directly works (mostly) like it does for NumPy arrays; however, Xarray indexing behvaior deviates from NumPy when using multiple arrays for indexing, like `arr[[0, 1], [0, 1]]`.\n", "\n", - "In this tutorial we learn about this difference and how to do vectorized/pointwise indexing using Xarray.\n", - "\n", - "For this notebook, first, we should learn about orthogonal (i.e. outer) and vectorized (i.e. pointwise) indexing concepts. \n", - "\n", - "* *Orthogonal* or *outer* indexing allows for indexing along each dimension independently, treating the indexers as one-dimensional arrays. The principle of outer or orthogonal indexing is that the result mirrors the effect of independently indexing along each dimension with integer or boolean arrays, treating both the indexed and indexing arrays as one-dimensional. This method of indexing is analogous to vector indexing in programming languages like MATLAB, Fortran, and R, where each indexer component *independently* selects along its corresponding dimension. This is the default behavior in Xarray.\n", - "\n", - "* *Vectorized* indexing is a more general form of indexing that allows for arbitrary combinations of indexing arrays. This method of indexing is analogous to the broadcasting rules in NumPy, where the dimensions of the indexers are aligned and the result is determined by the shape of the indexers. This is the default behavior in NumPy. \n", - "\n", - "\n", - "We can better understand this with an example: " + "To better understand this difference, let's take a look at an example of 2D 5x5 array:" ] }, { @@ -63,6 +55,13 @@ "da" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's see how the indexing behavior is different between NumPy array and Xarray DataArray when indexing with mutliple arrays:" + ] + }, { "cell_type": "code", "execution_count": null, @@ -85,7 +84,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The image below summarizes the difference between orthogonal and vectorized indexing for a 2D 5x5 array. \n", + "The image below summarizes the difference between vectorized and orthogonal indexing for a 2D 5x5 NumPy array and Xarray DataArray:\n", "\n", "\n", "\n", @@ -96,12 +95,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " Point-wise indexing, shown on the left, selects specific elements at given coordinates, resulting in an array of those individual elements. In the example shown, the indices `[0, 2, 4]`, `[0, 2, 4]` select the elements at positions (0, 0), (2, 2), and (4, 4), resulting in the values `[1, 13, 25]`. This is shown in NumPy indexing example. \n", + "**Pointwise** or **Vectorized indexing**, shown on the left, selects specific elements at given coordinates, resulting in an array of those individual elements. In the example shown, the indices `[0, 2, 4]`, `[0, 2, 4]` select the elements at positions `(0, 0)`, `(2, 2)`, and `(4, 4)`, resulting in the values `[1, 13, 25]`. This is the default behavior of NumPy arrays.\n", + " \n", + "In contrast, **orthogonal indexing** uses the same indices to select entire rows and columns, forming a cross-product of the specified indices. This method results in sub-arrays that include all combinations of the selected rows and columns. The example demonstrates this by selecting rows 0, 2, and 4 and columns 0, 2, and 4, resulting in a subarray containing `[[1, 3, 5], [11, 13, 15], [21, 23, 25]]`. This is Xarray DataArray's default behavior.\n", + " \n", + "The output of vectorized indexing is a `1D array`, while the output of orthogonal indexing is a `3x3` array. \n", "\n", "\n", - " In contrast, **orthogonal indexing** uses the same indices to select entire rows and columns, forming a cross-product of the specified indices. This method results in subarrays that include all combinations of the selected rows and columns. The example demonstrates this by selecting rows 0, 2, and 4 and columns 0, 2, and 4, resulting in a subarray containing `[[1, 3, 5], [11, 13, 15], [21, 23, 25]]`. This is shown in Xarray indexing example.\n", - " \n", - " The output of orthogonal indexing is a 3x3 array, while the output of vectorized indexing is a 1D array." + ":::{tip} To Summarize: \n", + "\n", + "- *Pointwise* or *vectorized* indexing is a more general form of indexing that allows for arbitrary combinations of indexing arrays. This method of indexing is analogous to the broadcasting rules in NumPy, where the dimensions of the indexers are aligned and the result is determined by the shape of the indexers. This is the default behavior in NumPy.\n", + "\n", + "- *Orthogonal* or *outer* indexing allows for indexing along each dimension independently, treating the indexers as one-dimensional arrays. The principle of outer or orthogonal indexing is that the result mirrors the effect of independently indexing along each dimension with integer or boolean arrays, treating both the indexed and indexing arrays as one-dimensional. This method of indexing is analogous to vector indexing in programming languages like MATLAB, Fortran, and R, where each indexer component independently selects along its corresponding dimension. This is the default behavior in Xarray.\n", + "\n", + "\n", + ":::" ] }, { @@ -110,7 +118,9 @@ "source": [ "## Orthogonal Indexing in Xarray\n", "\n", - "If you only provide integers, slices, or unlabeled arrays (array without dimension names, such as `np.ndarray`, `list`, but not `DataArray()`) indexing can be understood as orthogonally (i.e. along independent axes, instead of using NumPy’s broadcasting rules to vectorize indexers). In the example above we saw this behavior, but let's see it in action with a real dataset." + "As explained earlier, when you use only integers, slices, or unlabeled arrays (arrays without dimension names, such as `np.ndarray` or `list`, but not `DataArray`) to index an `Xarray DataArray`, Xarray interprets these indexers orthogonally. This means it indexes along independent axes, rather than using NumPy's broadcasting rules to vectorize the indexers. \n", + "\n", + "In the example above we saw this behavior, but let's see this behavior in action with a real dataset. Here we’ll use `air temperature` data from the National Center for Environmental Prediction:" ] }, { @@ -122,7 +132,6 @@ "outputs": [], "source": [ "import numpy as np\n", - "import pandas as pd\n", "import xarray as xr\n", "\n", "\n", @@ -148,7 +157,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "👆 please notice how the output if the indexing example above resulted in an array of 3x4. " + "👆 please notice how the output of the indexing example above resulted in an array of size `3x4`" ] }, { @@ -178,7 +187,23 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In the above example, you can see how the output shape is `time` x `lats` x `lons`. " + "In the above example, you can see how the output shape is `time` x `lats` x `lons`.\n", + "\n", + "```{attention}\n", + "Please note that slices or sequences/arrays without named-dimensions are treated as if they have the same dimension which is indexed along.\n", + "```\n", + "\n", + "For example:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "da_air.sel(lat=[20, 30, 40], lon=target_lon, method=\"nearest\")" ] }, { @@ -188,19 +213,62 @@ }, "source": [ "\n", - "But what if we would like to find the information from the nearest grid cell to a collection of specified points (for example, weather stations or tower data)?\n", + "But what if we'd like to find the nearest climate model grid cell to a collection of specified points (for example observation sites, or weather stations)?\n", "\n", "## Vectorized or Pointwise Indexing in Xarray\n", "\n", "Like NumPy and pandas, Xarray supports indexing many array elements at once in a *vectorized* manner. \n", "\n", - "**Vectorized indexing** or **Pointwise Indexing** using `DataArrays()` can be used to extract information from the nearest grid cells of interest, for example, the nearest climate model grid cells to a collection of specified weather station latitudes and longitudes.\n", + "**Vectorized indexing** or **Pointwise Indexing** using `DataArrays()` can be used to extract information from the nearest grid cells of interest, for example, the nearest climate model grid cells to a collection of specified observation tower data latitudes and longitudes.\n", "\n", "```{hint}\n", - "To trigger vectorized indexing behavior, you will need to provide the selection dimensions with a different name than the original dimensions. This dimension name will be used in the output array.\n", + "To trigger vectorized indexing behavior, you will need to provide the selection dimensions with a new **shared** output dimension name. This means that the dimensions of both indexers must be the same, and the output will have the same dimension name as the indexers.\n", "```\n", "\n", - "In the example below, the selections of the closest latitude and longitude are renamed to an output dimension named `points`:" + "Let's see how this works with an example. A researcher wants to find the nearest climate model grid cell to a collection of observation sites. She has the latitude and longitude of the observation sites as following:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "obs_lats = [31.81,\n", + " 41.26,\n", + " 22.59,\n", + " 44.47,\n", + " 28.57]\n", + "\n", + "obs_lons = [200.16,\n", + " 201.57,\n", + " 305.54,\n", + " 210.56,\n", + " 226.59]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If the researcher use the lists to index the DataArray, they will get the orthogonal indexing behavior, which is not what they wants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "da_air.sel(lat=obs_lats, lon=obs_lats, method=\"nearest\") # -- orthogonal indexing" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To trigger the pointwise indexing, they need to create DataArray objects with the same dimension name, and then use them to index the DataArray. \n", + "For example, the code below first create DataArray objects for the latitude and longitude of the observation sites using a shared dimension name `points`, and then use them to index the DataArray `air_temperature`:" ] }, { @@ -211,8 +279,8 @@ }, "outputs": [], "source": [ - "# Define target latitude and longitude (where weather stations might be)\n", - "lat_points = xr.DataArray([31, 41, 42, 42], dims=\"points\")\n", + "## latitudes of weather stations with a dimension of \"points\"\n", + "lat_points = xr.DataArray(obs_lats, dims=\"points\")\n", "lat_points" ] }, @@ -224,7 +292,8 @@ }, "outputs": [], "source": [ - "lon_points = xr.DataArray([200, 201, 202, 205], dims=\"points\")\n", + "## longitudes of weather stations with a dimension of \"points\"\n", + "lon_points = xr.DataArray(obs_lons, dims=\"points\")\n", "lon_points" ] }, @@ -243,7 +312,7 @@ }, "outputs": [], "source": [ - "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\")" + "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\") # -- pointwise indexing" ] }, { @@ -268,34 +337,29 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "```{attention}\n", - "Please note that slices or sequences/arrays without named-dimensions are treated as if they have the same dimension which is indexed along.\n", - "```\n", - "\n", - "For example:" + "Now, let's plot the data for all stations." ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "tags": [] - }, + "metadata": {}, "outputs": [], "source": [ - "da_air.sel(lat=[20, 30, 40], lon=lon_points, method=\"nearest\")" + "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\").plot(x='time', hue='points');\n", + "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Excersises\n", + "## Exercises\n", "\n", "::::{admonition} Exercise\n", ":class: tip\n", "\n", - "In the simple 2D 5x5 Xarray data array above, select the sub-array containing (0,0),(2,2),(4,4) : \n", + "In the simple 2D 5x5 Xarray data array above, select the sub-array containing (0,0),(2,2),(4,4):\n", "\n", ":::{admonition} Solution\n", ":class: dropdown\n", @@ -319,11 +383,23 @@ "source": [ "## Additional Resources\n", "\n", - "- [Xarray Docs - Indexing and Selecting Data](https://docs.xarray.dev/en/stable/indexing.html)\n" + "- [Xarray Docs - Indexing and Selecting Data](https://docs.xarray.dev/en/stable/indexing.html)\n", + "\n", + "\n", + ":::{seealso}\n", + "- [NumPy Fancy Indexing](https://numpy.org/doc/stable/reference/arrays.indexing.html#fancy-indexing)\n", + "- [Xarray Indexing](indexing.md)\n", + "\n", + ":::\n" ] } ], "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, "language_info": { "codemirror_mode": { "name": "ipython", @@ -333,7 +409,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.9.0" }, "toc": { "base_numbering": 1, From f6706055b65e138bbf0a84e53a6b79eefd7c1144 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 23:46:17 +0000 Subject: [PATCH 14/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- intermediate/indexing/advanced-indexing.ipynb | 27 +++++-------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index b6e8af62..c52754cc 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -234,17 +234,9 @@ "metadata": {}, "outputs": [], "source": [ - "obs_lats = [31.81,\n", - " 41.26,\n", - " 22.59,\n", - " 44.47,\n", - " 28.57]\n", + "obs_lats = [31.81, 41.26, 22.59, 44.47, 28.57]\n", "\n", - "obs_lons = [200.16,\n", - " 201.57,\n", - " 305.54,\n", - " 210.56,\n", - " 226.59]" + "obs_lons = [200.16, 201.57, 305.54, 210.56, 226.59]" ] }, { @@ -260,7 +252,7 @@ "metadata": {}, "outputs": [], "source": [ - "da_air.sel(lat=obs_lats, lon=obs_lats, method=\"nearest\") # -- orthogonal indexing" + "da_air.sel(lat=obs_lats, lon=obs_lats, method=\"nearest\") # -- orthogonal indexing" ] }, { @@ -312,7 +304,7 @@ }, "outputs": [], "source": [ - "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\") # -- pointwise indexing" + "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\") # -- pointwise indexing" ] }, { @@ -346,8 +338,7 @@ "metadata": {}, "outputs": [], "source": [ - "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\").plot(x='time', hue='points');\n", - "\n" + "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\").plot(x='time', hue='points');" ] }, { @@ -395,11 +386,6 @@ } ], "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, "language_info": { "codemirror_mode": { "name": "ipython", @@ -409,8 +395,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.0" + "pygments_lexer": "ipython3" }, "toc": { "base_numbering": 1, From 2a5ffb200819acbad795b7809cd7cacd0414116a Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Mon, 1 Jul 2024 17:56:21 -0600 Subject: [PATCH 15/27] add numpy advanced indexing --- intermediate/indexing/advanced-indexing.ipynb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index c52754cc..827c9be6 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -379,10 +379,15 @@ "\n", ":::{seealso}\n", "- [NumPy Fancy Indexing](https://numpy.org/doc/stable/reference/arrays.indexing.html#fancy-indexing)\n", - "- [Xarray Indexing](indexing.md)\n", + "- [NumPy Advanced Indexing](https://numpy.org/doc/stable/user/basics.indexing.html#advanced-indexing)\n", "\n", ":::\n" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] } ], "metadata": { From 82d7bf1dc070735dc046a21d7f6fc2251baf499a Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Mon, 1 Jul 2024 18:04:57 -0600 Subject: [PATCH 16/27] update learning objectives --- intermediate/indexing/advanced-indexing.ipynb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 827c9be6..91cdfd3f 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -8,8 +8,9 @@ "\n", "## Learning Objectives\n", "\n", - "* Orthogonal vs. Pointwise (Vectorized) Indexing\n", - "* Pointwise indexing in Xarray to extract data at a collection of points." + "* Orthogonal vs. Pointwise (Vectorized) Indexing.\n", + "* Pointwise indexing in Xarray to extract data at a collection of points.\n", + "* Understand the difference between NumPy and Xarray indexing behavior." ] }, { From 5e3ef9ba8331a27ac68f87cdd90d21810100477f Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Mon, 1 Jul 2024 18:18:50 -0600 Subject: [PATCH 17/27] few minor updates and wording changes --- intermediate/indexing/advanced-indexing.ipynb | 4276 ++++++++++++++++- 1 file changed, 4250 insertions(+), 26 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 91cdfd3f..a49c12a7 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -26,9 +26,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 1, 2, 3, 4, 5],\n", + " [ 6, 7, 8, 9, 10],\n", + " [11, 12, 13, 14, 15],\n", + " [16, 17, 18, 19, 20],\n", + " [21, 22, 23, 24, 25]])" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "import numpy as np\n", "\n", @@ -46,9 +61,402 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
                    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
                    <xarray.DataArray (x: 5, y: 5)>\n",
                    +       "array([[ 1,  2,  3,  4,  5],\n",
                    +       "       [ 6,  7,  8,  9, 10],\n",
                    +       "       [11, 12, 13, 14, 15],\n",
                    +       "       [16, 17, 18, 19, 20],\n",
                    +       "       [21, 22, 23, 24, 25]])\n",
                    +       "Dimensions without coordinates: x, y
                    " + ], + "text/plain": [ + "\n", + "array([[ 1, 2, 3, 4, 5],\n", + " [ 6, 7, 8, 9, 10],\n", + " [11, 12, 13, 14, 15],\n", + " [16, 17, 18, 19, 20],\n", + " [21, 22, 23, 24, 25]])\n", + "Dimensions without coordinates: x, y" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "import xarray as xr\n", "\n", @@ -65,18 +473,416 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 1, 13, 25])" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "np_array[[0, 2, 4], [0, 2, 4]]" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
                    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
                    <xarray.DataArray (x: 3, y: 3)>\n",
                    +       "array([[ 1,  3,  5],\n",
                    +       "       [11, 13, 15],\n",
                    +       "       [21, 23, 25]])\n",
                    +       "Dimensions without coordinates: x, y
                    " + ], + "text/plain": [ + "\n", + "array([[ 1, 3, 5],\n", + " [11, 13, 15],\n", + " [21, 23, 25]])\n", + "Dimensions without coordinates: x, y" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "da[[0, 2, 4], [0, 2, 4]]" ] @@ -126,11 +932,459 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
                    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
                    <xarray.Dataset>\n",
                    +       "Dimensions:  (lat: 25, time: 2920, lon: 53)\n",
                    +       "Coordinates:\n",
                    +       "  * lat      (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
                    +       "  * lon      (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n",
                    +       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    +       "Data variables:\n",
                    +       "    air      (time, lat, lon) float32 241.2 242.5 243.5 ... 296.5 296.2 295.7\n",
                    +       "Attributes: (5)
                    " + ], + "text/plain": [ + "\n", + "Dimensions: (lat: 25, time: 2920, lon: 53)\n", + "Coordinates:\n", + " * lat (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n", + " * lon (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n", + " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", + "Data variables:\n", + " air (time, lat, lon) float32 241.2 242.5 243.5 ... 296.5 296.2 295.7\n", + "Attributes: (5)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "import numpy as np\n", "import xarray as xr\n", @@ -146,9 +1400,407 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
                    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
                    <xarray.DataArray 'air' (lat: 4, lon: 3)>\n",
                    +       "array([[249.79999, 243.09999, 242.39   ],\n",
                    +       "       [274.29   , 271.79   , 270.6    ],\n",
                    +       "       [277.4    , 280.6    , 280.9    ],\n",
                    +       "       [283.19998, 285.5    , 285.9    ]], dtype=float32)\n",
                    +       "Coordinates:\n",
                    +       "  * lat      (lat) float32 70.0 65.0 50.0 42.5\n",
                    +       "  * lon      (lon) float32 202.5 215.0 217.5\n",
                    +       "    time     datetime64[ns] 2013-01-01\n",
                    +       "Attributes: (11)
                    " + ], + "text/plain": [ + "\n", + "array([[249.79999, 243.09999, 242.39 ],\n", + " [274.29 , 271.79 , 270.6 ],\n", + " [277.4 , 280.6 , 280.9 ],\n", + " [283.19998, 285.5 , 285.9 ]], dtype=float32)\n", + "Coordinates:\n", + " * lat (lat) float32 70.0 65.0 50.0 42.5\n", + " * lon (lon) float32 202.5 215.0 217.5\n", + " time datetime64[ns] 2013-01-01\n", + "Attributes: (11)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "selected_da = da_air.isel(time=0, lat=[2, 4, 10, 13], lon=[1, 6, 7]) # -- orthogonal indexing\n", "selected_da" @@ -172,11 +1824,476 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
                    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
                    <xarray.DataArray 'air' (time: 2920, degrees_north: 4, degrees_east: 4)>\n",
                    +       "array([[[293.1    , 293.1    , 293.29   , 293.29   ],\n",
                    +       "        [284.6    , 284.6    , 284.9    , 284.19998],\n",
                    +       "        [282.79   , 282.79   , 283.19998, 282.6    ],\n",
                    +       "        [282.79   , 282.79   , 283.19998, 282.6    ]],\n",
                    +       "\n",
                    +       "       [[293.19998, 293.19998, 293.9    , 294.19998],\n",
                    +       "        [283.29   , 283.29   , 285.19998, 285.19998],\n",
                    +       "        [281.4    , 281.4    , 282.79   , 283.5    ],\n",
                    +       "        [281.4    , 281.4    , 282.79   , 283.5    ]],\n",
                    +       "\n",
                    +       "       ...,\n",
                    +       "\n",
                    +       "       [[288.29   , 288.29   , 289.19   , 290.79   ],\n",
                    +       "        [282.09   , 282.09   , 281.59   , 282.38998],\n",
                    +       "        [280.99   , 280.99   , 280.38998, 280.59   ],\n",
                    +       "        [280.99   , 280.99   , 280.38998, 280.59   ]],\n",
                    +       "\n",
                    +       "       [[289.49   , 289.49   , 290.38998, 291.59   ],\n",
                    +       "        [282.09   , 282.09   , 281.99   , 283.09   ],\n",
                    +       "        [281.38998, 281.38998, 280.59   , 280.99   ],\n",
                    +       "        [281.38998, 281.38998, 280.59   , 280.99   ]]], dtype=float32)\n",
                    +       "Coordinates:\n",
                    +       "    lat      (degrees_north) float32 30.0 40.0 42.5 42.5\n",
                    +       "    lon      (degrees_east) float32 200.0 200.0 202.5 205.0\n",
                    +       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    +       "Dimensions without coordinates: degrees_north, degrees_east\n",
                    +       "Attributes: (11)
                    " + ], + "text/plain": [ + "\n", + "array([[[293.1 , 293.1 , 293.29 , 293.29 ],\n", + " [284.6 , 284.6 , 284.9 , 284.19998],\n", + " [282.79 , 282.79 , 283.19998, 282.6 ],\n", + " [282.79 , 282.79 , 283.19998, 282.6 ]],\n", + "\n", + " [[293.19998, 293.19998, 293.9 , 294.19998],\n", + " [283.29 , 283.29 , 285.19998, 285.19998],\n", + " [281.4 , 281.4 , 282.79 , 283.5 ],\n", + " [281.4 , 281.4 , 282.79 , 283.5 ]],\n", + "\n", + " ...,\n", + "\n", + " [[288.29 , 288.29 , 289.19 , 290.79 ],\n", + " [282.09 , 282.09 , 281.59 , 282.38998],\n", + " [280.99 , 280.99 , 280.38998, 280.59 ],\n", + " [280.99 , 280.99 , 280.38998, 280.59 ]],\n", + "\n", + " [[289.49 , 289.49 , 290.38998, 291.59 ],\n", + " [282.09 , 282.09 , 281.99 , 283.09 ],\n", + " [281.38998, 281.38998, 280.59 , 280.99 ],\n", + " [281.38998, 281.38998, 280.59 , 280.99 ]]], dtype=float32)\n", + "Coordinates:\n", + " lat (degrees_north) float32 30.0 40.0 42.5 42.5\n", + " lon (degrees_east) float32 200.0 200.0 202.5 205.0\n", + " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", + "Dimensions without coordinates: degrees_north, degrees_east\n", + "Attributes: (11)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "target_lat = xr.DataArray([31, 41, 42, 42], dims=\"degrees_north\")\n", "target_lon = xr.DataArray([200, 201, 202, 205], dims=\"degrees_east\")\n", @@ -188,7 +2305,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In the above example, you can see how the output shape is `time` x `lats` x `lons`.\n", + "In the above example, you can see how the output shape is `time` x `lats` x `lons`. Please note that there are no shared dimensions between the indexers, so the output shape is the union of the dimensions of the indexers.\n", "\n", "```{attention}\n", "Please note that slices or sequences/arrays without named-dimensions are treated as if they have the same dimension which is indexed along.\n", @@ -200,9 +2317,462 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
                    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
                    <xarray.DataArray 'air' (time: 2920, lat: 3, degrees_east: 4)>\n",
                    +       "array([[[296.6    , 296.6    , 296.19998, 296.4    ],\n",
                    +       "        [293.1    , 293.1    , 293.29   , 293.29   ],\n",
                    +       "        [284.6    , 284.6    , 284.9    , 284.19998]],\n",
                    +       "\n",
                    +       "       [[296.4    , 296.4    , 295.9    , 296.19998],\n",
                    +       "        [293.19998, 293.19998, 293.9    , 294.19998],\n",
                    +       "        [283.29   , 283.29   , 285.19998, 285.19998]],\n",
                    +       "\n",
                    +       "       ...,\n",
                    +       "\n",
                    +       "       [[293.69   , 293.69   , 293.88998, 295.38998],\n",
                    +       "        [288.29   , 288.29   , 289.19   , 290.79   ],\n",
                    +       "        [282.09   , 282.09   , 281.59   , 282.38998]],\n",
                    +       "\n",
                    +       "       [[293.79   , 293.79   , 293.69   , 295.09   ],\n",
                    +       "        [289.49   , 289.49   , 290.38998, 291.59   ],\n",
                    +       "        [282.09   , 282.09   , 281.99   , 283.09   ]]], dtype=float32)\n",
                    +       "Coordinates:\n",
                    +       "  * lat      (lat) float32 20.0 30.0 40.0\n",
                    +       "    lon      (degrees_east) float32 200.0 200.0 202.5 205.0\n",
                    +       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    +       "Dimensions without coordinates: degrees_east\n",
                    +       "Attributes: (11)
                    " + ], + "text/plain": [ + "\n", + "array([[[296.6 , 296.6 , 296.19998, 296.4 ],\n", + " [293.1 , 293.1 , 293.29 , 293.29 ],\n", + " [284.6 , 284.6 , 284.9 , 284.19998]],\n", + "\n", + " [[296.4 , 296.4 , 295.9 , 296.19998],\n", + " [293.19998, 293.19998, 293.9 , 294.19998],\n", + " [283.29 , 283.29 , 285.19998, 285.19998]],\n", + "\n", + " ...,\n", + "\n", + " [[293.69 , 293.69 , 293.88998, 295.38998],\n", + " [288.29 , 288.29 , 289.19 , 290.79 ],\n", + " [282.09 , 282.09 , 281.59 , 282.38998]],\n", + "\n", + " [[293.79 , 293.79 , 293.69 , 295.09 ],\n", + " [289.49 , 289.49 , 290.38998, 291.59 ],\n", + " [282.09 , 282.09 , 281.99 , 283.09 ]]], dtype=float32)\n", + "Coordinates:\n", + " * lat (lat) float32 20.0 30.0 40.0\n", + " lon (degrees_east) float32 200.0 200.0 202.5 205.0\n", + " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", + "Dimensions without coordinates: degrees_east\n", + "Attributes: (11)" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "da_air.sel(lat=[20, 30, 40], lon=target_lon, method=\"nearest\")" ] @@ -231,7 +2801,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -249,9 +2819,484 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
                    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
                    <xarray.DataArray 'air' (time: 2920, lat: 5, lon: 5)>\n",
                    +       "array([[[290.19998, 290.19998, ..., 290.19998, 290.19998],\n",
                    +       "        [282.79   , 282.79   , ..., 282.79   , 282.79   ],\n",
                    +       "        ...,\n",
                    +       "        [280.     , 280.     , ..., 280.     , 280.     ],\n",
                    +       "        [293.79   , 293.79   , ..., 293.79   , 293.79   ]],\n",
                    +       "\n",
                    +       "       [[290.19998, 290.19998, ..., 290.19998, 290.19998],\n",
                    +       "        [281.4    , 281.4    , ..., 281.4    , 281.4    ],\n",
                    +       "        ...,\n",
                    +       "        [279.19998, 279.19998, ..., 279.19998, 279.19998],\n",
                    +       "        [294.29   , 294.29   , ..., 294.29   , 294.29   ]],\n",
                    +       "\n",
                    +       "       ...,\n",
                    +       "\n",
                    +       "       [[286.69   , 286.69   , ..., 286.69   , 286.69   ],\n",
                    +       "        [280.99   , 280.99   , ..., 280.99   , 280.99   ],\n",
                    +       "        ...,\n",
                    +       "        [279.69   , 279.69   , ..., 279.69   , 279.69   ],\n",
                    +       "        [289.49   , 289.49   , ..., 289.49   , 289.49   ]],\n",
                    +       "\n",
                    +       "       [[287.59   , 287.59   , ..., 287.59   , 287.59   ],\n",
                    +       "        [281.38998, 281.38998, ..., 281.38998, 281.38998],\n",
                    +       "        ...,\n",
                    +       "        [279.79   , 279.79   , ..., 279.79   , 279.79   ],\n",
                    +       "        [289.79   , 289.79   , ..., 289.79   , 289.79   ]]], dtype=float32)\n",
                    +       "Coordinates:\n",
                    +       "  * lat      (lat) float32 32.5 42.5 22.5 45.0 27.5\n",
                    +       "  * lon      (lon) float32 200.0 200.0 200.0 200.0 200.0\n",
                    +       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    +       "Attributes: (11)
                    " + ], + "text/plain": [ + "\n", + "array([[[290.19998, 290.19998, ..., 290.19998, 290.19998],\n", + " [282.79 , 282.79 , ..., 282.79 , 282.79 ],\n", + " ...,\n", + " [280. , 280. , ..., 280. , 280. ],\n", + " [293.79 , 293.79 , ..., 293.79 , 293.79 ]],\n", + "\n", + " [[290.19998, 290.19998, ..., 290.19998, 290.19998],\n", + " [281.4 , 281.4 , ..., 281.4 , 281.4 ],\n", + " ...,\n", + " [279.19998, 279.19998, ..., 279.19998, 279.19998],\n", + " [294.29 , 294.29 , ..., 294.29 , 294.29 ]],\n", + "\n", + " ...,\n", + "\n", + " [[286.69 , 286.69 , ..., 286.69 , 286.69 ],\n", + " [280.99 , 280.99 , ..., 280.99 , 280.99 ],\n", + " ...,\n", + " [279.69 , 279.69 , ..., 279.69 , 279.69 ],\n", + " [289.49 , 289.49 , ..., 289.49 , 289.49 ]],\n", + "\n", + " [[287.59 , 287.59 , ..., 287.59 , 287.59 ],\n", + " [281.38998, 281.38998, ..., 281.38998, 281.38998],\n", + " ...,\n", + " [279.79 , 279.79 , ..., 279.79 , 279.79 ],\n", + " [289.79 , 289.79 , ..., 289.79 , 289.79 ]]], dtype=float32)\n", + "Coordinates:\n", + " * lat (lat) float32 32.5 42.5 22.5 45.0 27.5\n", + " * lon (lon) float32 200.0 200.0 200.0 200.0 200.0\n", + " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", + "Attributes: (11)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "da_air.sel(lat=obs_lats, lon=obs_lats, method=\"nearest\") # -- orthogonal indexing" ] @@ -266,11 +3311,392 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
                    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
                    <xarray.DataArray (points: 5)>\n",
                    +       "array([31.81, 41.26, 22.59, 44.47, 28.57])\n",
                    +       "Dimensions without coordinates: points
                    " + ], + "text/plain": [ + "\n", + "array([31.81, 41.26, 22.59, 44.47, 28.57])\n", + "Dimensions without coordinates: points" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "## latitudes of weather stations with a dimension of \"points\"\n", "lat_points = xr.DataArray(obs_lats, dims=\"points\")\n", @@ -279,11 +3705,392 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
                    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
                    <xarray.DataArray (points: 5)>\n",
                    +       "array([200.16, 201.57, 305.54, 210.56, 226.59])\n",
                    +       "Dimensions without coordinates: points
                    " + ], + "text/plain": [ + "\n", + "array([200.16, 201.57, 305.54, 210.56, 226.59])\n", + "Dimensions without coordinates: points" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "## longitudes of weather stations with a dimension of \"points\"\n", "lon_points = xr.DataArray(obs_lons, dims=\"points\")\n", @@ -299,11 +4106,428 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
                    \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
                    <xarray.DataArray 'air' (time: 2920, degrees_north: 5)>\n",
                    +       "array([[290.19998, 283.19998, ..., 280.29   , 290.4    ],\n",
                    +       "       [290.19998, 282.79   , ..., 280.1    , 290.4    ],\n",
                    +       "       ...,\n",
                    +       "       [286.69   , 280.38998, ..., 283.38998, 292.49   ],\n",
                    +       "       [287.59   , 280.59   , ..., 283.59   , 292.38998]], dtype=float32)\n",
                    +       "Coordinates:\n",
                    +       "    lat      (degrees_north) float32 32.5 42.5 22.5 45.0 27.5\n",
                    +       "    lon      (degrees_north) float32 200.0 202.5 305.0 210.0 227.5\n",
                    +       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    +       "Dimensions without coordinates: degrees_north\n",
                    +       "Attributes: (11)
                    " + ], + "text/plain": [ + "\n", + "array([[290.19998, 283.19998, ..., 280.29 , 290.4 ],\n", + " [290.19998, 282.79 , ..., 280.1 , 290.4 ],\n", + " ...,\n", + " [286.69 , 280.38998, ..., 283.38998, 292.49 ],\n", + " [287.59 , 280.59 , ..., 283.59 , 292.38998]], dtype=float32)\n", + "Coordinates:\n", + " lat (degrees_north) float32 32.5 42.5 22.5 45.0 27.5\n", + " lon (degrees_north) float32 200.0 202.5 305.0 210.0 227.5\n", + " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", + "Dimensions without coordinates: degrees_north\n", + "Attributes: (11)" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\") # -- pointwise indexing" ] From 7ff7a19b95cac88c3bde2aa8c4e67508f105c952 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 00:19:04 +0000 Subject: [PATCH 18/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- intermediate/indexing/advanced-indexing.ipynb | 4274 +---------------- 1 file changed, 25 insertions(+), 4249 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index a49c12a7..e69dfec7 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -26,24 +26,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[ 1, 2, 3, 4, 5],\n", - " [ 6, 7, 8, 9, 10],\n", - " [11, 12, 13, 14, 15],\n", - " [16, 17, 18, 19, 20],\n", - " [21, 22, 23, 24, 25]])" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import numpy as np\n", "\n", @@ -61,402 +46,9 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray (x: 5, y: 5)>\n",
                    -       "array([[ 1,  2,  3,  4,  5],\n",
                    -       "       [ 6,  7,  8,  9, 10],\n",
                    -       "       [11, 12, 13, 14, 15],\n",
                    -       "       [16, 17, 18, 19, 20],\n",
                    -       "       [21, 22, 23, 24, 25]])\n",
                    -       "Dimensions without coordinates: x, y
                    " - ], - "text/plain": [ - "\n", - "array([[ 1, 2, 3, 4, 5],\n", - " [ 6, 7, 8, 9, 10],\n", - " [11, 12, 13, 14, 15],\n", - " [16, 17, 18, 19, 20],\n", - " [21, 22, 23, 24, 25]])\n", - "Dimensions without coordinates: x, y" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import xarray as xr\n", "\n", @@ -473,416 +65,18 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 1, 13, 25])" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "np_array[[0, 2, 4], [0, 2, 4]]" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray (x: 3, y: 3)>\n",
                    -       "array([[ 1,  3,  5],\n",
                    -       "       [11, 13, 15],\n",
                    -       "       [21, 23, 25]])\n",
                    -       "Dimensions without coordinates: x, y
                    " - ], - "text/plain": [ - "\n", - "array([[ 1, 3, 5],\n", - " [11, 13, 15],\n", - " [21, 23, 25]])\n", - "Dimensions without coordinates: x, y" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "da[[0, 2, 4], [0, 2, 4]]" ] @@ -932,459 +126,11 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.Dataset>\n",
                    -       "Dimensions:  (lat: 25, time: 2920, lon: 53)\n",
                    -       "Coordinates:\n",
                    -       "  * lat      (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
                    -       "  * lon      (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n",
                    -       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    -       "Data variables:\n",
                    -       "    air      (time, lat, lon) float32 241.2 242.5 243.5 ... 296.5 296.2 295.7\n",
                    -       "Attributes: (5)
                    " - ], - "text/plain": [ - "\n", - "Dimensions: (lat: 25, time: 2920, lon: 53)\n", - "Coordinates:\n", - " * lat (lat) float32 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n", - " * lon (lon) float32 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n", - " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", - "Data variables:\n", - " air (time, lat, lon) float32 241.2 242.5 243.5 ... 296.5 296.2 295.7\n", - "Attributes: (5)" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import numpy as np\n", "import xarray as xr\n", @@ -1400,407 +146,9 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray 'air' (lat: 4, lon: 3)>\n",
                    -       "array([[249.79999, 243.09999, 242.39   ],\n",
                    -       "       [274.29   , 271.79   , 270.6    ],\n",
                    -       "       [277.4    , 280.6    , 280.9    ],\n",
                    -       "       [283.19998, 285.5    , 285.9    ]], dtype=float32)\n",
                    -       "Coordinates:\n",
                    -       "  * lat      (lat) float32 70.0 65.0 50.0 42.5\n",
                    -       "  * lon      (lon) float32 202.5 215.0 217.5\n",
                    -       "    time     datetime64[ns] 2013-01-01\n",
                    -       "Attributes: (11)
                    " - ], - "text/plain": [ - "\n", - "array([[249.79999, 243.09999, 242.39 ],\n", - " [274.29 , 271.79 , 270.6 ],\n", - " [277.4 , 280.6 , 280.9 ],\n", - " [283.19998, 285.5 , 285.9 ]], dtype=float32)\n", - "Coordinates:\n", - " * lat (lat) float32 70.0 65.0 50.0 42.5\n", - " * lon (lon) float32 202.5 215.0 217.5\n", - " time datetime64[ns] 2013-01-01\n", - "Attributes: (11)" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "selected_da = da_air.isel(time=0, lat=[2, 4, 10, 13], lon=[1, 6, 7]) # -- orthogonal indexing\n", "selected_da" @@ -1824,476 +172,11 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray 'air' (time: 2920, degrees_north: 4, degrees_east: 4)>\n",
                    -       "array([[[293.1    , 293.1    , 293.29   , 293.29   ],\n",
                    -       "        [284.6    , 284.6    , 284.9    , 284.19998],\n",
                    -       "        [282.79   , 282.79   , 283.19998, 282.6    ],\n",
                    -       "        [282.79   , 282.79   , 283.19998, 282.6    ]],\n",
                    -       "\n",
                    -       "       [[293.19998, 293.19998, 293.9    , 294.19998],\n",
                    -       "        [283.29   , 283.29   , 285.19998, 285.19998],\n",
                    -       "        [281.4    , 281.4    , 282.79   , 283.5    ],\n",
                    -       "        [281.4    , 281.4    , 282.79   , 283.5    ]],\n",
                    -       "\n",
                    -       "       ...,\n",
                    -       "\n",
                    -       "       [[288.29   , 288.29   , 289.19   , 290.79   ],\n",
                    -       "        [282.09   , 282.09   , 281.59   , 282.38998],\n",
                    -       "        [280.99   , 280.99   , 280.38998, 280.59   ],\n",
                    -       "        [280.99   , 280.99   , 280.38998, 280.59   ]],\n",
                    -       "\n",
                    -       "       [[289.49   , 289.49   , 290.38998, 291.59   ],\n",
                    -       "        [282.09   , 282.09   , 281.99   , 283.09   ],\n",
                    -       "        [281.38998, 281.38998, 280.59   , 280.99   ],\n",
                    -       "        [281.38998, 281.38998, 280.59   , 280.99   ]]], dtype=float32)\n",
                    -       "Coordinates:\n",
                    -       "    lat      (degrees_north) float32 30.0 40.0 42.5 42.5\n",
                    -       "    lon      (degrees_east) float32 200.0 200.0 202.5 205.0\n",
                    -       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    -       "Dimensions without coordinates: degrees_north, degrees_east\n",
                    -       "Attributes: (11)
                    " - ], - "text/plain": [ - "\n", - "array([[[293.1 , 293.1 , 293.29 , 293.29 ],\n", - " [284.6 , 284.6 , 284.9 , 284.19998],\n", - " [282.79 , 282.79 , 283.19998, 282.6 ],\n", - " [282.79 , 282.79 , 283.19998, 282.6 ]],\n", - "\n", - " [[293.19998, 293.19998, 293.9 , 294.19998],\n", - " [283.29 , 283.29 , 285.19998, 285.19998],\n", - " [281.4 , 281.4 , 282.79 , 283.5 ],\n", - " [281.4 , 281.4 , 282.79 , 283.5 ]],\n", - "\n", - " ...,\n", - "\n", - " [[288.29 , 288.29 , 289.19 , 290.79 ],\n", - " [282.09 , 282.09 , 281.59 , 282.38998],\n", - " [280.99 , 280.99 , 280.38998, 280.59 ],\n", - " [280.99 , 280.99 , 280.38998, 280.59 ]],\n", - "\n", - " [[289.49 , 289.49 , 290.38998, 291.59 ],\n", - " [282.09 , 282.09 , 281.99 , 283.09 ],\n", - " [281.38998, 281.38998, 280.59 , 280.99 ],\n", - " [281.38998, 281.38998, 280.59 , 280.99 ]]], dtype=float32)\n", - "Coordinates:\n", - " lat (degrees_north) float32 30.0 40.0 42.5 42.5\n", - " lon (degrees_east) float32 200.0 200.0 202.5 205.0\n", - " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", - "Dimensions without coordinates: degrees_north, degrees_east\n", - "Attributes: (11)" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "target_lat = xr.DataArray([31, 41, 42, 42], dims=\"degrees_north\")\n", "target_lon = xr.DataArray([200, 201, 202, 205], dims=\"degrees_east\")\n", @@ -2317,462 +200,9 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray 'air' (time: 2920, lat: 3, degrees_east: 4)>\n",
                    -       "array([[[296.6    , 296.6    , 296.19998, 296.4    ],\n",
                    -       "        [293.1    , 293.1    , 293.29   , 293.29   ],\n",
                    -       "        [284.6    , 284.6    , 284.9    , 284.19998]],\n",
                    -       "\n",
                    -       "       [[296.4    , 296.4    , 295.9    , 296.19998],\n",
                    -       "        [293.19998, 293.19998, 293.9    , 294.19998],\n",
                    -       "        [283.29   , 283.29   , 285.19998, 285.19998]],\n",
                    -       "\n",
                    -       "       ...,\n",
                    -       "\n",
                    -       "       [[293.69   , 293.69   , 293.88998, 295.38998],\n",
                    -       "        [288.29   , 288.29   , 289.19   , 290.79   ],\n",
                    -       "        [282.09   , 282.09   , 281.59   , 282.38998]],\n",
                    -       "\n",
                    -       "       [[293.79   , 293.79   , 293.69   , 295.09   ],\n",
                    -       "        [289.49   , 289.49   , 290.38998, 291.59   ],\n",
                    -       "        [282.09   , 282.09   , 281.99   , 283.09   ]]], dtype=float32)\n",
                    -       "Coordinates:\n",
                    -       "  * lat      (lat) float32 20.0 30.0 40.0\n",
                    -       "    lon      (degrees_east) float32 200.0 200.0 202.5 205.0\n",
                    -       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    -       "Dimensions without coordinates: degrees_east\n",
                    -       "Attributes: (11)
                    " - ], - "text/plain": [ - "\n", - "array([[[296.6 , 296.6 , 296.19998, 296.4 ],\n", - " [293.1 , 293.1 , 293.29 , 293.29 ],\n", - " [284.6 , 284.6 , 284.9 , 284.19998]],\n", - "\n", - " [[296.4 , 296.4 , 295.9 , 296.19998],\n", - " [293.19998, 293.19998, 293.9 , 294.19998],\n", - " [283.29 , 283.29 , 285.19998, 285.19998]],\n", - "\n", - " ...,\n", - "\n", - " [[293.69 , 293.69 , 293.88998, 295.38998],\n", - " [288.29 , 288.29 , 289.19 , 290.79 ],\n", - " [282.09 , 282.09 , 281.59 , 282.38998]],\n", - "\n", - " [[293.79 , 293.79 , 293.69 , 295.09 ],\n", - " [289.49 , 289.49 , 290.38998, 291.59 ],\n", - " [282.09 , 282.09 , 281.99 , 283.09 ]]], dtype=float32)\n", - "Coordinates:\n", - " * lat (lat) float32 20.0 30.0 40.0\n", - " lon (degrees_east) float32 200.0 200.0 202.5 205.0\n", - " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", - "Dimensions without coordinates: degrees_east\n", - "Attributes: (11)" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "da_air.sel(lat=[20, 30, 40], lon=target_lon, method=\"nearest\")" ] @@ -2801,7 +231,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -2819,484 +249,9 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray 'air' (time: 2920, lat: 5, lon: 5)>\n",
                    -       "array([[[290.19998, 290.19998, ..., 290.19998, 290.19998],\n",
                    -       "        [282.79   , 282.79   , ..., 282.79   , 282.79   ],\n",
                    -       "        ...,\n",
                    -       "        [280.     , 280.     , ..., 280.     , 280.     ],\n",
                    -       "        [293.79   , 293.79   , ..., 293.79   , 293.79   ]],\n",
                    -       "\n",
                    -       "       [[290.19998, 290.19998, ..., 290.19998, 290.19998],\n",
                    -       "        [281.4    , 281.4    , ..., 281.4    , 281.4    ],\n",
                    -       "        ...,\n",
                    -       "        [279.19998, 279.19998, ..., 279.19998, 279.19998],\n",
                    -       "        [294.29   , 294.29   , ..., 294.29   , 294.29   ]],\n",
                    -       "\n",
                    -       "       ...,\n",
                    -       "\n",
                    -       "       [[286.69   , 286.69   , ..., 286.69   , 286.69   ],\n",
                    -       "        [280.99   , 280.99   , ..., 280.99   , 280.99   ],\n",
                    -       "        ...,\n",
                    -       "        [279.69   , 279.69   , ..., 279.69   , 279.69   ],\n",
                    -       "        [289.49   , 289.49   , ..., 289.49   , 289.49   ]],\n",
                    -       "\n",
                    -       "       [[287.59   , 287.59   , ..., 287.59   , 287.59   ],\n",
                    -       "        [281.38998, 281.38998, ..., 281.38998, 281.38998],\n",
                    -       "        ...,\n",
                    -       "        [279.79   , 279.79   , ..., 279.79   , 279.79   ],\n",
                    -       "        [289.79   , 289.79   , ..., 289.79   , 289.79   ]]], dtype=float32)\n",
                    -       "Coordinates:\n",
                    -       "  * lat      (lat) float32 32.5 42.5 22.5 45.0 27.5\n",
                    -       "  * lon      (lon) float32 200.0 200.0 200.0 200.0 200.0\n",
                    -       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    -       "Attributes: (11)
                    " - ], - "text/plain": [ - "\n", - "array([[[290.19998, 290.19998, ..., 290.19998, 290.19998],\n", - " [282.79 , 282.79 , ..., 282.79 , 282.79 ],\n", - " ...,\n", - " [280. , 280. , ..., 280. , 280. ],\n", - " [293.79 , 293.79 , ..., 293.79 , 293.79 ]],\n", - "\n", - " [[290.19998, 290.19998, ..., 290.19998, 290.19998],\n", - " [281.4 , 281.4 , ..., 281.4 , 281.4 ],\n", - " ...,\n", - " [279.19998, 279.19998, ..., 279.19998, 279.19998],\n", - " [294.29 , 294.29 , ..., 294.29 , 294.29 ]],\n", - "\n", - " ...,\n", - "\n", - " [[286.69 , 286.69 , ..., 286.69 , 286.69 ],\n", - " [280.99 , 280.99 , ..., 280.99 , 280.99 ],\n", - " ...,\n", - " [279.69 , 279.69 , ..., 279.69 , 279.69 ],\n", - " [289.49 , 289.49 , ..., 289.49 , 289.49 ]],\n", - "\n", - " [[287.59 , 287.59 , ..., 287.59 , 287.59 ],\n", - " [281.38998, 281.38998, ..., 281.38998, 281.38998],\n", - " ...,\n", - " [279.79 , 279.79 , ..., 279.79 , 279.79 ],\n", - " [289.79 , 289.79 , ..., 289.79 , 289.79 ]]], dtype=float32)\n", - "Coordinates:\n", - " * lat (lat) float32 32.5 42.5 22.5 45.0 27.5\n", - " * lon (lon) float32 200.0 200.0 200.0 200.0 200.0\n", - " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", - "Attributes: (11)" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "da_air.sel(lat=obs_lats, lon=obs_lats, method=\"nearest\") # -- orthogonal indexing" ] @@ -3311,392 +266,11 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray (points: 5)>\n",
                    -       "array([31.81, 41.26, 22.59, 44.47, 28.57])\n",
                    -       "Dimensions without coordinates: points
                    " - ], - "text/plain": [ - "\n", - "array([31.81, 41.26, 22.59, 44.47, 28.57])\n", - "Dimensions without coordinates: points" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "## latitudes of weather stations with a dimension of \"points\"\n", "lat_points = xr.DataArray(obs_lats, dims=\"points\")\n", @@ -3705,392 +279,11 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray (points: 5)>\n",
                    -       "array([200.16, 201.57, 305.54, 210.56, 226.59])\n",
                    -       "Dimensions without coordinates: points
                    " - ], - "text/plain": [ - "\n", - "array([200.16, 201.57, 305.54, 210.56, 226.59])\n", - "Dimensions without coordinates: points" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "## longitudes of weather stations with a dimension of \"points\"\n", "lon_points = xr.DataArray(obs_lons, dims=\"points\")\n", @@ -4106,428 +299,11 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": { "tags": [] }, - "outputs": [ - { - "data": { - "text/html": [ - "
                    \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
                    <xarray.DataArray 'air' (time: 2920, degrees_north: 5)>\n",
                    -       "array([[290.19998, 283.19998, ..., 280.29   , 290.4    ],\n",
                    -       "       [290.19998, 282.79   , ..., 280.1    , 290.4    ],\n",
                    -       "       ...,\n",
                    -       "       [286.69   , 280.38998, ..., 283.38998, 292.49   ],\n",
                    -       "       [287.59   , 280.59   , ..., 283.59   , 292.38998]], dtype=float32)\n",
                    -       "Coordinates:\n",
                    -       "    lat      (degrees_north) float32 32.5 42.5 22.5 45.0 27.5\n",
                    -       "    lon      (degrees_north) float32 200.0 202.5 305.0 210.0 227.5\n",
                    -       "  * time     (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n",
                    -       "Dimensions without coordinates: degrees_north\n",
                    -       "Attributes: (11)
                    " - ], - "text/plain": [ - "\n", - "array([[290.19998, 283.19998, ..., 280.29 , 290.4 ],\n", - " [290.19998, 282.79 , ..., 280.1 , 290.4 ],\n", - " ...,\n", - " [286.69 , 280.38998, ..., 283.38998, 292.49 ],\n", - " [287.59 , 280.59 , ..., 283.59 , 292.38998]], dtype=float32)\n", - "Coordinates:\n", - " lat (degrees_north) float32 32.5 42.5 22.5 45.0 27.5\n", - " lon (degrees_north) float32 200.0 202.5 305.0 210.0 227.5\n", - " * time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00\n", - "Dimensions without coordinates: degrees_north\n", - "Attributes: (11)" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "da_air.sel(lat=lat_points, lon=lon_points, method=\"nearest\") # -- pointwise indexing" ] From 24462e4f801496d53bafee7686cb0c33b2bf9401 Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Mon, 1 Jul 2024 18:22:45 -0600 Subject: [PATCH 19/27] update indexing docs --- intermediate/indexing/advanced-indexing.ipynb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index e69dfec7..2516f1f6 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -379,16 +379,11 @@ "\n", "\n", ":::{seealso}\n", - "- [NumPy Fancy Indexing](https://numpy.org/doc/stable/reference/arrays.indexing.html#fancy-indexing)\n", - "- [NumPy Advanced Indexing](https://numpy.org/doc/stable/user/basics.indexing.html#advanced-indexing)\n", + "- [Introductions to Fancy Indexing](https://jakevdp.github.io/PythonDataScienceHandbook/02.07-fancy-indexing.html)\n", + "- [NumPy Docs - Advanced Indexing](https://numpy.org/doc/stable/user/basics.indexing.html#advanced-indexing)\n", "\n", ":::\n" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] } ], "metadata": { From 792fc33ffec68010c916b20093ee189f25502770 Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Mon, 1 Jul 2024 18:25:26 -0600 Subject: [PATCH 20/27] quick merge conflict resolve --- intermediate/indexing/advanced-indexing.ipynb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 2516f1f6..1d87a9d1 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -387,6 +387,11 @@ } ], "metadata": { + "kernelspec": { + "display_name": "dask-tutorial", + "language": "python", + "name": "python3" + }, "language_info": { "codemirror_mode": { "name": "ipython", @@ -396,7 +401,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.9.18" }, "toc": { "base_numbering": 1, From c22c825df3a81ff425c856d0ea42a6ab2ecaf7cd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 00:25:38 +0000 Subject: [PATCH 21/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- intermediate/indexing/advanced-indexing.ipynb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 1d87a9d1..2516f1f6 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -387,11 +387,6 @@ } ], "metadata": { - "kernelspec": { - "display_name": "dask-tutorial", - "language": "python", - "name": "python3" - }, "language_info": { "codemirror_mode": { "name": "ipython", @@ -401,8 +396,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.18" + "pygments_lexer": "ipython3" }, "toc": { "base_numbering": 1, From 11e2aa4f1210edc8bf806d458ef3c8477c2e634e Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Mon, 1 Jul 2024 18:29:38 -0600 Subject: [PATCH 22/27] update docs --- intermediate/indexing/advanced-indexing.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 2516f1f6..ada9a69b 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -19,7 +19,7 @@ "source": [ "## Overview\n", "\n", - "In the previous notebooks, we learned basic forms of indexing with Xarray, including positional and label-based indexing, datetime indexing, and nearest neighbor lookups. We also learned that indexing an Xarray DataArray directly works (mostly) like it does for NumPy arrays; however, Xarray indexing behvaior deviates from NumPy when using multiple arrays for indexing, like `arr[[0, 1], [0, 1]]`.\n", + "In the previous notebooks, we learned basic forms of indexing with Xarray, including positional and label-based indexing, datetime indexing, and nearest neighbor lookups. We also learned that indexing an Xarray DataArray directly works (mostly) like it does for NumPy arrays; however, Xarray indexing behavior deviates from NumPy when using multiple arrays for indexing, like `arr[[0, 1], [0, 1]]`.\n", "\n", "To better understand this difference, let's take a look at an example of 2D 5x5 array:" ] @@ -60,7 +60,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now, let's see how the indexing behavior is different between NumPy array and Xarray DataArray when indexing with mutliple arrays:" + "Now, let's see how the indexing behavior is different between NumPy array and Xarray DataArray when indexing with multiple arrays:" ] }, { From 7d70d22b6cb27ef301a0948257ecf5fcc269d19b Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Tue, 2 Jul 2024 17:39:21 -0600 Subject: [PATCH 23/27] adding np.ix_ --- intermediate/indexing/advanced-indexing.ipynb | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index ada9a69b..7029124b 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -110,6 +110,18 @@ "- *Orthogonal* or *outer* indexing allows for indexing along each dimension independently, treating the indexers as one-dimensional arrays. The principle of outer or orthogonal indexing is that the result mirrors the effect of independently indexing along each dimension with integer or boolean arrays, treating both the indexed and indexing arrays as one-dimensional. This method of indexing is analogous to vector indexing in programming languages like MATLAB, Fortran, and R, where each indexer component independently selects along its corresponding dimension. This is the default behavior in Xarray.\n", "\n", "\n", + ":::\n", + "\n", + ":::{note} Orthogonal indexing with NumPy\n", + ":class: dropdown\n", + "\n", + "While Pointwise indexing is the default behavior in NumPy, you can achieve orthogonal indexing by using the [`np.ix_` function](https://numpy.org/doc/stable/reference/generated/numpy.ix_.html). This function constructs an open mesh from multiple arrays, allowing you to index along each dimension independently similar to Xarray indexig behavior. For example: \n", + "\n", + "```python\n", + "ixgrid = np.ix_([0, 2, 4], [0, 2, 4])\n", + "np_array[ixgrid]\n", + "```\n", + "\n", ":::" ] }, @@ -138,6 +150,7 @@ "\n", "xr.set_options(display_expand_attrs=False)\n", "np.set_printoptions(threshold=10, edgeitems=2)\n", + "%config InlineBackend.figure_format='retina'\n", "\n", "ds = xr.tutorial.load_dataset(\"air_temperature\")\n", "da_air = ds.air\n", @@ -387,6 +400,11 @@ } ], "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, "language_info": { "codemirror_mode": { "name": "ipython", @@ -396,7 +414,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.12.3" }, "toc": { "base_numbering": 1, From 89459e565f2e160a6ebd5043bee67635433aaa60 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 23:39:34 +0000 Subject: [PATCH 24/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- intermediate/indexing/advanced-indexing.ipynb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 7029124b..d8553475 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -400,11 +400,6 @@ } ], "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, "language_info": { "codemirror_mode": { "name": "ipython", @@ -414,8 +409,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" + "pygments_lexer": "ipython3" }, "toc": { "base_numbering": 1, From 5f18954578daa51b2f09410f8826ba5cbef1667c Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Tue, 2 Jul 2024 17:44:48 -0600 Subject: [PATCH 25/27] fix merge --- intermediate/indexing/advanced-indexing.ipynb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index d8553475..3f350941 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -115,7 +115,7 @@ ":::{note} Orthogonal indexing with NumPy\n", ":class: dropdown\n", "\n", - "While Pointwise indexing is the default behavior in NumPy, you can achieve orthogonal indexing by using the [`np.ix_` function](https://numpy.org/doc/stable/reference/generated/numpy.ix_.html). This function constructs an open mesh from multiple arrays, allowing you to index along each dimension independently similar to Xarray indexig behavior. For example: \n", + "While Pointwise indexing is the default behavior in NumPy, you can achieve orthogonal indexing by using the [`np.ix_` function](https://numpy.org/doc/stable/reference/generated/numpy.ix_.html). This function constructs an open mesh from multiple arrays, allowing you to index along each dimension independently similar to Xarray indexing behavior. For example: \n", "\n", "```python\n", "ixgrid = np.ix_([0, 2, 4], [0, 2, 4])\n", @@ -410,6 +410,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3" + "version": "3.9.18" }, "toc": { "base_numbering": 1, From 3081b360a17781694a07f83fa431f1a4f83cdd4e Mon Sep 17 00:00:00 2001 From: Negin Sobhani Date: Tue, 2 Jul 2024 17:47:32 -0600 Subject: [PATCH 26/27] typo fix --- intermediate/indexing/advanced-indexing.ipynb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 3f350941..6cfd9d0f 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -115,7 +115,7 @@ ":::{note} Orthogonal indexing with NumPy\n", ":class: dropdown\n", "\n", - "While Pointwise indexing is the default behavior in NumPy, you can achieve orthogonal indexing by using the [`np.ix_` function](https://numpy.org/doc/stable/reference/generated/numpy.ix_.html). This function constructs an open mesh from multiple arrays, allowing you to index along each dimension independently similar to Xarray indexing behavior. For example: \n", + "While pointwise indexing is the default behavior in NumPy, you can achieve orthogonal indexing by using the [`np.ix_` function](https://numpy.org/doc/stable/reference/generated/numpy.ix_.html). This function constructs an open mesh from multiple arrays, allowing you to index along each dimension independently similar to Xarray indexing behavior. For example: \n", "\n", "```python\n", "ixgrid = np.ix_([0, 2, 4], [0, 2, 4])\n", @@ -400,6 +400,11 @@ } ], "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, "language_info": { "codemirror_mode": { "name": "ipython", @@ -409,7 +414,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", "version": "3.9.18" }, "toc": { From 383eeae6263bf4db3ee4db17e4657231ba42fd12 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 23:47:45 +0000 Subject: [PATCH 27/27] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- intermediate/indexing/advanced-indexing.ipynb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/intermediate/indexing/advanced-indexing.ipynb b/intermediate/indexing/advanced-indexing.ipynb index 6cfd9d0f..ca3f2d5c 100644 --- a/intermediate/indexing/advanced-indexing.ipynb +++ b/intermediate/indexing/advanced-indexing.ipynb @@ -400,11 +400,6 @@ } ], "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, "language_info": { "codemirror_mode": { "name": "ipython", @@ -414,8 +409,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.18" + "pygments_lexer": "ipython3" }, "toc": { "base_numbering": 1,