Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions book/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ parts:
- file: notebooks
- file: markdown-notebooks
- file: first-figure
- file: ecosystem
266 changes: 266 additions & 0 deletions book/ecosystem.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "b862b964-62fc-48b7-96db-d7f3b868ced1",
"metadata": {
"tags": []
},
"source": [
"# Integration with the scientific Python ecosystem 🐍\n",
"\n",
"In this tutorial, we'll try out the integration between PyGMT and other common packages in the scientific Python ecosystem.\n",
"\n",
"\n",
"Besides [pygmt](https://www.pygmt.org), we'll also be using:\n",
"\n",
"- [GeoPandas](https://geopandas.org/en/stable/) for managing geospatial tabular data\n",
"- [Panel](https://panel.holoviz.org/index.html) for interactive visualizations\n",
"- [Xarray](https://xarray.dev/) for managing n-dimensional labelled arrays\n"
]
},
{
"cell_type": "markdown",
"id": "62d489cd-c901-42a2-b51a-9b21842b34df",
"metadata": {},
"source": [
"## Plotting geospatial vector data with GeoPandas and PyGMT\n",
"\n",
"We'll extend the GeoPandas [Mapping and Plotting Tools Examples](https://geopandas.org/en/stable/docs/user_guide/mapping.html) to show how to create choropleth maps using PyGMT.\n",
"\n",
"**References**:\n",
"\n",
" - GeoPandas User Guide - https://geopandas.org/en/stable/docs/user_guide/"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6436dfbb-be9c-4c2b-901a-a8fc7cde4ae8",
"metadata": {},
"outputs": [],
"source": [
"import pygmt\n",
"import geopandas as gpd"
]
},
{
"cell_type": "markdown",
"id": "a0f88acb-e463-4193-a7ef-33837b2f5fdf",
"metadata": {},
"source": [
"We'll load sample data provided through the GeoPandas package and inspect the GeoDataFrame."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8cf79e91-8ce0-48ec-8812-1395d3d0eddf",
"metadata": {},
"outputs": [],
"source": [
"world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))\n",
"world.head()"
]
},
{
"cell_type": "markdown",
"id": "65adae6a-3933-453b-bd4b-4e04e018d02d",
"metadata": {},
"source": [
"Following the [GeoPandas example](https://geopandas.org/en/stable/docs/user_guide/mapping.html#choropleth-maps), we'll create a Choropleth map showing world population estimates, but will use PyGMT to plot the data using the [Hammer projection](https://www.pygmt.org/latest/projections/misc/misc_hammer.html#hammer)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "76b850c4-e5bc-42bd-ba13-7b52b4f60dc2",
"metadata": {},
"outputs": [],
"source": [
"# Calculate the populations in millions per capita\n",
"world = world[(world.pop_est>0) & (world.name!=\"Antarctica\")]\n",
"world['pop_est'] = world.pop_est * 1e-6\n",
"\n",
"# Find the range of data values for creating a colormap\n",
"cmap_bounds = pygmt.info(data=world['pop_est'], per_column=True)\n",
"cmap_bounds"
]
},
{
"cell_type": "markdown",
"id": "864091e5-85e2-4452-ab44-5cbeaa2ac8a9",
"metadata": {},
"source": [
"Now, we'll plot the data on a PyGMT figure, by creating a figure instance, laying down a basemap, plotting the GeoDataFrame, and adding a colorbar!"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15a21a74-8531-4e74-86e1-a85e6eaef793",
"metadata": {},
"outputs": [],
"source": [
"# Create an instance of the pygmt.Figure class\n",
"fig = pygmt.Figure()\n",
"# Create a colormap for the figure\n",
"pygmt.makecpt(cmap=\"bilbao\", series=cmap_bounds)\n",
"# Create a basemap\n",
"fig.basemap(region=\"d\", projection=\"H15c\", frame=True)\n",
"# Plot the GeoDataFrame\n",
"# - Use `close=True` to specify that the polygons should be forced closed\n",
"# - Plot the polygon outlines with a 1 point, black pen\n",
"# - Set that the color should be based on the `pop_est` using the `color, `cmap`, and `aspatial` parameters\n",
"fig.plot(data=world, pen=\"1p,black\", close=True, color=\"+z\", cmap=True, aspatial=\"Z=pop_est\")\n",
"# Add a colorbar\n",
"fig.colorbar(position=\"JMR\", frame='a200+lPopulation (millions)')\n",
"# Display the output\n",
"fig.show()\n"
]
},
{
"cell_type": "markdown",
"id": "b73a6666-6c2c-4f49-a92b-995ade576ccc",
"metadata": {},
"source": [
"## Interactive data visualization with Xarray, Panel, and PyGMT"
]
},
{
"cell_type": "markdown",
"id": "1bf15df6-6a4f-4221-af66-0db1c5b1e328",
"metadata": {},
"source": [
"In this section, we'll create some interactive visualizations of oceanographic data!\n",
"\n",
"We'll use [Panel](https://panel.holoviz.org/index.html), which is a Python library\n",
"for connecting interactive widgets with plots! We'll use Panel with\n",
"[PyGMT](https://www.pygmt.org) and [xarray](https://www.xarray.dev) to visualize\n",
"the objectively interpolated mean field for in-situ temperature from the World Ocean Atlas.\n",
"\n",
"**References**:\n",
"\n",
"- Temperature visualization based on https://rabernat.github.io/intro_to_physical_oceanography/02-c_ocean_temperature_salinity_stratification.html\n",
"- Interactive setup based on https://github.com/weiji14/30DayMapChallenge2021/blob/main/day25_interactive.py\n",
"- Data from the NOAA World Ocean Atlas, stored on the IRI Data Library at http://iridl.ldeo.columbia.edu/SOURCES/.NOAA/.NODC/.WOA09/."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dbcff01f-fac0-4c1d-bb66-89dcb2e7711b",
"metadata": {},
"outputs": [],
"source": [
"import panel as pn\n",
"import xarray as xr\n",
"import pygmt\n",
"pn.extension()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7b2f9cb8-add6-45c2-9f54-8e33ed9e6f02",
"metadata": {},
"outputs": [],
"source": [
"# Download the dataset from the IRI Data Library\n",
"url = 'https://iridl.ldeo.columbia.edu/SOURCES/.NOAA/.NODC/.WOA09/.Grid-1x1/.Annual/.temperature/.t_an/data.nc'\n",
"netcdf_file = pygmt.which(fname=url, download=True)\n",
"woa_temp = xr.open_dataset(netcdf_file).isel(time=0)\n",
"woa_temp"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1c72a673",
"metadata": {},
"outputs": [],
"source": [
"# Make a static plot of sea surface temperature\n",
"fig = pygmt.Figure()\n",
"fig.grdimage(grid=woa_temp.t_an.sel(depth=0), cmap=\"vik\", projection=\"R15c\", frame=True)\n",
"fig.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b11ea510-7540-475e-9217-be4204cb1ea3",
"metadata": {},
"outputs": [],
"source": [
"# Make a panel widget for controlling the depth plotted\n",
"depth_slider = pn.widgets.DiscreteSlider(name='Depth (m)', options=woa_temp.depth.values.astype(int).tolist(), value=0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3496d4db-92d9-45ee-9d48-6b4f00a19361",
"metadata": {},
"outputs": [],
"source": [
"# Make a function for plotting the depth slice with PyGMT\n",
"\n",
"@pn.depends(depth=depth_slider)\n",
"def view(depth: int):\n",
" fig = pygmt.Figure()\n",
" pygmt.makecpt(cmap=\"vik\", series=[-2,30])\n",
" fig.grdimage(grid=woa_temp.t_an.sel(depth=depth), cmap=True, projection=\"R15c\", frame=True)\n",
" fig.colorbar(frame=\"a5\")\n",
" return fig"
]
},
{
"cell_type": "markdown",
"id": "d339433c-1c7a-4769-8986-edfb2a9897ed",
"metadata": {},
"source": [
"### Make the interactive dashboard!\n",
"\n",
"Now to put everything together! The 'dashboard' will be very simple.\n",
"The 'depth' slider is placed next to the map using `panel.Column`.\n",
"Selecting different depths will update the data plotted! Find out more at\n",
"https://panel.holoviz.org/getting_started/index.html#using-panel.\n",
"\n",
"Note: This is meant to run in a Jupyter lab/notebook environment.\n",
"The grdinfo warning can be ignored."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cc8d2f88-6e37-4ca4-9ebc-4bdf1e00ec8e",
"metadata": {},
"outputs": [],
"source": [
"pn.Column(depth_slider, view)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.9.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dependencies:
- python=3.9
- pip=22
# Optional dependencies
- panel=0.13.0
- geopandas=0.10.2
- jupyter-book=0.12.3
- laspy=2.1.2
Expand Down