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.
Files changed (60) hide show
  1. {anta_database-0.4.1 → anta_database-0.4.2}/PKG-INFO +1 -1
  2. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/__init__.py +2 -0
  3. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/database/database.py +8 -0
  4. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/plotting/__init__.py +2 -1
  5. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/plotting/plotting.py +29 -26
  6. anta_database-0.4.2/anta_database/plotting/plotting_pism.py +859 -0
  7. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database.egg-info/PKG-INFO +1 -1
  8. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database.egg-info/SOURCES.txt +1 -0
  9. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database.egg-info/scm_file_list.json +1 -0
  10. anta_database-0.4.2/anta_database.egg-info/scm_version.json +8 -0
  11. anta_database-0.4.1/anta_database.egg-info/scm_version.json +0 -8
  12. {anta_database-0.4.1 → anta_database-0.4.2}/.github/workflows/deploy.yml +0 -0
  13. {anta_database-0.4.1 → anta_database-0.4.2}/.github/workflows/release.yml +0 -0
  14. {anta_database-0.4.1 → anta_database-0.4.2}/.gitignore +0 -0
  15. {anta_database-0.4.1 → anta_database-0.4.2}/LICENSE +0 -0
  16. {anta_database-0.4.1 → anta_database-0.4.2}/README.md +0 -0
  17. {anta_database-0.4.1 → anta_database-0.4.2}/ROADMAP.md +0 -0
  18. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/compiling/__init__.py +0 -0
  19. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/compiling/compile.py +0 -0
  20. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/compiling/reconnect.py +0 -0
  21. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/compiling/zarr_converter_simple.py +0 -0
  22. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.cpg +0 -0
  23. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.dbf +0 -0
  24. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.parquet +0 -0
  25. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.prj +0 -0
  26. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.shp +0 -0
  27. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ANT_Basins_IMBIE2_v1.6.shx +0 -0
  28. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/GL.parquet +0 -0
  29. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coords_basins.cpg +0 -0
  30. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coords_basins.dbf +0 -0
  31. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coords_basins.prj +0 -0
  32. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coords_basins.shp +0 -0
  33. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coords_basins.shx +0 -0
  34. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/centeroid_coors_basins.parquet +0 -0
  35. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/convert_data.py +0 -0
  36. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/ice-core-coordinates.csv +0 -0
  37. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/data/site-coords.parquet +0 -0
  38. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/database/__init__.py +0 -0
  39. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/figures/AntA_38ka.png +0 -0
  40. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/indexing/__init__.py +0 -0
  41. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/indexing/index_database.py +0 -0
  42. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/test_interactive.py +0 -0
  43. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database/test_interactive_full.py +0 -0
  44. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database.egg-info/dependency_links.txt +0 -0
  45. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database.egg-info/requires.txt +0 -0
  46. {anta_database-0.4.1 → anta_database-0.4.2}/anta_database.egg-info/top_level.txt +0 -0
  47. {anta_database-0.4.1 → anta_database-0.4.2}/book/_config.yml +0 -0
  48. {anta_database-0.4.1 → anta_database-0.4.2}/book/_toc.yml +0 -0
  49. {anta_database-0.4.1 → anta_database-0.4.2}/book/advanced.md +0 -0
  50. {anta_database-0.4.1 → anta_database-0.4.2}/book/contact.md +0 -0
  51. {anta_database-0.4.1 → anta_database-0.4.2}/book/contribute.md +0 -0
  52. {anta_database-0.4.1 → anta_database-0.4.2}/book/figures/Overview_all.png +0 -0
  53. {anta_database-0.4.1 → anta_database-0.4.2}/book/intro.md +0 -0
  54. {anta_database-0.4.1 → anta_database-0.4.2}/book/logo.png +0 -0
  55. {anta_database-0.4.1 → anta_database-0.4.2}/book/pism_example.ipynb +0 -0
  56. {anta_database-0.4.1 → anta_database-0.4.2}/book/quick_start.ipynb +0 -0
  57. {anta_database-0.4.1 → anta_database-0.4.2}/book/references.bib +0 -0
  58. {anta_database-0.4.1 → anta_database-0.4.2}/book/requirements.txt +0 -0
  59. {anta_database-0.4.1 → anta_database-0.4.2}/pyproject.toml +0 -0
  60. {anta_database-0.4.1 → anta_database-0.4.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anta_database
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: SQLite database for the AntArchitecture Community Data
5
5
  Author: Antoine Hermant
6
6
  Author-email: antoine.hermant@etik.com
@@ -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):
@@ -5,5 +5,6 @@ Contains functions for data visualization and plotting.
5
5
  """
6
6
 
7
7
  from .plotting import Plotting
8
+ from .plotting_pism import PISMPlotting
8
9
 
9
- __all__ = ["Plotting"]
10
+ __all__ = ["Plotting", "PISMPlotting"]
@@ -241,7 +241,7 @@ class Plotting:
241
241
  mini_map=mini_map,
242
242
  )
243
243
 
244
- def transect_1D(
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="transect_1D",
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 != "transect_1D": # FIXME
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 == "transect_1D":
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 == "transect_1D":
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
- scatter = ax.scatter(
810
- ds.Distance / 1000,
811
- ds.ICE_THK,
812
- color="k",
813
- s=marker_size,
814
- linewidths=0.1,
815
- )
816
- ax.plot([], [], color="k", label="Bed Depth", linewidth=3)
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 == "transect_1D":
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 != "transect_1D":
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 == "transect_1D":
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 != "transect_1D":
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 != "transect_1D":
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()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anta_database
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: SQLite database for the AntArchitecture Community Data
5
5
  Author: Antoine Hermant
6
6
  Author-email: antoine.hermant@etik.com
@@ -42,6 +42,7 @@ anta_database/indexing/__init__.py
42
42
  anta_database/indexing/index_database.py
43
43
  anta_database/plotting/__init__.py
44
44
  anta_database/plotting/plotting.py
45
+ anta_database/plotting/plotting_pism.py
45
46
  book/_config.yml
46
47
  book/_toc.yml
47
48
  book/advanced.md
@@ -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",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.4.2",
3
+ "distance": 0,
4
+ "node": "gecc1a9d04f84149cfcd28fbf983da7b256371eef",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-08-06"
8
+ }
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "0.4.1",
3
- "distance": 0,
4
- "node": "g32f375d25f4f849dacf941f4f330522d88fc8f06",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-08-04"
8
- }
File without changes
File without changes
File without changes
File without changes
File without changes