川の水位変化をグラフにする
現在住んでいる場所は大きめの川が近くにあるところで、シミュレーションによっては洪水で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時間のデータをグラフ化させています。
各種フレームワークのおかげで思ったより簡単に作成することができました。
参考にしたサイト