plans 1.1.0.post1.dev0__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.
- plans/__init__.py +41 -0
- plans/analyst.py +3092 -0
- plans/config.py +103 -0
- plans/data/.gitkeep +2 -0
- plans/data/fields.csv +61 -0
- plans/data/files.csv +26 -0
- plans/data/tools.csv +2 -0
- plans/datasets/__init__.py +42 -0
- plans/datasets/chrono.py +540 -0
- plans/datasets/core.py +6224 -0
- plans/datasets/spatial.py +1298 -0
- plans/geo.py +1397 -0
- plans/hydrology/__init__.py +42 -0
- plans/hydrology/core.py +723 -0
- plans/hydrology/downscaled.py +1024 -0
- plans/hydrology/upscaled.py +3890 -0
- plans/parsers/__init__.py +40 -0
- plans/parsers/flare.py +484 -0
- plans/parsers/inmet.py +587 -0
- plans/parsers/snirh.py +219 -0
- plans/project.py +964 -0
- plans/qutils.py +3648 -0
- plans/root.py +2256 -0
- plans/tools/__init__.py +0 -0
- plans/tools/analysis_climate_series_lulc.py +231 -0
- plans/tools/analysis_dto.py +193 -0
- plans/tools/analysis_lulc_parameters.py +269 -0
- plans/tools/analysis_lulc_series.py +220 -0
- plans/tools/analysis_soils_parameters.py +253 -0
- plans/tools/core.py +559 -0
- plans/tools/demo.py +168 -0
- plans/viewer.py +414 -0
- plans-1.1.0.post1.dev0.dist-info/METADATA +120 -0
- plans-1.1.0.post1.dev0.dist-info/RECORD +37 -0
- plans-1.1.0.post1.dev0.dist-info/WHEEL +5 -0
- plans-1.1.0.post1.dev0.dist-info/licenses/LICENSE +674 -0
- plans-1.1.0.post1.dev0.dist-info/top_level.txt +1 -0
plans/datasets/chrono.py
ADDED
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2025 The Project Authors
|
|
4
|
+
# See pyproject.toml for authors/maintainers.
|
|
5
|
+
# See LICENSE for license details.
|
|
6
|
+
"""
|
|
7
|
+
Handle chronological (time series) datasets.
|
|
8
|
+
|
|
9
|
+
Overview
|
|
10
|
+
--------
|
|
11
|
+
|
|
12
|
+
# todo [major docstring improvement] -- overview
|
|
13
|
+
Mauris gravida ex quam, in porttitor lacus lobortis vitae.
|
|
14
|
+
In a lacinia nisl. Pellentesque habitant morbi tristique senectus
|
|
15
|
+
et netus et malesuada fames ac turpis egestas.
|
|
16
|
+
|
|
17
|
+
Example
|
|
18
|
+
-------
|
|
19
|
+
|
|
20
|
+
# todo [major docstring improvement] -- examples
|
|
21
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
22
|
+
Nulla mollis tincidunt erat eget iaculis. Mauris gravida ex quam,
|
|
23
|
+
in porttitor lacus lobortis vitae. In a lacinia nisl.
|
|
24
|
+
|
|
25
|
+
.. code-block:: python
|
|
26
|
+
|
|
27
|
+
import numpy as np
|
|
28
|
+
print("Hello World!")
|
|
29
|
+
|
|
30
|
+
Mauris gravida ex quam, in porttitor lacus lobortis vitae.
|
|
31
|
+
In a lacinia nisl. Mauris gravida ex quam, in porttitor lacus lobortis vitae.
|
|
32
|
+
In a lacinia nisl.
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
from types import NoneType
|
|
36
|
+
|
|
37
|
+
# IMPORTS
|
|
38
|
+
# ***********************************************************************
|
|
39
|
+
# import modules from other libs
|
|
40
|
+
|
|
41
|
+
# Native imports
|
|
42
|
+
# =======================================================================
|
|
43
|
+
# import {module}
|
|
44
|
+
# ... {develop}
|
|
45
|
+
|
|
46
|
+
# External imports
|
|
47
|
+
# =======================================================================
|
|
48
|
+
import matplotlib.pyplot as plt
|
|
49
|
+
import numpy as np
|
|
50
|
+
import pandas as pd
|
|
51
|
+
|
|
52
|
+
# ... {develop}
|
|
53
|
+
|
|
54
|
+
# Project-level imports
|
|
55
|
+
# =======================================================================
|
|
56
|
+
from plans.datasets.core import *
|
|
57
|
+
|
|
58
|
+
# ... {develop}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# CONSTANTS
|
|
62
|
+
# ***********************************************************************
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# FUNCTIONS
|
|
66
|
+
# ***********************************************************************
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Classes
|
|
70
|
+
# ***********************************************************************
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# TIME SERIES
|
|
74
|
+
# ======================================================================
|
|
75
|
+
|
|
76
|
+
# Water Balance Series
|
|
77
|
+
# ----------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class WaterBalanceSeries(TimeSeries):
|
|
81
|
+
|
|
82
|
+
def __init__(self, name="MyWaterBalanceSeries", alias=None):
|
|
83
|
+
# Use the superior initialization from the parent class (TimeSeries)
|
|
84
|
+
super().__init__(name, alias=alias)
|
|
85
|
+
self.varname = "Flow"
|
|
86
|
+
self.varalias = "Wb"
|
|
87
|
+
self.varfield = "wb"
|
|
88
|
+
self.units = "mm"
|
|
89
|
+
self.name_object = "Water Balance Time Series"
|
|
90
|
+
self.agg = "sum" # Aggregation method
|
|
91
|
+
self.outlier_min = 0
|
|
92
|
+
self.rawcolor = "blue"
|
|
93
|
+
self.datarange_max = 10000 # absurd yearly precipitation
|
|
94
|
+
self.datarange_min = 0
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def view_pq_plot(ts_rain, ts_flow, specs, show=True, return_fig=False):
|
|
98
|
+
|
|
99
|
+
# setup hard coded of Streamflow specs
|
|
100
|
+
ts_flow.view_specs["zorder_data"] = 2
|
|
101
|
+
ts_flow.view_specs["zorder_histh"] = 2
|
|
102
|
+
ts_flow.view_specs["zorder_cdf"] = 2
|
|
103
|
+
|
|
104
|
+
# setup hard coded Rain specs
|
|
105
|
+
ts_rain.view_specs["zorder_data"] = 1
|
|
106
|
+
ts_rain.view_specs["zorder_histh"] = 1
|
|
107
|
+
ts_rain.view_specs["zorder_cdf"] = 1
|
|
108
|
+
ts_rain.view_specs["fill"] = True
|
|
109
|
+
ts_rain.view_specs["color_fill"] = None
|
|
110
|
+
ts_rain.view_specs["fill_only"] = True
|
|
111
|
+
|
|
112
|
+
output = TimeSeries.view_compare_times_series(
|
|
113
|
+
ts_first=ts_flow,
|
|
114
|
+
ts_second=ts_rain,
|
|
115
|
+
specs=specs,
|
|
116
|
+
show=show,
|
|
117
|
+
return_fig=return_fig,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
return output
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class RainSeries(WaterBalanceSeries):
|
|
124
|
+
"""
|
|
125
|
+
A class for representing and working with rainfall time series data.
|
|
126
|
+
|
|
127
|
+
**Notes**
|
|
128
|
+
|
|
129
|
+
todo notes
|
|
130
|
+
|
|
131
|
+
**Examples**
|
|
132
|
+
|
|
133
|
+
todo examples
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
def __init__(self, name="MyRainSeries", alias=None):
|
|
139
|
+
# Use the superior initialization from the parent class (TimeSeries)
|
|
140
|
+
super().__init__(name, alias=alias)
|
|
141
|
+
self.varname = "Rain"
|
|
142
|
+
self.varalias = "P"
|
|
143
|
+
self.varfield = "ppt"
|
|
144
|
+
# Overwrite attributes specific to RainSeries
|
|
145
|
+
self.name_object = "Rain Time Series"
|
|
146
|
+
self.gapsize = (
|
|
147
|
+
7 * 72
|
|
148
|
+
) # Maximum gap size of 1 week assuming measure device turns off when is not raining
|
|
149
|
+
self.rawcolor = "slateblue"
|
|
150
|
+
|
|
151
|
+
def interpolate_gaps(self, inplace=False, method=None):
|
|
152
|
+
# overwrite interpolation method with constant=0
|
|
153
|
+
super().interpolate_gaps(method="constant", constant=0, inplace=inplace)
|
|
154
|
+
return None
|
|
155
|
+
|
|
156
|
+
def _set_frequency(self):
|
|
157
|
+
super()._set_frequency()
|
|
158
|
+
# overwrite gapsize to 1 week
|
|
159
|
+
dict_gaps = {
|
|
160
|
+
"second": int(7 * 24 * 60 * 60),
|
|
161
|
+
"minute": int(7 * 24 * 3),
|
|
162
|
+
"hour": int(7 * 24),
|
|
163
|
+
"day": int(7),
|
|
164
|
+
"month": 1,
|
|
165
|
+
"year": 1,
|
|
166
|
+
}
|
|
167
|
+
self.gapsize = dict_gaps[self.dtres]
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class StreamflowSeries(WaterBalanceSeries):
|
|
172
|
+
"""
|
|
173
|
+
A class for representing and working with streamflow data (specific flow).
|
|
174
|
+
|
|
175
|
+
**Notes**
|
|
176
|
+
|
|
177
|
+
todo notes
|
|
178
|
+
|
|
179
|
+
**Examples**
|
|
180
|
+
|
|
181
|
+
todo examples
|
|
182
|
+
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
def __init__(self, name="MyStreaFlowSeries", alias=None):
|
|
186
|
+
# Use the superior initialization from the parent class (TimeSeries)
|
|
187
|
+
super().__init__(name, alias=alias)
|
|
188
|
+
self.varname = "Streamflow"
|
|
189
|
+
self.varalias = "Q"
|
|
190
|
+
self.varfield = "q"
|
|
191
|
+
# Overwrite attributes specific
|
|
192
|
+
self.name_object = "Streamflow Time Series"
|
|
193
|
+
self.rawcolor = "blue"
|
|
194
|
+
|
|
195
|
+
def get_baseflow(self):
|
|
196
|
+
# todo docstring
|
|
197
|
+
df = StreamflowSeries.separate_baseflow(
|
|
198
|
+
df=self.data, dt_field=self.dtfield, var_field=self.varfield
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
return df
|
|
202
|
+
|
|
203
|
+
@staticmethod
|
|
204
|
+
def separate_baseflow(df, dt_field="datetime", var_field="q"):
|
|
205
|
+
# todo docstring
|
|
206
|
+
|
|
207
|
+
df = df[[dt_field, var_field]].copy()
|
|
208
|
+
|
|
209
|
+
# todo develop -- improve with method options
|
|
210
|
+
w_size = 1
|
|
211
|
+
v_rises = np.zeros(len(df))
|
|
212
|
+
for i in range(w_size, len(v_rises) - w_size):
|
|
213
|
+
lcl_v = df[var_field].values[i]
|
|
214
|
+
lcl_v_last = df[var_field].values[i - w_size]
|
|
215
|
+
lcl_v_next = df[var_field].values[i + w_size]
|
|
216
|
+
if lcl_v_next > lcl_v and lcl_v_last >= lcl_v:
|
|
217
|
+
v_rises[i] = lcl_v
|
|
218
|
+
|
|
219
|
+
df_qb = df.copy()
|
|
220
|
+
df_qb["qb"] = v_rises
|
|
221
|
+
df_qb["qb"] = df_qb["qb"].replace(0, np.nan)
|
|
222
|
+
df_qb.dropna(inplace=True)
|
|
223
|
+
|
|
224
|
+
ts = StreamflowSeries()
|
|
225
|
+
ts.varfield = "qb"
|
|
226
|
+
|
|
227
|
+
# todo develop -- handle gapsize better
|
|
228
|
+
ts.gapsize = 100
|
|
229
|
+
|
|
230
|
+
ts.set_data(input_df=df_qb, input_dtfield=dt_field, input_varfield="qb")
|
|
231
|
+
ts.standardize()
|
|
232
|
+
df_qb = ts.interpolate_gaps(method="linear", inplace=False)
|
|
233
|
+
df_qb = df_qb[[ts.dtfield, f"{ts.varfield}_interp"]].copy()
|
|
234
|
+
df_qb = df_qb.rename(
|
|
235
|
+
columns={f"{ts.varfield}_interp": ts.varfield, ts.dtfield: dt_field}
|
|
236
|
+
)
|
|
237
|
+
df = pd.merge(left=df_qb, right=df, on=dt_field, how="left")
|
|
238
|
+
|
|
239
|
+
# fix qb
|
|
240
|
+
vq = df[var_field].values
|
|
241
|
+
vqb = df["qb"].values
|
|
242
|
+
df["qb"] = np.where(vqb > vq, vq, vqb)
|
|
243
|
+
|
|
244
|
+
# get qq
|
|
245
|
+
df["qq"] = df[var_field] - df["qb"]
|
|
246
|
+
|
|
247
|
+
return df
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class ETSeries(WaterBalanceSeries):
|
|
251
|
+
"""
|
|
252
|
+
A class for representing and working with ET data.
|
|
253
|
+
|
|
254
|
+
**Notes**
|
|
255
|
+
|
|
256
|
+
todo notes
|
|
257
|
+
|
|
258
|
+
**Examples**
|
|
259
|
+
|
|
260
|
+
todo examples
|
|
261
|
+
|
|
262
|
+
"""
|
|
263
|
+
|
|
264
|
+
def __init__(self, name="MyETSeries", alias=None):
|
|
265
|
+
# Use the superior initialization from the parent class
|
|
266
|
+
super().__init__(name, alias=alias)
|
|
267
|
+
self.varname = "ET"
|
|
268
|
+
self.varfield = "et"
|
|
269
|
+
# Overwrite attributes specific
|
|
270
|
+
self.name_object = "ET Time Series"
|
|
271
|
+
self.rawcolor = "red"
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
class PETSeries(WaterBalanceSeries):
|
|
275
|
+
"""
|
|
276
|
+
A class for representing and working with PET data.
|
|
277
|
+
|
|
278
|
+
**Notes**
|
|
279
|
+
|
|
280
|
+
todo notes
|
|
281
|
+
|
|
282
|
+
**Examples**
|
|
283
|
+
|
|
284
|
+
todo examples
|
|
285
|
+
|
|
286
|
+
"""
|
|
287
|
+
|
|
288
|
+
def __init__(self, name="MyPETSeries", alias=None):
|
|
289
|
+
# Use the superior initialization from the parent class (TimeSeries)
|
|
290
|
+
super().__init__(name, alias=alias)
|
|
291
|
+
self.varname = "PET"
|
|
292
|
+
self.varalias = "PET"
|
|
293
|
+
self.varfield = "pet"
|
|
294
|
+
# Overwrite attributes specific
|
|
295
|
+
self.name_object = "PET Time Series"
|
|
296
|
+
self.rawcolor = "darkred"
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# Other
|
|
300
|
+
# ----------------------------------------------------------------------
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class TemperatureSeries(TimeSeries):
|
|
304
|
+
"""
|
|
305
|
+
A class for representing and working with temperature time series data.
|
|
306
|
+
|
|
307
|
+
**Notes**
|
|
308
|
+
|
|
309
|
+
todo notes
|
|
310
|
+
|
|
311
|
+
**Examples**
|
|
312
|
+
|
|
313
|
+
todo examples
|
|
314
|
+
|
|
315
|
+
"""
|
|
316
|
+
|
|
317
|
+
def __init__(self, name="MyTemperatureSeries", alias=None):
|
|
318
|
+
# Use the superior initialization from the parent class (TimeSeries)
|
|
319
|
+
super().__init__(name, alias=alias)
|
|
320
|
+
self.varname = "Temperature"
|
|
321
|
+
self.varalias = "TAS"
|
|
322
|
+
self.varfield = "tas"
|
|
323
|
+
self.units = "Celcius"
|
|
324
|
+
# Overwrite attributes specific
|
|
325
|
+
self.name_object = "Temperature Time Series"
|
|
326
|
+
self.agg = "mean" # Aggregation method,
|
|
327
|
+
self.gapsize = 6 # Maximum gap size of 6 hours assuming hourly Temperature
|
|
328
|
+
self.datarange_max = 50
|
|
329
|
+
self.datarange_min = -20
|
|
330
|
+
self.rawcolor = "orange"
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class StageSeries(TimeSeries):
|
|
334
|
+
"""
|
|
335
|
+
A class for representing and working with river stage time series data.
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
**Notes**
|
|
339
|
+
|
|
340
|
+
todo notes
|
|
341
|
+
|
|
342
|
+
**Examples**
|
|
343
|
+
|
|
344
|
+
todo examples
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
"""
|
|
348
|
+
|
|
349
|
+
def __init__(self, name="MyStageSeries", alias=None):
|
|
350
|
+
"""
|
|
351
|
+
Initialize a ``StageSeries`` object.
|
|
352
|
+
"""
|
|
353
|
+
# Use the superior initialization from the parent class (TimeSeries)
|
|
354
|
+
super().__init__(name, alias=alias)
|
|
355
|
+
self.varname = "Stage"
|
|
356
|
+
self.varalias = "H"
|
|
357
|
+
self.varfield = "H"
|
|
358
|
+
self.units = "cm"
|
|
359
|
+
# Overwrite attributes specific to StageSeries
|
|
360
|
+
self.name_object = "Stage Time Series"
|
|
361
|
+
self.agg = "mean" # Aggregation method, set to "mean" by default
|
|
362
|
+
self.gapsize = 10 # Maximum gap size allowed for data interpolation
|
|
363
|
+
# Extra attributes specific to StageSeries
|
|
364
|
+
self.upstream_area = None
|
|
365
|
+
|
|
366
|
+
def get_metadata(self):
|
|
367
|
+
# Get metadata from the base class (TimeSeries)
|
|
368
|
+
base_metadata = super().get_metadata()
|
|
369
|
+
# Additional TimeSeries-specific metadata
|
|
370
|
+
extra_metadata = {
|
|
371
|
+
"UpstreamArea": self.upstream_area,
|
|
372
|
+
}
|
|
373
|
+
# Combine both base and specific metadata
|
|
374
|
+
base_metadata.update(extra_metadata)
|
|
375
|
+
return base_metadata
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
class DischargeSeries(TimeSeries):
|
|
379
|
+
"""
|
|
380
|
+
A class for representing and working with discharge time series data (volumentric flow).
|
|
381
|
+
|
|
382
|
+
**Notes**
|
|
383
|
+
|
|
384
|
+
todo notes
|
|
385
|
+
|
|
386
|
+
**Examples**
|
|
387
|
+
|
|
388
|
+
todo examples
|
|
389
|
+
|
|
390
|
+
"""
|
|
391
|
+
|
|
392
|
+
def __init__(self, name="MyFlowSeries", alias=None):
|
|
393
|
+
# Use the superior initialization from the parent class (TimeSeries)
|
|
394
|
+
super().__init__(name, alias=alias)
|
|
395
|
+
self.varname = "Discharge"
|
|
396
|
+
self.varfield = "Q"
|
|
397
|
+
self.varalias = self.varfield
|
|
398
|
+
self.units = "m3/s"
|
|
399
|
+
# Overwrite attributes specific
|
|
400
|
+
self.name_object = "Discharge Time Series"
|
|
401
|
+
self.agg = "mean" # Aggregation method, set to "mean" by default
|
|
402
|
+
self.gapsize = 6 # Maximum gap size of 6 hours assuming hourly Flow
|
|
403
|
+
self.datarange_max = 300000 # Amazon discharge
|
|
404
|
+
self.datarange_min = 0
|
|
405
|
+
self.rawcolor = "navy"
|
|
406
|
+
# Specific attributes
|
|
407
|
+
self.upstream_area = None # in sq km
|
|
408
|
+
|
|
409
|
+
@staticmethod
|
|
410
|
+
def view_cfcs(freqs, specs=None, show=True, colors=None, labels=None):
|
|
411
|
+
import matplotlib.pyplot as plt
|
|
412
|
+
|
|
413
|
+
default_specs = {
|
|
414
|
+
"folder": "C:/data",
|
|
415
|
+
"filename": "cfcs",
|
|
416
|
+
"fig_format": "jpg",
|
|
417
|
+
"dpi": 300,
|
|
418
|
+
"width": 4,
|
|
419
|
+
"height": 6,
|
|
420
|
+
"xmin": 0,
|
|
421
|
+
"xmax": 100,
|
|
422
|
+
"ymin": 0,
|
|
423
|
+
"ymin_log": 1,
|
|
424
|
+
"ymax": None,
|
|
425
|
+
"log": True,
|
|
426
|
+
"title": "CFCs",
|
|
427
|
+
"ylabel": "m3/s",
|
|
428
|
+
"xlabel": "Exeed. Prob. (%)",
|
|
429
|
+
}
|
|
430
|
+
# get specs
|
|
431
|
+
if specs is not None:
|
|
432
|
+
default_specs.update(specs)
|
|
433
|
+
specs = default_specs.copy()
|
|
434
|
+
|
|
435
|
+
# --------------------- figure setup --------------------- #
|
|
436
|
+
fig = plt.figure(figsize=(specs["width"], specs["height"])) # Width, Height
|
|
437
|
+
|
|
438
|
+
# handle min max
|
|
439
|
+
if specs["ymax"] is None:
|
|
440
|
+
lst_max = [freq["Values"].max() for freq in freqs]
|
|
441
|
+
specs["ymax"] = max(lst_max)
|
|
442
|
+
|
|
443
|
+
if colors is None:
|
|
444
|
+
colors = ["navy" for freq in freqs]
|
|
445
|
+
if labels is None:
|
|
446
|
+
labels = [None for freq in freqs]
|
|
447
|
+
|
|
448
|
+
# --------------------- plotting --------------------- #
|
|
449
|
+
for i in range(len(freqs)):
|
|
450
|
+
plt.plot(
|
|
451
|
+
freqs[i]["Exceedance"],
|
|
452
|
+
freqs[i]["Values"],
|
|
453
|
+
color=colors[i],
|
|
454
|
+
label=labels[i],
|
|
455
|
+
)
|
|
456
|
+
if labels is not None:
|
|
457
|
+
plt.legend()
|
|
458
|
+
|
|
459
|
+
# --------------------- post-plotting --------------------- #
|
|
460
|
+
# set basic plotting stuff
|
|
461
|
+
plt.title(specs["title"])
|
|
462
|
+
plt.ylabel(specs["ylabel"])
|
|
463
|
+
plt.xlabel(specs["xlabel"])
|
|
464
|
+
plt.xlim(specs["xmin"], specs["xmax"])
|
|
465
|
+
if specs["log"]:
|
|
466
|
+
plt.ylim(specs["ymin_log"], 1.2 * specs["ymax"])
|
|
467
|
+
plt.yscale("log")
|
|
468
|
+
else:
|
|
469
|
+
plt.ylim(specs["ymin"], 1.2 * specs["ymax"])
|
|
470
|
+
|
|
471
|
+
# Get current axes
|
|
472
|
+
ax = plt.gca()
|
|
473
|
+
# Set the y-ticks more densely
|
|
474
|
+
ax.set_yticks([1, 2.5, 5, 10, 25, 50, 100, 250, 500])
|
|
475
|
+
|
|
476
|
+
# Adjust layout to prevent cutoff
|
|
477
|
+
plt.tight_layout()
|
|
478
|
+
|
|
479
|
+
# --------------------- end --------------------- #
|
|
480
|
+
# show or save
|
|
481
|
+
if show:
|
|
482
|
+
plt.show()
|
|
483
|
+
return None
|
|
484
|
+
else:
|
|
485
|
+
file_path = "{}/{}.{}".format(
|
|
486
|
+
specs["folder"], specs["filename"], specs["fig_format"]
|
|
487
|
+
)
|
|
488
|
+
plt.savefig(file_path, dpi=specs["dpi"])
|
|
489
|
+
plt.close(fig)
|
|
490
|
+
return file_path
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
# ------------- TIME SERIES COLLECTIONS ------------- #
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
class RainSeriesSamples(TimeSeriesSpatialSamples):
|
|
497
|
+
# todo docstring
|
|
498
|
+
|
|
499
|
+
def __init__(self, name="MyRSColection"):
|
|
500
|
+
# todo docstring
|
|
501
|
+
super().__init__(name=name, base_object=RainSeries)
|
|
502
|
+
# overwrite parent attributes
|
|
503
|
+
self.name_object = "Rainfall Series Samples"
|
|
504
|
+
self._set_view_specs()
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
class TemperatureSeriesSamples(TimeSeriesSpatialSamples):
|
|
508
|
+
# todo docstring
|
|
509
|
+
|
|
510
|
+
def __init__(self, name="MyTempSColection"):
|
|
511
|
+
# todo docstring
|
|
512
|
+
super().__init__(name=name, base_object=TemperatureSeries)
|
|
513
|
+
# overwrite parent attributes
|
|
514
|
+
self.name_object = "Temperature Series Sample"
|
|
515
|
+
self._set_view_specs()
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
class StageSeriesCollection(TimeSeriesCluster):
|
|
519
|
+
# todo docstring
|
|
520
|
+
def __init__(self, name="MySSColection"):
|
|
521
|
+
# todo docstring
|
|
522
|
+
super().__init__(name=name, base_object=StageSeries)
|
|
523
|
+
# overwrite parent attributes
|
|
524
|
+
self.name_object = "Stage Series Collection"
|
|
525
|
+
self._set_view_specs()
|
|
526
|
+
|
|
527
|
+
def set_data(self, df_info, src_dir=None, filter_dates=None):
|
|
528
|
+
# generic part
|
|
529
|
+
super().set_data(df_info=df_info, filter_dates=filter_dates)
|
|
530
|
+
# custom part
|
|
531
|
+
for i in range(len(df_info)):
|
|
532
|
+
name = df_info["Name"].values[i]
|
|
533
|
+
self.collection[name].upstream_area = df_info["UpstreamArea"].values[i]
|
|
534
|
+
self.update(details=True)
|
|
535
|
+
return None
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
if __name__ == "__main__":
|
|
539
|
+
print("Hello World")
|
|
540
|
+
# todo [move to testing]
|