{
 "cells": [
  {
   "attachments": {
    "MTBS_SFL_perims_2018.jpg": {
     "image/jpeg": "[encoded data, 707524 characters]"
    },
    "image-2.png": {
     "image/png": "[encoded data, 1050980 characters]"
    },
    "image-3.png": {
     "image/png": "[encoded data, 1254956 characters]"
    },
    "image.png": {
     "image/png": "[encoded data, 414412 characters]"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Geospatial data visualization with Web Map Service (WMS) and NASA Global Imagery Browse Services (GIBS)\n",
    "\n",
    "When mapping geospatial data (e.g. PM2.5 station data, aircraft flight tracks, model output), it is often informative and aesthetically pleasing to visually overlay other datasets as well, such as true-color Earth imagery, surface elevation, or other variables. \n",
    "\n",
    "Example. The figure below shows the locations of large (>400 ac) wildfires (red) and prescribed fires (green) in South Florida in 2018. True-color imagery from Landsat WELD provides information on land use and land cover. Fire perimeters are from MTBS.\n",
    "\n",
    "![MTBS_SFL_perims_2018.jpg](attachment:MTBS_SFL_perims_2018.jpg)\n",
    "\n",
    "### WMS, WMTS and WFS\n",
    "WMS, Web Map Tile Service (WMTS), and the Web Feature Service (WFS) are *protocols* for sharing geospatial data over the internet as images, without requiring the user to download the underlying data. (Quantitative analysis likely requires downloading the data.) Google Maps uses a protocol like WMS to deliver satellite, terrain, and political maps. \n",
    "\n",
    "Examples from Google Maps\n",
    "\n",
    "![image.png](attachment:image.png)\n",
    "![image-2.png](attachment:image-2.png)\n",
    "\n",
    "### OWSlib\n",
    "[OWSlib](https://owslib.readthedocs.io) is a Python package for accessing WMTS, WMS, and other online geospatial data.\n",
    "\n",
    "### GIBS\n",
    "The [NASA GIBS](https://www.earthdata.nasa.gov/eosdis/science-system-description/eosdis-components/gibs) server provides a lot of Earth imagery and geospatial data through WMTS. See \n",
    "[NASA Worldview](https://worldview.earthdata.nasa.gov) to check out the available imagery. [GIBS Product catalog](https://nasa-gibs.github.io/gibs-api-docs/available-visualizations/#visualization-product-catalog)\n",
    "\n",
    "![image-3.png](attachment:image-3.png)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import packages\n",
    "import matplotlib.pyplot as plt\n",
    "from owslib.wmts import WebMapTileService\n",
    "import cartopy.crs as ccrs\n",
    "\n",
    "# NASA GIBS currently seems to return a faulty projection code (2022-11-19)\n",
    "# These lines enable OWS to understand the faulty code\n",
    "# This may become unneccessary in the future.\n",
    "import cartopy.io.ogc_clients as ogcc\n",
    "ogcc._URN_TO_CRS['urn:ogc:def:crs:EPSG:6.18:3:3857'] = ccrs.GOOGLE_MERCATOR\n",
    "ogcc.METERS_PER_UNIT['urn:ogc:def:crs:EPSG:6.18:3:3857'] = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/cdholmes/anaconda3/envs/general/lib/python3.10/site-packages/owslib/wmts.py:645: RuntimeWarning: TileMatrixLimits with tileMatrix \"1\" already exists\n",
      "  warnings.warn(msg, RuntimeWarning)\n",
      "/Users/cdholmes/anaconda3/envs/general/lib/python3.10/site-packages/owslib/wmts.py:645: RuntimeWarning: TileMatrixLimits with tileMatrix \"2\" already exists\n",
      "  warnings.warn(msg, RuntimeWarning)\n",
      "/Users/cdholmes/anaconda3/envs/general/lib/python3.10/site-packages/owslib/wmts.py:645: RuntimeWarning: TileMatrixLimits with tileMatrix \"3\" already exists\n",
      "  warnings.warn(msg, RuntimeWarning)\n",
      "/Users/cdholmes/anaconda3/envs/general/lib/python3.10/site-packages/owslib/wmts.py:645: RuntimeWarning: TileMatrixLimits with tileMatrix \"4\" already exists\n",
      "  warnings.warn(msg, RuntimeWarning)\n",
      "/Users/cdholmes/anaconda3/envs/general/lib/python3.10/site-packages/owslib/wmts.py:645: RuntimeWarning: TileMatrixLimits with tileMatrix \"5\" already exists\n",
      "  warnings.warn(msg, RuntimeWarning)\n",
      "/Users/cdholmes/anaconda3/envs/general/lib/python3.10/site-packages/owslib/wmts.py:645: RuntimeWarning: TileMatrixLimits with tileMatrix \"6\" already exists\n",
      "  warnings.warn(msg, RuntimeWarning)\n"
     ]
    }
   ],
   "source": [
    "# Address for GIBS data\n",
    "# epsg3857 (Web Mercator) and epsg4326 (Cylindrical Equirectangular, i.e. PlateCarree) are both fine for most purposes\n",
    "# epsg3413 for Arctic \n",
    "# epsg3031 for Antarctic\n",
    "URL = 'https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/wmts.cgi'\n",
    "\n",
    "#Ignore RuntimeWarning\n",
    "wmts = WebMapTileService(URL)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Getting GIBS imagery products\n",
    "\n",
    "* Find the product that interests you in the \n",
    "[GIBS product catalog](https://nasa-gibs.github.io/gibs-api-docs/available-visualizations/#visualization-product-catalog). Worldview can give you a preview of the images. \n",
    "* True color imagery is in the \"Corrected Reflectance\" and \"Geostationary\" categories.\n",
    "* Locate the Name/Identifier for the product. e.g. \"BlueMarble_NextGeneration\"\n",
    "* Products with temporal resolution have a period and temporal range specified in the catalog. Other products are static images (e.g. Blue Marble.) \n",
    "\n",
    "#### Some useful products\n",
    "* BlueMarble_NextGeneration \n",
    "* VIIRS_Black_Marble \n",
    "* MODIS_Aqua_CorrectedReflectance_TrueColor - daily, 250 m resolution, also available from Terra instead of Aqua\n",
    "* VIIRS_SNPP_CorrectedReflectance_TrueColor - daily, 250 m resolution, also available from NOAA20 instead of SNPP\n",
    "* Landsat_WELD_CorrectedReflectance_TrueColor_Global_Annual - 30 m resolution, also available monthly\n",
    "* GOES-East_ABI_GeoColor - 10 minute, 1 km, aslo available from GOES-West and HIMAWARI\n",
    "* GPW_Population_Density_2020 - also 2000, 2005, 2010, 2015\n",
    "* Reference_Features_15m - coastlines, borders, roads\n",
    "* Reference_Labels_15m - place names\n",
    "* ASTER_GDEM_Color_Shaded_Relief - terrain altitude, also Index instead of Shaded_Relief\n",
    "* MODIS_Combined_Thermal_Anomalies_All, VIIRS_NOAA20_Thermal_Anomalies_375m_All, VIIRS_SNPP_Thermal_Anomalies_375m_All \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Examples: Blue Marble and MODIS daily"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<cartopy.mpl.slippy_image_artist.SlippyImageArtist at 0x12c739090>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 327216 characters]",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Map projection\n",
    "mapproj = ccrs.EuroPP()\n",
    "\n",
    "# Create the plot axes with desired projection\n",
    "fig, axs  = plt.subplots( nrows=1, ncols=2, \n",
    "            subplot_kw=dict(projection=mapproj) )\n",
    "\n",
    "# Add Blue Marble\n",
    "axs[0].add_wmts( wmts, 'BlueMarble_NextGeneration' ) \n",
    "\n",
    "# Add MODIS for specific day\n",
    "axs[1].add_wmts( wmts, 'MODIS_Aqua_CorrectedReflectance_TrueColor', \n",
    "                wmts_kwargs={'time': '2015-07-01'} ) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Examples: Population density and fire detections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<cartopy.mpl.slippy_image_artist.SlippyImageArtist at 0x13603beb0>"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 333272 characters]",
      "text/plain": [
       "<Figure size 1200x700 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Map projection\n",
    "mapproj = ccrs.EqualEarth()\n",
    "\n",
    "# Create the plot axes with desired projection\n",
    "fig, axs  = plt.subplots( nrows=1, ncols=2, \n",
    "            subplot_kw=dict(projection=mapproj),\n",
    "             figsize=(12,7) )\n",
    "\n",
    "# Population density\n",
    "axs[0].add_wmts( wmts, 'GPW_Population_Density_2020' ) \n",
    "\n",
    "# MODIS and MODIS fire detections\n",
    "# Note that this uses WMS because fire detections is a vector object\n",
    "axs[1].add_wms( 'https://gibs.earthdata.nasa.gov/wms/epsg4326/best/wms.cgi',\n",
    "                ['MODIS_Aqua_CorrectedReflectance_TrueColor',\n",
    "                 'MODIS_Combined_Thermal_Anomalies_All', ], \n",
    "                wms_kwargs={'time': '2015-07-01',\n",
    "                            'transparent':True} ) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "general",
   "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.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
