mpcaHydro 2.2.0__tar.gz → 2.2.1__tar.gz
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.
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/PKG-INFO +1 -1
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/demo.py +68 -9
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/pyproject.toml +1 -1
- mpcahydro-2.2.0/src/mpcaHydro/data/outlets.duckdb → mpcahydro-2.2.1/src/mpcaHydro/data/outlet.duckdb +0 -0
- mpcahydro-2.2.1/src/mpcaHydro/data/stations_EQUIS.gpkg +0 -0
- mpcahydro-2.2.1/src/mpcaHydro/data/stations_wiski.gpkg +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/data_manager.py +105 -60
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/etlSWD.py +21 -15
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/outlets.py +70 -74
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/reports.py +1 -1
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/warehouse.py +276 -146
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/warehouseManager.py +8 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/wiski.py +57 -5
- mpcahydro-2.2.1/tests/integration/observations.duckdb +0 -0
- mpcahydro-2.2.1/tests/integration/test_dataManager.py +61 -0
- mpcahydro-2.2.1/tests/integration/test_warehouse.duckdb +0 -0
- mpcahydro-2.2.1/tests/integration/test_warehouse.py +113 -0
- mpcahydro-2.2.1/tests/unit/test_equis.py +19 -0
- mpcahydro-2.2.0/src/mpcaHydro/data/stations_EQUIS.gpkg +0 -0
- mpcahydro-2.2.0/src/mpcaHydro/data/stations_wiski.gpkg +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/.gitattributes +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/.gitignore +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/ERROR.FIL +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/README.md +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/__init__.py +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/data/EQUIS_PARAMETER_XREF.csv +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/data/WISKI_EQUIS_XREF.csv +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/data/WISKI_QUALITY_CODES.csv +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/equis.py +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/etlCSG.py +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/etlWISKI.py +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/etlWPLMN.py +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/pywisk.py +0 -0
- {mpcahydro-2.2.0 → mpcahydro-2.2.1}/src/mpcaHydro/xref.py +0 -0
|
@@ -6,7 +6,7 @@ import duckdb
|
|
|
6
6
|
from mpcaHydro import equis, warehouse, wiski
|
|
7
7
|
from hspf.hspfModel import hspfModel
|
|
8
8
|
from hspf.uci import UCI
|
|
9
|
-
|
|
9
|
+
from mpcaHydro import etlSWD
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
#%%
|
|
@@ -34,19 +34,78 @@ wiski_stations = outlets.wiski_stations(model_name)
|
|
|
34
34
|
equis.connect('MFRATKI',password = 'DeltaT#MPCA3')
|
|
35
35
|
warehouse.init_db(db_path,reset = True)
|
|
36
36
|
|
|
37
|
-
#%%
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
#%% Old approach. Store as indvidual processed station files then load to warehouse
|
|
39
|
+
#df_equis = equis.download(equis_stations)
|
|
40
|
+
#df_wiski = wiski.download(wiski_stations,start_year = start_year, end_year = end_year)
|
|
41
|
+
|
|
42
|
+
#%% equis
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def download_equis_data(db_path,station_ids,replace = False):
|
|
48
|
+
with warehouse.connect(db_path,read_only = False) as con:
|
|
49
|
+
df = equis.download(station_ids)
|
|
50
|
+
if not df.empty:
|
|
51
|
+
warehouse.load_df_to_table(con,df, 'staging.equis',replace = replace)
|
|
52
|
+
warehouse.load_df_to_table(con,equis.transform(df), 'analytics.equis',replace = replace)
|
|
53
|
+
else:
|
|
54
|
+
print('No data neccesary for HSPF calibration available from equis for stations:',station_ids)
|
|
55
|
+
|
|
56
|
+
def download_wiski_data(db_path,station_ids,replace = False):
|
|
57
|
+
with warehouse.connect(db_path,read_only = False) as con:
|
|
58
|
+
df = wiski.download(station_ids,start_year = start_year, end_year = end_year)
|
|
59
|
+
if not df.empty:
|
|
60
|
+
warehouse.load_df_to_table(con,df, 'staging.wiski', replace = replace)
|
|
61
|
+
warehouse.load_df_to_table(con,wiski.transform(df), 'analytics.wiski',replace = replace)
|
|
62
|
+
else:
|
|
63
|
+
print('No data neccesary for HSPF calibration available from wiski for stations:',station_ids)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# Add to warehouse from custom df. Must contain required normalized columns.
|
|
67
|
+
with warehouse.connect(db_path,read_only = False) as con:
|
|
68
|
+
if replace:
|
|
69
|
+
warehouse.drop_station_id(con,station_id,station_origin='equis')
|
|
70
|
+
warehouse.add_to_table(con,df, 'staging','equis_normalized')
|
|
71
|
+
|
|
72
|
+
|
|
41
73
|
warehouse.load_df_to_staging(con,df, 'equis_raw',replace = replace)
|
|
42
|
-
|
|
74
|
+
df = equis.normalize(df.copy())
|
|
75
|
+
warehouse.add_to_table(con,df, 'staging','equis_normalized')
|
|
76
|
+
df = equis.transform(df)
|
|
77
|
+
warehouse.add_to_table(con,df, 'analytics','equis')
|
|
78
|
+
|
|
43
79
|
|
|
44
|
-
df = wiski.download(wiski_stations,start_year = start_year, end_year = end_year)
|
|
45
|
-
warehouse.load_df_to_staging(con,df, 'wiski_raw', replace = replace)
|
|
46
|
-
warehouse.load_df_to_analytics(con,wiski.transform(df,filter_qc_codes = filter_qc_codes),'wiski') # method includes normalization
|
|
47
80
|
|
|
48
|
-
|
|
81
|
+
#%% swd
|
|
49
82
|
|
|
83
|
+
df = etlSWD.download(equis_stations)
|
|
84
|
+
|
|
85
|
+
with warehouse.connect(db_path,read_only = False) as con:
|
|
86
|
+
warehouse.load_df_to_staging(con,df, 'equis_raw',replace = replace)
|
|
87
|
+
df = equis.normalize(df.copy())
|
|
88
|
+
warehouse.add_to_table(con,df, 'staging','equis_normalized')
|
|
89
|
+
df = equis.transform(df)
|
|
90
|
+
warehouse.add_to_table(con,df, 'analytics','equis')
|
|
91
|
+
#%% wiski
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
if station_origin == 'wiski':
|
|
96
|
+
df = wiski.download(station_ids,start_year = start_year, end_year = end_year)
|
|
97
|
+
warehouse.load_df_to_staging(con,df, 'wiski_raw', replace = replace)
|
|
98
|
+
df = wiski.normalize(df.copy())
|
|
99
|
+
warehouse.add_to_table(con,df, 'staging','wiski_normalized')
|
|
100
|
+
df = wiski.transform(df,filter_qc_codes = filter_qc_codes)
|
|
101
|
+
warehouse.add_to_table(con,df, 'analytics','wiski') # method includes normalization
|
|
102
|
+
|
|
103
|
+
if station_origin == 'swd':
|
|
104
|
+
df = pd.concat([etlSWD.download(station_id) for station_id in station_ids])
|
|
105
|
+
warehouse.load_df_to_staging(con,df, 'equis_raw', replace = replace)
|
|
106
|
+
df = etlSWD.transform(df.copy())
|
|
107
|
+
warehouse.add_to_table(con,df, 'analytics','equis')
|
|
108
|
+
warehouse.update_views(con)
|
|
50
109
|
|
|
51
110
|
with warehouse.connect(db_path) as con:
|
|
52
111
|
warehouse.update_views(con)
|
mpcahydro-2.2.0/src/mpcaHydro/data/outlets.duckdb → mpcahydro-2.2.1/src/mpcaHydro/data/outlet.duckdb
RENAMED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -5,6 +5,7 @@ Created on Fri Jun 3 10:01:14 2022
|
|
|
5
5
|
@author: mfratki
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
from copy import replace
|
|
8
9
|
import pandas as pd
|
|
9
10
|
#from abc import abstractmethod
|
|
10
11
|
from pathlib import Path
|
|
@@ -64,88 +65,115 @@ def constituent_summary(db_path):
|
|
|
64
65
|
return res.fetch_df()
|
|
65
66
|
|
|
66
67
|
|
|
68
|
+
|
|
69
|
+
|
|
67
70
|
class dataManager():
|
|
68
71
|
|
|
69
|
-
def __init__(self,folderpath,
|
|
72
|
+
def __init__(self,folderpath, oracle_username = None, oracle_password =None, reset = False):
|
|
70
73
|
|
|
71
74
|
self.data = {}
|
|
72
75
|
self.folderpath = Path(folderpath)
|
|
73
76
|
self.db_path = self.folderpath.joinpath('observations.duckdb')
|
|
74
|
-
|
|
75
|
-
self.oracle_user = oracle_user
|
|
77
|
+
self.oracle_username = oracle_username
|
|
76
78
|
self.oracle_password = oracle_password
|
|
77
|
-
|
|
78
|
-
self.
|
|
79
|
-
|
|
79
|
+
|
|
80
|
+
if not self.db_path.exists() or reset:
|
|
81
|
+
self._build_warehouse()
|
|
82
|
+
|
|
83
|
+
self.xref = xref #TODO: implement xref manager class
|
|
84
|
+
self.outlets = outlets #TODO: implement outlets manager class
|
|
80
85
|
self.reports = reportManager(self.db_path)
|
|
81
86
|
|
|
82
87
|
|
|
83
88
|
def connect_to_oracle(self):
|
|
84
89
|
assert (self.credentials_exist(), 'Oracle credentials not found. Set ORACLE_USER and ORACLE_PASSWORD environment variables or use swd as station_origin')
|
|
85
|
-
equis.connect(user = self.
|
|
90
|
+
equis.connect(user = self.oracle_username, password = self.oracle_password)
|
|
86
91
|
|
|
87
92
|
def credentials_exist(self):
|
|
88
|
-
if (self.
|
|
93
|
+
if (self.oracle_username is not None) & (self.oracle_password is not None):
|
|
89
94
|
return True
|
|
90
95
|
else:
|
|
91
96
|
return False
|
|
92
97
|
|
|
93
98
|
def _build_warehouse(self):
|
|
94
|
-
|
|
99
|
+
warehouse.init_db(self.db_path.as_posix(),True)
|
|
95
100
|
|
|
96
|
-
def
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
:param station_origin: source of station data: wiski, equis, or swd
|
|
103
|
-
:param overwrite: Whether to overwrite existing data
|
|
104
|
-
:param to_csv: Whether to export data to CSV
|
|
105
|
-
:param filter_qc_codes: Whether to filter quality control codes
|
|
106
|
-
:param start_year: Start year for data download
|
|
107
|
-
:param end_year: End year for data download
|
|
108
|
-
:param baseflow_method: Method for baseflow calculation
|
|
109
|
-
'''
|
|
110
|
-
with duckdb.connect(self.db_path,read_only=False) as con:
|
|
111
|
-
if overwrite:
|
|
112
|
-
warehouse.drop_station_id(con,station_id,station_origin)
|
|
113
|
-
warehouse.update_views(con)
|
|
101
|
+
def _process_wiski_data(self,filter_qc_codes = True, data_codes = None, baseflow_method = 'Boughton'):
|
|
102
|
+
with warehouse.connect(self.db_path,read_only = False) as con:
|
|
103
|
+
df = con.execute("SELECT * FROM staging.wiski").df()
|
|
104
|
+
df_transformed = wiski.transform(df, filter_qc_codes, data_codes, baseflow_method)
|
|
105
|
+
warehouse.load_df_to_table(con,df_transformed, 'analytics.wiski')
|
|
106
|
+
warehouse.update_views(con)
|
|
114
107
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
elif station_origin == 'equis':
|
|
121
|
-
assert (self.credentials_exist(), 'Oracle credentials not found. Set ORACLE_USER and ORACLE_PASSWORD environment variables or use swd as station_origin')
|
|
122
|
-
df = equis.download([station_id])
|
|
123
|
-
warehouse.load_df_to_staging(con,df, 'equis_raw',replace = overwrite)
|
|
124
|
-
warehouse.load_df_to_analytics(con,equis.transform(df),'equis')
|
|
125
|
-
|
|
126
|
-
elif station_origin == 'swd':
|
|
127
|
-
df = etlSWD.download(station_id)
|
|
128
|
-
warehouse.load_df_to_staging(con,df, 'swd_raw', replace = overwrite)
|
|
129
|
-
warehouse.load_df_to_analytics(con,etlSWD.transform(df),'swd')
|
|
130
|
-
else:
|
|
131
|
-
raise ValueError('station_origin must be wiski, equis, or swd')
|
|
132
|
-
|
|
133
|
-
with duckdb.connect(self.db_path,read_only=False) as con:
|
|
108
|
+
def _process_equis_data(self):
|
|
109
|
+
with warehouse.connect(self.db_path,read_only = False) as con:
|
|
110
|
+
df = con.execute("SELECT * FROM staging.equis").df()
|
|
111
|
+
df_transformed = equis.transform(df)
|
|
112
|
+
warehouse.load_df_to_table(con,df_transformed, 'analytics.equis')
|
|
134
113
|
warehouse.update_views(con)
|
|
135
114
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
115
|
+
def _process_data(self,filter_qc_codes = True, data_codes = None, baseflow_method = 'Boughton'):
|
|
116
|
+
self._process_wiski_data(filter_qc_codes, data_codes, baseflow_method)
|
|
117
|
+
self._process_equis_data()
|
|
118
|
+
|
|
119
|
+
def _update_views(self):
|
|
120
|
+
with warehouse.connect(self.db_path,read_only = False) as con:
|
|
121
|
+
warehouse.update_views(con)
|
|
122
|
+
|
|
123
|
+
def _download_wiski_data(self,station_ids,start_year = 1996, end_year = 2030, filter_qc_codes = True, data_codes = None, baseflow_method = 'Boughton'):
|
|
124
|
+
with warehouse.connect(self.db_path,read_only = False) as con:
|
|
125
|
+
df = wiski.download(station_ids,start_year = start_year, end_year = end_year)
|
|
126
|
+
if not df.empty:
|
|
127
|
+
warehouse.load_df_to_table(con,df, 'staging.wiski')
|
|
128
|
+
warehouse.load_df_to_table(con,wiski.transform(df, filter_qc_codes,data_codes,baseflow_method), 'analytics.wiski')
|
|
129
|
+
warehouse.update_views(con)
|
|
130
|
+
else:
|
|
131
|
+
print('No data neccesary for HSPF calibration available from wiski for stations:',station_ids)
|
|
132
|
+
|
|
133
|
+
def _download_equis_data(self,station_ids):
|
|
134
|
+
if self.credentials_exist():
|
|
135
|
+
self.connect_to_oracle()
|
|
136
|
+
print('Connected to Oracle database.')
|
|
137
|
+
with warehouse.connect(self.db_path,read_only = False) as con:
|
|
138
|
+
df = equis.download(station_ids)
|
|
139
|
+
if not df.empty:
|
|
140
|
+
warehouse.load_df_to_table(con,df, 'staging.equis')
|
|
141
|
+
warehouse.load_df_to_table(con,equis.transform(df.copy()), 'analytics.equis')
|
|
142
|
+
warehouse.update_views(con)
|
|
143
|
+
else:
|
|
144
|
+
print('No data neccesary for HSPF calibration available from equis for stations:',station_ids)
|
|
145
|
+
else:
|
|
146
|
+
raise ValueError('Oracle credentials not found. Set ORACLE_USER and ORACLE_PASSWORD environment variables or use swd as station_origin')
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _get_equis_template(self):
|
|
150
|
+
with duckdb.connect(self.db_path,read_only=True) as con:
|
|
151
|
+
query = '''
|
|
152
|
+
SELECT *
|
|
153
|
+
FROM staging.equis
|
|
154
|
+
LIMIT 0'''
|
|
155
|
+
df = con.execute(query).fetch_df().to_csv(self.folderpath.joinpath('equis_template.csv'), index=False)
|
|
139
156
|
return df
|
|
140
157
|
|
|
141
|
-
def
|
|
158
|
+
def _get_wiski_template(self):
|
|
159
|
+
with duckdb.connect(self.db_path,read_only=True) as con:
|
|
160
|
+
query = '''
|
|
161
|
+
SELECT *
|
|
162
|
+
FROM staging.wiski
|
|
163
|
+
LIMIT 0'''
|
|
164
|
+
df = con.execute(query).fetch_df().to_csv(self.folderpath.joinpath('wiski_template.csv'), index=False)
|
|
165
|
+
return df
|
|
166
|
+
|
|
167
|
+
def get_outlets(self,model_name):
|
|
142
168
|
with duckdb.connect(self.db_path,read_only=True) as con:
|
|
143
169
|
query = '''
|
|
144
170
|
SELECT *
|
|
145
171
|
FROM outlets.station_reach_pairs
|
|
172
|
+
WHERE repository_name = ?
|
|
146
173
|
ORDER BY outlet_id'''
|
|
147
|
-
df = con.execute(query).fetch_df()
|
|
174
|
+
df = con.execute(query,[model_name]).fetch_df()
|
|
148
175
|
return df
|
|
176
|
+
|
|
149
177
|
def get_station_ids(self,station_origin = None):
|
|
150
178
|
with duckdb.connect(self.db_path,read_only=True) as con:
|
|
151
179
|
if station_origin is None:
|
|
@@ -163,9 +191,7 @@ class dataManager():
|
|
|
163
191
|
return df['station_id'].to_list()
|
|
164
192
|
|
|
165
193
|
|
|
166
|
-
def
|
|
167
|
-
|
|
168
|
-
|
|
194
|
+
def get_observation_data(self,station_ids,constituent,agg_period = None):
|
|
169
195
|
with duckdb.connect(self.db_path,read_only=True) as con:
|
|
170
196
|
query = '''
|
|
171
197
|
SELECT *
|
|
@@ -184,9 +210,9 @@ class dataManager():
|
|
|
184
210
|
df.attrs['agg_period'] = agg_period
|
|
185
211
|
|
|
186
212
|
df.rename(columns={'value': 'observed'}, inplace=True)
|
|
187
|
-
return df
|
|
213
|
+
return df.dropna(subset=['observed'])
|
|
188
214
|
|
|
189
|
-
def get_outlet_data(self,outlet_id,constituent,agg_period = 'D'):
|
|
215
|
+
def get_outlet_data(self,outlet_id,constituent,agg_period = 'D',to_csv = False):
|
|
190
216
|
with duckdb.connect(self.db_path,read_only=True) as con:
|
|
191
217
|
query = '''
|
|
192
218
|
SELECT *
|
|
@@ -207,16 +233,35 @@ class dataManager():
|
|
|
207
233
|
df.rename(columns={'value': 'observed',
|
|
208
234
|
'flow_value': 'observed_flow',
|
|
209
235
|
'baseflow_value': 'observed_baseflow'}, inplace=True)
|
|
210
|
-
return df
|
|
211
|
-
|
|
236
|
+
return df.dropna(subset=['observed'])
|
|
212
237
|
|
|
238
|
+
def get_raw_data(self,station_id,station_origin, to_csv = False):
|
|
239
|
+
with duckdb.connect(self.db_path,read_only=True) as con:
|
|
240
|
+
if station_origin.lower() == 'equis':
|
|
241
|
+
query = '''
|
|
242
|
+
SELECT *
|
|
243
|
+
FROM staging.equis_raw
|
|
244
|
+
WHERE station_id = ?'''
|
|
245
|
+
elif station_origin.lower() == 'wiski':
|
|
246
|
+
query = '''
|
|
247
|
+
SELECT *
|
|
248
|
+
FROM staging.wiski_raw
|
|
249
|
+
WHERE station_id = ?'''
|
|
250
|
+
else:
|
|
251
|
+
raise ValueError(f'Station origin {station_origin} not recognized. Valid options are equis or wiski.')
|
|
252
|
+
|
|
253
|
+
df = con.execute(query,[station_id]).fetch_df()
|
|
254
|
+
|
|
255
|
+
if to_csv:
|
|
256
|
+
df.to_csv(self.folderpath.joinpath(f'{station_id}_raw.csv'), index=False)
|
|
257
|
+
return df
|
|
213
258
|
|
|
214
|
-
def to_csv(self,station_id,folderpath = None):
|
|
259
|
+
def to_csv(self,station_id ,station_origin,folderpath = None):
|
|
215
260
|
if folderpath is None:
|
|
216
261
|
folderpath = self.folderpath
|
|
217
262
|
else:
|
|
218
263
|
folderpath = Path(folderpath)
|
|
219
|
-
df = self.
|
|
264
|
+
df = self.get_station_data([station_id],constituent = 'Q',agg_period = None)
|
|
220
265
|
if len(df) > 0:
|
|
221
266
|
df.to_csv(folderpath.joinpath(station_id + '.csv'))
|
|
222
267
|
else:
|
|
@@ -26,19 +26,21 @@ CONSTITUENT_MAP = {i[0]:i[1] for i in EQUIS_PARAMETER_XREF[['PARAMETER','constit
|
|
|
26
26
|
# return df
|
|
27
27
|
import requests
|
|
28
28
|
|
|
29
|
-
def _download(
|
|
29
|
+
def _download(station_id):
|
|
30
30
|
# Replace {station_no} in the URL with the actual station number
|
|
31
|
-
url = f"https://services.pca.state.mn.us/api/v1/surfacewater/monitoring-stations/results?stationId={station_no}&format=json"
|
|
32
|
-
|
|
31
|
+
#url = f"https://services.pca.state.mn.us/api/v1/surfacewater/monitoring-stations/results?stationId={station_no}&format=json"
|
|
32
|
+
url = 'https://services.pca.state.mn.us/api/v1/surfacewater/monitoring-stations/results'
|
|
33
|
+
|
|
33
34
|
try:
|
|
34
35
|
# Send a GET request to the URL
|
|
35
|
-
|
|
36
|
+
params = {
|
|
37
|
+
'stationId': station_id,
|
|
38
|
+
'format': 'json'
|
|
39
|
+
}
|
|
40
|
+
response = requests.get(url,params = params)
|
|
36
41
|
response.raise_for_status() # Raise exception for HTTP errors
|
|
37
42
|
# Parse the JSON data
|
|
38
|
-
|
|
39
|
-
return pd.DataFrame(columns = response.json()['column_names'])
|
|
40
|
-
else:
|
|
41
|
-
return pd.DataFrame(response.json()['data'])
|
|
43
|
+
return pd.DataFrame(response.json()['data'])
|
|
42
44
|
|
|
43
45
|
except requests.exceptions.RequestException as e:
|
|
44
46
|
print(f"An error occurred: {e}")
|
|
@@ -46,14 +48,18 @@ def _download(station_no):
|
|
|
46
48
|
|
|
47
49
|
|
|
48
50
|
|
|
49
|
-
def download(
|
|
51
|
+
def download(station_ids):
|
|
50
52
|
#df = pd.read_csv(f'https://services.pca.state.mn.us/api/v1/surfacewater/monitoring-stations/results?stationId={station_no}&format=csv')
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
dfs = []
|
|
54
|
+
for station_id in station_ids:
|
|
55
|
+
df = _download(station_id)
|
|
56
|
+
if not df.empty:
|
|
57
|
+
df['station_id'] = station_id
|
|
58
|
+
dfs.append(df)
|
|
59
|
+
|
|
60
|
+
return pd.concat(dfs, ignore_index=True)
|
|
61
|
+
|
|
62
|
+
|
|
57
63
|
|
|
58
64
|
def info(station_no):
|
|
59
65
|
#df = pd.read_csv(f'https://services.pca.state.mn.us/api/v1/surfacewater/monitoring-stations/results?stationId={station_no}&format=csv')
|