{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Raster awareness API\n",
    "\n",
    "This notebook will give an overview of newly developed raster interface. We'll cover \n",
    "basic usage of the functionality offered by the interface which mainly involves:\n",
    "1. converting `xarray.DataArray` object to the PySAL's weights object (`libpysal.weights.W`/`WSP`).\n",
    "2. going back to the `xarray.DataArray` from weights object.\n",
    "\n",
    "using different datasets:\n",
    "- with missing values.\n",
    "- with multiple layers.\n",
    "- with non conventional dimension names."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "\n",
    "from libpysal.weights import Rook, Queen, raster\n",
    "import matplotlib.pyplot as plt\n",
    "from splot import libpysal as splot\n",
    "import numpy as np\n",
    "import xarray as xr\n",
    "import pandas as pd\n",
    "from esda import Moran_Local"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loading Data\n",
    "\n",
    "*The interface only accepts `xarray.DataArray`*, this can be easily obtained from raster data\n",
    "format using `xarray`'s I/O functionality which can read from a variety of data formats some of them are listed below: \n",
    "- [GDAL Raster Formats](https://svn.osgeo.org/gdal/tags/gdal_1_2_5/frmts/formats_list.html) via `open_rasterio` method.\n",
    "- [NetCDF](https://www.unidata.ucar.edu/software/netcdf/) via `open_dataset` method.\n",
    "\n",
    "In this notebook we'll work with `NetCDF` and `GeoTIFF` data. \n",
    "\n",
    "### Using xarray example dataset\n",
    "First lets load up a `netCDF` dataset offered by xarray."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<xarray.DataArray 'air' (time: 2920, lat: 25, lon: 53)>\n",
      "[3869000 values with dtype=float32]\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",
      "Attributes:\n",
      "    long_name:     4xDaily Air temperature at sigma level 995\n",
      "    units:         degK\n",
      "    precision:     2\n",
      "    GRIB_id:       11\n",
      "    GRIB_name:     TMP\n",
      "    var_desc:      Air temperature\n",
      "    dataset:       NMC Reanalysis\n",
      "    level_desc:    Surface\n",
      "    statistic:     Individual Obs\n",
      "    parent_stat:   Other\n",
      "    actual_range:  [185.16 322.1 ]\n"
     ]
    }
   ],
   "source": [
    "ds = xr.tutorial.open_dataset(\"air_temperature.nc\")  # -> returns a xarray.Dataset object\n",
    "da = ds[\"air\"]  # we'll use the \"air\" data variable for further analysis\n",
    "print(da)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`xarray`'s data structures like `Dataset` and `DataArray` provides `pandas` like functionality for multidimensional-array or ndarray. \n",
    "\n",
    "In our case we'll mainly deal with `DataArray`, we can see above that the `da` holds the data for air temperature, it has 2 dims coordinate dimensions `x` and `y`, and it's layered on `time` dimension so in total 3 dims (`time`, `lat`, `lon`).\n",
    "\n",
    "We'll now group `da` by month and take average over the `time` dimension\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "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",
      "  * month    (month) int64 1 2 3 4 5 6 7 8 9 10 11 12\n"
     ]
    }
   ],
   "source": [
    "da = da.groupby('time.month').mean()\n",
    "print(da.coords)  # as a result time dim is replaced by month "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<xarray.plot.facetgrid.FacetGrid at 0x7f68f71b8100>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 87848 characters]\n",
      "text/plain": [
       "<Figure size 936x648 with 13 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# let's plot over month, each facet will represent the mean air temperature in a given month.\n",
    "da.plot(col=\"month\", col_wrap=4,) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can use `from_xarray` method from the contiguity classes like `Rook` and `Queen`, and also from `KNN`.\n",
    "\n",
    "This uses a util function in `raster.py` file called `da2W`, which can also be called directly to build `W` object, similarly `da2WSP` for building `WSP` object.\n",
    "\n",
    "**Weight builders (`from_xarray`, `da2W`, `da2WSP`) can recognise dimensions belonging to this list `[band, time, lat, y, lon, x]`, if any of the dimension in the `DataArray` does not belong to the mentioned list then we need to pass a dictionary (specifying that dimension's name) to the weight builder.** \n",
    "\n",
    "e.g. `dims` dictionary:\n",
    "```python\n",
    ">>> da.dims                  # none of the dimension belong to the default dimension list\n",
    "('year', 'height', 'width')\n",
    ">>> coords_labels = {                 # dimension values should be properly aligned with the following keys\n",
    "        \"z_label\": \"year\",\n",
    "        \"y_label\": \"height\",\n",
    "        \"x_label\": \"width\"\n",
    "    }\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/data/GSoC/libpysal/libpysal/weights/raster.py:119: UserWarning: You are trying to build a full W object from xarray.DataArray (raster) object. This computation can be very slow and not scale well. It is recommended, if possible, to instead build WSP object, which is more efficient and faster. You can do this by using da2WSP method.\n",
      "  warn(\n"
     ]
    }
   ],
   "source": [
    "coords_labels = {}\n",
    "coords_labels[\"z_label\"] = \"month\"  # since month does not belong to the default list we need to pass it using a dictionary\n",
    "w_queen = Queen.from_xarray(\n",
    "    da, z_value=12, coords_labels=coords_labels, sparse=False)  # We'll use data from 12th layer (in our case layer=month)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`index` is a newly added attribute to the weights object, this holds the multi-indices of the non-missing values belonging to `pandas.Series` created from the passed `DataArray`, this series can be easily obtained using `DataArray.to_series()` method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "MultiIndex([(12, 75.0, 200.0),\n",
       "            (12, 75.0, 202.5),\n",
       "            (12, 75.0, 205.0),\n",
       "            (12, 75.0, 207.5),\n",
       "            (12, 75.0, 210.0)],\n",
       "           names=['month', 'lat', 'lon'])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w_queen.index[:5]  # indices are aligned to the ids of the weight object"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can then obtain raster data by converting the `DataArray` to `Series` and then using indices from `index` attribute to get non-missing values by subsetting the `Series`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = da.to_series()[w_queen.index]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We now have the required data for further analysis (we can now use methods such as ESDA/spatial regression), for this example let's compute a local Moran statistic for the extracted data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Quickly computing and loading a LISA\n",
    "np.random.seed(12345)\n",
    "lisa = Moran_Local(np.array(data, dtype=np.float64), w_queen)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After getting our calculated results it's time to store them back to the `DataArray`, we can use `w2da` function directly to convert the `W` object back to `DataArray`. \n",
    "\n",
    "*Your use case might differ but the steps for using the interface will be similar to this example.* "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<xarray.DataArray (month: 1, lat: 25, lon: 53)>\n",
      "array([[[0.018, 0.001, 0.001, ..., 0.001, 0.001, 0.001],\n",
      "        [0.001, 0.001, 0.001, ..., 0.001, 0.001, 0.001],\n",
      "        [0.003, 0.001, 0.001, ..., 0.001, 0.001, 0.001],\n",
      "        ...,\n",
      "        [0.002, 0.001, 0.001, ..., 0.001, 0.001, 0.003],\n",
      "        [0.001, 0.001, 0.001, ..., 0.001, 0.001, 0.003],\n",
      "        [0.002, 0.001, 0.001, ..., 0.001, 0.002, 0.006]]])\n",
      "Coordinates:\n",
      "  * month    (month) int64 12\n",
      "  * lat      (lat) float64 75.0 72.5 70.0 67.5 65.0 ... 25.0 22.5 20.0 17.5 15.0\n",
      "  * lon      (lon) float64 200.0 202.5 205.0 207.5 ... 322.5 325.0 327.5 330.0\n"
     ]
    }
   ],
   "source": [
    "# Converting obtained data back to DataArray\n",
    "moran_da = raster.w2da(lisa.p_sim, w_queen)  # w2da accepts list/1d array/pd.Series and a weight object aligned to passed data\n",
    "print(moran_da)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.QuadMesh at 0x7f68f4044940>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 12428 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "moran_da.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Using local `NetCDF` dataset\n",
    "\n",
    "In the earlier example we used an example dataset from xarray for building weights object. Additonally, we had to pass the custom layer name to the builder. \n",
    "\n",
    "In this small example we'll build `KNN` distance weight object using a local `NetCDF` dataset with different dimensions names which doesn't belong to the default list of dimensions.\n",
    "\n",
    "We'll also see how to speed up the reverse journey (from weights object to `DataArray`) by passing prebuilt `coords` and `attrs` to `w2da` method. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<xarray.Dataset>\n",
      "Dimensions:    (latitude: 73, longitude: 144, time: 62)\n",
      "Coordinates:\n",
      "  * longitude  (longitude) float32 0.0 2.5 5.0 7.5 ... 350.0 352.5 355.0 357.5\n",
      "  * latitude   (latitude) float32 90.0 87.5 85.0 82.5 ... -85.0 -87.5 -90.0\n",
      "  * time       (time) datetime64[ns] 2002-07-01T12:00:00 ... 2002-07-31T18:00:00\n",
      "Data variables:\n",
      "    tcw        (time, latitude, longitude) float32 ...\n",
      "    tcwv       (time, latitude, longitude) float32 ...\n",
      "    lsp        (time, latitude, longitude) float32 ...\n",
      "    cp         (time, latitude, longitude) float32 ...\n",
      "    msl        (time, latitude, longitude) float32 ...\n",
      "    blh        (time, latitude, longitude) float32 ...\n",
      "    tcc        (time, latitude, longitude) float32 ...\n",
      "    p10u       (time, latitude, longitude) float32 ...\n",
      "    p10v       (time, latitude, longitude) float32 ...\n",
      "    p2t        (time, latitude, longitude) float32 ...\n",
      "    p2d        (time, latitude, longitude) float32 ...\n",
      "    e          (time, latitude, longitude) float32 ...\n",
      "    lcc        (time, latitude, longitude) float32 ...\n",
      "    mcc        (time, latitude, longitude) float32 ...\n",
      "    hcc        (time, latitude, longitude) float32 ...\n",
      "    tco3       (time, latitude, longitude) float32 ...\n",
      "    tp         (time, latitude, longitude) float32 ...\n",
      "Attributes:\n",
      "    Conventions:  CF-1.0\n",
      "    history:      2004-09-15 17:04:29 GMT by mars2netcdf-0.92\n"
     ]
    }
   ],
   "source": [
    "# Lets load a netCDF Surface dataset\n",
    "ds = xr.open_dataset('ECMWF_ERA-40_subset.nc')    # After loading netCDF dataset we obtained a xarray.Dataset object\n",
    "print(ds)                                         # This Dataset object containes several data variables"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Out of 17 data variables we'll use `p2t` for our analysis. This will give us our desired `DataArray` object `da`, we will further group `da` by day, taking average over the `time` dimension."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('day', 'latitude', 'longitude')\n"
     ]
    }
   ],
   "source": [
    "da = ds[\"p2t\"]  # this will give us the required DataArray with p2t (2 metre temperature) data variable\n",
    "da = da.groupby('time.day').mean()\n",
    "print(da.dims)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**We can see that the none of dimensions of `da` matches with the default dimensions (`[band, time, lat, y, lon, x]`)**\n",
    "\n",
    "This means we have to create a dictionary mentioning the dimensions and ship it to weight builder, similar to our last example. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "coords_labels = {}\n",
    "coords_labels[\"y_label\"] = \"latitude\"\n",
    "coords_labels[\"x_label\"] = \"longitude\"\n",
    "coords_labels[\"z_label\"] = \"day\"\n",
    "w_rook = Rook.from_xarray(da, z_value=13, coords_labels=coords_labels, sparse=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = da.to_series()[w_rook.index]  # we derived the data from DataArray similar to our last example "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the last example we only passed the `data` values and weight object to `w2da` method, which then created the necessary `coords` to build our required `DataArray`. This process can be speed up by passing `coords` from the existing `DataArray` `da` which we used earlier.\n",
    "\n",
    "Along with `coords` we can also pass `attrs` of the same `DataArray` this will help `w2da` to retain all the properties of original `DataArray`.\n",
    "\n",
    "Let's compare the `DataArray` returned by `w2da` and original `DataArray`. For this we'll ship the derived data straight to `w2da` without any statistical analysis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "da1 = raster.wsp2da(data, w_rook, attrs=da.attrs, coords=da[12:13].coords)\n",
    "xr.DataArray.equals(da[12:13], da1)  # method to compare 2 DataArray, if true then w2da was successfull"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Using local `GeoTIFF` dataset\n",
    "\n",
    "Up until now we've only played with `netCDF` datasets but in this example we'll use a `raster.tif` file to see how interface interacts with it. We'll also see how these methods handle missing data. \n",
    "\n",
    "Unlike earlier we'll use weight builder methods from `raster.py`, which we can call directly. Just a reminder that `from_xarray` uses methods from `raster.py` and therefore only difference exists in the API. \n",
    "\n",
    "To access GDAL Raster Formats `xarray` offers `open_rasterio` method which uses `rasterio` as backend. It loads metadata, coordinate values from the raster file and assign them to the `DataArray`.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<xarray.DataArray (band: 1, y: 880, x: 940)>\n",
      "[827200 values with dtype=float32]\n",
      "Coordinates:\n",
      "  * band     (band) int64 1\n",
      "  * y        (y) float64 50.18 50.18 50.18 50.18 ... 49.45 49.45 49.45 49.45\n",
      "  * x        (x) float64 5.745 5.746 5.747 5.747 ... 6.525 6.526 6.527 6.527\n",
      "Attributes:\n",
      "    transform:      (0.0008333333297872345, 0.0, 5.744583325, 0.0, -0.0008333...\n",
      "    crs:            +init=epsg:4326\n",
      "    res:            (0.0008333333297872345, 0.0008333333295454553)\n",
      "    is_tiled:       0\n",
      "    nodatavals:     (-99999.0,)\n",
      "    scales:         (1.0,)\n",
      "    offsets:        (0.0,)\n",
      "    AREA_OR_POINT:  Area\n"
     ]
    }
   ],
   "source": [
    "# Loading raster data with missing values\n",
    "da = xr.open_rasterio('/data/Downloads/lux_ppp_2019.tif')\n",
    "print(da)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.QuadMesh at 0x7f68ef4c5ca0>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 47120 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "da.where(da.values>da.attrs[\"nodatavals\"][0]).plot() # we can see that the DataArray contains missing values."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We'll look at how weight builders handle missing values. Firstly we'll slice the `DataArray` to reduce overall size for easier visualization.\n",
    "\n",
    "This time we'll create `WSP` object using `da2WSP` method inside `raster.py`. Since our DataArray is single banded and all of its dimensions belong to the default list, we only have to ship the DataArray and the type of contiguity we need."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Slicing the dataarray\n",
    "da_s = da[:, 330:340, 129:139]\n",
    "w_queen = raster.da2WSP(da_s)  # default contiguity is queen\n",
    "w_rook = raster.da2WSP(da_s, \"rook\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After plotting both contiguities and sliced `DataArray`, we can see that the missing values are ignored by the `da2WSP` method and only indices of non missing values are stored in `index` attribute of `WSP` object. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 53536 characters]\n",
      "text/plain": [
       "<Figure size 1152x288 with 4 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "f,ax = plt.subplots(1,3,figsize=(4*4,4), subplot_kw=dict(aspect='equal'))\n",
    "da_s.where(da_s.values>da_s.attrs[\"nodatavals\"][0]).plot(ax=ax[0])\n",
    "ax[0].set_title(\"Sliced raster\")\n",
    "splot.plot_spatial_weights(w_rook, data=da_s, ax=ax[1])\n",
    "ax[1].set_title(\"Rook contiguity\")\n",
    "splot.plot_spatial_weights(w_queen, data=da_s, ax=ax[2])\n",
    "ax[2].set_title(\"Queen contiguity\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `higher_order` neighbors\n",
    "\n",
    "In some cases `Rook` and `Queen` contiguities don't provide sufficient neighbors when performing spatial analysis on a raster data, this is because `Rook` contiguity provides max 4 neighbors and `Queen` provides max 8.\n",
    "\n",
    "Therefore we've added `higher_order` functionality inside the builder method. We can now pass `k` value to the weight builder to obtain upto kth order neighbors. Since this can be computionally expensive we can take advantage of parallel processing using `n_jobs` argument. Now lets take a look at this functionality."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Building a test DataArray \n",
    "da_s = raster.testDataArray((1,5,10), rand=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Below we can see that builder selected all the neighbors of order less than equal to 2, with `rook` contiguity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/anaconda/lib/python3.8/site-packages/scipy/sparse/_index.py:124: SparseEfficiencyWarning: Changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient.\n",
      "  self._set_arrayXarray(i, j, x)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(<Figure size 720x720 with 1 Axes>, <AxesSubplot:>)"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 14984 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "w_rook2 = raster.da2WSP(da_s, \"rook\", k=2, n_jobs=-1)\n",
    "splot.plot_spatial_weights(w_rook2, data=da_s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Few times we require the kth order neighbors for our analysis even if lower order neighbors are absent, hence we can use `include_nas` argument to do the same.\n",
    "\n",
    "We can also look in both the examples we used `n_jobs` parameter, and assigned -1 which equats to all the cores present in the computer for multithreading"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<Figure size 720x720 with 1 Axes>, <AxesSubplot:>)"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 23944 characters]\n",
      "text/plain": [
       "<Figure size 720x720 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "w_rook2 = raster.da2WSP(da_s, \"rook\", k=2, n_jobs=-1, include_nodata=True)\n",
    "splot.plot_spatial_weights(w_rook2, data=da_s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Additional resources\n",
    "\n",
    "1. [Reading and writing files using Xarray](http://xarray.pydata.org/en/stable/io.html)\n",
    "2. [Xarray Data Structures](http://xarray.pydata.org/en/stable/data-structures.html)\n",
    "3. Dataset links:\n",
    "    - [ECMWF_ERA-40_subset.nc](https://www.unidata.ucar.edu/software/netcdf/examples/files.html)\n",
    "    - [lux_ppp_2019.tif](https://data.humdata.org/dataset/worldpop-population-counts-for-luxembourg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
