hydroanomaly 0.2.0__py3-none-any.whl → 0.4.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.
- hydroanomaly/__init__.py +133 -3
- hydroanomaly/plotting.py +389 -0
- hydroanomaly/sentinel_data.py +516 -0
- hydroanomaly-0.4.0.dist-info/METADATA +405 -0
- hydroanomaly-0.4.0.dist-info/RECORD +11 -0
- hydroanomaly-0.2.0.dist-info/METADATA +0 -227
- hydroanomaly-0.2.0.dist-info/RECORD +0 -9
- {hydroanomaly-0.2.0.dist-info → hydroanomaly-0.4.0.dist-info}/WHEEL +0 -0
- {hydroanomaly-0.2.0.dist-info → hydroanomaly-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {hydroanomaly-0.2.0.dist-info → hydroanomaly-0.4.0.dist-info}/top_level.txt +0 -0
hydroanomaly/__init__.py
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
"""
|
2
2
|
HydroAnomaly
|
3
3
|
|
4
|
-
A Python package for hydro anomaly detection
|
4
|
+
A Python package for hydro anomaly detection, USGS data retrieval,
|
5
|
+
time series visualization, and Sentinel satellite data analysis.
|
5
6
|
"""
|
6
7
|
|
7
|
-
__version__ = "0.
|
8
|
+
__version__ = "0.4.0"
|
8
9
|
__author__ = "Your Name"
|
9
10
|
__email__ = "your.email@example.com"
|
10
11
|
|
@@ -12,5 +13,134 @@ __email__ = "your.email@example.com"
|
|
12
13
|
from .hello import greet
|
13
14
|
from .math_utils import add, multiply
|
14
15
|
from .usgs_data import get_usgs_data, USGSDataRetriever
|
16
|
+
from .plotting import plot_usgs_data, plot_multiple_gages, quick_plot, WaterDataPlotter
|
15
17
|
|
16
|
-
|
18
|
+
# Base exports
|
19
|
+
__all__ = [
|
20
|
+
'greet',
|
21
|
+
'add', 'multiply',
|
22
|
+
'get_usgs_data', 'USGSDataRetriever',
|
23
|
+
'plot_usgs_data', 'plot_multiple_gages', 'quick_plot', 'WaterDataPlotter',
|
24
|
+
'get_discharge', 'get_temperature', 'get_water_level'
|
25
|
+
]
|
26
|
+
|
27
|
+
# Try to import Sentinel functionality (optional GEE dependency)
|
28
|
+
try:
|
29
|
+
from .sentinel_data import (
|
30
|
+
SentinelDataRetriever,
|
31
|
+
SentinelConfig,
|
32
|
+
setup_gee_authentication,
|
33
|
+
initialize_gee,
|
34
|
+
get_water_area_time_series,
|
35
|
+
detect_water_changes
|
36
|
+
)
|
37
|
+
_SENTINEL_AVAILABLE = True
|
38
|
+
|
39
|
+
# Add Sentinel functions to exports
|
40
|
+
__all__.extend([
|
41
|
+
'SentinelDataRetriever',
|
42
|
+
'SentinelConfig',
|
43
|
+
'setup_gee_authentication',
|
44
|
+
'initialize_gee',
|
45
|
+
'get_water_area_time_series',
|
46
|
+
'detect_water_changes'
|
47
|
+
])
|
48
|
+
|
49
|
+
except ImportError as e:
|
50
|
+
print("⚠️ Sentinel data functionality not available.")
|
51
|
+
print("💡 To use Google Earth Engine features, install:")
|
52
|
+
print(" pip install earthengine-api")
|
53
|
+
print(" Then authenticate: earthengine authenticate")
|
54
|
+
_SENTINEL_AVAILABLE = False
|
55
|
+
|
56
|
+
# Create placeholder functions for better error messages
|
57
|
+
def setup_gee_authentication(*args, **kwargs):
|
58
|
+
raise ImportError("Google Earth Engine not available. Install with: pip install earthengine-api")
|
59
|
+
|
60
|
+
def initialize_gee(*args, **kwargs):
|
61
|
+
raise ImportError("Google Earth Engine not available. Install with: pip install earthengine-api")
|
62
|
+
|
63
|
+
def get_water_area_time_series(*args, **kwargs):
|
64
|
+
raise ImportError("Google Earth Engine not available. Install with: pip install earthengine-api")
|
65
|
+
|
66
|
+
def detect_water_changes(*args, **kwargs):
|
67
|
+
raise ImportError("Google Earth Engine not available. Install with: pip install earthengine-api")
|
68
|
+
|
69
|
+
# Convenience functions for common use cases
|
70
|
+
def get_discharge(gage_number, start_date, end_date, save_file=None):
|
71
|
+
"""
|
72
|
+
Quick function to get discharge data from any USGS gage.
|
73
|
+
|
74
|
+
Args:
|
75
|
+
gage_number (str): USGS gage number (e.g., "08158000")
|
76
|
+
start_date (str): Start date in YYYY-MM-DD format
|
77
|
+
end_date (str): End date in YYYY-MM-DD format
|
78
|
+
save_file (str, optional): Filename to save data
|
79
|
+
|
80
|
+
Returns:
|
81
|
+
pandas.DataFrame: Discharge data
|
82
|
+
|
83
|
+
Example:
|
84
|
+
>>> import hydroanomaly
|
85
|
+
>>> data = hydroanomaly.get_discharge("08158000", "2023-01-01", "2023-01-31")
|
86
|
+
>>> print(f"Got {len(data)} discharge measurements")
|
87
|
+
"""
|
88
|
+
return get_usgs_data(
|
89
|
+
site_number=gage_number,
|
90
|
+
parameter_code="00060", # Discharge
|
91
|
+
start_date=start_date,
|
92
|
+
end_date=end_date,
|
93
|
+
save_to_file=save_file,
|
94
|
+
parameter_name="Discharge_cfs"
|
95
|
+
)
|
96
|
+
|
97
|
+
def get_water_level(gage_number, start_date, end_date, save_file=None):
|
98
|
+
"""
|
99
|
+
Quick function to get water level data from any USGS gage.
|
100
|
+
|
101
|
+
Args:
|
102
|
+
gage_number (str): USGS gage number (e.g., "08158000")
|
103
|
+
start_date (str): Start date in YYYY-MM-DD format
|
104
|
+
end_date (str): End date in YYYY-MM-DD format
|
105
|
+
save_file (str, optional): Filename to save data
|
106
|
+
|
107
|
+
Returns:
|
108
|
+
pandas.DataFrame: Water level data
|
109
|
+
"""
|
110
|
+
return get_usgs_data(
|
111
|
+
site_number=gage_number,
|
112
|
+
parameter_code="00065", # Gage height
|
113
|
+
start_date=start_date,
|
114
|
+
end_date=end_date,
|
115
|
+
save_to_file=save_file,
|
116
|
+
parameter_name="WaterLevel_ft"
|
117
|
+
)
|
118
|
+
|
119
|
+
def get_temperature(gage_number, start_date, end_date, save_file=None):
|
120
|
+
"""
|
121
|
+
Quick function to get water temperature data from any USGS gage.
|
122
|
+
|
123
|
+
Args:
|
124
|
+
gage_number (str): USGS gage number (e.g., "08158000")
|
125
|
+
start_date (str): Start date in YYYY-MM-DD format
|
126
|
+
end_date (str): End date in YYYY-MM-DD format
|
127
|
+
save_file (str, optional): Filename to save data
|
128
|
+
|
129
|
+
Returns:
|
130
|
+
pandas.DataFrame: Temperature data
|
131
|
+
"""
|
132
|
+
return get_usgs_data(
|
133
|
+
site_number=gage_number,
|
134
|
+
parameter_code="00010", # Temperature
|
135
|
+
start_date=start_date,
|
136
|
+
end_date=end_date,
|
137
|
+
save_to_file=save_file,
|
138
|
+
parameter_name="Temperature_C"
|
139
|
+
)
|
140
|
+
|
141
|
+
__all__ = [
|
142
|
+
"greet", "add", "multiply",
|
143
|
+
"get_usgs_data", "USGSDataRetriever",
|
144
|
+
"get_discharge", "get_water_level", "get_temperature",
|
145
|
+
"plot_usgs_data", "plot_multiple_gages", "quick_plot", "WaterDataPlotter"
|
146
|
+
]
|
hydroanomaly/plotting.py
ADDED
@@ -0,0 +1,389 @@
|
|
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()
|