pastastore 1.10.2__py3-none-any.whl → 1.12.0__py3-none-any.whl

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.
pastastore/datasets.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Module containing example dataset."""
2
2
 
3
- import os
3
+ from pathlib import Path
4
4
 
5
5
  import pandas as pd
6
6
  from hydropandas import Obs, ObsCollection
@@ -30,8 +30,8 @@ def example_pastastore(conn="DictConnector"):
30
30
  PastaStore containing example dataset
31
31
  """
32
32
  # check it test dataset is available
33
- datadir = os.path.join(os.path.dirname(__file__), "../tests/data")
34
- if not os.path.exists(datadir):
33
+ datadir = Path(__file__).parent / "../tests/data"
34
+ if not datadir.exists():
35
35
  raise FileNotFoundError(
36
36
  "Test datasets not available! Clone repository from GitHub."
37
37
  )
@@ -46,63 +46,57 @@ def example_pastastore(conn="DictConnector"):
46
46
  # add data
47
47
 
48
48
  # oseries 1
49
- o = pd.read_csv(os.path.join(datadir, "obs.csv"), index_col=0, parse_dates=True)
49
+ o = pd.read_csv(datadir / "obs.csv", index_col=0, parse_dates=True)
50
50
  pstore.add_oseries(o, "oseries1", metadata={"x": 165000, "y": 424000})
51
51
  # oseries 2
52
- o = pd.read_csv(
53
- os.path.join(datadir, "head_nb1.csv"), index_col=0, parse_dates=True
54
- )
52
+ o = pd.read_csv(datadir / "head_nb1.csv", index_col=0, parse_dates=True)
55
53
  pstore.add_oseries(o, "oseries2", metadata={"x": 164000, "y": 423000})
56
54
 
57
55
  # oseries 3
58
- o = pd.read_csv(os.path.join(datadir, "gw_obs.csv"), index_col=0, parse_dates=True)
56
+ o = pd.read_csv(datadir / "gw_obs.csv", index_col=0, parse_dates=True)
59
57
  pstore.add_oseries(o, "oseries3", metadata={"x": 165554, "y": 422685})
60
58
 
61
59
  # prec 1
62
- s = pd.read_csv(os.path.join(datadir, "rain.csv"), index_col=0, parse_dates=True)
60
+ s = pd.read_csv(datadir / "rain.csv", index_col=0, parse_dates=True)
63
61
  pstore.add_stress(s, "prec1", kind="prec", metadata={"x": 165050, "y": 424050})
64
62
 
65
63
  # prec 2
66
- s = pd.read_csv(
67
- os.path.join(datadir, "rain_nb1.csv"), index_col=0, parse_dates=True
68
- )
64
+ s = pd.read_csv(datadir / "rain_nb1.csv", index_col=0, parse_dates=True)
69
65
  pstore.add_stress(s, "prec2", kind="prec", metadata={"x": 164010, "y": 423000})
70
66
 
71
67
  # evap 1
72
- s = pd.read_csv(os.path.join(datadir, "evap.csv"), index_col=0, parse_dates=True)
68
+ s = pd.read_csv(datadir / "evap.csv", index_col=0, parse_dates=True)
73
69
  pstore.add_stress(s, "evap1", kind="evap", metadata={"x": 164500, "y": 424000})
74
70
 
75
71
  # evap 2
76
- s = pd.read_csv(
77
- os.path.join(datadir, "evap_nb1.csv"), index_col=0, parse_dates=True
78
- )
72
+ s = pd.read_csv(datadir / "evap_nb1.csv", index_col=0, parse_dates=True)
79
73
  pstore.add_stress(s, "evap2", kind="evap", metadata={"x": 164000, "y": 423030})
80
74
 
81
75
  # well 1
82
- s = pd.read_csv(os.path.join(datadir, "well.csv"), index_col=0, parse_dates=True)
76
+ s = pd.read_csv(datadir / "well.csv", index_col=0, parse_dates=True)
83
77
  s = timestep_weighted_resample(s, pd.date_range(s.index[0], s.index[-1], freq="D"))
