forked from DOI-USGS/dataretrieval-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnwis.py
More file actions
1255 lines (1017 loc) · 39.2 KB
/
nwis.py
File metadata and controls
1255 lines (1017 loc) · 39.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""Functions for downloading data from the `National Water Information System (NWIS)`_.
.. _National Water Information System (NWIS): https://waterdata.usgs.gov/nwis
"""
import re
import warnings
from io import StringIO
from typing import List, Optional, Tuple, Union
import pandas as pd
import requests
from dataretrieval.utils import BaseMetadata, format_datetime
from .utils import query
try:
import geopandas as gpd
except ImportError:
gpd = None
# Issue deprecation warning upon import
warnings.warn(
"The 'nwis' services are deprecated and being decommissioned. "
"Please use the 'waterdata' module to access the new services.",
DeprecationWarning,
stacklevel=2
)
WATERDATA_BASE_URL = "https://nwis.waterdata.usgs.gov/"
WATERDATA_URL = WATERDATA_BASE_URL + "nwis/"
WATERSERVICE_URL = "https://waterservices.usgs.gov/nwis/"
PARAMCODES_URL = "https://help.waterdata.usgs.gov/code/parameter_cd_nm_query?"
ALLPARAMCODES_URL = "https://help.waterdata.usgs.gov/code/parameter_cd_query?"
WATERSERVICES_SERVICES = ["dv", "iv", "site", "stat"]
WATERDATA_SERVICES = [
"peaks",
"water_use",
"ratings",
]
# NAD83
_CRS = "EPSG:4269"
def format_response(
df: pd.DataFrame, service: Optional[str] = None, **kwargs
) -> pd.DataFrame:
"""Setup index for response from query.
This function formats the response from the NWIS web services, in
particular it sets the index of the data frame. This function tries to
convert the NWIS response into pandas datetime values localized to UTC,
and if possible, uses these timestamps to define the data frame index.
Parameters
----------
df: ``pandas.DataFrame``
The data frame to format
service: string, optional, default is None
The NWIS service that was queried, important because the 'peaks'
service returns a different format than the other services.
**kwargs: optional
Additional keyword arguments, e.g., 'multi_index'
Returns
-------
df: ``pandas.DataFrame``
The formatted data frame
"""
mi = kwargs.pop("multi_index", True)
if service == "peaks":
df = preformat_peaks_response(df)
if gpd is not None:
if "dec_lat_va" in list(df):
geoms = gpd.points_from_xy(df.dec_long_va.values, df.dec_lat_va.values)
df = gpd.GeoDataFrame(df, geometry=geoms, crs=_CRS)
# check for multiple sites:
if "datetime" not in df.columns:
# XXX: consider making site_no index
return df
elif len(df["site_no"].unique()) > 1 and mi:
# setup multi-index
df.set_index(["site_no", "datetime"], inplace=True)
if hasattr(df.index.levels[1], "tzinfo") and df.index.levels[1].tzinfo is None:
df = df.tz_localize("UTC", level=1)
else:
df.set_index(["datetime"], inplace=True)
if hasattr(df.index, "tzinfo") and df.index.tzinfo is None:
df = df.tz_localize("UTC")
return df.sort_index()
def preformat_peaks_response(df: pd.DataFrame) -> pd.DataFrame:
"""Datetime formatting for the 'peaks' service response.
Function to format the datetime column of the 'peaks' service response.
Parameters
----------
df: ``pandas.DataFrame``
The data frame to format
Returns
-------
df: ``pandas.DataFrame``
The formatted data frame
"""
df["datetime"] = pd.to_datetime(df.pop("peak_dt"), errors="coerce")
df.dropna(subset=["datetime"], inplace=True)
return df
def get_qwdata(
sites: Optional[Union[List[str], str]] = None,
start: Optional[str] = None,
end: Optional[str] = None,
multi_index: bool = True,
wide_format: bool = True,
datetime_index: bool = True,
ssl_check: bool = True,
**kwargs,
) -> Tuple[pd.DataFrame, BaseMetadata]:
"""
Get water sample data from qwdata service - deprecated, use `get_samples()`
in the waterdata module.
"""
raise NameError(
"`nwis.get_qwdata` has been replaced with `waterdata.get_samples()`."
)
def get_discharge_measurements(
sites: Optional[Union[List[str], str]] = None,
start: Optional[str] = None,
end: Optional[str] = None,
ssl_check: bool = True,
**kwargs,
) -> Tuple[pd.DataFrame, BaseMetadata]:
"""
Get discharge measurements from the waterdata service -
deprecated, use `get_field_measurements()` in the waterdata
module.
"""
raise NameError(
"`nwis.get_discharge_measurements` has been replaced with `waterdata.get_field_measurements`."
)
def get_discharge_peaks(
sites: Optional[Union[List[str], str]] = None,
start: Optional[str] = None,
end: Optional[str] = None,
multi_index: bool = True,
ssl_check: bool = True,
**kwargs,
) -> Tuple[pd.DataFrame, BaseMetadata]:
"""
Get discharge peaks from the waterdata service.
Parameters
----------
sites: string or list of strings, optional, default is None
If the waterdata parameter site_no is supplied, it will overwrite the
sites parameter
start: string, optional, default is None
If the waterdata parameter begin_date is supplied, it will overwrite
the start parameter (YYYY-MM-DD)
end: string, optional, default is None
If the waterdata parameter end_date is supplied, it will overwrite
the end parameter (YYYY-MM-DD)
multi_index: bool, optional
If False, a dataframe with a single-level index (datetime) is returned,
default is True
ssl_check: bool, optional
If True, check SSL certificates, if False, do not check SSL,
default is True
**kwargs: optional
If supplied, will be used as query parameters
Returns
-------
df: ``pandas.DataFrame``
Times series data from the NWIS JSON
md: :obj:`dataretrieval.utils.Metadata`
A custom metadata object
Examples
--------
.. doctest::
>>> # Get discharge peaks for site 01491000
>>> df, md = dataretrieval.nwis.get_discharge_peaks(
... sites="01491000", start="1980-01-01", end="1990-01-01"
... )
>>> # Get discharge peaks for sites in Hawaii
>>> df, md = dataretrieval.nwis.get_discharge_peaks(
... start="1980-01-01", end="1980-01-02", stateCd="HI"
... )
"""
_check_sites_value_types(sites)
kwargs["site_no"] = kwargs.pop("site_no", sites)
kwargs["begin_date"] = kwargs.pop("begin_date", start)
kwargs["end_date"] = kwargs.pop("end_date", end)
kwargs["multi_index"] = multi_index
response = query_waterdata("peaks", format="rdb", ssl_check=ssl_check, **kwargs)
df = _read_rdb(response.text)
return format_response(df, service="peaks", **kwargs), NWIS_Metadata(
response, **kwargs
)
def get_gwlevels(
sites: Optional[Union[List[str], str]] = None,
start: str = "1851-01-01",
end: Optional[str] = None,
multi_index: bool = True,
datetime_index: bool = True,
ssl_check: bool = True,
**kwargs,
) -> Tuple[pd.DataFrame, BaseMetadata]:
"""
Queries the groundwater level service from waterservices -
deprecated, use `get_field_measurements()` in the waterdata
module.
"""
raise NameError(
"`nwis.get_gwlevels` has been replaced with `waterdata.get_field_measurements()`."
)
def get_stats(
sites: Optional[Union[List[str], str]] = None, ssl_check: bool = True, **kwargs
) -> Tuple[pd.DataFrame, BaseMetadata]:
"""
Queries water services statistics information.
For more information about the water services statistics service, visit
https://waterservices.usgs.gov/docs/statistics/statistics-details/
Parameters
----------
sites: string or list of strings, optional, default is None
USGS site number (or list of site numbers)
ssl_check: bool, optional
If True, check SSL certificates, if False, do not check SSL,
default is True
**kwargs: optional
If supplied, will be used as query parameters
Keyword Arguments
---------------------
statReportType: string
daily (default), monthly, or annual
statTypeCd: string
all, mean, max, min, median
Returns
-------
df: ``pandas.DataFrame``
Statistics data from the statistics service
md: :obj:`dataretrieval.utils.Metadata`
A custom metadata object
.. todo::
fix date parsing
Examples
--------
.. doctest::
>>> # Get annual water statistics for a site
>>> df, md = dataretrieval.nwis.get_stats(
... sites="01646500", statReportType="annual", statYearType="water"
... )
>>> # Get monthly statistics for a site
>>> df, md = dataretrieval.nwis.get_stats(
... sites="01646500", statReportType="monthly"
... )
"""
_check_sites_value_types(sites)
response = query_waterservices(
service="stat", sites=sites, ssl_check=ssl_check, **kwargs
)
return _read_rdb(response.text), NWIS_Metadata(response, **kwargs)
def query_waterdata(
service: str, ssl_check: bool = True, **kwargs
) -> requests.models.Response:
"""
Queries waterdata.
Parameters
----------
service: string
Name of the service to query: 'site', 'stats', etc.
ssl_check: bool, optional
If True, check SSL certificates, if False, do not check SSL,
default is True
**kwargs: optional
If supplied, will be used as query parameters
Returns
-------
request: ``requests.models.Response``
The response object from the API request to the web service
"""
major_params = ["site_no", "state_cd"]
bbox_params = [
"nw_longitude_va",
"nw_latitude_va",
"se_longitude_va",
"se_latitude_va",
]
if not any(key in kwargs for key in major_params + bbox_params):
raise TypeError("Query must specify a major filter: site_no, stateCd, bBox")
elif any(key in kwargs for key in bbox_params) and not all(
key in kwargs for key in bbox_params
):
raise TypeError("One or more lat/long coordinates missing or invalid.")
if service not in WATERDATA_SERVICES:
raise TypeError("Service not recognized")
url = WATERDATA_URL + service
return query(url, payload=kwargs, ssl_check=ssl_check)
def query_waterservices(
service: str, ssl_check: bool = True, **kwargs
) -> requests.models.Response:
"""
Queries waterservices.usgs.gov
For more documentation see https://waterservices.usgs.gov/docs/
.. note::
User must specify one major filter: sites, stateCd, or bBox
Parameters
----------
service: string
Name of the service to query: 'site', 'stats', etc.
ssl_check: bool, optional
If True, check SSL certificates, if False, do not check SSL,
default is True
ssl_check: bool, optional
If True, check SSL certificates, if False, do not check SSL,
default is True
**kwargs: optional
If supplied, will be used as query parameters
Keyword Arguments
----------------
bBox: string
7-digit Hydrologic Unit Code (HUC)
startDT: string
Start date (e.g., '2017-12-31')
endDT: string
End date (e.g., '2018-01-01')
modifiedSince: string
Used to return only sites where attributes or period of record data
have changed during the request period. String expected to be formatted
in ISO-8601 duration format (e.g., 'P1D' for one day,
'P1Y' for one year)
Returns
-------
request: ``requests.models.Response``
The response object from the API request to the web service
"""
if not any(
key in kwargs for key in ["sites", "stateCd", "bBox", "huc", "countyCd"]
):
raise TypeError(
"Query must specify a major filter: sites, stateCd, bBox, huc, or countyCd"
)
if service not in WATERSERVICES_SERVICES:
raise TypeError("Service not recognized")
if "format" not in kwargs:
kwargs["format"] = "rdb"
url = WATERSERVICE_URL + service
return query(url, payload=kwargs, ssl_check=ssl_check)
def get_dv(
sites: Optional[Union[List[str], str]] = None,
start: Optional[str] = None,
end: Optional[str] = None,
multi_index: bool = True,
ssl_check: bool = True,
**kwargs,
) -> Tuple[pd.DataFrame, BaseMetadata]:
"""
Get daily values data from NWIS and return it as a ``pandas.DataFrame``.
.. note:
If no start or end date are provided, only the most recent record
is returned.
Parameters
----------
sites: string or list of strings, optional, default is None
USGS site number (or list of site numbers)
start: string, optional, default is None
If the waterdata parameter startDT is supplied, it will overwrite the
start parameter (YYYY-MM-DD)
end: string, optional, default is None
If the waterdata parameter endDT is supplied, it will overwrite the
end parameter (YYYY-MM-DD)
multi_index: bool, optional
If True, return a multi-index dataframe, if False, return a
single-index dataframe, default is True
ssl_check: bool, optional
If True, check SSL certificates, if False, do not check SSL,
default is True
**kwargs: optional
If supplied, will be used as query parameters
Returns
-------
df: ``pandas.DataFrame``
Times series data from the NWIS JSON
md: :obj:`dataretrieval.utils.Metadata`
A custom metadata object
Examples
--------
.. doctest::
>>> # Get mean statistic daily values for site 04085427
>>> df, md = dataretrieval.nwis.get_dv(
... sites="04085427",
... start="2012-01-01",
... end="2012-06-30",
... statCd="00003",
... )
>>> # Get the latest daily values for site 01646500
>>> df, md = dataretrieval.nwis.get_dv(sites="01646500")
"""
_check_sites_value_types(sites)
kwargs["startDT"] = kwargs.pop("startDT", start)
kwargs["endDT"] = kwargs.pop("endDT", end)
kwargs["sites"] = kwargs.pop("sites", sites)
kwargs["multi_index"] = multi_index
response = query_waterservices("dv", format="json", ssl_check=ssl_check, **kwargs)
df = _read_json(response.json())
return format_response(df, **kwargs), NWIS_Metadata(response, **kwargs)
def get_info(ssl_check: bool = True, **kwargs) -> Tuple[pd.DataFrame, BaseMetadata]:
"""
Get site description information from NWIS.
**Note:** *Must specify one major parameter.*
For additional parameter options see
https://waterservices.usgs.gov/docs/site-service/site-service-details/
Parameters
----------
ssl_check: bool, optional
If True, check SSL certificates, if False, do not check SSL,
default is True
**kwargs: optional
If supplied, will be used as query parameters
Keyword Arguments
----------------
sites: string or list of strings
A list of site numbers. Sites may be prefixed with an optional agency
code followed by a colon.
stateCd: string
U.S. postal service (2-digit) state code. Only 1 state can be specified
per request.
huc: string or list of strings
A list of hydrologic unit codes (HUC) or aggregated watersheds. Only 1
major HUC can be specified per request, or up to 10 minor HUCs. A major
HUC has two digits.
bBox: string or list of strings
A contiguous range of decimal latitude and longitude, starting with the
west longitude, then the south latitude, then the east longitude, and
then the north latitude with each value separated by a comma. The
product of the range of latitude range and longitude cannot exceed 25
degrees. Whole or decimal degrees must be specified, up to six digits
of precision. Minutes and seconds are not allowed.
countyCd: string or list of strings
A list of county numbers, in a 5 digit numeric format. The first two
digits of a county's code are the FIPS State Code.
(url: https://help.waterdata.usgs.gov/code/county_query?fmt=html)
startDt: string
Selects sites based on whether data was collected at a point in time
beginning after startDt (start date). Dates must be in ISO-8601
Calendar Date format (for example: 1990-01-01).
endDt: string
The end date for the period of record. Dates must be in ISO-8601
Calendar Date format (for example: 1990-01-01).
period: string
Selects sites based on whether they were active between now
and a time in the past. For example, period=P10W will select sites
active in the last ten weeks.
modifiedSince: string
Returns only sites where site attributes or period of record data have
changed during the request period.
parameterCd: string or list of strings
Returns only site data for those sites containing the requested USGS
parameter codes.
siteType: string or list of strings
Restricts sites to those having one or more major and/or minor site
types, such as stream, spring or well. For a list of all valid site
types see https://help.waterdata.usgs.gov/site_tp_cd
For example, siteType='ST' returns streams only.
siteOutput: string ('basic' or 'expanded')
Indicates the richness of metadata you want for site attributes. Note
that for visually oriented formats like Google Map format, this
argument has no meaning. Note: for performance reasons,
siteOutput=expanded cannot be used if seriesCatalogOutput=true or with
any values for outputDataTypeCd.
seriesCatalogOutput: bool
A switch that provides detailed period of record information for
certain output formats. The period of record indicates date ranges for
a certain kind of information about a site, for example the start and
end dates for a site's daily mean streamflow.
Returns
-------
df: ``pandas.DataFrame``
Site data from the NWIS web service
md: :obj:`dataretrieval.utils.Metadata`
A custom metadata object
Examples
--------
.. doctest::
>>> # Get site information for a single site
>>> df, md = dataretrieval.nwis.get_info(sites="05114000")
>>> # Get site information for multiple sites
>>> df, md = dataretrieval.nwis.get_info(sites=["05114000", "09423350"])
"""
seriesCatalogOutput = kwargs.pop("seriesCatalogOutput", None)
if seriesCatalogOutput in ["True", "TRUE", "true", True]:
warnings.warn(
(
"WARNING: Starting in March 2024, the NWIS qw data endpoint is "
"retiring and no longer receives updates. For more information, "
"refer to https://waterdata.usgs.gov.nwis/qwdata and "
"https://doi-usgs.github.io/dataRetrieval/articles/Status.html "
"or email CompTools@usgs.gov."
)
)
# convert bool to string if necessary
kwargs["seriesCatalogOutput"] = "True"
else:
# cannot have both seriesCatalogOutput and the expanded format
kwargs["siteOutput"] = "Expanded"
response = query_waterservices("site", ssl_check=ssl_check, **kwargs)
return _read_rdb(response.text), NWIS_Metadata(response, **kwargs)
def get_iv(
sites: Optional[Union[List[str], str]] = None,
start: Optional[str] = None,
end: Optional[str] = None,
multi_index: bool = True,
ssl_check: bool = True,
**kwargs,
) -> Tuple[pd.DataFrame, BaseMetadata]:
"""Get instantaneous values data from NWIS and return it as a DataFrame.
.. note::
If no start or end date are provided, only the most recent record
is returned.
Parameters
----------
sites: string or list of strings, optional, default is None
If the waterdata parameter site_no is supplied, it will overwrite the
sites parameter
start: string, optional, default is None
If the waterdata parameter startDT is supplied, it will overwrite the
start parameter (YYYY-MM-DD)
end: string, optional, default is None
If the waterdata parameter endDT is supplied, it will overwrite the
end parameter (YYYY-MM-DD)
multi_index: bool, optional
If False, a dataframe with a single-level index (datetime) is returned,
default is True
ssl_check: bool, optional
If True, check SSL certificates, if False, do not check SSL,
default is True
**kwargs: optional
If supplied, will be used as query parameters
Returns
-------
df: ``pandas.DataFrame``
Times series data from the NWIS JSON
md: :obj:`dataretrieval.utils.Metadata`
A custom metadata object
Examples
--------
.. doctest::
>>> # Get instantaneous discharge data for site 05114000
>>> df, md = dataretrieval.nwis.get_iv(
... sites="05114000",
... start="2013-11-03",
... end="2013-11-03",
... parameterCd="00060",
... )
"""
_check_sites_value_types(sites)
kwargs["startDT"] = kwargs.pop("startDT", start)
kwargs["endDT"] = kwargs.pop("endDT", end)
kwargs["sites"] = kwargs.pop("sites", sites)
kwargs["multi_index"] = multi_index
response = query_waterservices(
service="iv", format="json", ssl_check=ssl_check, **kwargs
)
df = _read_json(response.json())
return format_response(df, **kwargs), NWIS_Metadata(response, **kwargs)
def get_pmcodes(
parameterCd: Union[str, List[str]] = "All",
partial: bool = True,
ssl_check: bool = True,
) -> Tuple[pd.DataFrame, BaseMetadata]:
"""
Return a ``pandas.DataFrame`` containing all NWIS parameter codes -
deprecated, use `get_reference_table(collection="parameter-codes")`.
"""
raise NameError(
"`nwis.get_pmcodes` has been replaced with `get_reference_table(collection='parameter-codes')`."
)
def get_water_use(
years: Union[str, List[str]] = "ALL",
state: Optional[str] = None,
counties: Union[str, List[str]] = "ALL",
categories: Union[str, List[str]] = "ALL",
ssl_check: bool = True,
) -> Tuple[pd.DataFrame, BaseMetadata]:
"""
Water use data retrieval from USGS (NWIS).
Parameters
----------
years: string or list of strings
List or comma delimited string of years. Must be years ending in 0 or
5, or "ALL", which retrieves all available years, default is "ALL"
state: string, optional, default is None
full name, abbreviation or id
counties: string or list of strings
County IDs from county lookup or "ALL", default is "ALL"
categories: string or list of strings
List or comma delimited string of Two-letter category abbreviations,
default is "ALL"
ssl_check: bool, optional
If True, check SSL certificates, if False, do not check SSL,
default is True
Returns
-------
df: ``pandas.DataFrame``
Data from NWIS
md: :obj:`dataretrieval.utils.Metadata`
A custom metadata object
Examples
--------
.. doctest::
>>> # Get total population for RI from the NWIS water use service
>>> df, md = dataretrieval.nwis.get_water_use(
... years="2000", state="RI", categories="TP"
... )
>>> # Get the national total water use for livestock in Bgal/day
>>> df, md = dataretrieval.nwis.get_water_use(years="2010", categories="L")
>>> # Get 2005 domestic water use for Apache County in Arizona
>>> df, md = dataretrieval.nwis.get_water_use(
... years="2005", state="Arizona", counties="001", categories="DO"
... )
"""
if years:
if not isinstance(years, list) and not isinstance(years, str):
raise TypeError("years must be a string or a list of strings")
if counties:
if not isinstance(counties, list) and not isinstance(counties, str):
raise TypeError("counties must be a string or a list of strings")
if categories:
if not isinstance(categories, list) and not isinstance(categories, str):
raise TypeError("categories must be a string or a list of strings")
payload = {
"rdb_compression": "value",
"format": "rdb",
"wu_year": years,
"wu_category": categories,
"wu_county": counties,
}
url = WATERDATA_URL + "water_use"
if state is not None:
url = WATERDATA_BASE_URL + state + "/nwis/water_use"
payload.update({"wu_area": "county"})
response = query(url, payload, ssl_check=ssl_check)
return _read_rdb(response.text), NWIS_Metadata(response)
def get_ratings(
site: Optional[str] = None,
file_type: str = "base",
ssl_check: bool = True,
**kwargs,
) -> Tuple[pd.DataFrame, BaseMetadata]:
"""
Rating table for an active USGS streamgage retrieval.
Reads current rating table for an active USGS streamgage from NWISweb.
Data is retrieved from https://waterdata.usgs.gov/nwis.
Parameters
----------
site: string, optional, default is None
USGS site number. This is usually an 8 digit number as a string.
If the nwis parameter site_no is supplied, it will overwrite the site
parameter
file_type: string, default is "base"
can be "base", "corr", or "exsa"
ssl_check: bool, optional
If True, check SSL certificates, if False, do not check SSL,
default is True
**kwargs: optional
If supplied, will be used as query parameters
Return
------
df: ``pandas.DataFrame``
Formatted requested data
md: :obj:`dataretrieval.utils.Metadata`
A custom metadata object
Examples
--------
.. doctest::
>>> # Get the rating table for USGS streamgage 01594440
>>> df, md = dataretrieval.nwis.get_ratings(site="01594440")
"""
site = kwargs.pop("site_no", site)
payload = {}
url = WATERDATA_BASE_URL + "nwisweb/get_ratings/"
if site is not None:
payload.update({"site_no": site})
if file_type is not None:
if file_type not in ["base", "corr", "exsa"]:
raise ValueError(
f'Unrecognized file_type: {file_type}, must be "base", "corr" or "exsa"'
)
payload.update({"file_type": file_type})
response = query(url, payload, ssl_check=ssl_check)
return _read_rdb(response.text), NWIS_Metadata(response, site_no=site)
def what_sites(ssl_check: bool = True, **kwargs) -> Tuple[pd.DataFrame, BaseMetadata]:
"""
Search NWIS for sites within a region with specific data.
Parameters
----------
ssl_check: bool, optional
If True, check SSL certificates, if False, do not check SSL,
default is True
**kwargs: optional
Accepts the same parameters as :obj:`dataretrieval.nwis.get_info`
Return
------
df: ``pandas.DataFrame``
Formatted requested data
md: :obj:`dataretrieval.utils.Metadata`
A custom metadata object
Examples
--------
.. doctest::
>>> # get information about a single site
>>> df, md = dataretrieval.nwis.what_sites(sites="05114000")
>>> # get information about sites with phosphorus in Ohio
>>> df, md = dataretrieval.nwis.what_sites(
... stateCd="OH", parameterCd="00665"
... )
"""
response = query_waterservices(service="site", ssl_check=ssl_check, **kwargs)
df = _read_rdb(response.text)
return df, NWIS_Metadata(response, **kwargs)
def get_record(
sites: Optional[Union[List[str], str]] = None,
start: Optional[str] = None,
end: Optional[str] = None,
multi_index: bool = True,
wide_format: bool = True,
datetime_index: bool = True,
state: Optional[str] = None,
service: str = "iv",
ssl_check: bool = True,
**kwargs,
) -> pd.DataFrame:
"""
Get data from NWIS and return it as a ``pandas.DataFrame``.
.. note::
If no start or end date are provided, only the most recent record is
returned.
Parameters
----------
sites: string or list of strings, optional, default is None
List or comma delimited string of site.
start: string, optional, default is None
Starting date of record (YYYY-MM-DD)
end: string, optional, default is None
Ending date of record. (YYYY-MM-DD)
multi_index: bool, optional
If False, a dataframe with a single-level index (datetime) is returned,
default is True
wide_format : bool, optional
If True, return data in wide format with multiple samples per row and
one row per time, default is True
datetime_index : bool, optional
If True, create a datetime index. default is True
state: string, optional, default is None
full name, abbreviation or id
service: string, default is 'iv'
- 'iv' : instantaneous data
- 'dv' : daily mean data
- 'site' : site description
- 'peaks': discharge peaks
- 'water_use': get water use data
- 'ratings': get rating table
- 'stat': get statistics
ssl_check: bool, optional
If True, check SSL certificates, if False, do not check SSL,
default is True
**kwargs: optional
If supplied, will be used as query parameters
Returns
-------
``pandas.DataFrame`` containing requested data
Examples
--------
.. doctest::
>>> # Get latest instantaneous data from site 01585200
>>> df = dataretrieval.nwis.get_record(sites="01585200", service="iv")
>>> # Get latest daily mean data from site 01585200
>>> df = dataretrieval.nwis.get_record(sites="01585200", service="dv")
>>> # Get site description for site 01585200
>>> df = dataretrieval.nwis.get_record(sites="01585200", service="site")
>>> # Get discharge peaks for site 01585200
>>> df = dataretrieval.nwis.get_record(sites="01585200", service="peaks")
>>> # Get water use data for livestock nationally in 2010
>>> df = dataretrieval.nwis.get_record(
... service="water_use", years="2010", categories="L"
... )
>>> # Get rating table for USGS streamgage 01585200
>>> df = dataretrieval.nwis.get_record(sites="01585200", service="ratings")
>>> # Get annual statistics for USGS station 01646500
>>> df = dataretrieval.nwis.get_record(
... sites="01646500",
... service="stat",
... statReportType="annual",
... statYearType="water",
... )
"""
_check_sites_value_types(sites)
if service not in WATERSERVICES_SERVICES + WATERDATA_SERVICES:
raise TypeError(f"Unrecognized service: {service}")
if service == "iv":
df, _ = get_iv(
sites=sites,
startDT=start,
endDT=end,
multi_index=multi_index,
ssl_check=ssl_check,
**kwargs,
)
return df
elif service == "dv":
df, _ = get_dv(
sites=sites,
startDT=start,
endDT=end,
multi_index=multi_index,
ssl_check=ssl_check,
**kwargs,
)
return df
elif service == "site":
df, _ = get_info(sites=sites, ssl_check=ssl_check, **kwargs)
return df
elif service == "peaks":
df, _ = get_discharge_peaks(
site_no=sites,
begin_date=start,
end_date=end,
multi_index=multi_index,
ssl_check=ssl_check,
**kwargs,
)
return df
elif service == "water_use":
df, _ = get_water_use(state=state, ssl_check=ssl_check, **kwargs)