Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support creating global graphs by introducing haversine distance metric #37

Draft
wants to merge 27 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8a11527
Start looking into where xy has to be changed
joeloskarsson Oct 2, 2024
2c7e4eb
Change shapes in docstrings
joeloskarsson Oct 3, 2024
6f03908
Make flat mesh graphs work with new coordinate layout
joeloskarsson Oct 3, 2024
d2a081a
Merge PR #26 into branch
joeloskarsson Oct 13, 2024
9dbd2a5
Fix coordinate handling in multirange graph creation
joeloskarsson Oct 13, 2024
eada6ea
Rename grid_refinement_factor to mesh_node_distance
joeloskarsson Oct 13, 2024
01180a1
Fix existing tests to work with new coordinate format
joeloskarsson Oct 13, 2024
d103ad6
Add test for irregularlygridded coordinates
joeloskarsson Oct 13, 2024
7ba387e
Remove unneeded eps in mesh level calculation
joeloskarsson Oct 14, 2024
9069c84
Change documentation to use new format and arguments for coordinates
joeloskarsson Oct 14, 2024
d592c2b
Fix bug in coordinate order for flat graphs
joeloskarsson Oct 14, 2024
fd695b1
Start working on allowing latlon coordinates
joeloskarsson Oct 14, 2024
2c781ee
Introduce coords and projection
joeloskarsson Oct 14, 2024
5cf3bbf
Merge branch 'main' into general_coordinates
joeloskarsson Oct 14, 2024
0f17d2c
Fix linting
joeloskarsson Oct 14, 2024
f145025
Fix tests with coords keyword argument
joeloskarsson Oct 14, 2024
cc4cc5e
Implement lat-lon transformation through projection
joeloskarsson Oct 16, 2024
2627e37
Add documentation page about graphs constructed using lat-lons
joeloskarsson Oct 16, 2024
c764fd7
Adjust coords keyword arg in docs
joeloskarsson Oct 16, 2024
f6ae35b
Add test for lat-lon coordinates
joeloskarsson Oct 16, 2024
22caf65
Fix linting of docs
joeloskarsson Oct 16, 2024
7ec34ff
Merge main into branch
joeloskarsson Oct 17, 2024
3ee25ae
Fix typos and clarifications as suggested from code review
joeloskarsson Oct 22, 2024
70eef3e
Change euclidean coordinates to Cartesian coordinates
joeloskarsson Oct 23, 2024
3c4866b
Merge branch 'main' into general_coordinates
joeloskarsson Oct 23, 2024
4fb69dc
Merge branch 'main' into general_coordinates
joeloskarsson Nov 18, 2024
e0f0825
add 1D periodic domain as havesine dist example
leifdenby Nov 25, 2024
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 docs/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ chapters:
- file: background
- file: design
- file: creating_the_graph
- file: lat_lons
15 changes: 7 additions & 8 deletions docs/background.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,16 @@
"\n",
"# create some fake cartesian coordinates\n",
"def _create_fake_xy(N=10):\n",
" x = np.linspace(0.0, 1.0, N)\n",
" y = np.linspace(0.0, 1.0, N)\n",
" xy = np.stack(np.meshgrid(x, y), axis=0)\n",
" x = np.linspace(0.0, N, N)\n",
" y = np.linspace(0.0, N, N)\n",
" xy_mesh = np.meshgrid(x, y)\n",
" xy = np.stack([mg_coord.flatten() for mg_coord in xy_mesh], axis=1) # Shaped (N, 2)\n",
" return xy\n",
"\n",
"\n",
"xy_grid = _create_fake_xy(N=10)\n",
"xy = _create_fake_xy(N=10)\n",
"\n",
"graph = wmg.create.archetype.create_keisler_graph(xy_grid=xy_grid)\n",
"graph = wmg.create.archetype.create_keisler_graph(coords=xy)\n",
"\n",
"# remove all edges from the graph\n",
"graph.remove_edges_from(list(graph.edges))\n",
Expand Down Expand Up @@ -85,9 +86,7 @@
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"graph = wmg.create.archetype.create_keisler_graph(\n",
" xy_grid=xy_grid, grid_refinement_factor=2\n",
")\n",
"graph = wmg.create.archetype.create_keisler_graph(coords=xy, mesh_node_distance=2)\n",
"graph_components = wmg.split_graph_by_edge_attribute(graph=graph, attr=\"component\")\n",
"\n",
"fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(16, 5))\n",
Expand Down
233 changes: 201 additions & 32 deletions docs/creating_the_graph.ipynb

Large diffs are not rendered by default.

199 changes: 199 additions & 0 deletions docs/equator_line_1d.ipynb

Large diffs are not rendered by default.