84
78
  pstore.add_stress(s, "well1", kind="well", metadata={"x": 164691, "y": 423579})
85
79
 
86
80
  # river notebook data (nb5)
87
81
  oseries = pd.read_csv(
88
- os.path.join(datadir, "nb5_head.csv"), parse_dates=True, index_col=0
82
+ datadir / "nb5_head.csv", parse_dates=True, index_col=0
89
83
  ).squeeze("columns")
90
84
  pstore.add_oseries(oseries, "head_nb5", metadata={"x": 200_000, "y": 450_000.0})
91
85
 
92
- rain = pd.read_csv(
93
- os.path.join(datadir, "nb5_prec.csv"), parse_dates=True, index_col=0
94
- ).squeeze("columns")
86
+ rain = pd.read_csv(datadir / "nb5_prec.csv", parse_dates=True, index_col=0).squeeze(
87
+ "columns"
88
+ )
95
89
  pstore.add_stress(
96
90
  rain, "prec_nb5", kind="prec", metadata={"x": 200_000, "y": 450_000.0}
97
91
  )
98
- evap = pd.read_csv(
99
- os.path.join(datadir, "nb5_evap.csv"), parse_dates=True, index_col=0
100
- ).squeeze("columns")
92
+ evap = pd.read_csv(datadir / "nb5_evap.csv", parse_dates=True, index_col=0).squeeze(
93
+ "columns"
94
+ )
101
95
  pstore.add_stress(
102
96
  evap, "evap_nb5", kind="evap", metadata={"x": 200_000, "y": 450_000.0}
103
97
  )
104
98
  waterlevel = pd.read_csv(
105
- os.path.join(datadir, "nb5_riv.csv"), parse_dates=True, index_col=0
99
+ datadir / "nb5_riv.csv", parse_dates=True, index_col=0
106
100
  ).squeeze("columns")
107
101
  pstore.add_stress(
108
102
  waterlevel,
@@ -110,11 +104,7 @@ def example_pastastore(conn="DictConnector"):
110
104
  kind="riv",
111
105
  metadata={"x": 200_000, "y": 450_000.0},
112
106
  )
113
- # TODO: temporary fix for older version of hydropandas that does not
114
- # read Menyanthes time series names correctly.
115
- # multiwell notebook data
116
- fname = os.path.join(datadir, "MenyanthesTest.men")
117
- # meny = ps.read.MenyData(fname)
107
+ fname = datadir / "MenyanthesTest.men"
118
108
  meny = ObsCollection.from_menyanthes(fname, Obs)
119
109
 
120
110
  oseries = meny.loc["Obsevation well", "obs"]
@@ -184,12 +174,12 @@ def _default_connector(conntype: str):
184
174
  default Connector based on type.
