hydroanomaly 0.5.0__py3-none-any.whl → 0.7.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.
@@ -1,11 +1,30 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hydroanomaly
3
- Version: 0.5.0
3
+ Version: 0.7.0
4
4
  Summary: A Python package for hydro anomaly detection with simple USGS data retrieval
5
- Home-page: https://github.com/yourusername/hydroanomaly
6
- Author: Your Name
7
- Author-email: Your Name <your.email@example.com>
8
- License-Expression: MIT
5
+ Author-email: Ehsan Kahrizi <ehsan.kahrizi@usu.edu>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Your Name
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
9
28
  Project-URL: Homepage, https://github.com/yourusername/hydroanomaly
10
29
  Project-URL: Bug Reports, https://github.com/yourusername/hydroanomaly/issues
11
30
  Project-URL: Source, https://github.com/yourusername/hydroanomaly
@@ -30,10 +49,7 @@ Requires-Dist: pytest>=6.0; extra == "dev"
30
49
  Requires-Dist: black>=21.0; extra == "dev"
31
50
  Requires-Dist: flake8>=3.8; extra == "dev"
32
51
  Requires-Dist: mypy>=0.800; extra == "dev"
33
- Dynamic: author
34
- Dynamic: home-page
35
52
  Dynamic: license-file
36
- Dynamic: requires-python
37
53
 
38
54
  # HydroAnomaly
39
55
 