177 changes: 177 additions & 0 deletions docs/lat_lons.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "65f79439-0b75-483f-858b-932422f7599d",
"metadata": {},
"source": [
"# Working with lat-lon coordinates\n",
"\n",
"In the previous sections we have considered grid point positions `coords` given as Cartesian coordinates. However, it is common that we have coordinates given as latitudes and longitudes. This notebook describes how we can constuct graphs directly using lat-lon coordinates. This is achieved by also providing a specific projection, used to project the lat-lons to a euclidean space where the graph can be construced."
]
},
{
"cell_type": "markdown",
"id": "8cbcd3bd-a80c-41e4-a54b-bcfb5dfbb75c",
"metadata": {},
"source": [
"## A motivating example"
]
},
{
"cell_type": "markdown",
"id": "4c710a27-7e03-4f4f-a4dd-5d1c53a1e4eb",
"metadata": {},
"source": [
"Let's start by defining some example lat-lons to use in our example. When using lat-lons the first column of `coords` should contain longitudes and the second column latitudes.\n",
"\n",
"In the example below we create lat-lons laid out around the geographic North Pole. These example points are equidistantly spaced, but this does not have to be the case."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9d577c2f-6dca-4b1b-8bdc-1359e6573cda",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import cartopy.crs as ccrs\n",
"\n",
"longitudes = np.linspace(-180, 180, 40)\n",
"latitudes = np.linspace(65, 85, 5) # Very close to north pole\n",
"\n",
"meshgridded_lat_lons = np.meshgrid(longitudes, latitudes)\n",
"coords = np.stack([mg_coord.flatten() for mg_coord in meshgridded_lat_lons], axis=1)\n",
"\n",
"fig, ax = plt.subplots(figsize=(15, 9), subplot_kw={\"projection\": ccrs.PlateCarree()})\n",
"ax.scatter(coords[:, 0], coords[:, 1], marker=\".\")\n",
"ax.coastlines()\n",
"ax.set_extent((-180, 180, -90, 90))"
]
},
{
"cell_type": "markdown",
"id": "4d4f5f35-01bf-4eeb-be52-d7deabbf2039",
"metadata": {},
"source": [
"We first consider what happens if we directly feed these lat-lons as `coords`, treating them as if they were Cartesian coordinates. In this notebook we will only create flat \"Keisler-like\" graphs, but everything works analogously for the other graph types."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8e04abfd-f3e2-4f77-908c-6e2374431e9e",
"metadata": {},
"outputs": [],
"source": [
"import weather_model_graphs as wmg\n",
"\n",
"graph = wmg.create.archetype.create_keisler_graph(coords, mesh_node_distance=10)\n",
"fig, ax = plt.subplots(figsize=(15, 9), subplot_kw={\"projection\": ccrs.PlateCarree()})\n",
"wmg.visualise.nx_draw_with_pos_and_attr(\n",
" graph, ax=ax, node_size=30, edge_color_attr=\"component\", node_color_attr=\"type\"\n",
")\n",
"ax.coastlines()\n",
"ax.set_extent((-180, 180, -90, 90))"
]
},
{
"cell_type": "markdown",
"id": "65b39a86-d64f-46a8-a732-0e608a3fb07f",
"metadata": {},
"source": [
"This creates a useable mesh graph, but we can note a few problems with it:\n",
"\n",
"* There are no connections between nodes around longitude -180/180, i.e. the periodicity of longitude is not considered.\n",
"* All nodes at the top of the plot, close to the pole, are actually very close spatially. Yet there are no connections between them.\n",
"\n",
"These are issues both in the connection between the grid nodes and the mesh, and in the connections between mesh nodes. This points to the fact that we should probably use a different projection when building our graph. "
]
},
{
"cell_type": "markdown",
"id": "103a3784-6ad4-4188-ba02-189f9cf71b2f",
"metadata": {},
"source": [
"## Constructing a graph within a projection\n",
"For our example above, let's instead try to construct the graph based on first projecting our lat-lon coordinates to within a specific projection. This can be done by giving a `projection` argument to the graph creation functions. The projection should be an instance of `cartopy.crs.CRS`. See [the cartopy documentation](https://scitools.org.uk/cartopy/docs/latest/reference/projections.html) for a list of available projections. \n",
"\n",
"We will here try the same thing as above, but using a Azimuthal equidistant projection centered at the pole:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fffd518b-f323-4e24-8544-60edeaaa8bb2",
"metadata": {},
"outputs": [],
"source": [
"# Define our projection\n",
"ae_projection = ccrs.AzimuthalEquidistant(central_latitude=90)\n",
"\n",
"fig, ax = plt.subplots(figsize=(15, 9), subplot_kw={\"projection\": ae_projection})\n",
"ax.scatter(coords[:, 0], coords[:, 1], marker=\".\", transform=ccrs.PlateCarree())\n",
"_ = ax.coastlines()"
]
},
{
"cell_type": "markdown",
"id": "afa6b933-121b-41c4-a341-9e548b92ad87",
"metadata": {},
"source": [
"Note that distances within projections tend to have very large magnitudes, so the distance between mesh nodes should be specified accordingly."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1ddd7ec3-0d66-4feb-a0d3-293f3194dddd",
"metadata": {},
"outputs": [],
"source": [
"mesh_distance = (\n",
" 10**6\n",
") # Large euclidean distance in projection coordinates between mesh nodes\n",
"graph = wmg.create.archetype.create_keisler_graph(\n",
" coords, mesh_node_distance=mesh_distance, projection=ae_projection\n",
") # Note that we here specify the projection argument\n",
"fig, ax = plt.subplots(figsize=(15, 9), subplot_kw={\"projection\": ae_projection})\n",
"wmg.visualise.nx_draw_with_pos_and_attr(\n",
" graph, ax=ax, node_size=30, edge_color_attr=\"component\", node_color_attr=\"type\"\n",
")\n",
"_ = ax.coastlines()"
]
},
{
"cell_type": "markdown",
"id": "f5acf83a-df33-4925-bb32-c106e27e51a4",
"metadata": {},
"source": [
"Now this looks like a more reasonable graph layout, that better respects the spatial relations between the grid points. There are still things that could be tweaked further (e.g. the large number of grid nodes connected to the center mesh node), but this ends our example of defining graphs using lat-lon coordinates."
]
}
],
"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.10.14"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading
Loading