185
175
  """
186
176
  Conn = getattr(pst, conntype)
187
- if Conn.conn_type == "arcticdb":
177
+ if Conn._conn_type == "arcticdb":
188
178
  uri = "lmdb://./arctic_db"
189
179
  conn = Conn("my_db", uri)
190
- elif Conn.conn_type == "dict":
180
+ elif Conn._conn_type == "dict":
191
181
  conn = Conn("my_db")
192
- elif Conn.conn_type == "pas":
182
+ elif Conn._conn_type == "pas":
193
183
  conn = Conn("my_db", "./pas_db")
194
184
  else:
195
185
  raise ValueError(f"Unrecognized connector type! '{conntype}'")
@@ -1,14 +1,18 @@
1
1
  # ruff: noqa: D104 F401
2
+ import logging
3
+
2
4
  from pastastore.extensions.accessor import (
3
5
  register_pastastore_accessor as register_pastastore_accessor,
4
6
  )
5
7
 
8
+ logger = logging.getLogger(__name__)
9
+
6
10
 
7
11
  def activate_hydropandas_extension():
8
- """Register Plotly extension for pastas.Model class for interactive plotting."""
12
+ """Register HydroPandas extension for downloading time series data."""
9
13
  from pastastore.extensions.hpd import HydroPandasExtension as _
10
14
 
11
- print(
12
- "Registered HydroPandas extension in PastaStore class, "
15
+ logger.info(
16
+ "Registered HydroPandas extension in PastaStore, "
13
17
  "e.g. `pstore.hpd.download_bro_gmw()`."
14
18
  )
@@ -18,6 +18,7 @@ from pastas.timeseries_utils import timestep_weighted_resample
18
18
  from tqdm.auto import tqdm
19
19
 
20
20
  from pastastore.extensions.accessor import register_pastastore_accessor
21
+ from pastastore.typing import TimeSeriesLibs
21
22
 
22
23
  logger = logging.getLogger("hydropandas_extension")
23
24
 
@@ -68,7 +69,7 @@ class HydroPandasExtension:
68
69
 
69
70
  def add_obscollection(
70
71
  self,
71
- libname: str,
72
+ libname: TimeSeriesLibs,
72
73
  oc: hpd.ObsCollection,
73
74
  kind: Optional[str] = None,
74
75
  data_column: Optional[str] = None,
@@ -113,7 +114,7 @@ class HydroPandasExtension:
113
114
 
114
115
  def add_observation(
115
116
  self,
116
- libname: str,
117
+ libname: TimeSeriesLibs,
117
118
  obs: hpd.Obs,
118
119
  name: Optional[str] = None,
119
120
  kind: Optional[str] = None,
@@ -173,7 +174,7 @@ class HydroPandasExtension:
173
174
  )
174
175
 
175
176
  # gather metadata from obs object
176
- metadata = {key: getattr(obs, key) for key in obs._metadata}
177
+ metadata = {key: getattr(obs, key) for key in obs._metadata} # noqa: SLF001
177
178
 
178
179
  # convert np dtypes to builtins
179
180
  for k, v in metadata.items():
@@ -200,7 +201,9 @@ class HydroPandasExtension:
200
201
  action_msg = "added to"
201
202
 
202
203
  if libname == "oseries":
203
- self._store.upsert_oseries(o.squeeze(axis=1), name, metadata=metadata)
204
+ self._store.upsert_oseries(
205
+ o.squeeze(axis=1), name, metadata=metadata, force=True
206
+ )
204
207
  logger.info(
205
208
  "%sobservation '%s' %s oseries library.", source, name, action_msg
206
209
  )
@@ -208,7 +211,11 @@ class HydroPandasExtension:
208
211
  if kind is None:
209
212
  raise ValueError("`kind` must be specified for stresses!")
210
213
  self._store.upsert_stress(
211
- (o * unit_multiplier).squeeze(axis=1), name, kind, metadata=metadata
214
+ (o * unit_multiplier).squeeze(axis=1),
215
+ name,
216
+ kind,
217
+ metadata=metadata,
218
+ force=True,
212
219
  )
213
220
  logger.info(
214
221
  "%sstress '%s' (kind='%s') %s stresses library.",
@@ -242,10 +249,10 @@ class HydroPandasExtension:
242
249
  tmintmax = self._store.get_tmin_tmax(
243
250
  "oseries", names=[oseries] if oseries else None
244
251
  )
245
- if tmin is None:
246
- tmin = tmintmax.loc[:, "tmin"].min() - Timedelta(days=10 * 365)
247
- if tmax is None:
248
- tmax = tmintmax.loc[:, "tmax"].max()
252
+ if tmin is None:
253
+ tmin = tmintmax.loc[:, "tmin"].min() - Timedelta(days=10 * 365)
254
+ if tmax is None:
255
+ tmax = tmintmax.loc[:, "tmax"].max()
249
256
  return tmin, tmax
250
257
 
251
258
  @staticmethod
@@ -263,12 +270,13 @@ class HydroPandasExtension:
263
270
  observation series with normalized datetime index
264
271
  """
