川の水位変化をグラフにする
現在住んでいる場所は大きめの川が近くにあるところで、シミュレーションによっては洪水で5m近くの浸水になる可能性が示唆されているところです。
幸い引っ越してきてからはそういった水害はありませんが、一応河川の水量がどんな風に変化しているのか見てみたいなと思ってグラフ化に挑戦してみました。
Ruby を使って書いています。
なお、リアルタイム 川の防災情報というサイトで観測所ごとに水位変化をグラフで見られるので今回の作業はほぼ趣味です。
もっとスマートな書き方とかあるんだろうなぁ…。
川の防災情報のサイトからデータを取ろうと思ったのですが、Q&A を見ると水情報国土データ管理センター クリアリングハウスから取ってねという文章があったので、クリアリングハウスからデータを頂くことにします。
目的の観測所のリアルタイム10分水位一覧表を見るとデータが一覧になっています。
フロッピーディスクのアイコンからデータをダウンロードできるようです。
このフロッピーディスクからのリンク先が動的に変化するようなので、HTMLを取得してリンク先を探した後にダウンロードするスクリプトをまずは書きました。

取得するリアルタイム10分水位一覧表のURLは外部のJSONに保存しました。
{
"url": "%URL%"
}
データを取得するスクリプトはget_river_level.rbという名前で保存しています。
#!/usr/bin/env ruby
# coding: utf-8
require 'open-uri'
require 'nokogiri'
require 'json'
url = ""
json_data = open('./config.json') do |io|
url = JSON.load(io)
end
url = json_data['url']
uri = "http://www1.river.go.jp/"
html = open(url, 'r:euc-jp').read
html.split("\n").each do |line|
if line =~ /download.gif/
href = Nokogiri::HTML(line)
uri += href.css('a').attribute('href').value
end
end
dat = open(uri, 'r:sjis').read
File.open('./level.dat', 'w:UTF-8:sjis') do |data|
data << dat
end
次に取得したデータを SQLite3 に突っ込むスクリプトです。
set_river_level.rb という名前にしました。
#!/usr/bin/env ruby
# coding: utf-8
require 'sqlite3'
sqlite = './level.sqlite'
unless File.exist?(sqlite)
db = SQLite3::Database.new(sqlite)
sql = <<-SQL
CREATE TABLE level (
time text,
level real
);
SQL
db.execute_batch(sql)
db.close
end
river_level = ""
open('./level.dat') do |dat|
river_level = dat.readlines[9..-1]
end
db = SQLite3::Database.new(sqlite)
river_level.each do |line|
data = line.split(',')
time = data[0..1].join(' ')
unless data[2] == '-'
sql = <<-SQL
SELECT * FROM level
WHERE time="#{time}";
SQL
result = db.execute(sql)
if result == []
sql = <<-SQL
INSERT INTO level VALUES(
"#{time}",
"#{data[2]}"
);
SQL
db.execute_batch(sql)
end
end
end
db.close
最後にグラフ化するスクリプトです。
HTML をガリガリ書きたくなかったので sinatra と slim を使っていますが、sinatra がうまく動かなかったので Ruby のバージョンを上げたりとか違うところで苦労しました。
myapp.rb という名前で保存しています。
#!/usr/bin/env ruby
# coding: utf-8
require 'sinatra'
require 'sinatra/reloader'
require 'sqlite3'
require 'slim'
require 'json'
set :bind, '0.0.0.0'
get '/' do
slim :index
end
get '/data' do
db = SQLite3::Database.new('./level.sqlite')
count = db.execute("SELECT COUNT(time) FROM level;")[0][0] - 150
sql = "SELECT * FROM level LIMIT #{count}, 150;"
data = db.execute(sql)
db.close
data.to_json
end
views ディレクトリを作成して、中に index.slim を作成しています。
doctype html
html
head
title River Level Data
meta charset='utf-8'
body
script src='jquery.min.js' type='text/javascript'
script src='https://www.google.com/jsapi' type='text/javascript'
script src='chartkick.js' type='text/javascript'
div id='chart'
javascript:
$(function(){
$.ajax({
type: 'GET',
url: '/data',
dataType: 'json',
}).done(function(d){
new Chartkick.AreaChart("chart",d);
});
});
myapp.rb を実行してからブラウザで接続するとグラフが現れます。
直近概ね48時間のデータをグラフ化させています。

各種フレームワークのおかげで思ったより簡単に作成することができました。
参考にしたサイト