Skip to content

Commit 8820d21

Browse files
Overlay particle trajectories with velocity field vectors+speed color
1 parent 41118e9 commit 8820d21

1 file changed

Lines changed: 4 additions & 7 deletions

File tree

docs/user_guide/examples/tutorial_fesom.ipynb

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"execution_count": null,
2727
"metadata": {},
2828
"outputs": [],
29-
"source": "from pathlib import Path\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport uxarray as ux\n\nimport parcels\nimport parcels.tutorial\nfrom parcels.convert import fesom_to_ugrid"
29+
"source": "from pathlib import Path\n\nimport matplotlib.pyplot as plt\nimport matplotlib.tri as mtri\nimport numpy as np\nimport uxarray as ux\n\nimport parcels\nimport parcels.tutorial"
3030
},
3131
{
3232
"cell_type": "markdown",
@@ -113,10 +113,7 @@
113113
"execution_count": null,
114114
"metadata": {},
115115
"outputs": [],
116-
"source": [
117-
"ds = fesom_to_ugrid(ds)\n",
118-
"print(\"dims:\", dict(ds.sizes))"
119-
]
116+
"source": "ds = parcels.convert.fesom_to_ugrid(ds)\nprint(\"dims:\", dict(ds.sizes))"
120117
},
121118
{
122119
"cell_type": "markdown",
@@ -163,14 +160,14 @@
163160
{
164161
"cell_type": "markdown",
165162
"metadata": {},
166-
"source": "## Plot the result\n\nEach particle trajectory is coloured by observation time so we can follow how the particles drift through the FESOM2 velocity field:"
163+
"source": "## Plot the velocity field and trajectories\n\nWe plot the particle paths on top of the velocity field they advect through: triangle colour shows the speed at the release depth (≈50 m), black arrows show the velocity at face centres (drawn in lon/lat space, length proportional to speed), grey lines trace each particle's path, and the coloured dots mark the positions over time. Drawing the arrows with `angles=\"xy\"` keeps them aligned with the trajectories, so you can see the particles streak along the fast jets and barely move in the quiet bands between them:"
167164
},
168165
{
169166
"cell_type": "code",
170167
"execution_count": null,
171168
"metadata": {},
172169
"outputs": [],
173-
"source": "df = parcels.read_particlefile(\"output-fesom.parquet\")\n\nfig, ax = plt.subplots(figsize=(10, 5))\nax.scatter(lon, lat, facecolors=\"none\", edgecolors=\"k\", s=60, label=\"release\")\nsc = ax.scatter(df[\"lon\"], df[\"lat\"], c=df[\"time\"].dt.total_seconds(), s=8, cmap=\"viridis\")\nfig.colorbar(sc, ax=ax, label=\"time since release [s]\")\nax.set_xlabel(\"Longitude [deg E]\")\nax.set_ylabel(\"Latitude [deg N]\")\nax.legend(loc=\"upper right\")\nplt.show()"
170+
"source": "df = parcels.read_particlefile(\"output-fesom.parquet\")\n\ntriang = mtri.Triangulation(\n ds.uxgrid.node_lon.values,\n ds.uxgrid.node_lat.values,\n triangles=ds.uxgrid.face_node_connectivity.values,\n)\n\ndepth_idx = int(np.argmin(np.abs(ds.zc.values - 50.0)))\nU_face = np.asarray(ds[\"U\"].isel(zc=depth_idx)).squeeze()\nV_face = np.asarray(ds[\"V\"].isel(zc=depth_idx)).squeeze()\nspeed = np.hypot(U_face, V_face)\n\nfig, ax = plt.subplots(figsize=(11, 5))\n\n# Background: speed at the release depth.\ntpc = ax.tripcolor(triang, facecolors=speed, shading=\"flat\", cmap=\"Blues\")\nfig.colorbar(tpc, ax=ax, label=\"speed [m/s]\", location=\"left\", shrink=0.85)\n\n# Velocity arrows at face centres. Drawing in lon/lat space (angles/scale_units\n# \"xy\") keeps the arrows aligned with the trajectories; length tracks speed.\nstep = max(1, U_face.size // 400)\nxf = ds.uxgrid.face_lon.values\nyf = ds.uxgrid.face_lat.values\nmax_speed = float(np.nanmax(speed))\nq = ax.quiver(\n xf[::step], yf[::step], U_face[::step], V_face[::step],\n angles=\"xy\", scale_units=\"xy\", scale=max_speed / 0.3,\n color=\"k\", width=0.0018, pivot=\"tail\",\n)\nax.quiverkey(q, 0.86, 1.04, max_speed, f\"{max_speed:.2f} m/s\", labelpos=\"E\", coordinates=\"axes\")\n\n# Particle paths (grey lines) and positions coloured by time.\nfor traj in df.sort(\"time\").partition_by(\"particle_id\"):\n ax.plot(traj[\"lon\"], traj[\"lat\"], color=\"0.4\", linewidth=0.6, alpha=0.7, zorder=2)\nax.scatter(lon, lat, facecolors=\"none\", edgecolors=\"k\", s=60, label=\"release\", zorder=3)\nsc = ax.scatter(\n df[\"lon\"], df[\"lat\"], c=df[\"time\"].dt.total_seconds(), s=6, cmap=\"viridis\", zorder=3,\n)\nfig.colorbar(sc, ax=ax, label=\"time since release [s]\", shrink=0.85)\n\nax.set_xlabel(\"Longitude [deg E]\")\nax.set_ylabel(\"Latitude [deg N]\")\nax.set_title(f\"FESOM2 velocity at z ≈ {float(ds.zc.values[depth_idx]):.1f} m with particle trajectories\")\nax.legend(loc=\"upper right\")\nplt.show()"
174171
},
175172
{
176173
"cell_type": "markdown",

0 commit comments

Comments
 (0)