|
36 | 36 | "import geopandas as gpd\n", |
37 | 37 | "import numpy as np\n", |
38 | 38 | "import pandas as pd\n", |
| 39 | + "import pint\n", |
| 40 | + "import pint_pandas\n", |
39 | 41 | "import pygmt\n", |
40 | 42 | "import shapely.geometry\n", |
41 | | - "import tqdm" |
| 43 | + "import tqdm\n", |
| 44 | + "import uncertainties" |
42 | 45 | ] |
43 | 46 | }, |
44 | 47 | { |
|
49 | 52 | }, |
50 | 53 | "outputs": [], |
51 | 54 | "source": [ |
| 55 | + "ureg = pint.UnitRegistry()\n", |
| 56 | + "pint_pandas.PintType.ureg = ureg\n", |
52 | 57 | "tag: str = \"X2SYS\"\n", |
53 | 58 | "os.environ[\"X2SYS_HOME\"] = os.path.abspath(tag)\n", |
54 | 59 | "client = dask.distributed.Client(\n", |
|
111 | 116 | "outputs": [], |
112 | 117 | "source": [ |
113 | 118 | "# Choose one Antarctic active subglacial lake polygon with EPSG:3031 coordinates\n", |
114 | | - "lake_name: str = \"Subglacial Lake Conway\"\n", |
| 119 | + "lake_name: str = \"Whillans 12\"\n", |
115 | 120 | "lake_catalog = deepicedrain.catalog.subglacial_lakes()\n", |
116 | 121 | "lake_ids: list = (\n", |
117 | 122 | " pd.json_normalize(lake_catalog.metadata[\"lakedict\"])\n", |
|
142 | 147 | "source": [ |
143 | 148 | "# Subset data to lake of interest\n", |
144 | 149 | "placename: str = region.name.lower().replace(\" \", \"_\")\n", |
145 | | - "df_lake: pd.DataFrame = region.subset(data=df_dhdt)" |
| 150 | + "df_lake: cudf.DataFrame = region.subset(data=df_dhdt) # bbox subset\n", |
| 151 | + "gdf_lake = gpd.GeoDataFrame(\n", |
| 152 | + " df_lake, geometry=gpd.points_from_xy(x=df_lake.x, y=df_lake.y, crs=3031)\n", |
| 153 | + ")\n", |
| 154 | + "df_lake: pd.DataFrame = df_lake.loc[gdf_lake.within(lake.geometry)] # polygon subset" |
146 | 155 | ] |
147 | 156 | }, |
148 | 157 | { |
|
251 | 260 | { |
252 | 261 | "cell_type": "code", |
253 | 262 | "execution_count": null, |
254 | | - "metadata": { |
255 | | - "lines_to_next_cell": 2 |
256 | | - }, |
| 263 | + "metadata": {}, |
257 | 264 | "outputs": [], |
258 | 265 | "source": [ |
259 | 266 | "# 2D plot of crossover locations\n", |
|
318 | 325 | " stubnames=[\"t\", \"h\"],\n", |
319 | 326 | " j=\"track\",\n", |
320 | 327 | ")\n", |
321 | | - "df_th = df_th.drop_duplicates(ignore_index=True)" |
| 328 | + "df_th: pd.DataFrame = df_th.drop_duplicates(ignore_index=True)\n", |
| 329 | + "df_th: pd.DataFrame = df_th.sort_values(by=\"t\").reset_index(drop=True)" |
322 | 330 | ] |
323 | 331 | }, |
324 | 332 | { |
|
328 | 336 | "outputs": [], |
329 | 337 | "source": [ |
330 | 338 | "# Plot at single location with **maximum** absolute crossover height error (max_h_X)\n", |
331 | | - "df_max = df_th.query(expr=\"x == @max_h_X.x & y == @max_h_X.y\").sort_values(by=\"t\")\n", |
| 339 | + "df_max = df_th.query(expr=\"x == @max_h_X.x & y == @max_h_X.y\")\n", |
332 | 340 | "track1, track2 = df_max.track1_track2.iloc[0].split(\"x\")\n", |
333 | | - "print(f\"{round(max_h_X.h_X, 2)} metres height change at {max_h_X.x}, {max_h_X.y}\")\n", |
| 341 | + "print(f\"{max_h_X.h_X:.2f} metres height change at {max_h_X.x}, {max_h_X.y}\")\n", |
334 | 342 | "plotregion = np.array(\n", |
335 | 343 | " [df_max.t.min(), df_max.t.max(), *pygmt.info(table=df_max[[\"h\"]], spacing=2.5)[:2]]\n", |
336 | 344 | ")\n", |
|
384 | 392 | "metadata": {}, |
385 | 393 | "outputs": [], |
386 | 394 | "source": [ |
387 | | - "# Plot all crossover height points over time over the lake area\n", |
388 | | - "# with height values normalized to 0 from the first observation date\n", |
389 | | - "normfunc = lambda h: h - h.iloc[0] # lambda h: h - h.mean()\n", |
390 | | - "df_th[\"h_norm\"] = df_th.groupby(by=\"track1_track2\").h.transform(func=normfunc)\n", |
391 | | - "\n", |
| 395 | + "# Calculate height anomaly at crossover point as\n", |
| 396 | + "# height at t=n minus height at t=0 (first observation date at crossover point)\n", |
| 397 | + "anomfunc = lambda h: h - h.iloc[0] # lambda h: h - h.mean()\n", |
| 398 | + "df_th[\"h_anom\"] = df_th.groupby(by=\"track1_track2\").h.transform(func=anomfunc)\n", |
| 399 | + "# Calculate ice volume displacement (dvol) in unit metres^3\n", |
| 400 | + "# and rolling mean height anomaly (h_roll) in unit metres\n", |
| 401 | + "surface_area: pint.Quantity = lake.geometry.area * ureg.metre ** 2\n", |
| 402 | + "ice_dvol: pd.Series = deepicedrain.ice_volume_over_time(\n", |
| 403 | + " df_elev=df_th.astype(dtype={\"h_anom\": \"pint[metre]\"}),\n", |
| 404 | + " surface_area=surface_area,\n", |
| 405 | + " time_col=\"t\",\n", |
| 406 | + " outfile=f\"figures/{placename}/ice_dvol_dt_{placename}.txt\",\n", |
| 407 | + ")\n", |
| 408 | + "df_th[\"h_roll\"]: pd.Series = uncertainties.unumpy.nominal_values(\n", |
| 409 | + " arr=ice_dvol.pint.magnitude / surface_area.magnitude\n", |
| 410 | + ")" |
| 411 | + ] |
| 412 | + }, |
| 413 | + { |
| 414 | + "cell_type": "code", |
| 415 | + "execution_count": null, |
| 416 | + "metadata": {}, |
| 417 | + "outputs": [], |
| 418 | + "source": [ |
| 419 | + "# Plot all crossover height point anomalies over time over the lake area\n", |
392 | 420 | "fig = deepicedrain.plot_crossovers(\n", |
393 | 421 | " df=df_th,\n", |
394 | 422 | " regionname=region.name,\n", |
395 | | - " elev_var=\"h_norm\",\n", |
| 423 | + " elev_var=\"h_anom\",\n", |
396 | 424 | " outline_points=f\"figures/{placename}/{placename}.gmt\",\n", |
397 | 425 | ")\n", |
| 426 | + "fig.plot(x=df_th.t, y=df_th.h_roll, pen=\"thick,-\") # plot rolling mean height anomaly\n", |
398 | 427 | "fig.savefig(\n", |
399 | | - " f\"figures/{placename}/crossover_many_normalized_{placename}_{min_date}_{max_date}.png\"\n", |
| 428 | + " f\"figures/{placename}/crossover_anomaly_{placename}_{min_date}_{max_date}.png\"\n", |
| 429 | + ")\n", |
| 430 | + "fig.show()" |
| 431 | + ] |
| 432 | + }, |
| 433 | + { |
| 434 | + "cell_type": "code", |
| 435 | + "execution_count": null, |
| 436 | + "metadata": {}, |
| 437 | + "outputs": [], |
| 438 | + "source": [] |
| 439 | + }, |
| 440 | + { |
| 441 | + "cell_type": "markdown", |
| 442 | + "metadata": {}, |
| 443 | + "source": [ |
| 444 | + "## Combined ice volume displacement plot\n", |
| 445 | + "\n", |
| 446 | + "Showing how subglacial water cascades down a drainage basin!" |
| 447 | + ] |
| 448 | + }, |
| 449 | + { |
| 450 | + "cell_type": "code", |
| 451 | + "execution_count": null, |
| 452 | + "metadata": { |
| 453 | + "lines_to_next_cell": 0 |
| 454 | + }, |
| 455 | + "outputs": [], |
| 456 | + "source": [ |
| 457 | + "fig = pygmt.Figure()\n", |
| 458 | + "fig.basemap(\n", |
| 459 | + " region=f\"2019-02-28/2020-09-30/-0.3/0.5\",\n", |
| 460 | + " frame=[\"wSnE\", \"xaf\", 'yaf+l\"Ice Volume Displacement (km@+3@+)\"'],\n", |
| 461 | + ")\n", |
| 462 | + "pygmt.makecpt(cmap=\"davosS\", color_model=\"+c\", series=(-2, 4, 0.5))\n", |
| 463 | + "for i, (_placename, linestyle) in enumerate(\n", |
| 464 | + " iterable=zip(\n", |
| 465 | + " [\"whillans_ix\", \"subglacial_lake_whillans\", \"whillans_12\", \"whillans_7\"],\n", |
| 466 | + " [\"\", \".-\", \"-\", \"..-\"],\n", |
| 467 | + " )\n", |
| 468 | + "):\n", |
| 469 | + " fig.plot(\n", |
| 470 | + " data=f\"figures/{_placename}/ice_dvol_dt_{_placename}.txt\",\n", |
| 471 | + " cmap=True,\n", |
| 472 | + " pen=f\"thick,{linestyle}\",\n", |
| 473 | + " zvalue=i,\n", |
| 474 | + " label=_placename,\n", |
| 475 | + " columns=\"0,3\", # time column (0), ice_dvol column (3)\n", |
| 476 | + " )\n", |
| 477 | + "fig.text(\n", |
| 478 | + " position=\"TL\",\n", |
| 479 | + " offset=\"j0.2c\",\n", |
| 480 | + " text=\"Whillans Ice Stream Central Catchment active subglacial lakes\",\n", |
400 | 481 | ")\n", |
| 482 | + "fig.legend(position=\"jML+jML+o0.2c\", box=\"+gwhite\")\n", |
| 483 | + "fig.savefig(\"figures/cascade_whillans_ice_stream.png\")\n", |
401 | 484 | "fig.show()" |
402 | 485 | ] |
403 | 486 | }, |
|
0 commit comments