2011年3月22日火曜日

東北地方太平洋沖地震 可視化地図

このブログ記事をはてなブックマークに追加

東日本大震災(東北関東大震災)により被害を受けられた方々には心よりお見舞い申し上げます。

以前、日本全国コンビニ店舗分布地図Processingで作ったが、今回の地震の震源とその大きさについて視覚的に表した地図を作成した。少しでも何かの役に立てば良いのだが。

震源とその大きさを日本地図上に円として表現している。円の大きさはマグニチュードと震源の深さに依存している(これは大まかな目安であり、揺れた地域や震度・エネルギーに正確に対応しているわけではない)。また、震源の深さによって円の色が変わり、浅ければ赤に、深ければ緑に近づく。海の色は時刻を現しており、正午が最も明るい青で表現され、深夜であれば真っ黒となる。データについては、日本気象協会が提供している3月9日から20日までの地震情報を利用させて頂いた。

操作方法は、スペースキーでポーズ、'N'キーで3時間進め、'B'キーで3時間戻る。'+'キーで時間の進みが速くなり、'-'キーで遅くなる。マウスの左クリックでドラッグすれば地図を動かすことができ、右クリックで上下にドラッグすれば拡大・縮小となる。



可視化地図から、3月11日14時46分のマグニチュード9.0の地震の起こる二日ほど前から、三陸沖で中規模の地震が頻発していることが分かる。ところが、M9.0の地震の数時間前からは揺れが全て途絶え、嵐の前の静けさの様相となる。そして、M9.0の地震の直後からはひっきりなしに揺れが続き、数日してやや沈静化してきている。ただ、M6程度の地震は未だに起こっているので、安心するにはまだ早いかもしれない。最近の地震では福島県沖や茨城県沖に多く、ややと南下している様子が分かる。

以下、ソースコードを示す。

earthquake.pde

/* earthquake.pde by nox, 2011.3.22 */ String convData = "quake.tsv.gz"; String japanMap = "japan.svg"; PShape mapShape; int totalCount; Place[] places; int placeCount = 0; final float minX = -0.19834; final float maxX = 0.2425; final float minY = -0.1875; final float maxY = 0.1845; PImage mapImage; PFont font; float offsetX = 0.0; float offsetY = 0.0; int centerX = 0; int centerY = 0; float zoom = 1.0; int mxStart, myStart, myPos; int startTime, currentTime, stopTime; int month_, day_, hour_, minute_; boolean is_paused = false; int speed = 10; public void setup() { mapShape = loadShape(japanMap); smooth(); loop(); size(int(mapShape.width), int(mapShape.height), JAVA2D); // 539, 563 shapeMode(CORNER); mapShape.disableStyle(); font = loadFont("CourierNewPSMT-14.vlw"); textMode(SCREEN); textFont(font); readData(); startTime = millis(); loop(); } public void draw() { if (!mousePressed) currentTime = millis() - startTime; int currentDate = currentTime + (hour_ * 60 + minute_) * speed; int mon_ = month_; int d_ = day_ + currentDate / (24 * 60 * speed); int h_ = currentDate / (60 * speed) % 24; int m_ = currentDate / speed % 60; if (d_ >= 21 || d_ <= 8 || h_ < 0 || m_ < 0) startTime = millis(); background(color(0, 0, (720 - abs(h_ * 60 + m_ - 720)) * 0.1)); noStroke(); fill(32); shape(mapShape, int(offsetX * zoom) + centerX, int(offsetY * zoom) + centerY); fill(127); String timeFormat = nf(mon_, 2) + "/" + nf(d_, 2) + " " + nf(h_, 2) + ":" + nf(m_, 2) + " speed: " + nf(10.0 / speed, 1, 2); text(timeFormat, 15, 20); for (int i = 0; i < placeCount; i++) places[i].draw(); } float TX(float x) { float offset = width * (1.0 - zoom) * 0.5; return map(x, minX, maxX, offset, width - offset); } float TY(float y) { float offset = height * (1.0 - zoom) * 0.5; return map(y, minY, maxY, height - offset, offset); } void mousePressed() { if (!is_paused) { mxStart = int(mouseX - offsetX * zoom); myStart = int(mouseY - offsetY * zoom); myPos = mouseY; stopTime(); loop(); } } void mouseReleased() { if (!is_paused) startTime(); } void mouseDragged() { if (is_paused) return; if (mouseButton == LEFT) { offsetX = (mouseX - mxStart) / zoom; offsetY = (mouseY - myStart) / zoom; } else if (mouseButton == RIGHT) { if (mouseY - myPos > 4) { float zoomOut = 9.8 / 10.0; mapShape.scale(zoomOut); zoom *= zoomOut; centerX = int(width * (1.0 - zoom) * 0.5); centerY = int(height * (1.0 - zoom) * 0.5); myPos = mouseY; } else if (mouseY - myPos < -4) { float zoom_in = 10.0 / 9.8; mapShape.scale(zoom_in); zoom *= zoom_in; centerX = int(width * (1.0 - zoom) * 0.5); centerY = int(height * (1.0 - zoom) * 0.5); myPos = mouseY; } } } void startTime() { startTime += millis() - stopTime; loop(); } void stopTime() { noLoop(); stopTime = millis(); } void keyPressed() { if (key == ' ') { if (is_paused) { startTime(); is_paused = false; } else { stopTime(); is_paused = true; } } else if (key == 'n' || key == 'N') startTime -= 180 * speed; else if (key == 'b' || key == 'B') startTime += 180 * speed; else if (key == '+' && speed > 3) speed -= 1; else if (key == '-' && speed < 30) speed += 1; } void readData() { new Slurper(); } Place parsePlace(String line) { String pieces[] = split(line, '\t'); int mins = int(pieces[0]); int mon = int(pieces[1]); int d = int(pieces[2]); int h = int(pieces[3]); int m = int(pieces[4]); float x = float(pieces[5]); float y = float(pieces[6]); float magnitude = float(pieces[7]); float depth = float(pieces[8]); String name = pieces[9]; return new Place(mins, mon, d, h, m, x, y, magnitude, depth, name); }

Place.pde

class Place { int mins; int mon, d, h, m; float x, y; float magnitude; float depth; String name; public Place(int mins, int mon, int d, int h, int m, float x, float y, float magnitude, float depth, String name) { this.mins = mins; this.mon = mon; this.d = d; this.h = h; this.m = m; this.x = x; this.y = y; this.magnitude = magnitude; this.depth = depth; this.name = name; } public void draw() { int xx = (int)TX(this.x) + int(offsetX * zoom); int yy = (int)TY(this.y) + int(offsetY * zoom); int a = mins * speed + 255 - currentTime; if (magnitude == 0.0 || a < 0 || a > 255) return; float r = pow(5.0, (magnitude / 2.7)) / sqrt(depth / 10 + 1); float m = r * ((255 - a) / 50.0) * zoom; fill(color(255 - this.depth * 2, this.depth * 2, 0), a); ellipse(xx, yy, m, m); } }

Slurper.pde

class Slurper implements Runnable { Slurper() { Thread thread = new Thread(this); thread.start(); } public void run() { try { BufferedReader reader = createReader(convData); String line = reader.readLine(); totalCount = int(line); places = new Place[totalCount]; line = reader.readLine(); places[placeCount++] = parsePlace(line); month_ = places[0].mon; day_ = places[0].d; hour_ = places[0].h; minute_ = places[0].m; while ((line = reader.readLine()) != null) places[placeCount++] = parsePlace(line); } catch (IOException e) { e.printStackTrace(); } } }

0 コメント: