{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1af65df6-4b1d-4019-96ba-f51d98aadec7",
   "metadata": {},
   "source": [
    "# Projecting data on a map\n",
    "\n",
    "In this example, we will see how to use xsar to project data on a map, or to export to geotiff."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "40fd3e6a-67c4-4a0b-9136-a083729e94d4",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import xsar\n",
    "import xarray as xr\n",
    "import numpy as np\n",
    "import geoviews as gv\n",
    "import holoviews as hv\n",
    "xr.set_options(display_expand_data=False, display_expand_attrs=False)\n",
    "gv.extension('bokeh')\n",
    "hv.extension('bokeh')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bcd2e0d2-c956-48fe-8e16-6bc7ec533f09",
   "metadata": {},
   "source": [
    "## Opening the dataset\n",
    "\n",
    "When using projection, it's mandatory to open the dataset with [xsar.Sentinel1Dataset](../basic_api.rst#xsar.Sentinel1Dataset)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4e174aac-ce89-4559-826a-c78909da7add",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "filename = xsar.get_test_file('S1B_IW_GRDH_1SDV_20181013T062322_20181013T062347_013130_018428_Z010.SAFE')\n",
    "s1meta = xsar.Sentinel1Meta(filename)\n",
    "xsar_obj = xsar.Sentinel1Dataset(s1meta, resolution='100m')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b0e045b-28e8-4159-aaa0-9529764bda6d",
   "metadata": {},
   "source": [
    "## Display the image without projection\n",
    "\n",
    "When using `holoviews.Image` the data is displayed as the memory order"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a6146297-5776-4f18-aae5-4ab01323bf69",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "hv.Image(xsar_obj.dataset.sigma0.sel(pol='VV')).opts(alpha=0.7, cmap='gray', clim=(0,0.05))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab8a4bb1-6523-4d93-b2a8-068355328498",
   "metadata": {},
   "source": [
    "To have it displayed the same way it was aquired, we need to pass `kdims=['sample', 'line']`.\n",
    "\n",
    "We can see here that the orbit pass is **descending**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0b1e0636-39a0-4b1f-be1c-f5288afb51a6",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "hv.Image(xsar_obj.dataset.sigma0.sel(pol='VV'), kdims=['sample', 'line']).opts(alpha=0.7, cmap='gray', clim=(0,0.05))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "04a71723-9003-4efb-b651-e40c935b033c",
   "metadata": {},
   "source": [
    "## Reprojecting to epsg 4326, using rioxarray.reproject\n",
    "\n",
    "Reprojection are done with the `rioxarray` [.rio](https://corteva.github.io/rioxarray/html/rioxarray.html#rioxarray-rio-accessors) accessor. \n",
    "\n",
    "Attributes accessor are volatile (see [Managing Information Loss with xarray operations](https://corteva.github.io/rioxarray/stable/getting_started/manage_information_loss.html)), so it's a good practice to call [xsar.BaseDataset.recompute_attrs()](../basic_api.rst#xsar.BaseDataset.recompute_attrs) before using it.\n",
    "\n",
    "\n",
    "'epsg:4326' is the standard lon/lat projection, in degrees. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "530ac853-1e43-4fbe-b1af-ad6b99dd3d76",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import rasterio\n",
    "xsar_obj.recompute_attrs()\n",
    "sigma0_proj = xsar_obj.dataset['sigma0'].rio.reproject('epsg:4326',shape=(1000,1000),nodata=np.nan)\n",
    "sigma0_proj"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cc409410-ede7-498e-94c3-59eb47757358",
   "metadata": {},
   "source": [
    "The `sigma0_proj` dataarray is georeferenced, so holoviews know how to deal with it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bb9e2502-58e7-4adb-bd1c-2e1e52ee9e94",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "sigma0_image = gv.Image(sigma0_proj.sel(pol='VV')).opts(alpha=0.3, cmap='gray', clim=(0,0.05))\n",
    "#(gv.tile_sources.Wikipedia * gv.feature.land.options(scale='50m') * sigma0_image).opts(width=600,height=600)\n",
    "(gv.tile_sources.EsriImagery * sigma0_image * gv.feature.coastline.options(scale='10m')).opts(width=600,height=600)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "604b45d7-fe32-40d0-bd34-686a41f1097d",
   "metadata": {},
   "source": [
    "## Exporting to geotiff\n",
    "\n",
    "### Exporting without colormap\n",
    "\n",
    "using [rioxarray.raster_array.RasterArray.to_raster](https://corteva.github.io/rioxarray/html/rioxarray.html#rioxarray.raster_array.RasterArray.to_raster), we can save our projected sigma0 to a geotiff"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b9d8658b-a5e3-456f-b046-db180b01d48e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "s0vvproj = sigma0_proj.sel(pol='VV')\n",
    "s0vvproj.attrs['name'] = 'sigma0 VV projected using rioxarray'\n",
    "s0vvproj.rio.to_raster('/tmp/sigma0_nocolor.tiff')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f872bee-95b4-4109-9f54-63da680bd3c9",
   "metadata": {},
   "source": [
    "The geotiff can be read with `rioxarray` via `rasterio` but it's stored as float, and we have to pass a cmap. This image cannot be viewed with google earth "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4143b543-6d00-4c02-95ab-dfafe7dae274",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "#gv.tile_sources.Wikipedia * gv.load_tiff('/tmp/sigma0_nocolor.tiff').opts(alpha=0.7, cmap='gray', clim=(0,0.05))\n",
    "import rioxarray\n",
    "tmp = rioxarray.open_rasterio('/tmp/sigma0_nocolor.tiff')\n",
    "tmp = tmp.rename('sigma0_nocolor')\n",
    "tmp2 = gv.util.from_xarray(tmp)\n",
    "gv.tile_sources.EsriImagery * gv.Image(tmp2,kdims=['x','y']).opts(alpha=0.7, cmap='gray', clim=(0,0.05),colorbar=True,width=500,height=200) # vdims='sigma0_nocolor'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4e8fb2c-d7e9-4247-be51-c51686d423ad",
   "metadata": {},
   "source": [
    "### Exporting with RGBA colormap\n",
    "\n",
    "We have to manually convert the sigma0 floating values to `np.uint8` in the range [0,255]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "04a8eacf-f173-480f-92eb-35340644e4fe",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from matplotlib import cm\n",
    "cmap=cm.ScalarMappable(cmap='jet')\n",
    "cmap.set_clim(vmin=0, vmax=0.05)\n",
    "rgb_sigma0 = xr.DataArray(\n",
    "    (cmap.to_rgba(xsar_obj.dataset['sigma0'].sel(pol='VV'), bytes=True)),  \n",
    "    dims=['line', 'sample', 'band']\n",
    ").transpose('band', 'line', 'sample')\n",
    "rgb_sigma0\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3570b206-ebac-4bc8-a58a-b3a24b4369a8",
   "metadata": {},
   "source": [
    "`rgb_sigma0` is now an `xarray.DataArray`, with sames spatials dims `['line', 'sample']`, and an new dim `band` that hold color in R,G,B,A. \n",
    "\n",
    "This dataarray is currently not georeferenced. To georefence it, we have **to store it into xsar_obj.dataset and call [xsar.BaseDataset.recompute_attrs()](../basic_api.rst#xsar.BaseDataset.recompute_attrs)**.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6a1fa55c-cb1d-4ff7-9c91-50a06348c01b",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "#xsar_obj.dataset['sigma0_rgba'] = rgb_sigma0 \n",
    "rgb_sigma0.name = 'sigma0_rgba'\n",
    "xsar_obj.datatree['measurement'] = xsar_obj.datatree['measurement'].assign(xr.merge([xsar_obj.dataset,rgb_sigma0]))\n",
    "xsar_obj.recompute_attrs()\n",
    "s0rgba = xsar_obj.dataset['sigma0_rgba'].rio.reproject('epsg:4326',shape=(1000,1000),nodata=0)\n",
    "s0rgba.attrs['name'] = 'sigma0 RGBA projected using rioxarray'\n",
    "s0rgba.rio.to_raster('/tmp/sigma0_color.tiff')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "13bf1e5b-4641-4536-b487-28d4062cf1dc",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# there is a transparency bug in geoviews (https://github.com/holoviz/geoviews/issues/571)\n",
    "# but if loading this tiff in google earth, it should render properly\n",
    "tmp = rioxarray.open_rasterio('/tmp/sigma0_color.tiff')\n",
    "tmp = tmp.rename('sigma0_color').isel(band=1)\n",
    "print(tmp)\n",
    "# tmp2 = gv.util.from_xarray(tmp,vdims='sigma0_color')\n",
    "# print('empt2\\n====================',tmp2)\n",
    "# (gv.tile_sources.Wikipedia * gv.load_tiff('/tmp/sigma0_color.tiff')).opts(width=600,height=600)\n",
    "(gv.tile_sources.EsriImagery * gv.Image(tmp,vdims='sigma0_color',kdims=['x','y']).opts(cmap='magma',colorbar=True,tools=['hover'])).opts(width=600,height=600) # "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21a44ee7-e47f-4d95-a29c-2e29198b5cad",
   "metadata": {},
   "source": [
    "## Reprojecting to pre-defined grid\n",
    "\n",
    "We now want to project ecmwf data and sigma0 data to the same grid.\n",
    "\n",
    "The grid is choosen to be 600km*600km , with a spacing of 1km. x and y coords are in **meters**, because we are going to use an **azimuthal equidistant projection**, centered on the xsar dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d0e23462-e809-4b10-b5eb-5f76e46bb9b0",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from rasterio.crs import CRS\n",
    "from xsar.raster_readers import ecmwf_0100_1h\n",
    "\n",
    "grid = xr.DataArray(\n",
    "    np.full((601,601), np.nan), \n",
    "    dims=['x','y'], \n",
    "    coords={\n",
    "        'x': np.linspace(-300 * 1000,300 * 1000, 601), \n",
    "        'y': np.linspace(-300 * 1000,300 * 1000, 601)\n",
    "    })\n",
    "\n",
    "\n",
    "crs = CRS({\n",
    "        'proj': 'aeqd',\n",
    "        'lat_0': xsar_obj.sar_meta.footprint.centroid.y,\n",
    "        'lon_0': xsar_obj.sar_meta.footprint.centroid.x,\n",
    "        'x_0': 0,\n",
    "        'y_0': 0,\n",
    "        'ellps': 'WGS84'\n",
    "    })\n",
    "\n",
    "grid.rio.write_crs(crs, inplace=True)\n",
    "grid"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02a9d18b-073e-40e7-8e1e-9d8873d30061",
   "metadata": {},
   "source": [
    "Now, we can use [reproject_match](https://corteva.github.io/rioxarray/stable/rioxarray.html#rioxarray.raster_array.RasterArray.reproject_match), to project onto `grid`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2b614346-a467-46c7-9678-e700515f541a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "\n",
    "xsar_obj.recompute_attrs()\n",
    "sigma0_grid = xsar_obj.dataset['sigma0'].rio.reproject_match(grid,nodata=np.nan).sel(pol='VV')\n",
    "ecmwf_ds = ecmwf_0100_1h(xsar.get_test_file('ECMWF_FORECAST_0100_202109091300_10U_10V.nc'))\n",
    "ecmwf_ds['spd'] = np.sqrt(ecmwf_ds['U10']**2+ecmwf_ds['V10']**2)\n",
    "ecmwf_grid = ecmwf_ds['spd'].rio.reproject_match(grid,nodata=np.nan)\n",
    "\n",
    "# ecmwf_grid and sigma0_grid has the same shape and the same coordinates, we are able to merge them\n",
    "\n",
    "merged_grid = xr.merge([sigma0_grid, ecmwf_grid])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0639c842-8e11-4078-b520-f8e307b98826",
   "metadata": {},
   "source": [
    "geoviews and cartopy are not able to handle azimuthal equidistant projection, so we use `holoviews` here.\n",
    "\n",
    "(But note that it will display properly in google earth, if exported to geotiff)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "03cd39e3-5b5a-458c-9173-216f0cea27d5",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import holoviews as hv\n",
    "hv.extension('bokeh')\n",
    "hv.Image(merged_grid['spd']).opts(cmap='jet') * hv.Image(merged_grid['sigma0']).opts(cmap='gray', clim=(0,0.05), tools=['hover']) "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6c4ccade-4bce-48fa-9bf0-2eb25c697fbb",
   "metadata": {},
   "source": [
    "To use holoviews, we can reproject to lon/lat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e3c49945-7e49-48e4-bf86-653a7cae2b18",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "merged_lonlat = merged_grid.rio.reproject(4326)\n",
    "(\n",
    "    gv.tile_sources.EsriImagery * gv.Image(merged_lonlat['spd']).opts(cmap='jet', alpha=0.3) \n",
    "    * gv.Image(merged_lonlat['sigma0']).opts(cmap='gray', clim=(0,0.05), alpha=0.7)\n",
    ").opts(width=600,height=600)\n",
    "                                                           "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "19640162-d173-4d6d-a39e-01aed5bba295",
   "metadata": {},
   "source": [
    "## Mapping a raster onto original xsar grid\n",
    "\n",
    "Using `rioxarray.reproject_match` with a destination grid containing gcps (like xsar dataset) is currently not supported.\n",
    "\n",
    "mapraster provides map_raster. \n",
    "\n",
    "One argument is a projected dataset, that we want to map onto the xsar grid.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "350d9cea",
   "metadata": {},
   "outputs": [],
   "source": [
    "from mapraster import map_raster"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e7d86b33-6a1b-464b-bbcd-e89bbb9e575a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "#xsar_obj.dataset['sigma0_rasterized'] = \n",
    "tmp_ds = map_raster(merged_grid['sigma0'], xsar_obj._dataset,footprint = xsar_obj.sar_meta.footprint, cross_antimeridian=xsar_obj.sar_meta.cross_antimeridian)\n",
    "tmp_ds.name = 'sigma0_rasterized'\n",
    "xsar_obj.datatree['measurement'] = xsar_obj.datatree['measurement'].assign(xr.merge([xsar_obj.dataset,tmp_ds]))\n",
    "xsar_obj.recompute_attrs()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14381b11-d17c-432c-bea3-6a695802e000",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "(\n",
    "    hv.Image(xsar_obj.dataset['sigma0_rasterized'], kdims=['sample','line']).opts(title='from raster') \n",
    "    + hv.Image(xsar_obj.dataset.sigma0.sel(pol='VV'), kdims=['sample','line']).opts(title='original') \n",
    ").opts(hv.opts.Image(tools=['hover'],cmap='gray', clim=(0,0.05), alpha=0.7))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "env_xsar",
   "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.10.15"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
