hydroanomaly 0.6.0__py3-none-any.whl → 0.7.1__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 +7 -7
- hydroanomaly/sentinel_bands.py +82 -135
- hydroanomaly/usgs_turbidity.py +41 -55
- {hydroanomaly-0.6.0.dist-info → hydroanomaly-0.7.1.dist-info}/METADATA +24 -8
- hydroanomaly-0.7.1.dist-info/RECORD +9 -0
- hydroanomaly-0.6.0.dist-info/RECORD +0 -9
- {hydroanomaly-0.6.0.dist-info → hydroanomaly-0.7.1.dist-info}/WHEEL +0 -0
- {hydroanomaly-0.6.0.dist-info → hydroanomaly-0.7.1.dist-info}/licenses/LICENSE +0 -0
- {hydroanomaly-0.6.0.dist-info → hydroanomaly-0.7.1.dist-info}/top_level.txt +0 -0
hydroanomaly/__init__.py
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
HydroAnomaly: Simple Water Data Analysis Package
|
3
3
|
|
4
4
|
A simple Python package with just 3 modules:
|
5
|
-
1. USGS turbidity data retrieval
|
5
|
+
1. USGS turbidity data retrieval (returns data and site coordinates)
|
6
6
|
2. Sentinel satellite bands retrieval
|
7
7
|
3. Time series visualization
|
8
8
|
|
9
9
|
That's it - nothing else!
|
10
10
|
"""
|
11
11
|
|
12
|
-
__version__ = "0.
|
13
|
-
__author__ = "
|
12
|
+
__version__ = "0.7.1"
|
13
|
+
__author__ = "Ehsan Kahrizi (Ehsan.kahrizi@usu.edu)"
|
14
14
|
|
15
15
|
# Import the 3 simple modules
|
16
16
|
from .usgs_turbidity import get_turbidity, get_usgs_turbidity
|
@@ -38,9 +38,9 @@ __all__ = [
|
|
38
38
|
'visualize'
|
39
39
|
]
|
40
40
|
|
41
|
-
print(f"
|
42
|
-
print("
|
43
|
-
print(" • get_turbidity() - Get USGS turbidity data")
|
41
|
+
print(f"HydroAnomaly v{__version__} - Simple Water Data Package")
|
42
|
+
print("Available functions:")
|
43
|
+
print(" • get_turbidity() - Get USGS turbidity data and site coordinates")
|
44
44
|
print(" • get_sentinel_bands() - Get satellite data")
|
45
45
|
print(" • plot_timeseries() - Visualize data")
|
46
|
-
print("
|
46
|
+
print("Try: help(hydroanomaly.get_turbidity) for examples")
|
hydroanomaly/sentinel_bands.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
"""
|
2
|
-
|
2
|
+
Sentinel-2 Satellite Data Retrieval using Google Earth Engine (GEE)
|
3
3
|
|
4
|
-
This module provides
|
5
|
-
|
4
|
+
This module provides a function to retrieve Sentinel-2 satellite band data
|
5
|
+
for a specified location and time period, with masking and cloud filtering.
|
6
6
|
"""
|
7
7
|
|
8
8
|
import pandas as pd
|
@@ -11,147 +11,94 @@ from datetime import datetime, timedelta
|
|
11
11
|
import requests
|
12
12
|
import warnings
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
def get_sentinel_bands_gee(
|
15
|
+
latitude: float,
|
16
|
+
longitude: float,
|
17
|
+
start_date: str,
|
18
|
+
end_date: str,
|
19
|
+
bands: list = None,
|
20
|
+
buffer_meters: int = 20,
|
21
|
+
cloudy_pixel_percentage: int = 20,
|
22
|
+
masks_to_apply: list = None
|
23
|
+
) -> pd.DataFrame:
|
16
24
|
"""
|
17
|
-
|
18
|
-
|
25
|
+
Retrieve Sentinel-2 bands from Google Earth Engine, applying custom masking.
|
26
|
+
|
19
27
|
Args:
|
20
|
-
latitude (float): Latitude
|
21
|
-
longitude (float): Longitude
|
22
|
-
start_date (str): Start date as "YYYY-MM-DD"
|
23
|
-
end_date (str): End date as "YYYY-MM-DD"
|
24
|
-
bands (list): List of bands to retrieve (default
|
25
|
-
|
28
|
+
latitude (float): Latitude of center point.
|
29
|
+
longitude (float): Longitude of center point.
|
30
|
+
start_date (str): Start date as "YYYY-MM-DD".
|
31
|
+
end_date (str): End date as "YYYY-MM-DD".
|
32
|
+
bands (list): List of bands to retrieve (default is common Sentinel-2 bands).
|
33
|
+
buffer_meters (int): Buffer size around the point, in meters.
|
34
|
+
cloudy_pixel_percentage (int): Maximum allowed cloud percentage for each image.
|
35
|
+
masks_to_apply (list): Masking strategies (e.g., ["water", "no_cloud_shadow", ...]).
|
36
|
+
|
26
37
|
Returns:
|
27
|
-
pd.DataFrame:
|
28
|
-
|
38
|
+
pd.DataFrame: DataFrame with band reflectance values per date.
|
39
|
+
|
29
40
|
Example:
|
30
|
-
>>>
|
31
|
-
>>>
|
41
|
+
>>> import ee
|
42
|
+
>>> ee.Authenticate()
|
43
|
+
>>> ee.Initialize()
|
44
|
+
>>> df = get_sentinel_bands_gee(29.77, -95.06, "2021-01-01", "2021-12-31")
|
45
|
+
>>> print(df.head())
|
32
46
|
"""
|
33
|
-
|
34
47
|
if bands is None:
|
35
|
-
bands = ['B2',
|
36
|
-
|
37
|
-
|
38
|
-
print(f"📅 Date range: {start_date} to {end_date}")
|
39
|
-
print(f"📡 Bands: {', '.join(bands)}")
|
40
|
-
|
41
|
-
try:
|
42
|
-
# Try to get real Sentinel data (this would normally use Google Earth Engine or similar)
|
43
|
-
# For now, we'll create realistic synthetic data
|
44
|
-
print("⚠️ Creating synthetic Sentinel data (real API integration would go here)")
|
45
|
-
return _create_synthetic_sentinel(latitude, longitude, start_date, end_date, bands)
|
46
|
-
|
47
|
-
except Exception as e:
|
48
|
-
print(f"❌ Error: {e}")
|
49
|
-
print("🔄 Creating synthetic Sentinel data...")
|
50
|
-
return _create_synthetic_sentinel(latitude, longitude, start_date, end_date, bands)
|
48
|
+
bands = ['B2','B3','B4','B8','SCL']
|
49
|
+
if masks_to_apply is None:
|
50
|
+
masks_to_apply = ["water", "no_cloud_shadow", "no_clouds", "no_snow_ice", "no_saturated"]
|
51
51
|
|
52
|
+
point = ee.Geometry.Point([longitude, latitude])
|
53
|
+
buffered_point = point.buffer(buffer_meters)
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end_dt = datetime.strptime(end_date, "%Y-%m-%d")
|
59
|
-
|
60
|
-
# Create observation dates (every 5-10 days, accounting for clouds)
|
61
|
-
observation_dates = []
|
62
|
-
current_date = start_dt
|
63
|
-
|
64
|
-
while current_date <= end_dt:
|
65
|
-
# Add some randomness to simulate real satellite schedule
|
66
|
-
if np.random.random() > 0.3: # 70% chance of successful observation
|
67
|
-
observation_dates.append(current_date)
|
68
|
-
|
69
|
-
# Next observation in 5-10 days
|
70
|
-
days_to_add = np.random.randint(5, 11)
|
71
|
-
current_date += timedelta(days=days_to_add)
|
72
|
-
|
73
|
-
if len(observation_dates) == 0:
|
74
|
-
print("⚠️ No observation dates generated")
|
75
|
-
return pd.DataFrame()
|
76
|
-
|
77
|
-
# Generate realistic band values
|
78
|
-
data_dict = {'datetime': observation_dates}
|
79
|
-
|
80
|
-
for band in bands:
|
81
|
-
if band == 'B2': # Blue (450-520nm)
|
82
|
-
base_value = 1200
|
83
|
-
variation = 300
|
84
|
-
elif band == 'B3': # Green (520-600nm)
|
85
|
-
base_value = 1400
|
86
|
-
variation = 350
|
87
|
-
elif band == 'B4': # Red (630-690nm)
|
88
|
-
base_value = 1300
|
89
|
-
variation = 400
|
90
|
-
elif band == 'B8': # NIR (760-900nm)
|
91
|
-
base_value = 2800
|
92
|
-
variation = 800
|
93
|
-
else: # Generic band
|
94
|
-
base_value = 1500
|
95
|
-
variation = 400
|
96
|
-
|
97
|
-
# Generate values with seasonal and random variation
|
98
|
-
band_values = []
|
99
|
-
for i, date in enumerate(observation_dates):
|
100
|
-
# Seasonal variation (higher vegetation in summer)
|
101
|
-
day_of_year = date.timetuple().tm_yday
|
102
|
-
seasonal_factor = np.sin(2 * np.pi * day_of_year / 365) * 0.2
|
103
|
-
|
104
|
-
# Random variation
|
105
|
-
noise = np.random.normal(0, variation * 0.3)
|
106
|
-
|
107
|
-
# Calculate final value
|
108
|
-
value = base_value * (1 + seasonal_factor) + noise
|
109
|
-
value = max(0, int(value)) # Ensure positive integer values
|
110
|
-
|
111
|
-
band_values.append(value)
|
112
|
-
|
113
|
-
data_dict[band] = band_values
|
114
|
-
|
115
|
-
# Create DataFrame
|
116
|
-
result = pd.DataFrame(data_dict)
|
117
|
-
result['datetime'] = pd.to_datetime(result['datetime'])
|
118
|
-
result = result.set_index('datetime')
|
119
|
-
|
120
|
-
print(f"📊 Created {len(result)} synthetic Sentinel observations")
|
121
|
-
print(f"📡 Bands included: {', '.join(bands)}")
|
122
|
-
|
123
|
-
return result
|
55
|
+
s2 = (ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED')
|
56
|
+
.filterBounds(buffered_point)
|
57
|
+
.filterDate(start_date, end_date)
|
58
|
+
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', cloudy_pixel_percentage))
|
59
|
+
.select(bands))
|
124
60
|
|
61
|
+
def dynamic_scl_mask(image):
|
62
|
+
scl = image.select('SCL')
|
63
|
+
mask = ee.Image.constant(1)
|
64
|
+
if "water" in masks_to_apply:
|
65
|
+
mask = mask.And(scl.eq(6))
|
66
|
+
if "no_cloud_shadow" in masks_to_apply:
|
67
|
+
mask = mask.And(scl.neq(3))
|
68
|
+
if "no_clouds" in masks_to_apply:
|
69
|
+
cloud_mask = scl.neq(8).And(scl.neq(9)).And(scl.neq(10))
|
70
|
+
mask = mask.And(cloud_mask)
|
71
|
+
if "no_snow_ice" in masks_to_apply:
|
72
|
+
mask = mask.And(scl.neq(11))
|
73
|
+
if "no_saturated" in masks_to_apply:
|
74
|
+
mask = mask.And(scl.neq(1))
|
75
|
+
return image.updateMask(mask)
|
125
76
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
# Calculate NDVI = (NIR - Red) / (NIR + Red)
|
142
|
-
red = sentinel_data['B4']
|
143
|
-
nir = sentinel_data['B8']
|
144
|
-
|
145
|
-
ndvi = (nir - red) / (nir + red)
|
146
|
-
|
147
|
-
result = pd.DataFrame({'NDVI': ndvi}, index=sentinel_data.index)
|
148
|
-
|
149
|
-
print(f"📊 Calculated NDVI for {len(result)} observations")
|
150
|
-
print(f"🌱 NDVI range: {ndvi.min():.3f} to {ndvi.max():.3f}")
|
151
|
-
|
152
|
-
return result
|
77
|
+
s2_masked = s2.map(dynamic_scl_mask)
|
78
|
+
|
79
|
+
def extract_features(image):
|
80
|
+
date = image.date().format('YYYY-MM-dd HH:mm:ss')
|
81
|
+
values = image.reduceRegion(
|
82
|
+
reducer=ee.Reducer.mean(),
|
83
|
+
geometry=buffered_point,
|
84
|
+
scale=20,
|
85
|
+
maxPixels=1e8
|
86
|
+
)
|
87
|
+
return ee.Feature(None, values.set('date', date))
|
88
|
+
|
89
|
+
features = s2_masked.map(extract_features)
|
90
|
+
fc = ee.FeatureCollection(features).filter(ee.Filter.notNull(['B2']))
|
153
91
|
|
92
|
+
data = fc.getInfo()
|
93
|
+
rows = [f['properties'] for f in data['features']]
|
94
|
+
df = pd.DataFrame(rows)
|
95
|
+
if not df.empty:
|
96
|
+
df['date'] = pd.to_datetime(df['date'])
|
97
|
+
df = df.sort_values('date')
|
98
|
+
df = df.set_index('date')
|
99
|
+
return df
|
154
100
|
|
155
|
-
#
|
156
|
-
|
157
|
-
|
101
|
+
# Aliases for user convenience
|
102
|
+
get_sentinel_bands = get_sentinel_bands_gee
|
103
|
+
get_satellite_data = get_sentinel_bands_gee
|
104
|
+
get_sentinel = get_sentinel_bands_gee
|
hydroanomaly/usgs_turbidity.py
CHANGED
@@ -11,7 +11,7 @@ from io import StringIO
|
|
11
11
|
from datetime import datetime
|
12
12
|
import numpy as np
|
13
13
|
|
14
|
-
|
14
|
+
# Function for retrive data ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
15
15
|
def get_turbidity(site_number: str, start_date: str, end_date: str) -> pd.DataFrame:
|
16
16
|
"""
|
17
17
|
Get turbidity data from a USGS station.
|
@@ -22,50 +22,75 @@ def get_turbidity(site_number: str, start_date: str, end_date: str) -> pd.DataFr
|
|
22
22
|
end_date (str): End date as "YYYY-MM-DD"
|
23
23
|
|
24
24
|
Returns:
|
25
|
-
pd.DataFrame
|
25
|
+
tuple: (pd.DataFrame, (latitude, longitude)) or (empty DataFrame, (None, None)) if not found.
|
26
|
+
* Note: pd.DataFrame: Time series data with datetime index and turbidity values
|
26
27
|
|
27
28
|
Example:
|
28
29
|
>>> data = get_turbidity("294643095035200", "2023-01-01", "2023-12-31")
|
29
30
|
>>> print(f"Got {len(data)} turbidity measurements")
|
30
31
|
"""
|
32
|
+
|
33
|
+
# --- Validate inputs ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
34
|
+
print(f"Getting turbidity data for site {site_number}")
|
35
|
+
print(f"Date range: {start_date} to {end_date}")
|
36
|
+
|
37
|
+
# --- Retrieve site metadata (lat/lon) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
38
|
+
site_url = (
|
39
|
+
f"https://waterservices.usgs.gov/nwis/site/"
|
40
|
+
f"?sites={site_number}"
|
41
|
+
f"&format=rdb")
|
42
|
+
try:
|
43
|
+
site_resp = requests.get(site_url, timeout=15)
|
44
|
+
if site_resp.status_code != 200:
|
45
|
+
print(f"Could not get site metadata: {site_resp.status_code}")
|
46
|
+
lat, lon = None, None
|
47
|
+
else:
|
48
|
+
df_meta = pd.read_csv(StringIO(site_resp.text), sep="\t", comment="#")
|
49
|
+
df_meta = df_meta.dropna(axis=1, how="all")
|
50
|
+
lat, lon = None, None
|
51
|
+
if not df_meta.empty:
|
52
|
+
lat = float(df_meta["dec_lat_va"].iloc[0]) if "dec_lat_va" in df_meta.columns else None
|
53
|
+
lon = float(df_meta["dec_long_va"].iloc[0]) if "dec_long_va" in df_meta.columns else None
|
54
|
+
except Exception as e:
|
55
|
+
print(f"Error getting site coordinates: {e}")
|
56
|
+
lat, lon = None, None
|
31
57
|
|
32
|
-
print(f"🌊 Getting turbidity data for site {site_number}")
|
33
|
-
print(f"📅 Date range: {start_date} to {end_date}")
|
34
58
|
|
35
|
-
# Build USGS API URL for turbidity (parameter code 63680)
|
59
|
+
# --- Retrieve turbidity data (Build USGS API URL for turbidity (parameter code 63680))------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
36
60
|
url = (
|
37
61
|
f"https://waterservices.usgs.gov/nwis/iv/"
|
38
62
|
f"?sites={site_number}"
|
39
63
|
f"¶meterCd=63680" # Turbidity parameter code
|
40
64
|
f"&startDT={start_date}"
|
41
65
|
f"&endDT={end_date}"
|
42
|
-
f"&format=rdb"
|
43
|
-
)
|
66
|
+
f"&format=rdb")
|
44
67
|
|
45
68
|
try:
|
46
69
|
# Get data from USGS
|
47
70
|
response = requests.get(url, timeout=30)
|
48
71
|
|
49
72
|
if response.status_code != 200:
|
50
|
-
print(f"
|
51
|
-
|
73
|
+
print(f"No data found: API returned status {response.status_code}.")
|
74
|
+
print("Data for the specified site or parameters does not exist.")
|
75
|
+
return pd.DataFrame(), (lat, lon)
|
52
76
|
|
53
77
|
# Parse the response
|
54
78
|
data = _parse_usgs_response(response.text)
|
55
79
|
|
56
80
|
if len(data) == 0:
|
57
|
-
print("
|
58
|
-
return
|
81
|
+
print("No data found for the specified parameters or date range.")
|
82
|
+
return pd.DataFrame(), (lat, lon)
|
59
83
|
|
60
|
-
print(f"
|
61
|
-
return data
|
84
|
+
print(f"Retrieved {len(data)} turbidity measurements")
|
85
|
+
return data, (lat, lon)
|
62
86
|
|
63
87
|
except Exception as e:
|
64
|
-
print(f"
|
65
|
-
print("
|
66
|
-
return
|
88
|
+
print(f"Error: {e}")
|
89
|
+
print("Data for the specified site or parameters does not exist.")
|
90
|
+
return pd.DataFrame(), (lat, lon)
|
67
91
|
|
68
92
|
|
93
|
+
# Function for parse and cleaning Turbidity Time Series from USGS API Respons as DataFrame ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
69
94
|
def _parse_usgs_response(content: str) -> pd.DataFrame:
|
70
95
|
"""Parse USGS response and extract turbidity data."""
|
71
96
|
|
@@ -107,44 +132,5 @@ def _parse_usgs_response(content: str) -> pd.DataFrame:
|
|
107
132
|
return pd.DataFrame()
|
108
133
|
|
109
134
|
|
110
|
-
def _create_synthetic_turbidity(start_date: str, end_date: str) -> pd.DataFrame:
|
111
|
-
"""Create realistic synthetic turbidity data."""
|
112
|
-
|
113
|
-
date_range = pd.date_range(start=start_date, end=end_date, freq='H')
|
114
|
-
|
115
|
-
# Generate realistic turbidity values (typically 0-50 NTU)
|
116
|
-
base_turbidity = 8.0 # Base level
|
117
|
-
daily_variation = 3.0 # Daily fluctuation
|
118
|
-
|
119
|
-
# Create synthetic values with realistic patterns
|
120
|
-
synthetic_values = []
|
121
|
-
for i, dt in enumerate(date_range):
|
122
|
-
# Base value with daily pattern
|
123
|
-
daily_factor = np.sin(2 * np.pi * dt.hour / 24) * daily_variation
|
124
|
-
|
125
|
-
# Add some noise
|
126
|
-
noise = np.random.normal(0, 1.5)
|
127
|
-
|
128
|
-
# Occasional high turbidity events (storms)
|
129
|
-
if np.random.random() < 0.02: # 2% chance of high event
|
130
|
-
storm_factor = np.random.uniform(10, 30)
|
131
|
-
else:
|
132
|
-
storm_factor = 0
|
133
|
-
|
134
|
-
value = base_turbidity + daily_factor + noise + storm_factor
|
135
|
-
value = max(0.1, value) # Ensure positive values
|
136
|
-
|
137
|
-
synthetic_values.append(value)
|
138
|
-
|
139
|
-
# Create DataFrame
|
140
|
-
synthetic_data = pd.DataFrame({
|
141
|
-
'turbidity': synthetic_values
|
142
|
-
}, index=date_range)
|
143
|
-
|
144
|
-
print(f"📊 Created {len(synthetic_data)} synthetic turbidity measurements")
|
145
|
-
|
146
|
-
return synthetic_data
|
147
|
-
|
148
|
-
|
149
135
|
# Simple alias for backwards compatibility
|
150
136
|
get_usgs_turbidity = get_turbidity
|
@@ -1,11 +1,30 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: hydroanomaly
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.7.1
|
4
4
|
Summary: A Python package for hydro anomaly detection with simple USGS data retrieval
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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=AFzyku0-OvyWnguhWZ-SoBcdPTKEPzV6GfOGLpPUFuQ,1375
|
2
|
+
hydroanomaly/sentinel_bands.py,sha256=TbdyvBRe9v3YGOz4umYhSJ-16a5lCF0YLwnmArZ9Gvs,3627
|
3
|
+
hydroanomaly/usgs_turbidity.py,sha256=k0cXRXpTe1YgjfR0Htw77SLD8hM--43jiEiJwx1vRg0,5664
|
4
|
+
hydroanomaly/visualize.py,sha256=gkLgI3agx291jK5o08nYEbEpGpr6cD-6aAKn2Ha2Lqk,6937
|
5
|
+
hydroanomaly-0.7.1.dist-info/licenses/LICENSE,sha256=OphKV48tcMv6ep-7j-8T6nycykPT0g8ZlMJ9zbGvdPs,1066
|
6
|
+
hydroanomaly-0.7.1.dist-info/METADATA,sha256=HIMGK2WWKXrX7PYfu_c5J3Fl-Zsetq9Ug9TiSZgyifM,12962
|
7
|
+
hydroanomaly-0.7.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
+
hydroanomaly-0.7.1.dist-info/top_level.txt,sha256=t-5Lc-eTLlkxIhR_N1Cpp6_YZafKS3xLLk9D2CtbE7o,13
|
9
|
+
hydroanomaly-0.7.1.dist-info/RECORD,,
|
@@ -1,9 +0,0 @@
|
|
1
|
-
hydroanomaly/__init__.py,sha256=pbS4SUDEYV8e9we3YqAe3Jo-EKX77eCdwirofp4Yk_4,1313
|
2
|
-
hydroanomaly/sentinel_bands.py,sha256=Zvy9vJ7RooJTWLJK-ihGZ6CEneQcHVJ8I5MgueYcoyQ,5534
|
3
|
-
hydroanomaly/usgs_turbidity.py,sha256=r0ozmiZXVYjtu04UnT3ijxra_WQVUUpus7WLcYCH3iM,4921
|
4
|
-
hydroanomaly/visualize.py,sha256=gkLgI3agx291jK5o08nYEbEpGpr6cD-6aAKn2Ha2Lqk,6937
|
5
|
-
hydroanomaly-0.6.0.dist-info/licenses/LICENSE,sha256=OphKV48tcMv6ep-7j-8T6nycykPT0g8ZlMJ9zbGvdPs,1066
|
6
|
-
hydroanomaly-0.6.0.dist-info/METADATA,sha256=cZxYHfAnYHP1Wqspxf--JUBlKDKs29mhybbhslS1Zx0,11873
|
7
|
-
hydroanomaly-0.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
-
hydroanomaly-0.6.0.dist-info/top_level.txt,sha256=t-5Lc-eTLlkxIhR_N1Cpp6_YZafKS3xLLk9D2CtbE7o,13
|
9
|
-
hydroanomaly-0.6.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|