265
272
  if isinstance(obs, hpd.Obs):
266
- metadata = {k: getattr(obs, k) for k in obs._metadata}
273
+ metadata = {k: getattr(obs, k) for k in obs._metadata} # noqa: SLF001
267
274
  else:
268
275
  metadata = {}
269
276
  return obs.__class__(
270
277
  timestep_weighted_resample(
271
- obs,
278
+ # force series, see https://github.com/pastas/pastas/issues/1020
279
+ obs.squeeze(),
272
280
  obs.index.normalize(),
273
281
  ).rename(obs.name),
274
282
  **metadata,
@@ -585,6 +593,17 @@ class HydroPandasExtension:
585
593
  ):
586
594
  """Update meteorological data from KNMI in PastaStore.
587
595
 
596
+ Warning
597
+ -------
598
+ When fill_missing_obs is True, time series will be filled with observations
599
+ from nearest stations with data. If certain stations are generally more up to
600
+ date than others, this can lead to time series being permanently filled with
601
+ data from another station. To overwrite these filled values with data from the
602
+ actual station in a subsequent update, ensure that tmin is set to a date prior
603
+ to the first update call, or to be very safe, set tmin to the beginning of the
604
+ time series. This will force re-downloading of all data from the actual
605
+ station.
606
+
588
607
  Parameters
589
608
  ----------
590
609
  names : list of str, optional
@@ -596,7 +615,7 @@ class HydroPandasExtension:
596
615
  end time, by default None, which defaults to today
597
616
  fill_missing_obs : bool, optional
598
617
  if True, fill missing observations by getting observations from nearest
599
- station with data.
618
+ station with data. Default is True.
600
619
  normalize_datetime_index : bool, optional
601
620
  if True, normalize the datetime so stress value at midnight represents
602
621
  the daily total, by default True.
@@ -625,7 +644,7 @@ class HydroPandasExtension:
625
644
 
626
645
  if tmax is not None:
627
646
  if tmintmax["tmax"].min() >= Timestamp(tmax):
628
- logger.info(f"All KNMI stresses are up to date till {tmax}.")
647
+ logger.info("All KNMI stresses are up to date till %s.", tmax)
629
648
  return
630
649
 
631
650
  try:
@@ -639,7 +658,7 @@ class HydroPandasExtension:
639
658
  maxtmax_rd = maxtmax_ev24 = Timestamp.today() - Timedelta(days=28)
640
659
  logger.info(
641
660
  "Using 28 days (4 weeks) prior to today as maxtmax: %s."
642
- % str(maxtmax_rd)
661
+ % maxtmax_rd.strftime("%Y-%m-%d")
643
662
  )
644
663
 
645
664
  for name in tqdm(names, desc="Updating KNMI meteo stresses"):
@@ -671,11 +690,14 @@ class HydroPandasExtension:
671
690
  # fix for duplicate station entry in metadata:
672
691
  stress_station = (
673
692
  self._store.stresses.at[name, "station"]
674
- if "station" in self._store.stresses.columns
693
+ if (
694
+ "station" in self._store.stresses.columns
695
+ and np.isfinite(self._store.stresses.at[name, "station"])
696
+ )
675
697
  else None
676
698
  )
677
699
  if stress_station is not None and not isinstance(
678
- stress_station, (int, np.integer)
700
+ stress_station, (int, np.integer, float)
679
701
  ):
680
702
  stress_station = stress_station.squeeze().unique().item()
681
703
 
@@ -700,7 +722,7 @@ class HydroPandasExtension:
700
722
  elif unit == "mm":
701
723
  unit_multiplier = 1e3
702
724
  elif unit.count("m") == 1 and unit.endswith("m"):
703
- unit_multiplier = float(unit.replace("m", ""))
725
+ unit_multiplier = float(unit.replace("m", "").replace("*", ""))
704
726
  else:
705
727
  unit_multiplier = 1.0
706
728
  logger.warning(
pastastore/plotting.py CHANGED
@@ -15,6 +15,9 @@ follows::
15
15
  pstore.maps.add_background_map(ax) # for adding a background map
16
16
  """