@@ -0,0 +1,9 @@
1
+ hydroanomaly/__init__.py,sha256=ogIwGNHlNygEY0V-GlUxvD4DBAjVTO3BXtQUZpk_WKM,1375
2
+ hydroanomaly/sentinel_bands.py,sha256=TbdyvBRe9v3YGOz4umYhSJ-16a5lCF0YLwnmArZ9Gvs,3627
3
+ hydroanomaly/usgs_turbidity.py,sha256=_KL7vKmm1StH_WfxZwhZ1g3vtiz42kNrOSEOCSGWm2E,7221
4
+ hydroanomaly/visualize.py,sha256=gkLgI3agx291jK5o08nYEbEpGpr6cD-6aAKn2Ha2Lqk,6937
5
+ hydroanomaly-0.7.0.dist-info/licenses/LICENSE,sha256=OphKV48tcMv6ep-7j-8T6nycykPT0g8ZlMJ9zbGvdPs,1066
6
+ hydroanomaly-0.7.0.dist-info/METADATA,sha256=6wPV6ouwCt8u7E7nNiet-ipKPTJM_QmSHmffKCPUgag,12962
7
+ hydroanomaly-0.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ hydroanomaly-0.7.0.dist-info/top_level.txt,sha256=t-5Lc-eTLlkxIhR_N1Cpp6_YZafKS3xLLk9D2CtbE7o,13
9
+ hydroanomaly-0.7.0.dist-info/RECORD,,
hydroanomaly/hello.py DELETED
@@ -1,29 +0,0 @@
1
- """
2
- Hello module - provides greeting functionality
3
- """
4
-
5
-
6
- def greet(name="World"):
7
- """
8
- Greet someone with a friendly message.
9
-
10
- Args:
11
- name (str): The name of the person to greet. Defaults to "World".
12
-
13
- Returns:
14
- str: A greeting message.
15
- """
16
- return f"Hello, {name}!"
17
-
18
-
19
- def say_goodbye(name="World"):
20
- """
21
- Say goodbye to someone.
22
-
23
- Args:
24
- name (str): The name of the person to say goodbye to. Defaults to "World".
25
-
26
- Returns:
27
- str: A goodbye message.
28
- """
29
- return f"Goodbye, {name}!"
@@ -1,50 +0,0 @@
1
- """
2
- Math utilities module - provides basic mathematical functions
3
- """
4
-
5
-
6
- def add(a, b):
7
- """
8
- Add two numbers together.
9
-
10
- Args:
11
- a (int/float): First number
12
- b (int/float): Second number
13
-
14
- Returns:
15
- int/float: Sum of a and b
16
- """
17
- return a + b
18
-
19
-
20
- def multiply(a, b):
21
- """
22
- Multiply two numbers together.
23
-
24
- Args:
25
- a (int/float): First number
26
- b (int/float): Second number
27
-
28
- Returns:
29
- int/float: Product of a and b
30
- """
31
- return a * b
32
-
33
-
34
- def divide(a, b):
35
- """
36
- Divide two numbers.
37
-
38
- Args:
39
- a (int/float): Dividend
40
- b (int/float): Divisor
41
-
42
- Returns:
43
- float: Result of a divided by b
44
-
45
- Raises:
46
- ValueError: If b is zero
47
- """
48
- if b == 0:
49
- raise ValueError("Cannot divide by zero")
50
- return a / b
hydroanomaly/plotting.py DELETED
@@ -1,389 +0,0 @@
1
- """
2
- Plotting Module for HydroAnomaly
3
-
4
- This module provides easy-to-use plotting functions for USGS water data time series.
5
- Creates professional-looking plots with minimal code.
6
- """
7
-
8
- import matplotlib.pyplot as plt
9
- import matplotlib.dates as mdates
10
- import seaborn as sns
11
- import pandas as pd
12
- import numpy as np
13
- from datetime import datetime
14
- from typing import Optional, Tuple, List, Dict, Any
15
- import warnings
16
-
17
- # Set style
18
- plt.style.use('default')
19
- sns.set_palette("husl")
20
-
21
-
22
- class WaterDataPlotter:
23
- """
24
- A class for creating professional time series plots of water data.
25
-
26
- This class provides methods to create various types of plots including
27
- basic time series, multi-parameter plots, and statistical visualizations.
28
- """
29
-
30
- def __init__(self, style: str = 'seaborn-v0_8', figsize: Tuple[int, int] = (12, 6)):
31
- """
32
- Initialize the plotter with default settings.
33
-
34
- Args:
35
- style (str): Matplotlib style to use
36
- figsize (tuple): Default figure size (width, height)
37
- """
38
- self.default_figsize = figsize
39
- self.colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd',
40
- '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']
41
-
42
- # Set plotting style
43
- try:
44
- plt.style.use(style)
45
- except:
46
- plt.style.use('default')
47
- warnings.warn(f"Style '{style}' not available, using default")
48
-
49
- def plot_timeseries(
50
- self,
51
- data: pd.DataFrame,
52
- parameter_name: str = "Value",
53
- title: Optional[str] = None,
54
- ylabel: Optional[str] = None,
55
- color: str = '#1f77b4',
56
- save_path: Optional[str] = None,
57
- show_stats: bool = True,
58
- figsize: Optional[Tuple[int, int]] = None
59
- ) -> plt.Figure:
60
- """
61
- Create a basic time series plot.
62
-
63
- Args:
64
- data (pd.DataFrame): Data with 'datetime' and 'value' columns
65
- parameter_name (str): Name of the parameter being plotted
66
- title (str, optional): Plot title
67
- ylabel (str, optional): Y-axis label
68
- color (str): Line color
69
- save_path (str, optional): Path to save the plot
70
- show_stats (bool): Whether to show statistics on the plot
71
- figsize (tuple, optional): Figure size
72
-
73
- Returns:
74
- matplotlib.figure.Figure: The created figure
75
- """
76
- if len(data) == 0:
77
- raise ValueError("No data to plot")
78
-
79
- figsize = figsize or self.default_figsize
80
- fig, ax = plt.subplots(figsize=figsize)
81
-
82
- # Plot the data
83
- ax.plot(data['datetime'], data['value'], color=color, linewidth=1.5, alpha=0.8)
84
-
85
- # Customize the plot
86
- if title is None:
87
- title = f"{parameter_name} Time Series"
88
- ax.set_title(title, fontsize=14, fontweight='bold', pad=20)
89
-
90
- if ylabel is None:
91
- ylabel = parameter_name
92
- ax.set_ylabel(ylabel, fontsize=12)
93
- ax.set_xlabel('Date', fontsize=12)
94
-
95
- # Format dates on x-axis
96
- self._format_date_axis(ax, data['datetime'])
97
-
98
- # Add grid
99
- ax.grid(True, alpha=0.3, linestyle='--')
100
-
101
- # Add statistics if requested
102
- if show_stats:
103
- self._add_statistics_text(ax, data['value'], parameter_name)
104
-
105
- # Improve layout
106
- plt.tight_layout()
107
-
108
- # Save if requested
109
- if save_path:
110
- plt.savefig(save_path, dpi=300, bbox_inches='tight')
111
- print(f"📊 Plot saved to: {save_path}")
112
-
113
- return fig
114
-
115
- def plot_multiple_parameters(
116
- self,
117
- data_dict: Dict[str, pd.DataFrame],
118
- title: str = "Multiple Parameters Time Series",
119
- save_path: Optional[str] = None,
120
- figsize: Optional[Tuple[int, int]] = None
121
- ) -> plt.Figure:
122
- """
123
- Plot multiple parameters on separate subplots.
124
-
125
- Args:
126
- data_dict (dict): Dictionary with parameter names as keys and DataFrames as values
127
- title (str): Main plot title
128
- save_path (str, optional): Path to save the plot
129
- figsize (tuple, optional): Figure size
130
-
131
- Returns:
132
- matplotlib.figure.Figure: The created figure
133
- """
134
- n_params = len(data_dict)
135
- if n_params == 0:
136
- raise ValueError("No data provided")
137
-
138
- figsize = figsize or (12, 4 * n_params)
139
- fig, axes = plt.subplots(n_params, 1, figsize=figsize, sharex=True)
140
-
141
- if n_params == 1:
142
- axes = [axes]
143
-
144
- colors = self.colors[:n_params]
145
-
146
- for i, (param_name, data) in enumerate(data_dict.items()):
147
- if len(data) == 0:
148
- continue
149
-
150
- ax = axes[i]
151
- ax.plot(data['datetime'], data['value'],
152
- color=colors[i], linewidth=1.5, alpha=0.8, label=param_name)
153
-
154
- ax.set_ylabel(param_name, fontsize=11)
155
- ax.grid(True, alpha=0.3, linestyle='--')
156
- ax.legend(loc='upper right')
157
-
158
- # Add basic stats
159
- mean_val = data['value'].mean()
160
- ax.axhline(y=mean_val, color=colors[i], linestyle=':', alpha=0.6,
161
- label=f'Mean: {mean_val:.2f}')
162
-
163
- # Format the bottom subplot x-axis
164
- if data_dict:
165
- sample_data = next(iter(data_dict.values()))
166
- self._format_date_axis(axes[-1], sample_data['datetime'])
167
-
168
- axes[-1].set_xlabel('Date', fontsize=12)
169
- fig.suptitle(title, fontsize=14, fontweight='bold')
170
-
171
- plt.tight_layout()
172
-
173
- if save_path:
174
- plt.savefig(save_path, dpi=300, bbox_inches='tight')
175
- print(f"📊 Plot saved to: {save_path}")
176
-
177
- return fig
178
-
179
- def plot_comparison(
180
- self,
181
- data_list: List[Tuple[pd.DataFrame, str]],
182
- title: str = "Data Comparison",
183
- ylabel: str = "Value",
184
- save_path: Optional[str] = None,
185
- figsize: Optional[Tuple[int, int]] = None
186
- ) -> plt.Figure:
187
- """
188
- Plot multiple datasets on the same axes for comparison.
189
-
190
- Args:
191
- data_list (list): List of tuples (DataFrame, label)
192
- title (str): Plot title
193
- ylabel (str): Y-axis label
194
- save_path (str, optional): Path to save the plot
195
- figsize (tuple, optional): Figure size
196
-
197
- Returns:
198
- matplotlib.figure.Figure: The created figure
199
- """
200
- if not data_list:
201
- raise ValueError("No data provided")
202
-
203
- figsize = figsize or self.default_figsize
204
- fig, ax = plt.subplots(figsize=figsize)
205
-
206
- colors = self.colors[:len(data_list)]
207
-
208
- for i, (data, label) in enumerate(data_list):
209
- if len(data) == 0:
210
- continue
211
-
212
- ax.plot(data['datetime'], data['value'],
213
- color=colors[i], linewidth=1.5, alpha=0.8, label=label)
214
-
215
- ax.set_title(title, fontsize=14, fontweight='bold', pad=20)
216
- ax.set_ylabel(ylabel, fontsize=12)
217
- ax.set_xlabel('Date', fontsize=12)
218
- ax.grid(True, alpha=0.3, linestyle='--')
219
- ax.legend()
220
-
221
- # Format dates
222
- if data_list and len(data_list[0][0]) > 0:
223
- self._format_date_axis(ax, data_list[0][0]['datetime'])
224
-
225
- plt.tight_layout()
226
-
227
- if save_path:
228
- plt.savefig(save_path, dpi=300, bbox_inches='tight')
229
- print(f"📊 Plot saved to: {save_path}")
230
-
231
- return fig
232
-
233
- def plot_statistics(
234
- self,
235
- data: pd.DataFrame,
236
- parameter_name: str = "Parameter",
237
- save_path: Optional[str] = None
238
- ) -> plt.Figure:
239
- """
240
- Create statistical plots (histogram and box plot).
241
-
242
- Args:
243
- data (pd.DataFrame): Data with 'datetime' and 'value' columns
244
- parameter_name (str): Name of the parameter
245
- save_path (str, optional): Path to save the plot
246
-
247
- Returns:
248
- matplotlib.figure.Figure: The created figure
249
- """
250
- if len(data) == 0:
251
- raise ValueError("No data to plot")
252
-
253
- fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
254
-
255
- # Histogram
256
- ax1.hist(data['value'], bins=30, alpha=0.7, color=self.colors[0], edgecolor='black')
257
- ax1.set_title(f'{parameter_name} Distribution', fontweight='bold')
258
- ax1.set_xlabel(parameter_name)
259
- ax1.set_ylabel('Frequency')
260
- ax1.grid(True, alpha=0.3)
261
-
262
- # Add statistics to histogram
263
- mean_val = data['value'].mean()
264
- median_val = data['value'].median()
265
- ax1.axvline(mean_val, color='red', linestyle='--', alpha=0.8, label=f'Mean: {mean_val:.2f}')
266
- ax1.axvline(median_val, color='orange', linestyle='--', alpha=0.8, label=f'Median: {median_val:.2f}')
267
- ax1.legend()
268
-
269
- # Box plot
270
- box_data = ax2.boxplot(data['value'], patch_artist=True)
271
- box_data['boxes'][0].set_facecolor(self.colors[1])
272
- box_data['boxes'][0].set_alpha(0.7)
273
-
274
- ax2.set_title(f'{parameter_name} Box Plot', fontweight='bold')
275
- ax2.set_ylabel(parameter_name)
276
- ax2.grid(True, alpha=0.3)
277
-
278
- plt.tight_layout()
279
-
280
- if save_path:
281
- plt.savefig(save_path, dpi=300, bbox_inches='tight')
282
- print(f"📊 Plot saved to: {save_path}")
283
-
284
- return fig
285
-
286
- def _format_date_axis(self, ax, dates):
287
- """Format the date axis based on the date range."""
288
- date_range = (dates.max() - dates.min()).days
289
-
290
- if date_range <= 7: # Less than a week
291
- ax.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d %H:%M'))
292
- ax.xaxis.set_major_locator(mdates.HourLocator(interval=6))
293
- elif date_range <= 31: # Less than a month
294
- ax.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d'))
295
- ax.xaxis.set_major_locator(mdates.DayLocator(interval=2))
296
- elif date_range <= 365: # Less than a year
297
- ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
298
- ax.xaxis.set_major_locator(mdates.MonthLocator())
299
- else: # More than a year
300
- ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))
301
- ax.xaxis.set_major_locator(mdates.YearLocator())
302
-
303
- plt.setp(ax.xaxis.get_majorticklabels(), rotation=45, ha='right')
304
-
305
- def _add_statistics_text(self, ax, values, parameter_name):
306
- """Add statistics text box to the plot."""
307
- stats_text = (
308
- f"Statistics:\n"
309
- f"Mean: {values.mean():.2f}\n"
310
- f"Median: {values.median():.2f}\n"
311
- f"Min: {values.min():.2f}\n"
312
- f"Max: {values.max():.2f}\n"
313
- f"Std: {values.std():.2f}"
314
- )
315
-
316
- # Position the text box
317
- ax.text(0.02, 0.98, stats_text, transform=ax.transAxes, fontsize=9,
318
- verticalalignment='top', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8))
319
-
320
-
321
- # Convenience functions for easy plotting
322
- def plot_usgs_data(
323
- data: pd.DataFrame,
324
- parameter_name: str = "Value",
325
- title: Optional[str] = None,
326
- save_path: Optional[str] = None,
327
- show_stats: bool = True
328
- ) -> plt.Figure:
329
- """
330
- Quick function to plot USGS time series data.
331
-
332
- Args:
333
- data (pd.DataFrame): Data with 'datetime' and 'value' columns
334
- parameter_name (str): Name of the parameter being plotted
335
- title (str, optional): Plot title
336
- save_path (str, optional): Path to save the plot
337
- show_stats (bool): Whether to show statistics on the plot
338
-
339
- Returns:
340
- matplotlib.figure.Figure: The created figure
341
-
342
- Example:
343
- >>> import hydroanomaly
344
- >>> data = hydroanomaly.get_discharge("08158000", "2023-01-01", "2023-01-31")
345
- >>> hydroanomaly.plot_usgs_data(data, "Discharge (cfs)", "Colorado River Discharge")
346
- """
347
- plotter = WaterDataPlotter()
348
- return plotter.plot_timeseries(
349
- data=data,
350
- parameter_name=parameter_name,
351
- title=title,
352
- save_path=save_path,
353
- show_stats=show_stats
354
- )
355
-
356
-
357
- def plot_multiple_gages(
358
- data_dict: Dict[str, pd.DataFrame],
359
- title: str = "Multiple Gage Comparison",
360
- parameter_name: str = "Value",
361
- save_path: Optional[str] = None
362
- ) -> plt.Figure:
363
- """
364
- Plot data from multiple gages for comparison.
365
-
366
- Args:
367
- data_dict (dict): Dictionary with gage IDs as keys and DataFrames as values
368
- title (str): Plot title
369
- parameter_name (str): Y-axis label
370
- save_path (str, optional): Path to save the plot
371
-
372
- Returns:
373
- matplotlib.figure.Figure: The created figure
374
- """
375
- plotter = WaterDataPlotter()
376
- data_list = [(data, f"Gage {gage_id}") for gage_id, data in data_dict.items()]
377
- return plotter.plot_comparison(data_list, title, parameter_name, save_path)
378
-
379
-
380
- def quick_plot(data: pd.DataFrame, title: str = "USGS Data") -> None:
381
- """
382
- Create a quick plot and show it immediately.
383
-
384
- Args:
385
- data (pd.DataFrame): Data to plot
386
- title (str): Plot title
387
- """
388
- plot_usgs_data(data, title=title)
389
- plt.show()