Click here to access the solution
\n",
"\n",
"\n",
"```python\n",
@@ -520,7 +520,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "Click here to access the solution
\n",
+ "Click here to access the solution
\n",
"\n",
"\n",
"```python\n",
@@ -611,7 +611,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "Click here to access the solution
\n",
+ "Click here to access the solution
\n",
"\n",
"\n",
"```python\n",
diff --git a/year2024/tutorial/solar_eclipse_08Apr2024_exercise.ipynb b/year2024/tutorial/solar_eclipse_08Apr2024_exercise.ipynb
new file mode 100644
index 0000000..a74d081
--- /dev/null
+++ b/year2024/tutorial/solar_eclipse_08Apr2024_exercise.ipynb
@@ -0,0 +1,658 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "ff4eb71a-be1f-40c1-b169-e4d7366ac232",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "\n",
+ " \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ "
\n",
+ "
\n",
+ "\n",
+ "\n",
+ " \n",
+ "\n",
+ "PyCon 2024 Tutorial
\n",
+ "\n",
+ "\n",
+ "---\n",
+ "\n",
+ "\n",
+ " Python Workflows to Extract and Plot Satellite Data Products along Tracks
\n",
+ " 2024 Solar Eclipse - Option 1
\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f1c4d95f-fcf3-4c9f-b7ea-43902693a7e1",
+ "metadata": {},
+ "source": [
+ "## Objective\n",
+ "\n",
+ "- We want to plot the path of the April 8, 2024 solar eclipse.\n",
+ "- We want to identify the cities that will have full view of the total eclipse.\n",
+ "\n",
+ "Part of this work was taken from: [Plan Your Next Eclipse Viewing](https://github.com/christyheaton/PlanYourNextEclipseViewing/blob/master/Notebook/Presentation.ipynb) by Christy Heaton"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d2b170cf-4d30-450d-b43b-44ebb4b43818",
+ "metadata": {},
+ "source": [
+ "## Import necessary modules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "919c6a68-a719-47c5-9427-e825739a8479",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import warnings\n",
+ "warnings.filterwarnings(\"ignore\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8f34f491-837a-4756-aebd-a60c921e6f61",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import datetime as dt\n",
+ "from pathlib import Path"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3bbf5dcf-04b8-4b58-ad43-c69f94435120",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%matplotlib inline\n",
+ "import matplotlib\n",
+ "import matplotlib.pyplot as plt\n",
+ "import matplotlib.ticker as mticker"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "deb827c4-d360-4dc1-9fc4-9c5cae12a63f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import geopandas as gpd"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "674e48b5-2afe-405e-a729-3596efc1840b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from shapely import geometry as shpgeom\n",
+ "from shapely import wkt as shpwkt"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cfd3fbd7-cf95-4c4d-9652-a187352f6a78",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import movingpandas as mpd"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9f66efa9-07f1-43bc-9d90-c54ad4b03af9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import holoviews as hv\n",
+ "import hvplot.pandas "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "34ddc136-6725-4676-853d-e980f058145c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "figsize = (17, 11)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "75573709-477f-42d5-b039-86e8eec89e1c",
+ "metadata": {},
+ "source": [
+ "## Read the CSV file with Pandas\n",
+ "\n",
+ "- The CSV file has three columns:\n",
+ " - `t`: for the date/time as strings\n",
+ " - `latitude` as floats\n",
+ " - `longitude` as floats\n",
+ "- While reading the file, make sure that you transform the `t` values into datetime objects.\n",
+ "- Rename the columns.\n",
+ "- Create a new `geometry` columns"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "64d22f55-0147-4ff9-bcc0-8df895584398",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "data_dir = \"/Users/jkouatch/myTasks/PythonTraining/ASTG606/Materials/sat_data/Eclipse_Data/\"\n",
+ "#data_dir = \"/tljh-data/sat_data/Eclipse_Data\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6ce63bb0-ee53-4199-acdd-835973f2af66",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "file_name = Path(data_dir) / \"eclipse_path_8April2024.csv\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0a89ef0c-0f40-42a0-bc33-7c77950b833a",
+ "metadata": {},
+ "source": [
+ "#### Read the file to create a Pandas DataFrame\n",
+ "\n",
+ "Do no forget to handle the date/time."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b53df351-19ee-4551-968d-51c89aa27b95",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "dateparse = lambda x: ...\n",
+ "df_eclipse = ..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8dff1c4d-55ca-45a0-9b77-c51b5bc47764",
+ "metadata": {},
+ "source": [
+ "Click here to access the solution
\n",
+ "\n",
+ "\n",
+ "```python\n",
+ "dateparse = lambda x: dt.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')\n",
+ "df_eclipse = pd.read_csv(file_name,\n",
+ " parse_dates={'datetime': [0,]}, \n",
+ " date_parser=dateparse)\n",
+ "```\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "608d3545-96fc-4d77-998f-4d530130284d",
+ "metadata": {},
+ "source": [
+ "#### Rename the `datetime` column to `t`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "16d59fc3-6294-4fb9-8358-603246f1f04b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_eclipse."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "32bb6533-c1c3-4bf9-a62f-8c8f89b0736f",
+ "metadata": {},
+ "source": [
+ "Click here to access the solution
\n",
+ "\n",
+ "\n",
+ "```python\n",
+ "df_eclipse.rename(columns = {'datetime': 't'}, inplace=True)\n",
+ "```\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d0902f9b-54ce-49ea-a8bb-7e41767b7190",
+ "metadata": {},
+ "source": [
+ "#### Add a `geometry` column"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5d445638-e769-447a-8250-750a009cb7a5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_eclipse['geometry'] = ..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "949b8f18-ec92-4b8c-84fc-c897a99deb41",
+ "metadata": {},
+ "source": [
+ "Click here to access the solution
\n",
+ "\n",
+ "\n",
+ "```python\n",
+ "df_eclipse['geometry'] = [shpgeom.Point(xy) for xy in zip(df_eclipse['longitude'], df_eclipse['latitude'])] \n",
+ "```\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f74d73d9-46d1-4696-9e3e-fcdc285df8e2",
+ "metadata": {},
+ "source": [
+ "## Manipulation with GeoPandas\n",
+ "\n",
+ "#### Use GeoPandas to create the GeoDataFrame"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "2d1fc0d2-b53d-4c28-ad3b-b8f6fab29b5a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "gdf_eclipse = ..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "371de972-a824-4718-9455-05eedf33dd89",
+ "metadata": {},
+ "source": [
+ "Click here to access the solution
\n",
+ "\n",
+ "\n",
+ "```python\n",
+ "gdf_eclipse = gpd.GeoDataFrame(df_eclipse, geometry=\"geometry\") \n",
+ "```\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4aa339ce-b3a5-4cdf-b6a5-f73ea1f795aa",
+ "metadata": {},
+ "source": [
+ "#### Interactive plot of the path of the eclipse"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "69ad241e-5cfc-4cc1-ace7-be9a8696b271",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "gdf_eclipse.hvplot(tiles='EsriTerrain', coastline=True, \n",
+ " hover_cols=[\"t\"])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "535c8fe7-5767-4623-89fc-d84606aef4b8",
+ "metadata": {},
+ "source": [
+ "#### Create a buffer along the path\n",
+ "- The buffer will correspond to the area along the path where we view the total elcipse."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3a99fbfd-5cfd-42e7-b8ae-ec29908c31ea",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "size_buffer = 1.5"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "93fd7c3a-7f8d-41fe-820c-de04a6d8fd3c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "gdf_eclipse_buffer = gpd.GeoDataFrame(geometry=gdf_eclipse.buffer(size_buffer))\n",
+ "gdf_eclipse_buffer"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "972a11a3-46cc-4c05-b6c1-14e571a314e3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig, ax = plt.subplots(figsize=figsize)\n",
+ "gdf_eclipse.plot(ax=ax, color=\"blue\", alpha=1.0)\n",
+ "gdf_eclipse_buffer.plot(ax=ax, color=\"pink\", alpha=0.2);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a7492552-e6d1-4c3a-8287-2315a8e35424",
+ "metadata": {},
+ "source": [
+ "## Manipulation with MovingPandas\n",
+ "\n",
+ "#### Create the MovingPandas trajectory"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "10bb2a38-97c9-44ea-b0e6-ac84b5b9741d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "mdf_eclipse = ..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e3115223-409c-40e6-b5b3-96119eea613b",
+ "metadata": {},
+ "source": [
+ "Click here to access the solution
\n",
+ "\n",
+ "\n",
+ "```python\n",
+ "mdf_eclipse = mpd.Trajectory(df_eclipse, traj_id=1,\n",
+ " x = \"longitude\", y=\"latitude\", t=\"t\")\n",
+ "```\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4a0767af-da4f-4713-9524-d0c9c758c48e",
+ "metadata": {},
+ "source": [
+ "#### Basic plot of the trajectory and the buffer"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "54a323d7-de5e-4a7f-8931-af47d3a3843e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig, ax = plt.subplots(1, figsize=(20,10))\n",
+ "gdf_eclipse.plot(ax=ax, color=\"pink\", )\n",
+ "mdf_eclipse.plot(ax=ax);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cbf0bcd7-c64a-493d-8c59-338393517c93",
+ "metadata": {},
+ "source": [
+ "#### Interactive plot of the trajectory"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "963e2f02-2d8b-4a3e-98c4-c05a75d12a75",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "mdf_eclipse.hvplot(line_width=0.9)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "51266370-680b-4c1f-a188-8aa7bf733c97",
+ "metadata": {},
+ "source": [
+ "## GeoDataFrame for all the countries of the world\n",
+ "\n",
+ "- We use the Naturel Earth database of the polygon geometry of each country of world"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cce70e17-e574-4471-896f-877fdcc899f5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))\n",
+ "world"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "156b05f8-0f3e-4511-9076-b66d340788a8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "world.plot(color='white', linewidth=0.5, edgecolor='black', figsize=figsize);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "39fe9af6-faad-4451-8c9d-077d81e71253",
+ "metadata": {},
+ "source": [
+ "## GeoDataFrame for all the major cities of the world"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "09effde0-fd34-4431-9255-5af92d6b2f14",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "url_cities = \"https://github.com/nvkelso/natural-earth-vector/raw/master/10m_cultural/ne_10m_populated_places.shp\"\n",
+ "world_cities = gpd.read_file(url_cities)\n",
+ "world_cities.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f3769af0-abab-4cb0-811e-70c87e0943cb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "base = world.plot(color='white', linewidth=0.5, edgecolor='black', figsize=figsize)\n",
+ "world_cities.plot(ax=base, color='orange', markersize=3)\n",
+ "base.set_axis_off() "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3afd0fa6-c465-4302-9fe4-738ef89563cf",
+ "metadata": {},
+ "source": [
+ "## Identify the cities that will have full view of the solar eclipse"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "fced2983-3d91-4fab-b9c3-025081dfc479",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "cities_eclipse = gpd.sjoin(world_cities, gdf_eclipse_buffer, \n",
+ " how='inner', op='intersects')\n",
+ "cities_eclipse"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b252eaa9-6e97-4035-bc9d-4502685ccf35",
+ "metadata": {},
+ "source": [
+ "#### Plot the cities that will have full view of the solar eclipse"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "83c0b45c-3e1e-4277-b438-fa43b7415d16",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "base = world.plot(color='white', linewidth=0.5, edgecolor='black', figsize=figsize)\n",
+ "cities_eclipse.plot(ax=base, color='orange', markersize=3)\n",
+ "base.set_axis_off() "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bb82571d-388f-46ec-a6cd-b9b3675ff780",
+ "metadata": {},
+ "source": [
+ "#### Use the `world` GeoDataFrame to zoom in on North America"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c971ea42-87ec-4769-a384-a20ba25c237f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "north_america = world[world['continent']=='North America']"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "aa736c8a-be89-4c54-8e4a-fe3c9de9eb04",
+ "metadata": {},
+ "source": [
+ "#### Plot the cities that will have full view of the solar eclipse"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "42a79880-e78c-4887-872c-1d8aade59f11",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "base = north_america.plot(color='white', linewidth=0.5, edgecolor='black', figsize=figsize)\n",
+ "cities_eclipse.plot(ax=base, color='orange', markersize=3)\n",
+ "base.set_axis_off() "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ff24e435-b523-4f8c-a45c-cadc9ebc064f",
+ "metadata": {},
+ "source": [
+ "#### Plot the solar eclipse path (buffer) and the cities\n",
+ "\n",
+ "Include the area along the path where the total eclipse will be seen."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "033eb077-7cc3-4b20-b9ed-45156e70b5d8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "base = north_america.plot(color='white', linewidth=0.5, edgecolor='black', figsize=figsize)\n",
+ "cities_eclipse.plot(ax=base, color='orange', markersize=3)\n",
+ "base.set_axis_off() "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c1bcfbff-c3e9-402a-8621-2cbd96fcae8f",
+ "metadata": {},
+ "source": [
+ "Click here to access the solution
\n",
+ "\n",
+ "\n",
+ "```python\n",
+ "base = north_america.plot(color='white', linewidth=0.5, edgecolor='black', figsize=figsize)\n",
+ "cities_eclipse.plot(ax=base, color='orange', markersize=3)\n",
+ "gdf_eclipse_buffer.plot(ax=base, color=\"black\", alpha=0.03);\n",
+ "base.set_axis_off() \n",
+ "```\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "fa2f4839-e596-426d-b481-dbc6344c6314",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "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.11.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}