17
17
 
18
+ import logging
19
+ import warnings
20
+
18
21
  import matplotlib.pyplot as plt
19
22
  import numpy as np
20
23
  import pandas as pd
@@ -25,6 +28,8 @@ from matplotlib.colors import BoundaryNorm, LogNorm
25
28
  from matplotlib.lines import Line2D
26
29
  from mpl_toolkits.axes_grid1 import make_axes_locatable
27
30
 
31
+ logger = logging.getLogger(__name__)
32
+
28
33
 
29
34
  class Plots:
30
35
  """Plot class for Pastastore.
@@ -101,7 +106,7 @@ class Plots:
101
106
  split=True is only supported if there are less than 20 time series
102
107
  to plot.
103
108
  """
104
- names = self.pstore.conn._parse_names(names, libname)
109
+ names = self.pstore.conn.parse_names(names, libname)
105
110
 
106
111
  if len(names) > 20 and split:
107
112
  raise ValueError(
@@ -116,7 +121,7 @@ class Plots:
116
121
  else:
117
122
  axes = ax
118
123
 
119
- tsdict = self.pstore.conn._get_series(
124
+ tsdict = self.pstore.conn._get_series( # noqa: SLF001
120
125
  libname, names, progressbar=progressbar, squeeze=False
121
126
  )
122
127
  for i, (n, ts) in enumerate(tsdict.items()):
@@ -236,7 +241,7 @@ class Plots:
236
241
  ax : matplotlib.Axes
237
242
  axes handle
238
243
  """
239
- names = self.pstore.conn._parse_names(names, "stresses")
244
+ names = self.pstore.conn.parse_names(names, "stresses")
240
245
  masknames = self.pstore.stresses.index.isin(names)
241
246
  stresses = self.pstore.stresses.loc[masknames]
242
247
 
@@ -315,7 +320,7 @@ class Plots:
315
320
  ax : matplotlib Axes
316
321
  The axes in which the data-availability is plotted
317
322
  """
318
- names = self.pstore.conn._parse_names(names, libname)
323
+ names = self.pstore.conn.parse_names(names, libname)
319
324
 
320
325
  if libname == "stresses":
321
326
  masknames = self.pstore.stresses.index.isin(names)
@@ -324,7 +329,7 @@ class Plots:
324
329
  mask = stresses["kind"] == kind
325
330
  names = stresses.loc[mask].index.to_list()
326
331
 
327
- series = self.pstore.conn._get_series(
332
+ series = self.pstore.conn._get_series( # noqa: SLF001
328
333
  libname, names, progressbar=progressbar, squeeze=False
329
334
  ).values()
330
335
 
@@ -434,6 +439,7 @@ class Plots:
434
439
  cmap = plt.get_cmap(cmap, 256)
435
440
  cmap.set_over((1.0, 1.0, 1.0))
436
441
 
442
+ pc = None
437
443
  for i, s in enumerate(series):
438
444
  if not s.empty:
439
445
  if dropna:
@@ -450,10 +456,14 @@ class Plots:
450
456
 
451
457
  # make a colorbar in an ax on the
452
458
  # right side, then set the current axes to ax again
453
- cb = fig.colorbar(pc, ax=ax, cax=cax, extend="both")
454
- cb.set_ticks(bounds)
455
- cb.ax.set_yticklabels(labels)
456
- cb.ax.minorticks_off()
459
+ if pc is not None:
460
+ cb = fig.colorbar(pc, ax=ax, cax=cax, extend="both")
461
+ cb.set_ticks(bounds)
462
+ cb.ax.set_yticklabels(labels)
463
+ cb.ax.minorticks_off()
464
+ else:
465
+ # nothing was plotted; skip colorbar to avoid UnboundLocalError
466
+ cb = None
457
467
 
458
468
  if set_yticks:
459
469
  ax.set_yticks(np.arange(0.5, len(series) + 0.5), minor=False)
@@ -600,6 +610,8 @@ class Plots:
600
610
  elif len(np.unique(onames)) > 1:
601
611
  names = modelnames
602
612
  cm = ps.CompareModels(models, names=names)
613
+ if ax is not None:
614
+ kwargs.setdefault("ax", ax)
603
615
  cm.plot(**kwargs)
604
616
  return cm
605
617
 
@@ -684,7 +696,7 @@ class Maps:
684
696
  --------
685
697
  self.add_background_map
686
698
  """
687
- names = self.pstore.conn._parse_names(names, "stresses")
699
+ names = self.pstore.conn.parse_names(names, "stresses")
688
700
  if extent is not None:
689
701
  names = self.pstore.within(extent, names=names, libname="stresses")
690
702
  df = self.pstore.stresses.loc[names]
@@ -707,7 +719,7 @@ class Maps:
707
719
  kind_to_color = {k: f"C{i}" for i, k in enumerate(c.unique())}
708
720
  c = c.apply(lambda k: kind_to_color[k])
709
721
 
710
- r = self._plotmap_dataframe(stresses.loc[mask0], c=c, figsize=figsize, **kwargs)
722
+ r = self.dataframe_scatter(stresses.loc[mask0], c=c, figsize=figsize, **kwargs)
711
723
  if "ax" in kwargs:
712
724
  ax = kwargs.pop("ax")
713
725
  else:
@@ -768,12 +780,12 @@ class Maps:
768
780
  --------
769
781
  self.add_background_map
770
782
  """
771
- names = self.pstore.conn._parse_names(names, "oseries")
783
+ names = self.pstore.conn.parse_names(names, "oseries")
772
784
  if extent is not None:
773
785
  names = self.pstore.within(extent, names=names)
774
786
  oseries = self.pstore.oseries.loc[names]
775
787
  mask0 = (oseries["x"] != 0.0) | (oseries["y"] != 0.0)
776
- r = self._plotmap_dataframe(oseries.loc[mask0], figsize=figsize, **kwargs)
788
+ r = self.dataframe_scatter(oseries.loc[mask0], figsize=figsize, **kwargs)
777
789
  if "ax" in kwargs:
778
790
  ax = kwargs["ax"]
779
791
  else:
@@ -829,7 +841,7 @@ class Maps:
829
841
 
830
842
  # mask out 0.0 coordinates
831
843
  mask0 = (models["x"] != 0.0) | (models["y"] != 0.0)
832
- r = self._plotmap_dataframe(models.loc[mask0], figsize=figsize, **kwargs)
844
+ r = self.dataframe_scatter(models.loc[mask0], figsize=figsize, **kwargs)
833
845
  if "ax" in kwargs:
834
846
  ax = kwargs["ax"]
835
847
  else:
@@ -842,7 +854,7 @@ class Maps:
842
854
 
843
855
  return ax
844
856
 
845
- def _map_helper(
857
+ def dataframe(
846
858
  self,
847
859
  df,
848
860
  column,
@@ -856,7 +868,7 @@ class Maps:
856
868
  backgroundmap=False,
857
869
  **kwargs,
858
870
  ):
859
- """Help function for plotting values on map.
871
+ """Plot dataframe on a map.
860
872
 
861
873
  Parameters
862
874
  ----------
@@ -905,11 +917,12 @@ class Maps:
905
917
  }
906
918
  scatter_kwargs.update(kwargs)
907
919
 
908
- ax = self._plotmap_dataframe(
920
+ ax = self.dataframe_scatter(
909
921
  df, column=column, figsize=figsize, **scatter_kwargs
910
922
  )
911
923
  if label:
912
- df.set_index("index", inplace=True)
924
+ if "index" in df:
925
+ df.set_index("index", inplace=True)
913
926
  self.add_labels(df, ax, adjust=adjust)
914
927
 
915
928
  if backgroundmap:
@@ -982,7 +995,7 @@ class Maps:
982
995
  statsdf = statsdf.reset_index().set_index("oseries")
983
996
  df = statsdf.join(self.pstore.oseries, how="left")
984
997
 
985
- return self._map_helper(
998
+ return self.dataframe(
986
999
  df,
987
1000
  column=statistic,
988
1001
  label=label,
@@ -999,6 +1012,7 @@ class Maps:
999
1012
  def modelparam(
1000
1013
  self,
1001
1014
  parameter,
1015
+ param_value="optimal",
1002
1016
  modelnames=None,
1003
1017
  label=True,
1004
1018
  adjust=False,
@@ -1017,6 +1031,9 @@ class Maps:
1017
1031
  ----------
1018
1032
  parameter: str
1019
1033
  name of the parameter, e.g. "rech_A" or "river_a"
1034
+ param_value: str, optional
1035
+ which parameter value to plot, by default "optimal", other options
1036
+ are "initial", "pmin", "pmax"
1020
1037
  modelnames : list of str, optional
1021
1038
  list of modelnames to include
1022
1039
  label: bool, optional
@@ -1052,6 +1069,7 @@ class Maps:
1052
1069
  """
1053
1070
  paramdf = self.pstore.get_parameters(
1054
1071
  [parameter],
1072
+ param_value=param_value,
1055
1073
  modelnames=modelnames,
1056
1074
  progressbar=progressbar,
1057
1075
  ignore_errors=True,
@@ -1064,7 +1082,7 @@ class Maps:
1064
1082
  paramdf = paramdf.reset_index().set_index("oseries")
1065
1083
  df = paramdf.join(self.pstore.oseries, how="left")
1066
1084
 
1067
- return self._map_helper(
1085
+ return self.dataframe(
1068
1086
  df,
1069
1087
  column=parameter,
1070
1088
  label=label,
@@ -1133,14 +1151,14 @@ class Maps:
1133
1151
  self.add_background_map
1134
1152
  """
1135
1153
  signature_df = self.pstore.get_signatures(
1136
- [signature],
1137
1154
  names=names,
1155
+ signatures=[signature],
1138
1156
  progressbar=progressbar,
1139
1157
  ignore_errors=True,
1140
- )
1158
+ ).transpose()
1141
1159
  df = signature_df.join(self.pstore.oseries, how="left")
1142
1160
 
1143
- return self._map_helper(
1161
+ return self.dataframe(
1144
1162
  df,
1145
1163
  column=signature,
1146
1164
  label=label,
@@ -1154,8 +1172,17 @@ class Maps:
1154
1172
  **kwargs,
1155
1173
  )
1156
1174
 
1175
+ def _plotmap_dataframe(self, *args, **kwargs):
1176
+ """Deprecated, use dataframe method.""" # noqa: D401
1177
+ warnings.warn(
1178
+ "maps._plotmap_dataframe is deprecated, use maps.dataframe_scatter instead",
1179
+ DeprecationWarning,
1180
+ stacklevel=2,
1181
+ )
1182
+ return self.dataframe_scatter(*args, **kwargs)
1183
+
1157
1184
  @staticmethod
1158
- def _plotmap_dataframe(
1185
+ def dataframe_scatter(
1159
1186
  df,
1160
1187
  x="x",
1161
1188
  y="y",
@@ -1165,9 +1192,7 @@ class Maps:
1165
1192
  figsize=(10, 8),
1166
1193
  **kwargs,
1167
1194
  ):
1168
- """Plot dataframe with point locations (internal method).
1169
-
1170
- Can be called directly for more control over plot characteristics.
1195
+ """Plot dataframe.
1171
1196
 
1172
1197
  Parameters
1173
1198
  ----------
@@ -1310,10 +1335,12 @@ class Maps:
1310
1335
  "metadata_source must be either 'model' or 'store'!"
1311
1336
  )
1312
1337
  if np.isnan(xi) or np.isnan(yi):
1313
- print(f"No x,y-data for {istress.name}!")
1338
+ logger.warning("No x,y-data for %s!", istress.name)
1314
1339
  continue
1315
1340
  if xi == 0.0 or yi == 0.0:
1316
- print(f"x,y-data is 0.0 for {istress.name}, not plotting!")
1341
+ logger.warning(
1342
+ "x,y-data is 0.0 for %s, not plotting!", istress.name
1343
+ )
1317
1344
  continue
1318
1345
 
1319
1346
  stresses.loc[istress.name, :] = (xi, yi, name, f"C{count % 10}")
@@ -1476,7 +1503,7 @@ class Maps:
1476
1503
  m_idx = self.pstore.search(libname="models", s=model_names)
1477
1504
  else:
1478
1505
  m_idx = self.pstore.model_names
1479
- struct = self.pstore.get_model_timeseries_names(progressbar=False).loc[m_idx]
1506
+ struct = self.pstore.get_model_time_series_names(progressbar=False).loc[m_idx]
1480
1507
 
1481
1508
  oseries = self.pstore.oseries
1482
1509
  stresses = self.pstore.stresses
@@ -1614,23 +1641,27 @@ class Maps:
1614
1641
  ctx.add_basemap(ax, source=providers[map_provider], crs=proj.srs, **kwargs)
1615
1642
 
1616
1643
  @staticmethod
1617
- def add_labels(df, ax, adjust=False, objects=None, **kwargs):
1644
+ def add_labels(
1645
+ df, ax, adjust=False, objects=None, adjust_text_kwargs=None, **kwargs
1646
+ ):
1618
1647
  """Add labels to points on plot.
1619
1648
 
1620
1649
  Uses dataframe index to label points.
1621
1650
 
1622
1651
  Parameters
1623
1652
  ----------
1624
- df: pd.DataFrame
1653
+ df : pd.DataFrame
1625
1654
  DataFrame containing x, y - data. Index is used as label
1626
- ax: matplotlib.Axes
1655
+ ax : matplotlib.Axes
1627
1656
  axes object to label points on
1628
- adjust: bool
1657
+ adjust : bool
1629
1658
  automated smart label placement using adjustText
1630
1659
  objects : list of matplotlib objects
1631
1660
  use to avoid labels overlapping markers
1632
- **kwargs:
1633
- keyword arguments to ax.annotate or adjusttext
1661
+ adjust_text_kwargs
1662
+ keyword arguments to adjust_text function, only used if adjust=True
1663
+ **kwargs
1664
+ keyword arguments to ax.annotate or ax.text
1634
1665
  """
1635
1666
  stroke = [patheffects.withStroke(linewidth=3, foreground="w")]
1636
1667
  fontsize = kwargs.pop("fontsize", 10)
@@ -1647,14 +1678,15 @@ class Maps:
1647
1678
  name,
1648
1679
  fontsize=fontsize,
1649
1680
  **{"path_effects": stroke},
1681
+ **kwargs,
1650
1682
  )
1651
1683
  )
1652
-
1684
+ if adjust_text_kwargs is None:
1685
+ adjust_text_kwargs = {}
1653
1686
  adjust_text(
1654
1687
  texts,
1655
1688
  objects=objects,
1656
1689
  force_text=(0.05, 0.10),
1657
- **kwargs,
1658
1690
  **{
1659
1691
  "arrowprops": {
1660
1692
  "arrowstyle": "-",
@@ -1662,6 +1694,7 @@ class Maps:
1662
1694
  "alpha": 0.5,
1663
1695
  }
1664
1696
  },
1697
+ **adjust_text_kwargs,
1665
1698
  )
1666
1699
 
1667
1700
  else: