ADLongwell-usgs-waterdata 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +1 -0
- data/License.txt +19 -0
- data/Manifest.txt +12 -0
- data/README.txt +3 -0
- data/Rakefile +12 -0
- data/init.rb +1 -0
- data/lib/usgs.rb +7 -0
- data/lib/usgs/gauge.rb +149 -0
- data/lib/usgs/water_data.rb +66 -0
- data/spec/gauge_spec.rb +51 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/waterdata_spec.rb +15 -0
- metadata +67 -0
data/History.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1 - Welcomed into the world, screaming and crying.
|
data/License.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2008 Aaron Longwell, Chris Tenbrink
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,3 @@
|
|
1
|
+
README.txt
|
2
|
+
|
3
|
+
The usgs-waterdata library is a tool for obtaining real-time and statistical river flow data from the United States Geological Survey's National Water Information System. It will fetch a list of all rivers for which gauge data exists along with the gauges on that river. For a particular gauge, the library will obtain the latest flow, the mean flow on all days for which data exists, and long-term statistical flow data.
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/usgs.rb'
|
6
|
+
|
7
|
+
Hoe.new('usgs-waterdata', USGS::VERSION) do |p|
|
8
|
+
# p.rubyforge_name = 'usgs-waterdata' # if different than lowercase project name
|
9
|
+
# p.developer('FIX', 'FIX@example.com')
|
10
|
+
end
|
11
|
+
|
12
|
+
# vim: syntax=Ruby
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Placeholder
|
data/lib/usgs.rb
ADDED
data/lib/usgs/gauge.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
module USGS
|
2
|
+
|
3
|
+
require 'open-uri'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
class Gauge
|
7
|
+
|
8
|
+
attr_reader :site_number
|
9
|
+
|
10
|
+
def initialize( site_number )
|
11
|
+
@site_number = site_number
|
12
|
+
end
|
13
|
+
|
14
|
+
# Determine the most recent instantaneous flow in CFS for this guage
|
15
|
+
def latest_flow
|
16
|
+
url = "http://waterdata.usgs.gov/nwis/uv?cb_00060=on&format=rdb&period=1&site_no=#{@site_number}"
|
17
|
+
flow = 0
|
18
|
+
open(url).each do |line|
|
19
|
+
next if line =~ /^#/
|
20
|
+
next if line =~ /^5/
|
21
|
+
next if line =~ /^agency/
|
22
|
+
|
23
|
+
fields = line.split(/\t/)
|
24
|
+
flow = fields[3]
|
25
|
+
end
|
26
|
+
flow
|
27
|
+
end
|
28
|
+
|
29
|
+
# todo: use lambda (or a similar construct) to minimize repetitive code
|
30
|
+
|
31
|
+
# Returns a 2-dimensional array of the statistical mean flows for this
|
32
|
+
# gauge on days for which data exists, sorted by date.
|
33
|
+
def get_statistical_mean_flows
|
34
|
+
populate_statistical_data if @statistical_mean_flows.nil? or @statistical_mean_flows.empty?
|
35
|
+
@statistical_mean_flows
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns a 2-dimensional array of the statistical median flows for this
|
39
|
+
# gauge on days for which data exists, sorted by date.
|
40
|
+
def get_statistical_median_flows
|
41
|
+
populate_statistical_data if @statistical_median_flows.nil? or @statistical_median_flows.empty?
|
42
|
+
@statistical_median_flows
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns a 2-dimensional array of the statistical 80th percentile flows for this
|
46
|
+
# gauge on days for which data exists, sorted by date.
|
47
|
+
def get_statistical_percentile80_flows
|
48
|
+
populate_statistical_data if @statistical_percentile80_flows.nil? or @statistical_percentile80_flows.empty?
|
49
|
+
@statistical_percentile80_flows
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns a 2-dimensional array of the statistical 20th percentile flows for this
|
53
|
+
# gauge on days for which data exists, sorted by date.
|
54
|
+
def get_statistical_percentile20_flows
|
55
|
+
populate_statistical_data if @statistical_percentile20_flows.nil? or @statistical_percentile20_flows.empty?
|
56
|
+
@statistical_percentile20_flows
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns a 2-dimensional array of the daily mean flows for this
|
60
|
+
# gauge on days for which data exists, sorted by date.
|
61
|
+
def get_daily_mean_flows
|
62
|
+
populate_daily_data if @daily_mean_flows.nil? or @daily_mean_flows.empty?
|
63
|
+
@daily_mean_flows
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# Populate daily data for a gauge from the USGS site
|
69
|
+
def populate_daily_data
|
70
|
+
url = "http://waterdata.usgs.gov/nwis/dv?site_no=#{@site_number}&cb_00060=on&begin_date=1880-01-01&format=rdb"
|
71
|
+
mean_flows_hash = {}
|
72
|
+
open(url).each do |line|
|
73
|
+
next if line =~ /^#/
|
74
|
+
next if line =~ /^5/
|
75
|
+
next if line =~ /^agency/
|
76
|
+
|
77
|
+
field_array = line.split(/\t/)
|
78
|
+
date_array = field_array[2].split('-')
|
79
|
+
date = Date.new(date_array[0].to_i, date_array[1].to_i, date_array[2].to_i)
|
80
|
+
mean = field_array[3]
|
81
|
+
mean_flows_hash[date] = mean
|
82
|
+
end
|
83
|
+
@daily_mean_flows = mean_flows_hash.sort
|
84
|
+
end
|
85
|
+
|
86
|
+
# Populate statistical data for a gauge from the USGS site
|
87
|
+
def populate_statistical_data
|
88
|
+
url = "http://waterdata.usgs.gov/id/nwis/dvstat/?site_no=#{@site_number}&por_#{@site_number}_2=1155369,00060,2,0000-01-01,9999-01-01&start_dt=0000-01-01&end_dt=9999-01-01&format=rdb&date_format=YYYY-MM-DD"
|
89
|
+
|
90
|
+
field_map = {
|
91
|
+
'agency' => 0,
|
92
|
+
'site' => 1,
|
93
|
+
'parameter' => 2,
|
94
|
+
'dd_nu' => 3,
|
95
|
+
'month_nu' => 4,
|
96
|
+
'day_nu' => 5,
|
97
|
+
'begin_yr' => 6,
|
98
|
+
'end_yr' => 7,
|
99
|
+
'count_nu' => 8,
|
100
|
+
'max_va_yr' => 9,
|
101
|
+
'max_va' => 10,
|
102
|
+
'min_va_yr' => 11,
|
103
|
+
'min_va' => 12,
|
104
|
+
'mean_va' => 13,
|
105
|
+
'p05_va' => 14, # 05 percentile of daily mean values for this day.
|
106
|
+
'p10_va' => 15, # 10 percentile of daily mean values for this day.
|
107
|
+
'p20_va' => 16, # 20 percentile of daily mean values for this day.
|
108
|
+
'p25_va' => 17, # 25 percentile of daily mean values for this day.
|
109
|
+
'p50_va' => 18, # 50 percentile (median) of daily mean values for this day.
|
110
|
+
'p75_va' => 19, # 75 percentile of daily mean values for this day.
|
111
|
+
'p80_va' => 20, # 80 percentile of daily mean values for this day.
|
112
|
+
'p90_va' => 21, # 90 percentile of daily mean values for this day.
|
113
|
+
'p95_va' => 22 # 95 percentile of daily mean values for this day.
|
114
|
+
}
|
115
|
+
|
116
|
+
mean_flows_hash = {}
|
117
|
+
median_flows_hash = {}
|
118
|
+
percentile20_flows_hash = {}
|
119
|
+
percentile80_flows_hash = {}
|
120
|
+
open(url).each do |line|
|
121
|
+
next if line =~ /^#/
|
122
|
+
next if line =~ /^5/
|
123
|
+
next if line =~ /^agency/
|
124
|
+
next if line =~ /^\s/
|
125
|
+
|
126
|
+
field_array = line.split(/\t/)
|
127
|
+
month = field_array[field_map['month_nu']]
|
128
|
+
day = field_array[field_map['day_nu']]
|
129
|
+
mean = field_array[field_map['mean_va']]
|
130
|
+
median = field_array[field_map['p50_va']]
|
131
|
+
percentile20 = field_array[field_map['p20_va']]
|
132
|
+
percentile80 = field_array[field_map['p80_va']]
|
133
|
+
|
134
|
+
d = Date.new(1500, month.to_i, day.to_i)
|
135
|
+
mean_flows_hash[d] = mean
|
136
|
+
median_flows_hash[d] = median
|
137
|
+
percentile20_flows_hash[d] = percentile20
|
138
|
+
percentile80_flows_hash[d] = percentile80
|
139
|
+
end
|
140
|
+
|
141
|
+
@statistical_mean_flows = mean_flows_hash.sort
|
142
|
+
@statistical_median_flows = median_flows_hash.sort
|
143
|
+
@statistical_percentile20_flows = percentile20_flows_hash.sort
|
144
|
+
@statistical_percentile80_flows = percentile80_flows_hash.sort
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module USGS
|
2
|
+
class WaterData
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def us_rivers
|
7
|
+
states = %w{al ar az ca co ct dc de fl ga hi ia id il in ks ky la ma md me mi mn mo ms mt nc nd ne nh nj nm nv ny oh ok or pa ri sc sd tn tx ut va vt wa wi wv wy}
|
8
|
+
state_rivers = {}
|
9
|
+
states.each do |state|
|
10
|
+
STDOUT.write("#{state} ") # REMOVE THIS REMOVE THIS REMOVE THIS
|
11
|
+
STDOUT.flush
|
12
|
+
state_rivers[state] = rivers_in_state(state)
|
13
|
+
end
|
14
|
+
state_rivers
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def rivers_in_state(st)
|
19
|
+
require 'open-uri'
|
20
|
+
|
21
|
+
url = "http://waterdata.usgs.gov/#{st}/nwis/current/?type=flow&format=rdb"
|
22
|
+
rivers = {}
|
23
|
+
|
24
|
+
open(url).each do |line|
|
25
|
+
next if line =~ /^#/
|
26
|
+
next if line =~ /^5/
|
27
|
+
next if line =~ /^agency/
|
28
|
+
|
29
|
+
fields = line.split(/\t/)
|
30
|
+
station_name = fields[2]
|
31
|
+
name_parts = station_name.split(/\b([A-Z]+ OF|ABV|AT|NR|NEAR|DS OF|US OF|ABOVE|BELOW|BEL|BL|BLW|AB|ABV)\b/i)
|
32
|
+
river_name = clean_river_name(name_parts[0])
|
33
|
+
|
34
|
+
rivers[river_name] ||= []
|
35
|
+
rivers[river_name] << fields[1]
|
36
|
+
end
|
37
|
+
|
38
|
+
rivers
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
# Given a river name from the USGS site, a clean and
|
43
|
+
# normalized river name is returned.
|
44
|
+
#
|
45
|
+
def clean_river_name(river_name)
|
46
|
+
val = river_name.strip.downcase.gsub(/\b('?[a-z])/) { $1.capitalize }
|
47
|
+
val.gsub!(/d'?\s*alene/i, "d'Alene")
|
48
|
+
val.gsub!(/[^A-Za-z' ]/, '')
|
49
|
+
val.gsub!(/\bSf\b/, 'South Fork')
|
50
|
+
val.gsub!(/\bMf\b/, 'Middle Fork')
|
51
|
+
val.gsub!(/\bNf\b/, 'North Fork')
|
52
|
+
val.gsub!(/\bDiv\b/, 'Diversion')
|
53
|
+
val.gsub!(/\bCrk?\b/, 'Creek')
|
54
|
+
val.gsub!(/\bC\b/, 'Creek')
|
55
|
+
val.gsub!(/\bR\b/, 'River')
|
56
|
+
val.gsub!(/\bBra?(nch)?\b/, 'Branch')
|
57
|
+
val.gsub!(/\bRvr\b/, 'River')
|
58
|
+
val.gsub!(/\bTrib\b/, 'Tributary')
|
59
|
+
val.gsub!(/\bSprngs\b/, 'Springs')
|
60
|
+
val
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
data/spec/gauge_spec.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
|
2
|
+
|
3
|
+
describe USGS::Gauge do
|
4
|
+
|
5
|
+
it 'should get mean flow data for a river' do
|
6
|
+
gauge = USGS::Gauge.new(13336500)
|
7
|
+
mean_flow = gauge.get_statistical_mean_flows
|
8
|
+
mean_flow.each do |record|
|
9
|
+
puts "Mean flow for the Selway River on #{record[0].strftime("%d %b")} is #{record[1]} CFS"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should get median flow data for a river' do
|
14
|
+
gauge = USGS::Gauge.new(13336500)
|
15
|
+
median_flow = gauge.get_statistical_median_flows
|
16
|
+
median_flow.each do |record|
|
17
|
+
puts "Median flow for the Selway River on #{record[0].strftime("%d %b")} is #{record[1]} CFS"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should get 80th percentile flow data for a river' do
|
22
|
+
gauge = USGS::Gauge.new(13336500)
|
23
|
+
percentile80_flow = gauge.get_statistical_percentile80_flows
|
24
|
+
percentile80_flow.each do |record|
|
25
|
+
puts "80th percentile flow for the Selway River on #{record[0].strftime("%d %b")} is #{record[1]} CFS"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should get 20th percentile flow data for a river' do
|
30
|
+
gauge = USGS::Gauge.new(13336500)
|
31
|
+
percentile20_flow = gauge.get_statistical_percentile20_flows
|
32
|
+
percentile20_flow.each do |record|
|
33
|
+
puts "20th percentile flow for the Selway River on #{record[0].strftime("%d %b")} is #{record[1]} CFS"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should get daily mean flows for a river' do
|
38
|
+
gauge = USGS::Gauge.new(13336500)
|
39
|
+
daily_mean_flows = gauge.get_daily_mean_flows
|
40
|
+
daily_mean_flows.each do |record|
|
41
|
+
puts "Daily mean flow for the Selway River on #{record[0].strftime("%d %b %Y")} is #{record[1]} CFS"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should get the current flow for a river' do
|
46
|
+
gauge = USGS::Gauge.new(13336500)
|
47
|
+
puts "Latest flow for the Selway River is #{gauge.latest_flow} CFS"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
|
2
|
+
|
3
|
+
describe USGS::WaterData do
|
4
|
+
|
5
|
+
it 'should retrieve data' do
|
6
|
+
USGS::WaterData.us_rivers.each do |state, rivers|
|
7
|
+
puts "#{state}"
|
8
|
+
puts '-' * 60
|
9
|
+
rivers.each do |river_name, gauge_ids|
|
10
|
+
puts " * #{river_name} => #{gauge_ids.join(', ')}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ADLongwell-usgs-waterdata
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Longwell
|
8
|
+
- Chris Tenbrink
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2008-10-16 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: A library for obtaining statistical and real-time flows from the Unite States Geological Survey's National Water Information System
|
18
|
+
email: ctenbrink@gmail.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files:
|
24
|
+
- History.txt
|
25
|
+
- Manifest.txt
|
26
|
+
- README.txt
|
27
|
+
files:
|
28
|
+
- History.txt
|
29
|
+
- init.rb
|
30
|
+
- Manifest.txt
|
31
|
+
- License.txt
|
32
|
+
- README.txt
|
33
|
+
- Rakefile
|
34
|
+
- lib/usgs.rb
|
35
|
+
- lib/usgs/gauge.rb
|
36
|
+
- lib/usgs/water_data.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/ADLongwell/usgs-waterdata
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options:
|
41
|
+
- --main
|
42
|
+
- README.txt
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.2.0
|
61
|
+
signing_key:
|
62
|
+
specification_version: 2
|
63
|
+
summary: Library for obtaining river flow data.
|
64
|
+
test_files:
|
65
|
+
- spec/gauge_spec.rb
|
66
|
+
- spec/spec_helper.rb
|
67
|
+
- spec/waterdata_spec.rb
|