{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Contextily 2: Other Image Providers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview:\n", "1. Explore contextily's `add_basemap` function\n", "2. Access a variety of image sources via the contextily `providers` object \n", "3. Plot satellite imagery from NASA" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Prerequisites\n", "\n", "| Concepts | Importance | Notes |\n", "| --- | --- | --- |\n", "| Contextily 1 | |\n", "\n", "* **Time to learn**: 20 minutes\n", "***" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Imports" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import cartopy.crs as ccrs\n", "import cartopy.feature as cfeature\n", "from metpy.plots import USCOUNTIES\n", "import contextily as ctx\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Explore contextily's `add_basemap` function" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In our previous notebook, we created a plot with **contextily**'s default basemap source (Openstreetmaps). Here, we will do the same, over a variety of regions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create a Python `dictionary` that pairs three regions with their corresponding lat-lon boundaries." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "extents = {'conus':[-125,-63,23,52],'nys':[-80, -72,40.5,45.2], 'alb':[-73.946,-73.735,42.648,42.707]}\n", "extents " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " Note: Python dictionaries are one of the language's core datatypes. Similar to a traditional dictionary, it consists of one or more \"words\" (termed keys in Python) followed by the corresponding \"definitions\" (termed values in Python).\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Show the keys, followed by the values, of this dictionary." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "extents.keys()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "extents.values()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Display the default Contextily basemap for each region." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll use what's called a **dictionary comprehension** to loop over each region." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "for key in extents:\n", " print(key,extents[key])\n", "\n", " fig = plt.figure(figsize=(15,10))\n", " ax = plt.axes(projection=ccrs.epsg('3857'))\n", "\n", " res='50m'\n", " plt.title('Default Contextily Basemap: '+ key)\n", " ax.coastlines(resolution=res)\n", "\n", " ax.add_feature (cfeature.LAKES.with_scale(res), alpha = 0.5)\n", " ax.add_feature (cfeature.STATES.with_scale(res))\n", " ax.set_extent(extents[key], ccrs.PlateCarree())\n", " ctx.add_basemap(ax)\n", " plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can see that the same basemap (OpenStreetMap/Stamen Design) appears, at zoom values automatically determined based on the plotted geographical extent. Notice the street-level resolution for the Albany region." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Access a variety of Contextily's tile providers." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We use Contextily's `providers` method. It returns a dictionary. Let's view that dictionary's `keys`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ctx.providers.keys()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's look at a couple of these providers in more detail.\n", "First, *CartoDB*:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ctx.providers.CartoDB" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see that CartoDB has several options itself. For each option, there are several default attributes, such as `name` and `max_zoom`. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Display two different CartoDB basemaps." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll use the `source` argument for [add_basemap](https://contextily.readthedocs.io/en/latest/reference.html#plotting-basemaps) via Contextily's [providers](https://contextily.readthedocs.io/en/latest/providers_deepdive.html) object." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "bm = {'CartoDB.Positron': ctx.providers.CartoDB.Positron,\n", " 'CartoDB.DarkMatter': ctx.providers.CartoDB.DarkMatter}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for key in bm:\n", " print (key,bm[key])\n", " \n", " fig = plt.figure(figsize=(15,10))\n", " ax = plt.axes(projection=ccrs.epsg('3857'))\n", "\n", " res='50m'\n", " plt.title(key)\n", " ax.coastlines(resolution=res)\n", "\n", " ax.add_feature (cfeature.LAKES.with_scale(res), alpha = 0.5)\n", " ax.add_feature (cfeature.STATES.with_scale(res))\n", "\n", " ax.set_extent(extents['conus'], ccrs.PlateCarree())\n", " ctx.add_basemap(ax,source=bm[key])\n", " plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, let's check out **NASAGIBS**." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Display the 2012 **Earth at Night** basemap." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ctx.providers.NASAGIBS" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "prov = ctx.providers.NASAGIBS.ViirsEarthAtNight2012\n", "fig = plt.figure(figsize=(15,10))\n", "ax = plt.axes(projection=ccrs.epsg('3857'))\n", "\n", "res='50m'\n", "plt.title(prov.name)\n", "ax.coastlines(resolution=res)\n", "\n", "ax.add_feature (cfeature.LAKES.with_scale(res), alpha = 0.5)\n", "ax.add_feature (cfeature.STATES.with_scale(res))\n", "\n", "ax.set_extent(extents['conus'], ccrs.PlateCarree())\n", "ctx.add_basemap(ax,source=prov)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cool! Now let's plot the MODIS True Color satellite mosaic." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot satellite imagery from NASA's Modis and Terra satellites." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "prov = ctx.providers.NASAGIBS.ModisTerraTrueColorCR\n", "fig = plt.figure(figsize=(15,10))\n", "ax = plt.axes(projection=ccrs.epsg('3857'))\n", "\n", "res='50m'\n", "plt.title(prov.name)\n", "ax.coastlines(resolution=res)\n", "\n", "ax.add_feature (cfeature.LAKES.with_scale(res), alpha = 0.5)\n", "ax.add_feature (cfeature.STATES.with_scale(res))\n", "\n", "ax.set_extent(extents['conus'], ccrs.PlateCarree())\n", "ctx.add_basemap(ax,source=prov)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You might see a satellite image, but you might not ... and if you do, it might not be current. What's up with that?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's look specifically at the dictionary corresponding to this satellite product." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ctx.providers.NASAGIBS.ModisTerraTrueColorCR" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `time` attribute is blank. This product is actually updated once a day, so let's pick a particular day." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "prov = ctx.providers.NASAGIBS.ModisTerraTrueColorCR\n", "fig = plt.figure(figsize=(15,10))\n", "ax = plt.axes(projection=ccrs.epsg('3857'))\n", "\n", "time = '2022-09-28'\n", "res='50m'\n", "plt.title(prov.name + ' ' + time)\n", "ax.coastlines(resolution=res)\n", "\n", "ax.add_feature (cfeature.LAKES.with_scale(res), alpha = 0.5)\n", "ax.add_feature (cfeature.STATES.with_scale(res))\n", "\n", "ax.set_extent(extents['conus'], ccrs.PlateCarree())\n", "ctx.add_basemap(ax,source=prov(time=time))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Oct 2022 Terra outage: Daily imagery will be unavailable from 10 Oct through at least 19 Oct 2022: see this NASA link
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On your own, explore some of the other providers. Some, such as [OpenWeatherMap](https://openweathermap.org/api) and [Mapbox](https://docs.mapbox.com/api/), require you to register for an API key, but have free access plans." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Summary\n", "* Contextily provides a number of attractive, tiled basemap images.\n", "\n", "### What's Next?\n", "We'll add interactivity to our visualizations, starting with the **ipyleaflet** package." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### References:\n", "1. [Python Dictionaries and Comprehensions](https://towardsdatascience.com/10-examples-to-master-python-dictionary-comprehensions-7aaa536f5960)\n", "1. [Contextily general documentation](https://contextily.readthedocs.io/en/latest/)\n", "2. [Contextily add_basemap documentation](https://contextily.readthedocs.io/en/latest/reference.html#plotting-basemaps)\n", "3. [Contextily providers documentation](https://contextily.readthedocs.io/en/latest/providers_deepdive.html)\n", "4. [NASA Global Imagery Browse Services](https://earthdata.nasa.gov/eosdis/science-system-description/eosdis-components/gibs)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 August 2022 Environment", "language": "python", "name": "aug22" }, "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.5" } }, "nbformat": 4, "nbformat_minor": 4 }