anta-database 0.4.1__tar.gz → 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {anta_database-0.4.1 → anta_database-0.4.2}/PKG-INFO +1 -1
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/__init__.py +2 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/database/database.py +8 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/plotting/__init__.py +2 -1
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/plotting/plotting.py +29 -26
- anta_database-0.4.2/anta_database/plotting/plotting_pism.py +859 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database.egg-info/PKG-INFO +1 -1
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database.egg-info/SOURCES.txt +1 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database.egg-info/scm_file_list.json +1 -0
- anta_database-0.4.2/anta_database.egg-info/scm_version.json +8 -0
- anta_database-0.4.1/anta_database.egg-info/scm_version.json +0 -8
- {anta_database-0.4.1 → anta_database-0.4.2}/.github/workflows/deploy.yml +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/.github/workflows/release.yml +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/.gitignore +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/LICENSE +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/README.md +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/ROADMAP.md +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/compiling/__init__.py +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/compiling/compile.py +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/compiling/reconnect.py +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/compiling/zarr_converter_simple.py +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.cpg +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.dbf +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.parquet +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.prj +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.shp +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.shx +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/GL.parquet +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coords_basins.cpg +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coords_basins.dbf +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coords_basins.prj +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coords_basins.shp +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coords_basins.shx +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coors_basins.parquet +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/convert_data.py +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ice-core-coordinates.csv +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/site-coords.parquet +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/database/__init__.py +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/figures/AntA_38ka.png +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/indexing/__init__.py +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/indexing/index_database.py +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/test_interactive.py +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/test_interactive_full.py +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database.egg-info/dependency_links.txt +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database.egg-info/requires.txt +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/anta_database.egg-info/top_level.txt +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/book/_config.yml +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/book/_toc.yml +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/book/advanced.md +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/book/contact.md +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/book/contribute.md +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/book/figures/Overview_all.png +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/book/intro.md +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/book/logo.png +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/book/pism_example.ipynb +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/book/quick_start.ipynb +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/book/references.bib +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/book/requirements.txt +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/pyproject.toml +0 -0
- {anta_database-0.4.1 → anta_database-0.4.2}/setup.cfg +0 -0
|
@@ -16,6 +16,7 @@ from .indexing.index_database import IndexDatabase
|
|
|
16
16
|
|
|
17
17
|
# Plotting modules
|
|
18
18
|
from .plotting.plotting import Plotting
|
|
19
|
+
from .plotting.plotting_pism import PISMPlotting
|
|
19
20
|
|
|
20
21
|
__all__ = [
|
|
21
22
|
# Database classes
|
|
@@ -27,4 +28,5 @@ __all__ = [
|
|
|
27
28
|
"IndexDatabase",
|
|
28
29
|
# Plotting functions
|
|
29
30
|
"Plotting",
|
|
31
|
+
"PISMPlotting",
|
|
30
32
|
]
|
|
@@ -8,6 +8,7 @@ from typing import Union, List, Dict, Tuple, Optional, Generator
|
|
|
8
8
|
from tqdm import tqdm
|
|
9
9
|
|
|
10
10
|
from anta_database.plotting.plotting import Plotting
|
|
11
|
+
from anta_database.plotting.plotting_pism import PISMPlotting
|
|
11
12
|
from anta_database.indexing.index_database import IndexDatabase
|
|
12
13
|
|
|
13
14
|
|
|
@@ -25,6 +26,7 @@ class Database:
|
|
|
25
26
|
self._file_db_path = os.path.join(self._db_dir, file_db)
|
|
26
27
|
self._md = None
|
|
27
28
|
self._plotting = None
|
|
29
|
+
self._pism_plotting = None
|
|
28
30
|
self._max_displayed_flight_ids = max_displayed_flight_ids
|
|
29
31
|
self._include_BM = include_BEDMAP
|
|
30
32
|
self._include_BM = index_database
|
|
@@ -981,6 +983,12 @@ class Database:
|
|
|
981
983
|
self._plotting = Plotting(self)
|
|
982
984
|
return self._plotting
|
|
983
985
|
|
|
986
|
+
@property
|
|
987
|
+
def plot_PISM(self):
|
|
988
|
+
if self._pism_plotting is None:
|
|
989
|
+
self._pism_plotting = PISMPlotting(self)
|
|
990
|
+
return self._pism_plotting
|
|
991
|
+
|
|
984
992
|
|
|
985
993
|
class MetadataResult:
|
|
986
994
|
def __init__(self, metadata, max_displayed_flight_ids):
|
|
@@ -241,7 +241,7 @@ class Plotting:
|
|
|
241
241
|
mini_map=mini_map,
|
|
242
242
|
)
|
|
243
243
|
|
|
244
|
-
def
|
|
244
|
+
def stratigraphy(
|
|
245
245
|
self,
|
|
246
246
|
metadata: Union[None, Dict, "MetadataResult"] = None,
|
|
247
247
|
elevation: Optional[bool] = False,
|
|
@@ -263,7 +263,7 @@ class Plotting:
|
|
|
263
263
|
Plot the color-coded values of the given variable on Antarcitic map
|
|
264
264
|
"""
|
|
265
265
|
self._base_plot(
|
|
266
|
-
color_by="
|
|
266
|
+
color_by="stratigraphy",
|
|
267
267
|
elevation=elevation,
|
|
268
268
|
metadata=metadata,
|
|
269
269
|
downsampling_factor=downsampling_factor,
|
|
@@ -334,12 +334,12 @@ class Plotting:
|
|
|
334
334
|
# else: FIXME: this seems to crash spyder for spyder users
|
|
335
335
|
# matplotlib.use('TkAgg')
|
|
336
336
|
|
|
337
|
-
fig, ax = plt.subplots()
|
|
337
|
+
fig, ax = plt.subplots(constrained_layout=True)
|
|
338
338
|
|
|
339
339
|
if basins:
|
|
340
340
|
grounding_line = False
|
|
341
341
|
# --- Plot Grounding Line ---
|
|
342
|
-
if True and color_by != "
|
|
342
|
+
if True and color_by != "stratigraphy": # FIXME
|
|
343
343
|
gl = pd.read_parquet(self._gl_path)
|
|
344
344
|
ax.plot(gl.x / 1000, gl.y / 1000, linewidth=1, color="k")
|
|
345
345
|
|
|
@@ -365,8 +365,8 @@ class Plotting:
|
|
|
365
365
|
xmin, xmax = xlim
|
|
366
366
|
ymin, ymax = ylim
|
|
367
367
|
|
|
368
|
-
if color_by == "
|
|
369
|
-
mini_map=False
|
|
368
|
+
if color_by == "stratigraphy":
|
|
369
|
+
mini_map = False
|
|
370
370
|
|
|
371
371
|
inset_pos = [0.7, 0.75, 0.25, 0.25]
|
|
372
372
|
inset = fig.add_axes(
|
|
@@ -509,6 +509,7 @@ class Plotting:
|
|
|
509
509
|
color=colors[institute],
|
|
510
510
|
s=marker_size,
|
|
511
511
|
linewidths=0,
|
|
512
|
+
zorder=10,
|
|
512
513
|
)
|
|
513
514
|
|
|
514
515
|
ax.plot([], [], color=colors[institute], label=institute, linewidth=3)
|
|
@@ -599,7 +600,7 @@ class Plotting:
|
|
|
599
600
|
subset["PSX"] / 1000,
|
|
600
601
|
subset["PSY"] / 1000,
|
|
601
602
|
color="darkgreen",
|
|
602
|
-
s=marker_size*0.5,
|
|
603
|
+
s=marker_size * 0.5,
|
|
603
604
|
linewidths=0,
|
|
604
605
|
zorder=11,
|
|
605
606
|
)
|
|
@@ -661,7 +662,7 @@ class Plotting:
|
|
|
661
662
|
df["PSX"] / 1000,
|
|
662
663
|
df["PSY"] / 1000,
|
|
663
664
|
color="darkgreen",
|
|
664
|
-
s=marker_size*0.5,
|
|
665
|
+
s=marker_size * 0.5,
|
|
665
666
|
linewidths=0,
|
|
666
667
|
zorder=11,
|
|
667
668
|
)
|
|
@@ -710,12 +711,12 @@ class Plotting:
|
|
|
710
711
|
df["PSX"] / 1000,
|
|
711
712
|
df["PSY"] / 1000,
|
|
712
713
|
color="darkgreen",
|
|
713
|
-
s=marker_size*0.5,
|
|
714
|
+
s=marker_size * 0.5,
|
|
714
715
|
linewidths=0,
|
|
715
716
|
zorder=11,
|
|
716
717
|
)
|
|
717
718
|
|
|
718
|
-
if color_by == "
|
|
719
|
+
if color_by == "stratigraphy":
|
|
719
720
|
flight_id = list(metadata["flight_id"])
|
|
720
721
|
if len(flight_id) > 1:
|
|
721
722
|
flight_id = flight_id[0]
|
|
@@ -806,14 +807,17 @@ class Plotting:
|
|
|
806
807
|
ax.plot([], [], color="grey", label="Surface Elevation", linewidth=3)
|
|
807
808
|
|
|
808
809
|
else:
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
810
|
+
if "ICE_THK" in ds.variables:
|
|
811
|
+
scatter = ax.scatter(
|
|
812
|
+
ds.Distance / 1000,
|
|
813
|
+
ds.ICE_THK,
|
|
814
|
+
color="k",
|
|
815
|
+
s=marker_size,
|
|
816
|
+
linewidths=0.1,
|
|
817
|
+
)
|
|
818
|
+
ax.plot([], [], color="k", label="Bed Depth", linewidth=3)
|
|
819
|
+
else:
|
|
820
|
+
print("Cannot plot Bed Depth from the variables in the file")
|
|
817
821
|
|
|
818
822
|
if elevation:
|
|
819
823
|
ylim = (
|
|
@@ -874,6 +878,7 @@ class Plotting:
|
|
|
874
878
|
color=colors[flight_id],
|
|
875
879
|
s=marker_size,
|
|
876
880
|
linewidths=0,
|
|
881
|
+
zorder=10,
|
|
877
882
|
)
|
|
878
883
|
|
|
879
884
|
ax.plot([], [], color=colors[flight_id], label=flight_id, linewidth=3)
|
|
@@ -892,10 +897,10 @@ class Plotting:
|
|
|
892
897
|
if not self._disable_tqdm:
|
|
893
898
|
print("Formatting ...")
|
|
894
899
|
|
|
895
|
-
if color_by == "
|
|
900
|
+
if color_by == "stratigraphy":
|
|
896
901
|
xmin, xmax = xlim
|
|
897
902
|
ymin, ymax = ylim
|
|
898
|
-
|
|
903
|
+
|
|
899
904
|
elif auto_zoom:
|
|
900
905
|
xmin = xmin - 10 if xmin is not None else None
|
|
901
906
|
xmax = xmax + 10 if xmax is not None else None
|
|
@@ -904,7 +909,7 @@ class Plotting:
|
|
|
904
909
|
|
|
905
910
|
ax.set_xlim(xmin, xmax)
|
|
906
911
|
ax.set_ylim(ymin, ymax)
|
|
907
|
-
if color_by != "
|
|
912
|
+
if color_by != "stratigraphy":
|
|
908
913
|
x0_ax, x1_ax = ax.get_xlim()
|
|
909
914
|
y0_ax, y1_ax = ax.get_ylim()
|
|
910
915
|
x0 = x0_ax if xlim[0] == None else xlim[0]
|
|
@@ -962,7 +967,7 @@ class Plotting:
|
|
|
962
967
|
cbar.ax.xaxis.set_ticks_position("bottom")
|
|
963
968
|
if label:
|
|
964
969
|
cbar.set_label(label)
|
|
965
|
-
elif color_by == "
|
|
970
|
+
elif color_by == "stratigraphy":
|
|
966
971
|
ax.legend(ncols=2)
|
|
967
972
|
ax.set_xlabel("Distance along transect [km]")
|
|
968
973
|
if elevation:
|
|
@@ -971,10 +976,8 @@ class Plotting:
|
|
|
971
976
|
ax.set_ylabel("Depth below surface [m]")
|
|
972
977
|
plt.gcf().set_size_inches(10 * scale_factor, 10 * 2 / 3)
|
|
973
978
|
|
|
974
|
-
plt.tight_layout()
|
|
975
|
-
|
|
976
979
|
# --- Plot IMBIE basins ---
|
|
977
|
-
if basins and color_by != "
|
|
980
|
+
if basins and color_by != "stratigraphy":
|
|
978
981
|
sf_basins = shapefile.Reader(self._imbie_path)
|
|
979
982
|
basin_patches = []
|
|
980
983
|
|
|
@@ -1074,7 +1077,7 @@ class Plotting:
|
|
|
1074
1077
|
inset.remove()
|
|
1075
1078
|
|
|
1076
1079
|
# --- Plot ice core sites ---
|
|
1077
|
-
if stations and color_by != "
|
|
1080
|
+
if stations and color_by != "stratigraphy":
|
|
1078
1081
|
site_coords = pd.read_parquet(self._site_coords_path)
|
|
1079
1082
|
for i in site_coords.index:
|
|
1080
1083
|
site = site_coords.loc[i]
|
|
@@ -0,0 +1,859 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import h5py
|
|
3
|
+
import pandas as pd
|
|
4
|
+
import numpy as np
|
|
5
|
+
import matplotlib.pyplot as plt
|
|
6
|
+
from scipy.interpolate import griddata
|
|
7
|
+
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
|
8
|
+
from matplotlib.colors import BoundaryNorm, ListedColormap, LinearSegmentedColormap
|
|
9
|
+
import shapefile
|
|
10
|
+
from matplotlib.patches import Polygon
|
|
11
|
+
from matplotlib.collections import PatchCollection
|
|
12
|
+
from matplotlib import patheffects as path_effects
|
|
13
|
+
import colormaps as cmaps
|
|
14
|
+
from contextlib import contextmanager
|
|
15
|
+
from typing import Union, Dict, TYPE_CHECKING, Optional
|
|
16
|
+
from tqdm import tqdm
|
|
17
|
+
from importlib.resources import files
|
|
18
|
+
from multiprocessing import Pool, cpu_count
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from anta_database.database.database import Database, MetadataResult
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PISMPlotting:
|
|
25
|
+
def __init__(self, database_instance: "Database") -> None:
|
|
26
|
+
self._db = database_instance
|
|
27
|
+
self._gl_path = files("anta_database.data").joinpath("GL.parquet")
|
|
28
|
+
self._site_coords_path = files("anta_database.data").joinpath(
|
|
29
|
+
"site-coords.parquet"
|
|
30
|
+
)
|
|
31
|
+
self._imbie_path = files("anta_database.data").joinpath(
|
|
32
|
+
"ANT_Basins_IMBIE2_v1.6.shp"
|
|
33
|
+
)
|
|
34
|
+
self._center_coords = files("anta_database.data").joinpath(
|
|
35
|
+
"centeroid_coords_basins.shp"
|
|
36
|
+
)
|
|
37
|
+
self._disable_tqdm = os.getenv("JUPYTER_BOOK_BUILD", False)
|
|
38
|
+
|
|
39
|
+
def _pre_plot_check(
|
|
40
|
+
self, metadata: Union[None, Dict, "MetadataResult"] = None
|
|
41
|
+
) -> bool:
|
|
42
|
+
|
|
43
|
+
if not metadata["age"] and not metadata["var"]:
|
|
44
|
+
print(
|
|
45
|
+
"Result from query provided is empty: nothing to plot. Please ensure that the query returns either valid age or var."
|
|
46
|
+
)
|
|
47
|
+
return False
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
def _is_notebook(self) -> bool:
|
|
51
|
+
try:
|
|
52
|
+
shell = get_ipython().__class__.__name__
|
|
53
|
+
if shell == "ZMQInteractiveShell":
|
|
54
|
+
return True # Jupyter notebook or qtconsole
|
|
55
|
+
elif shell == "TerminalInteractiveShell":
|
|
56
|
+
return False # Terminal running IPython
|
|
57
|
+
else:
|
|
58
|
+
return False # Other type (?)
|
|
59
|
+
except NameError:
|
|
60
|
+
return False # Probably standard Python interpreter
|
|
61
|
+
|
|
62
|
+
def _custom_cmap(self, reversed_: bool = False):
|
|
63
|
+
cm1 = cmaps.torch_r
|
|
64
|
+
cm2 = cmaps.deep_r
|
|
65
|
+
cm1_colors = cm1(np.linspace(0.15, 0.8, 256))
|
|
66
|
+
cm2_colors = cm2(np.linspace(0.1, 0.9, 256))
|
|
67
|
+
combined_colors = np.vstack((cm1_colors, cm2_colors))
|
|
68
|
+
custom_cmap = LinearSegmentedColormap.from_list(
|
|
69
|
+
"custom_cmap", combined_colors, N=512
|
|
70
|
+
)
|
|
71
|
+
return custom_cmap.reversed() if reversed_ else custom_cmap
|
|
72
|
+
|
|
73
|
+
def _custom_cmap_density(self):
|
|
74
|
+
return self._custom_cmap(reversed_=True)
|
|
75
|
+
|
|
76
|
+
def stratigraphy(
|
|
77
|
+
self,
|
|
78
|
+
PISM_file: str,
|
|
79
|
+
metadata: Union[None, Dict, "MetadataResult"] = None,
|
|
80
|
+
elevation: Optional[bool] = False,
|
|
81
|
+
downsampling_factor: Optional[int] = None,
|
|
82
|
+
cpus: int = 2,
|
|
83
|
+
firn_correction: Optional[int] = 31,
|
|
84
|
+
title: Optional[str] = None,
|
|
85
|
+
xlim: Optional[tuple] = (None, None),
|
|
86
|
+
ylim: Optional[tuple] = (None, None),
|
|
87
|
+
scale_factor: float = 1.0,
|
|
88
|
+
marker_size: Optional[float] = 2,
|
|
89
|
+
cmap: Optional["LinearSegmentedColormap"] = None,
|
|
90
|
+
grounding_line: Optional[bool] = True,
|
|
91
|
+
basins: Optional[bool] = True,
|
|
92
|
+
stations: Optional[bool] = True,
|
|
93
|
+
save: Optional[str] = None,
|
|
94
|
+
auto_zoom: Optional[bool] = True,
|
|
95
|
+
mini_map: Optional[bool] = True,
|
|
96
|
+
) -> None:
|
|
97
|
+
"""
|
|
98
|
+
Plot the color-coded values of the given variable on Antarcitic map
|
|
99
|
+
"""
|
|
100
|
+
self._base_plot(
|
|
101
|
+
color_by="stratigraphy",
|
|
102
|
+
PISM_file=PISM_file,
|
|
103
|
+
elevation=elevation,
|
|
104
|
+
metadata=metadata,
|
|
105
|
+
downsampling_factor=downsampling_factor,
|
|
106
|
+
cpus=cpus,
|
|
107
|
+
firn_correction=firn_correction,
|
|
108
|
+
title=title,
|
|
109
|
+
xlim=xlim,
|
|
110
|
+
ylim=ylim,
|
|
111
|
+
scale_factor=scale_factor,
|
|
112
|
+
marker_size=marker_size,
|
|
113
|
+
cmap=cmap,
|
|
114
|
+
grounding_line=grounding_line,
|
|
115
|
+
basins=basins,
|
|
116
|
+
stations=stations,
|
|
117
|
+
save=save,
|
|
118
|
+
auto_zoom=auto_zoom,
|
|
119
|
+
mini_map=mini_map,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def mismatch_2D(
|
|
123
|
+
self,
|
|
124
|
+
PISM_file: str,
|
|
125
|
+
metadata: Union[None, Dict, "MetadataResult"] = None,
|
|
126
|
+
elevation: Optional[bool] = False,
|
|
127
|
+
downsampling_factor: Optional[int] = None,
|
|
128
|
+
cpus: int = 2,
|
|
129
|
+
firn_correction: Optional[int] = 31,
|
|
130
|
+
title: Optional[str] = None,
|
|
131
|
+
xlim: Optional[tuple] = (None, None),
|
|
132
|
+
ylim: Optional[tuple] = (None, None),
|
|
133
|
+
vmin: Optional[int] = -400,
|
|
134
|
+
vmax: Optional[int] = 400,
|
|
135
|
+
scale_factor: float = 1.0,
|
|
136
|
+
marker_size: Optional[float] = 2,
|
|
137
|
+
cmap: Optional["LinearSegmentedColormap"] = None,
|
|
138
|
+
grounding_line: Optional[bool] = True,
|
|
139
|
+
basins: Optional[bool] = True,
|
|
140
|
+
stations: Optional[bool] = True,
|
|
141
|
+
save: Optional[str] = None,
|
|
142
|
+
auto_zoom: Optional[bool] = True,
|
|
143
|
+
mini_map: Optional[bool] = True,
|
|
144
|
+
) -> None:
|
|
145
|
+
"""
|
|
146
|
+
Plot the color-coded values of the given variable on Antarcitic map
|
|
147
|
+
"""
|
|
148
|
+
self._base_plot(
|
|
149
|
+
color_by="mismatch_2D",
|
|
150
|
+
PISM_file=PISM_file,
|
|
151
|
+
elevation=elevation,
|
|
152
|
+
metadata=metadata,
|
|
153
|
+
downsampling_factor=downsampling_factor,
|
|
154
|
+
cpus=cpus,
|
|
155
|
+
firn_correction=firn_correction,
|
|
156
|
+
title=title,
|
|
157
|
+
xlim=xlim,
|
|
158
|
+
ylim=ylim,
|
|
159
|
+
vmin=vmin,
|
|
160
|
+
vmax=vmax,
|
|
161
|
+
scale_factor=scale_factor,
|
|
162
|
+
marker_size=marker_size,
|
|
163
|
+
cmap=cmap,
|
|
164
|
+
grounding_line=grounding_line,
|
|
165
|
+
basins=basins,
|
|
166
|
+
stations=stations,
|
|
167
|
+
save=save,
|
|
168
|
+
auto_zoom=auto_zoom,
|
|
169
|
+
mini_map=mini_map,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
@contextmanager
|
|
173
|
+
def _plot_context(self, close=None):
|
|
174
|
+
if close is None:
|
|
175
|
+
close = not self._is_notebook()
|
|
176
|
+
try:
|
|
177
|
+
yield
|
|
178
|
+
finally:
|
|
179
|
+
if close:
|
|
180
|
+
plt.close()
|
|
181
|
+
|
|
182
|
+
def _process_mismatch(self, args) -> Union[None, pd.DataFrame]:
|
|
183
|
+
(
|
|
184
|
+
pism_ds,
|
|
185
|
+
f,
|
|
186
|
+
metadata,
|
|
187
|
+
) = args
|
|
188
|
+
|
|
189
|
+
X_ds, Y_ds = np.meshgrid(pism_ds.x, pism_ds.y)
|
|
190
|
+
pism_points = np.column_stack((X_ds.flatten(), Y_ds.flatten()))
|
|
191
|
+
|
|
192
|
+
full_path = os.path.join(self._db._db_dir, f)
|
|
193
|
+
all_psx = []
|
|
194
|
+
all_psy = []
|
|
195
|
+
all_depth_diff = []
|
|
196
|
+
|
|
197
|
+
with h5py.File(full_path, "r") as irh:
|
|
198
|
+
dataset = irh.attrs["dataset"]
|
|
199
|
+
flight_id = irh.attrs["flight ID"]
|
|
200
|
+
if self.elevation:
|
|
201
|
+
if "SURF_ELEV" not in irh.keys():
|
|
202
|
+
print(
|
|
203
|
+
"SURF_ELEV not in",
|
|
204
|
+
flight_id,
|
|
205
|
+
"for",
|
|
206
|
+
dataset,
|
|
207
|
+
": cannot compute IRH elevation. Stopping the process here.",
|
|
208
|
+
)
|
|
209
|
+
return
|
|
210
|
+
irh_values = irh["IRH_AGE"][:]
|
|
211
|
+
for age in metadata["age"]:
|
|
212
|
+
irh_index = np.where(irh_values == int(age))[0]
|
|
213
|
+
if len(irh_index) > 0:
|
|
214
|
+
irh_depth = irh["IRH_DEPTH"]
|
|
215
|
+
|
|
216
|
+
PSX_values = irh["PSX"][:: self.downsampling_factor]
|
|
217
|
+
PSY_values = irh["PSY"][:: self.downsampling_factor]
|
|
218
|
+
fl_depth = irh_depth[:: self.downsampling_factor, irh_index[0]]
|
|
219
|
+
|
|
220
|
+
all_psx.extend(PSX_values)
|
|
221
|
+
all_psy.extend(PSY_values)
|
|
222
|
+
|
|
223
|
+
age_seconds = -(int(age) + self.age_offset) * 3600 * 24 * 365
|
|
224
|
+
fl_line_xy = np.column_stack((PSX_values, PSY_values))
|
|
225
|
+
|
|
226
|
+
ds_depth_interp = griddata(
|
|
227
|
+
pism_points,
|
|
228
|
+
pism_ds.isochronal_layer_depth.sel(
|
|
229
|
+
deposition_time=age_seconds
|
|
230
|
+
).values.flatten(),
|
|
231
|
+
fl_line_xy,
|
|
232
|
+
method="linear",
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
if self.elevation:
|
|
236
|
+
pism_usurf_interp = griddata(
|
|
237
|
+
pism_points,
|
|
238
|
+
pism_ds.usurf.values.flatten(),
|
|
239
|
+
fl_line_xy,
|
|
240
|
+
method="linear",
|
|
241
|
+
)
|
|
242
|
+
ds_depth_interp = pism_usurf_interp - ds_depth_interp
|
|
243
|
+
|
|
244
|
+
fl_depth = (
|
|
245
|
+
irh["SURF_ELEV"][:: self.downsampling_factor] - fl_depth
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
results = ds_depth_interp + self.firn_correction - fl_depth
|
|
249
|
+
|
|
250
|
+
all_depth_diff.extend(results)
|
|
251
|
+
|
|
252
|
+
df = pd.DataFrame(
|
|
253
|
+
{"PSX": all_psx, "PSY": all_psy, "IRH_DEPTH_DIFF": all_depth_diff}
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
return df.dropna()
|
|
257
|
+
|
|
258
|
+
def _base_plot(
|
|
259
|
+
self,
|
|
260
|
+
PISM_file: str,
|
|
261
|
+
metadata: Union[None, Dict, "MetadataResult"] = None,
|
|
262
|
+
elevation: Optional[bool] = False,
|
|
263
|
+
fraction_depth: Optional[bool] = False,
|
|
264
|
+
downsampling_factor: Optional[int] = None,
|
|
265
|
+
age_offset: Optional[int] = -1950,
|
|
266
|
+
firn_correction: Optional[int] = 31,
|
|
267
|
+
cpus: int = 4,
|
|
268
|
+
title: Optional[str] = None,
|
|
269
|
+
xlim: Optional[tuple] = (None, None),
|
|
270
|
+
ylim: Optional[tuple] = (None, None),
|
|
271
|
+
vmin: Optional[float] = None,
|
|
272
|
+
vmax: Optional[float] = None,
|
|
273
|
+
scale_factor: float = 1.0,
|
|
274
|
+
marker_size: Optional[float] = 0.1,
|
|
275
|
+
save: Optional[str] = None,
|
|
276
|
+
auto_zoom: Optional[bool] = True,
|
|
277
|
+
mini_map: Optional[bool] = True,
|
|
278
|
+
color_by: str = "dataset", # 'dataset', 'flight_id', 'depth', 'density'
|
|
279
|
+
cmap: Optional["LinearSegmentedColormap"] = None,
|
|
280
|
+
grounding_line: Optional[bool] = True,
|
|
281
|
+
basins: Optional[bool] = True,
|
|
282
|
+
stations: Optional[bool] = True,
|
|
283
|
+
ncol: Optional[int] = None,
|
|
284
|
+
) -> None:
|
|
285
|
+
# --- Setup ---
|
|
286
|
+
if metadata is None:
|
|
287
|
+
if hasattr(self._db, "_md") and self._db._md:
|
|
288
|
+
metadata = self._db._md
|
|
289
|
+
else:
|
|
290
|
+
print(
|
|
291
|
+
"Please provide metadata of the files you want to generate the data from..."
|
|
292
|
+
)
|
|
293
|
+
return
|
|
294
|
+
|
|
295
|
+
total_traces = len(metadata["flight_id"])
|
|
296
|
+
|
|
297
|
+
if not self._pre_plot_check(metadata):
|
|
298
|
+
return
|
|
299
|
+
|
|
300
|
+
self.age_offset = age_offset
|
|
301
|
+
self.downsampling_factor = downsampling_factor
|
|
302
|
+
self.firn_correction = firn_correction
|
|
303
|
+
self.elevation = elevation
|
|
304
|
+
|
|
305
|
+
# if save:
|
|
306
|
+
# matplotlib.use('Agg')
|
|
307
|
+
# else: FIXME: this seems to crash spyder for spyder users
|
|
308
|
+
# matplotlib.use('TkAgg')
|
|
309
|
+
|
|
310
|
+
fig, ax = plt.subplots(constrained_layout=True)
|
|
311
|
+
|
|
312
|
+
if basins:
|
|
313
|
+
grounding_line = False
|
|
314
|
+
# --- Plot Grounding Line ---
|
|
315
|
+
if True and color_by != "stratigraphy": # FIXME
|
|
316
|
+
gl = pd.read_parquet(self._gl_path)
|
|
317
|
+
ax.plot(gl.x / 1000, gl.y / 1000, linewidth=1, color="k")
|
|
318
|
+
|
|
319
|
+
# --- Plot Data ---
|
|
320
|
+
colors = {}
|
|
321
|
+
scatter = None
|
|
322
|
+
values = None
|
|
323
|
+
label = None
|
|
324
|
+
extend = None
|
|
325
|
+
|
|
326
|
+
if auto_zoom and (
|
|
327
|
+
xlim[0] is not None
|
|
328
|
+
or xlim[1] is not None
|
|
329
|
+
or ylim[0] is not None
|
|
330
|
+
or ylim[1] is not None
|
|
331
|
+
):
|
|
332
|
+
auto_zoom = False
|
|
333
|
+
|
|
334
|
+
if auto_zoom:
|
|
335
|
+
xmin, xmax = None, None
|
|
336
|
+
ymin, ymax = None, None
|
|
337
|
+
else:
|
|
338
|
+
xmin, xmax = xlim
|
|
339
|
+
ymin, ymax = ylim
|
|
340
|
+
|
|
341
|
+
if color_by == "stratigraphy":
|
|
342
|
+
mini_map = False
|
|
343
|
+
|
|
344
|
+
inset_pos = [0.7, 0.75, 0.25, 0.25]
|
|
345
|
+
inset = fig.add_axes(
|
|
346
|
+
inset_pos, # [left, bottom, width, height] in figure coordinates
|
|
347
|
+
)
|
|
348
|
+
inset.set_xlim(-2700, 2700)
|
|
349
|
+
inset.set_ylim(-2700, 2700)
|
|
350
|
+
inset.set_facecolor("none")
|
|
351
|
+
|
|
352
|
+
if color_by == "mismatch_2D":
|
|
353
|
+
if cmap == None:
|
|
354
|
+
if elevation:
|
|
355
|
+
cmap = "RdBu"
|
|
356
|
+
else:
|
|
357
|
+
cmap = "RdBu_r"
|
|
358
|
+
|
|
359
|
+
if len(metadata["age"]) > 1:
|
|
360
|
+
print("\nWARNING: found multiple ages in query:", metadata["age"])
|
|
361
|
+
import xarray as xr
|
|
362
|
+
|
|
363
|
+
pism_ds = xr.open_dataset(PISM_file, decode_times=False)
|
|
364
|
+
pism_ds = pism_ds.isel(
|
|
365
|
+
deposition_time=np.unique(pism_ds.deposition_time, return_index=True)[1]
|
|
366
|
+
)
|
|
367
|
+
X_ds, Y_ds = np.meshgrid(pism_ds.x, pism_ds.y)
|
|
368
|
+
pism_points = np.column_stack((X_ds.flatten(), Y_ds.flatten()))
|
|
369
|
+
|
|
370
|
+
file_paths = self._db._get_file_paths_from_metadata(metadata)
|
|
371
|
+
file_paths = np.unique(file_paths)
|
|
372
|
+
|
|
373
|
+
args_list = [(pism_ds, f, metadata) for f in file_paths]
|
|
374
|
+
|
|
375
|
+
num_tasks = len(args_list)
|
|
376
|
+
num_workers = min(num_tasks, cpus)
|
|
377
|
+
|
|
378
|
+
print(
|
|
379
|
+
"\n",
|
|
380
|
+
"Interpolating",
|
|
381
|
+
num_tasks,
|
|
382
|
+
"transect(s) \n" "\n ",
|
|
383
|
+
num_workers,
|
|
384
|
+
"worker(s) allocated out of",
|
|
385
|
+
cpu_count(),
|
|
386
|
+
"available cpus\n",
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
dfs = []
|
|
390
|
+
if num_workers > 1:
|
|
391
|
+
with Pool(num_workers) as pool:
|
|
392
|
+
dfs = list(
|
|
393
|
+
tqdm(
|
|
394
|
+
pool.imap_unordered(self._process_mismatch, args_list),
|
|
395
|
+
total=num_tasks,
|
|
396
|
+
desc="Processing",
|
|
397
|
+
)
|
|
398
|
+
)
|
|
399
|
+
else:
|
|
400
|
+
for file_dict in tqdm(args_list, desc="Processing"):
|
|
401
|
+
dfs.append(self._process_mismatch(args=file_dict))
|
|
402
|
+
|
|
403
|
+
df = pd.concat(dfs, ignore_index=True)
|
|
404
|
+
|
|
405
|
+
scatter = ax.scatter(
|
|
406
|
+
df["PSX"] / 1000,
|
|
407
|
+
df["PSY"] / 1000,
|
|
408
|
+
c=df["IRH_DEPTH_DIFF"],
|
|
409
|
+
cmap=cmap,
|
|
410
|
+
s=marker_size,
|
|
411
|
+
vmin=vmin,
|
|
412
|
+
vmax=vmax,
|
|
413
|
+
linewidths=0,
|
|
414
|
+
rasterized=True,
|
|
415
|
+
)
|
|
416
|
+
inset.scatter(
|
|
417
|
+
df["PSX"] / 1000,
|
|
418
|
+
df["PSY"] / 1000,
|
|
419
|
+
color="darkgreen",
|
|
420
|
+
s=marker_size * 0.5,
|
|
421
|
+
linewidths=0,
|
|
422
|
+
zorder=11,
|
|
423
|
+
)
|
|
424
|
+
extend = "both"
|
|
425
|
+
|
|
426
|
+
if auto_zoom:
|
|
427
|
+
psx_min, psx_max = df["PSX"].min() / 1000, df["PSX"].max() / 1000
|
|
428
|
+
psy_min, psy_max = df["PSY"].min() / 1000, df["PSY"].max() / 1000
|
|
429
|
+
xmin = psx_min if xmin is None else min(xmin, psx_min)
|
|
430
|
+
xmax = psx_max if xmax is None else max(xmax, psx_max)
|
|
431
|
+
ymin = psy_min if ymin is None else min(ymin, psy_min)
|
|
432
|
+
ymax = psy_max if ymax is None else max(ymax, psy_max)
|
|
433
|
+
|
|
434
|
+
if color_by == "stratigraphy":
|
|
435
|
+
flight_id = list(metadata["flight_id"])
|
|
436
|
+
if len(flight_id) > 1:
|
|
437
|
+
flight_id = flight_id[0]
|
|
438
|
+
print(
|
|
439
|
+
"Found mutilple flight lines to plot, so will plot the first one: ",
|
|
440
|
+
flight_id,
|
|
441
|
+
)
|
|
442
|
+
elif len(flight_id) < 1:
|
|
443
|
+
print("No flight line found to plot")
|
|
444
|
+
plt.close()
|
|
445
|
+
return
|
|
446
|
+
|
|
447
|
+
metadata_impl = self._db.query(
|
|
448
|
+
flight_id=flight_id, dataset=metadata["dataset"], retain_query=False
|
|
449
|
+
)
|
|
450
|
+
if not title:
|
|
451
|
+
title = f"Transect {metadata_impl['flight_id'][0]} from {metadata_impl['reference'][0]}"
|
|
452
|
+
|
|
453
|
+
f = self._db._get_file_paths_from_metadata(metadata_impl)[0]
|
|
454
|
+
full_path = os.path.join(self._db._db_dir, f)
|
|
455
|
+
import xarray as xr
|
|
456
|
+
|
|
457
|
+
pism_ds = xr.open_dataset(PISM_file, decode_times=False)
|
|
458
|
+
pism_ds = pism_ds.isel(
|
|
459
|
+
deposition_time=np.unique(pism_ds.deposition_time, return_index=True)[1]
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
ds = xr.open_dataset(full_path, engine="h5netcdf")
|
|
463
|
+
fl_line_xy = np.column_stack((ds.PSX, ds.PSY))
|
|
464
|
+
|
|
465
|
+
pism_iso = -((pism_ds.deposition_time.values / (3600 * 24 * 365)) - 1950)
|
|
466
|
+
# layer_ages = ds.IRH_AGE
|
|
467
|
+
ages = [int(a) for a in metadata["age"]]
|
|
468
|
+
layer_ages = ages
|
|
469
|
+
common_values = np.intersect1d(layer_ages, pism_iso)
|
|
470
|
+
|
|
471
|
+
X_pism, Y_pism = np.meshgrid(pism_ds.x, pism_ds.y)
|
|
472
|
+
pism_points = np.column_stack((X_pism.flatten(), Y_pism.flatten()))
|
|
473
|
+
|
|
474
|
+
if "Distance" not in ds.variables:
|
|
475
|
+
print("Distance not in varibles, cannot plot along transect")
|
|
476
|
+
plt.close()
|
|
477
|
+
return
|
|
478
|
+
|
|
479
|
+
if elevation:
|
|
480
|
+
if "SURF_ELEV" in ds.variables:
|
|
481
|
+
ds["IRH_DEPTH"] = ds.SURF_ELEV - ds.IRH_DEPTH
|
|
482
|
+
|
|
483
|
+
elif "ICE_THK" in ds.variables and "BED_ELEV" in ds.variables:
|
|
484
|
+
ds["SURF_ELEV"] = (ds.ICE_THK + ds.BED_ELEV) - ds.IRH_DEPTH
|
|
485
|
+
ds["IRH_DEPTH"] = ds.SURF_ELEV - ds.IRH_DEPTH
|
|
486
|
+
else:
|
|
487
|
+
print(
|
|
488
|
+
"Cannot plot IRH Elevation from the variables in the file, missing either ICE_THK and BED_ELEV or SURF_ELEV"
|
|
489
|
+
)
|
|
490
|
+
plt.close()
|
|
491
|
+
return
|
|
492
|
+
|
|
493
|
+
pism_usurf_interp = griddata(
|
|
494
|
+
pism_points,
|
|
495
|
+
pism_ds.usurf.values.flatten(),
|
|
496
|
+
fl_line_xy,
|
|
497
|
+
method="linear",
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
cmap = self._custom_cmap_density()
|
|
501
|
+
colors = [cmap(i) for i in np.linspace(0.1, 0.9, len(metadata_impl["age"]))]
|
|
502
|
+
for age, color in zip(list(map(int, common_values)), colors):
|
|
503
|
+
if age not in ds.IRH_AGE:
|
|
504
|
+
print(
|
|
505
|
+
f"{metadata_impl['flight_id'][0]} does not contain age {age}, skipping"
|
|
506
|
+
)
|
|
507
|
+
continue
|
|
508
|
+
|
|
509
|
+
ax.scatter(
|
|
510
|
+
ds.Distance / 1000,
|
|
511
|
+
ds.IRH_DEPTH.sel(IRH_AGE=age),
|
|
512
|
+
color=color,
|
|
513
|
+
s=marker_size,
|
|
514
|
+
linewidths=0.1,
|
|
515
|
+
)
|
|
516
|
+
ax.plot([], [], color=color, label=age, linewidth=3)
|
|
517
|
+
|
|
518
|
+
age_offset = -1950
|
|
519
|
+
age_converted = -(age + age_offset) * (3600 * 24 * 365)
|
|
520
|
+
pism_layer = pism_ds.isochronal_layer_depth.sel(
|
|
521
|
+
deposition_time=age_converted,
|
|
522
|
+
).values.flatten()
|
|
523
|
+
|
|
524
|
+
depth_offset = 31 + 12 * 0.038
|
|
525
|
+
pism_depth_interp = (
|
|
526
|
+
griddata(pism_points, pism_layer, fl_line_xy, method="linear")
|
|
527
|
+
+ depth_offset
|
|
528
|
+
)
|
|
529
|
+
if elevation:
|
|
530
|
+
pism_depth_interp = pism_usurf_interp - pism_depth_interp
|
|
531
|
+
|
|
532
|
+
ax.plot(
|
|
533
|
+
ds.Distance / 1000,
|
|
534
|
+
pism_depth_interp,
|
|
535
|
+
linestyle="--",
|
|
536
|
+
color="k",
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
if elevation:
|
|
540
|
+
if "BED_ELEV" in ds.variables:
|
|
541
|
+
scatter = ax.scatter(
|
|
542
|
+
ds.Distance / 1000,
|
|
543
|
+
ds.BED_ELEV,
|
|
544
|
+
color="k",
|
|
545
|
+
s=marker_size,
|
|
546
|
+
linewidths=0.1,
|
|
547
|
+
)
|
|
548
|
+
ax.plot([], [], color="k", label="Bed Elevation", linewidth=3)
|
|
549
|
+
|
|
550
|
+
elif "ICE_THK" in ds.variables and "SURF_ELEV" in ds.variables:
|
|
551
|
+
ds["BED_ELEV"] = ds.SURF_ELEV - ds.ICE_THK
|
|
552
|
+
scatter = ax.scatter(
|
|
553
|
+
ds.Distance / 1000,
|
|
554
|
+
ds.BED_ELEV,
|
|
555
|
+
color="k",
|
|
556
|
+
s=marker_size,
|
|
557
|
+
linewidths=0.1,
|
|
558
|
+
)
|
|
559
|
+
ax.plot([], [], color="k", label="Bed Elevation", linewidth=3)
|
|
560
|
+
else:
|
|
561
|
+
print("Cannot plot Bed Elevation from the variables in the file")
|
|
562
|
+
if "SURF_ELEV" in ds.variables:
|
|
563
|
+
ax.scatter(
|
|
564
|
+
ds.Distance / 1000,
|
|
565
|
+
ds.SURF_ELEV,
|
|
566
|
+
color="darkred",
|
|
567
|
+
s=marker_size,
|
|
568
|
+
linewidths=0.1,
|
|
569
|
+
)
|
|
570
|
+
ax.plot(
|
|
571
|
+
[], [], color="darkred", label="Surface Elevation", linewidth=3
|
|
572
|
+
)
|
|
573
|
+
else:
|
|
574
|
+
print(
|
|
575
|
+
"Cannot plot Surface Elevation from the variables in the file"
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
pism_bed_elev_interp = griddata(
|
|
579
|
+
pism_points,
|
|
580
|
+
pism_ds.topg.values.flatten(),
|
|
581
|
+
fl_line_xy,
|
|
582
|
+
method="linear",
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
ax.plot(
|
|
586
|
+
ds.Distance / 1000,
|
|
587
|
+
pism_bed_elev_interp,
|
|
588
|
+
color="gray",
|
|
589
|
+
linestyle="--",
|
|
590
|
+
label="PISM Bed Elevation",
|
|
591
|
+
)
|
|
592
|
+
|
|
593
|
+
ax.plot(
|
|
594
|
+
ds.Distance / 1000,
|
|
595
|
+
pism_usurf_interp,
|
|
596
|
+
color="darkred",
|
|
597
|
+
linestyle="--",
|
|
598
|
+
label="PISM Surface Elevation",
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
ax.plot(
|
|
602
|
+
[],
|
|
603
|
+
[],
|
|
604
|
+
color="k",
|
|
605
|
+
label="PISM Isochrone Elevation",
|
|
606
|
+
linestyle="--",
|
|
607
|
+
linewidth=3,
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
else:
|
|
611
|
+
if "ICE_THK" in ds.variables:
|
|
612
|
+
scatter = ax.scatter(
|
|
613
|
+
ds.Distance / 1000,
|
|
614
|
+
ds.ICE_THK,
|
|
615
|
+
color="k",
|
|
616
|
+
s=marker_size,
|
|
617
|
+
linewidths=0.1,
|
|
618
|
+
)
|
|
619
|
+
ax.plot([], [], color="k", label="Bed Depth", linewidth=3)
|
|
620
|
+
else:
|
|
621
|
+
print("Cannot plot Bed Depth from the variables in the file")
|
|
622
|
+
|
|
623
|
+
pism_bed_depth_interp = griddata(
|
|
624
|
+
pism_points,
|
|
625
|
+
pism_ds.thk.values.flatten(),
|
|
626
|
+
fl_line_xy,
|
|
627
|
+
method="linear",
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
ax.plot(
|
|
631
|
+
[],
|
|
632
|
+
[],
|
|
633
|
+
color="k",
|
|
634
|
+
label="PISM Isochrone Depth",
|
|
635
|
+
linestyle="--",
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
ax.plot(
|
|
639
|
+
ds.Distance / 1000,
|
|
640
|
+
pism_bed_depth_interp,
|
|
641
|
+
color="gray",
|
|
642
|
+
linestyle="--",
|
|
643
|
+
label="PISM Bed Depth",
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
if elevation:
|
|
647
|
+
ylim = (
|
|
648
|
+
(ds.BED_ELEV.min() - 200, ds.SURF_ELEV.max() + 200)
|
|
649
|
+
if ylim == (None, None)
|
|
650
|
+
else ylim
|
|
651
|
+
)
|
|
652
|
+
else:
|
|
653
|
+
ylim = (ds.ICE_THK.max() + 200, 0) if ylim == (None, None) else ylim
|
|
654
|
+
|
|
655
|
+
if ncol == None:
|
|
656
|
+
if ds.sizes["IRH_AGE"] > 7:
|
|
657
|
+
ncol = 2
|
|
658
|
+
if ds.sizes["IRH_AGE"] > 15:
|
|
659
|
+
ncol = 3
|
|
660
|
+
|
|
661
|
+
# --- Format Figure ---
|
|
662
|
+
if not self._disable_tqdm:
|
|
663
|
+
print("Formatting ...")
|
|
664
|
+
|
|
665
|
+
if color_by == "stratigraphy":
|
|
666
|
+
xmin, xmax = xlim
|
|
667
|
+
ymin, ymax = ylim
|
|
668
|
+
|
|
669
|
+
elif auto_zoom:
|
|
670
|
+
xmin = xmin - 10 if xmin is not None else None
|
|
671
|
+
xmax = xmax + 10 if xmax is not None else None
|
|
672
|
+
ymin = ymin - 10 if ymin is not None else None
|
|
673
|
+
ymax = ymax + 10 if ymax is not None else None
|
|
674
|
+
|
|
675
|
+
ax.set_xlim(xmin, xmax)
|
|
676
|
+
ax.set_ylim(ymin, ymax)
|
|
677
|
+
if color_by != "stratigraphy":
|
|
678
|
+
x0_ax, x1_ax = ax.get_xlim()
|
|
679
|
+
y0_ax, y1_ax = ax.get_ylim()
|
|
680
|
+
x0 = x0_ax if xlim[0] == None else xlim[0]
|
|
681
|
+
x1 = x1_ax if xlim[1] == None else xlim[1]
|
|
682
|
+
y0 = y0_ax if ylim[0] == None else ylim[0]
|
|
683
|
+
y1 = y1_ax if ylim[1] == None else ylim[1]
|
|
684
|
+
|
|
685
|
+
x_extent = x1 - x0
|
|
686
|
+
y_extent = y1 - y0
|
|
687
|
+
aspect_ratio = y_extent / x_extent
|
|
688
|
+
ax.set_xlabel("x [km]")
|
|
689
|
+
ax.set_ylabel("y [km]")
|
|
690
|
+
ax.set_aspect("equal")
|
|
691
|
+
plt.gcf().set_size_inches(
|
|
692
|
+
10 * scale_factor, 10 * aspect_ratio * scale_factor
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
ax.set_title(title, fontsize=24 * scale_factor)
|
|
696
|
+
|
|
697
|
+
if ncol == None:
|
|
698
|
+
ncol = 1
|
|
699
|
+
# --- Legend/Colorbar ---
|
|
700
|
+
if color_by == "mismatch_2D" and scatter is not None:
|
|
701
|
+
if values is not None:
|
|
702
|
+
cbar = fig.colorbar(
|
|
703
|
+
scatter,
|
|
704
|
+
ax=ax,
|
|
705
|
+
ticks=values,
|
|
706
|
+
orientation="horizontal",
|
|
707
|
+
pad=0.1,
|
|
708
|
+
fraction=0.04,
|
|
709
|
+
extend=extend,
|
|
710
|
+
)
|
|
711
|
+
else:
|
|
712
|
+
cbar = fig.colorbar(
|
|
713
|
+
scatter,
|
|
714
|
+
ax=ax,
|
|
715
|
+
orientation="horizontal",
|
|
716
|
+
pad=0.1,
|
|
717
|
+
fraction=0.04,
|
|
718
|
+
extend=extend,
|
|
719
|
+
)
|
|
720
|
+
cbar.ax.xaxis.set_ticks_position("bottom")
|
|
721
|
+
if label:
|
|
722
|
+
cbar.set_label(label)
|
|
723
|
+
else:
|
|
724
|
+
if elevation:
|
|
725
|
+
cbar.set_label("Isochronal elevation mismatch")
|
|
726
|
+
else:
|
|
727
|
+
cbar.set_label("Isochronal depth mismatch")
|
|
728
|
+
|
|
729
|
+
elif color_by == "stratigraphy":
|
|
730
|
+
ax.legend(ncols=2)
|
|
731
|
+
ax.set_xlabel("Distance along transect [km]")
|
|
732
|
+
if elevation:
|
|
733
|
+
ax.set_ylabel("Elevation above sea level [m]")
|
|
734
|
+
else:
|
|
735
|
+
ax.set_ylabel("Depth below surface [m]")
|
|
736
|
+
plt.gcf().set_size_inches(10 * scale_factor, 10 * 2 / 3)
|
|
737
|
+
|
|
738
|
+
# --- Plot IMBIE basins ---
|
|
739
|
+
if basins and color_by != "stratigraphy":
|
|
740
|
+
sf_basins = shapefile.Reader(self._imbie_path)
|
|
741
|
+
basin_patches = []
|
|
742
|
+
|
|
743
|
+
for shape_rec in sf_basins.shapeRecords():
|
|
744
|
+
shp = shape_rec.shape
|
|
745
|
+
pts = shp.points
|
|
746
|
+
parts = list(shp.parts) + [len(pts)] # add sentinel end index
|
|
747
|
+
|
|
748
|
+
# build one polygon per part
|
|
749
|
+
for i in range(len(parts) - 1):
|
|
750
|
+
start, end = parts[i], parts[i + 1]
|
|
751
|
+
ring = pts[start:end]
|
|
752
|
+
|
|
753
|
+
# scale coordinates
|
|
754
|
+
scaled = [(x * 0.001, y * 0.001) for x, y in ring]
|
|
755
|
+
|
|
756
|
+
poly = Polygon(scaled, closed=True, fill=False)
|
|
757
|
+
basin_patches.append(poly)
|
|
758
|
+
|
|
759
|
+
pc = PatchCollection(
|
|
760
|
+
basin_patches,
|
|
761
|
+
facecolor="none",
|
|
762
|
+
edgecolor="black",
|
|
763
|
+
linewidth=0.5,
|
|
764
|
+
)
|
|
765
|
+
ax.add_collection(pc)
|
|
766
|
+
|
|
767
|
+
# ---- CENTERS: read + scale + label ----
|
|
768
|
+
sf_centers = shapefile.Reader(self._center_coords)
|
|
769
|
+
|
|
770
|
+
# find the field index for "Subregion" in the DBF
|
|
771
|
+
fields = sf_centers.fields[1:] # first is DeletionFlag
|
|
772
|
+
field_names = [f[0] for f in fields]
|
|
773
|
+
sub_idx = field_names.index("Subregion")
|
|
774
|
+
|
|
775
|
+
for shape_rec in sf_centers.shapeRecords():
|
|
776
|
+
# assuming center_coords are points
|
|
777
|
+
x_raw, y_raw = shape_rec.shape.points[0]
|
|
778
|
+
x = x_raw * 0.001
|
|
779
|
+
y = y_raw * 0.001
|
|
780
|
+
sub = shape_rec.record[sub_idx]
|
|
781
|
+
|
|
782
|
+
if x0 <= x <= x1 and y0 <= y <= y1:
|
|
783
|
+
ax.text(
|
|
784
|
+
x,
|
|
785
|
+
y,
|
|
786
|
+
sub,
|
|
787
|
+
fontsize=12,
|
|
788
|
+
color="k",
|
|
789
|
+
ha="center",
|
|
790
|
+
path_effects=[
|
|
791
|
+
path_effects.withStroke(
|
|
792
|
+
linewidth=5, foreground=(1, 1, 1, 0.7)
|
|
793
|
+
)
|
|
794
|
+
],
|
|
795
|
+
)
|
|
796
|
+
|
|
797
|
+
inset_basin_patches = []
|
|
798
|
+
for shape_rec in sf_basins.shapeRecords():
|
|
799
|
+
shp = shape_rec.shape
|
|
800
|
+
pts = shp.points
|
|
801
|
+
parts = list(shp.parts) + [len(pts)]
|
|
802
|
+
|
|
803
|
+
for i in range(len(parts) - 1):
|
|
804
|
+
start, end = parts[i], parts[i + 1]
|
|
805
|
+
ring = pts[start:end]
|
|
806
|
+
scaled = [(x * 0.001, y * 0.001) for x, y in ring]
|
|
807
|
+
poly = Polygon(scaled, closed=True, fill=True)
|
|
808
|
+
inset_basin_patches.append(poly)
|
|
809
|
+
|
|
810
|
+
pc = PatchCollection(
|
|
811
|
+
inset_basin_patches,
|
|
812
|
+
facecolor="white",
|
|
813
|
+
edgecolor="black",
|
|
814
|
+
linewidth=0.5,
|
|
815
|
+
)
|
|
816
|
+
inset.add_collection(pc)
|
|
817
|
+
|
|
818
|
+
# Add rectangle showing current view
|
|
819
|
+
inset.plot(
|
|
820
|
+
[xmin, xmax, xmax, xmin, xmin],
|
|
821
|
+
[ymin, ymin, ymax, ymax, ymin],
|
|
822
|
+
color="darkred",
|
|
823
|
+
linestyle="--",
|
|
824
|
+
)
|
|
825
|
+
inset.set_xlabel("")
|
|
826
|
+
inset.set_ylabel("")
|
|
827
|
+
inset.set_xticks([])
|
|
828
|
+
inset.set_yticks([])
|
|
829
|
+
|
|
830
|
+
inset.set_aspect("equal")
|
|
831
|
+
inset.spines[["right", "left", "top", "bottom"]].set_visible(False)
|
|
832
|
+
|
|
833
|
+
if xmin is None and ymin is None and xmax is None and ymax is None:
|
|
834
|
+
inset.remove()
|
|
835
|
+
if not mini_map:
|
|
836
|
+
inset.remove()
|
|
837
|
+
|
|
838
|
+
# --- Plot ice core sites ---
|
|
839
|
+
if stations and color_by != "stratigraphy":
|
|
840
|
+
site_coords = pd.read_parquet(self._site_coords_path)
|
|
841
|
+
for i in site_coords.index:
|
|
842
|
+
site = site_coords.loc[i]
|
|
843
|
+
ax.scatter(
|
|
844
|
+
site["x"] / 1000,
|
|
845
|
+
site["y"] / 1000,
|
|
846
|
+
color="red",
|
|
847
|
+
s=50,
|
|
848
|
+
marker="^",
|
|
849
|
+
edgecolor="black",
|
|
850
|
+
linewidth=1.5,
|
|
851
|
+
zorder=50,
|
|
852
|
+
)
|
|
853
|
+
# --- Save/Show ---
|
|
854
|
+
with self._plot_context():
|
|
855
|
+
if save:
|
|
856
|
+
plt.savefig(save, dpi=200)
|
|
857
|
+
print("Figure saved as", save)
|
|
858
|
+
else:
|
|
859
|
+
plt.show()
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"anta_database/indexing/__init__.py",
|
|
18
18
|
"anta_database/indexing/index_database.py",
|
|
19
19
|
"anta_database/figures/AntA_38ka.png",
|
|
20
|
+
"anta_database/plotting/plotting_pism.py",
|
|
20
21
|
"anta_database/plotting/__init__.py",
|
|
21
22
|
"anta_database/plotting/plotting.py",
|
|
22
23
|
"anta_database/database/database.py",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anta_database-0.4.1 → anta_database-0.4.2}/anta_database/compiling/zarr_converter_simple.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.parquet
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coors_basins.parquet
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|