スキップしてメイン コンテンツに移動

日本全国ハンバーガーショップ分布地図

以前、Processingを使って日本全国のコンビニ店舗の分布地図を作成したが、今回はハンバーガーショップの分布地図を作成してみた。

個人的にハンバーガーショップには小さい頃から思い入れがあって、小学生の頃、初めてマクドナルドのハンバーガーを食べたときに「なんて美味しいんだろう」と感動した覚えがある。しかし、今でこそ安価な食べ物という認識だが、当時は他の食べ物に比べて割高であまり頻繁に食べられなかった。

その後はだんだんとハンバーガーから離れていったが、モスバーガーと出会ったときに二度目の感動を覚えた。冷たくてジューシーな野菜と熱々のハンバーグが絶妙にマッチしてそれまで食べたことのないハンバーガーだった。少々食べにくくはあったが、逆にそれが溢れる美味しさを表現していたようにも思う。

最近気に入っているハンバーガーは、アトレヴィ 秋葉原2階にあるChelsea Marketのアボガドバーガーだ。少々値は張るが、普通のチェーン店に比べて味は飛び抜けていると思う。チェーン店ではないハンバーガー専門店なら他にも美味しいハンバーガーがいろいろとありそう。

閑話休題。以下に作成したプログラムを示す。


左上の店名をクリック: 分布の表示・非表示を切り替える。起動時はマクドナルドのみ表示。 右クリックしたままマウス移動: 地図を平行移動する。 左クリックしたままマウス上下移動: 地図を拡大・縮小する。

プログラムの作成方法は前回のコンビニ店舗分布地図を作成した方法とほとんど変わらない。まず、住所をネットから取得する。それをGoogle Maps APIで緯度経度変換し、さらにPythonスクリプトでUTM図法に合わせてXY座標変換する。そのデータをtar/gzipでアーカイブし、Processingを使って読み込み、日本地図に表示する。ブログへの貼り付けはProcessingでJavaアプレットにエクスポートできるのでそれを使う。

今回の分布地図を見て、マクドナルドよりもかなり後に出てきたモスバーガーの店舗が思ったより多く、全国的に展開していて驚いた。また、子供の頃に食べた森永LOVEは既に存在せずロッテリアに買収されたことも今回作成する過程で知った。他には東京に最近出現してきたバーガーキングや沖縄のみに存在するA&Wがやや気になった。沖縄のA&Wへは簡単には行けないが、バーガーキングは今度行ってみよう。

住所データさえあればコンビニ店舗やハンバーガーショップに限らずどんな分布地図でも作れることだし、何か面白い題材ないかな。

以下、ソースコード。

fastfood.pde

String shopData = "convert_xy.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 offset_x = 0.0; float offset_y = 0.0; int center_x = 0; int center_y = 0; float zoom = 1.0; int mx_start, my_start, my_pos; String[] shopName = { "McDonald", "MOS", "Lotteria", "Freshness", "First Kitchen", "DOMDOM", "Burger King", "A&W", "Becker's" }; color[] shopColor = { #ff0000, #007fff, #00ff00, #ffff00, #ff00ff, #00ffff, #7f0000, #0000ff, #007f00 }; boolean[] shopIds = { true, false, false, false, false, false, false, false, false }; int numShops = 9; 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(); } public void draw() { background(0); noStroke(); fill(32); shape(mapShape, int(offset_x * zoom) + center_x, int(offset_y * zoom) + center_y); for (int i = 0; i < placeCount; i++) places[i].draw(); for (int i = 0; i < numShops; i++) { fill(shopColor[i]); text(shopName[i], 15, 15 * (i + 1)); if (shopIds[i]) text("*", 5, 15 * (i + 1)); } } 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() { mx_start = int(mouseX - offset_x * zoom); my_start = int(mouseY - offset_y * zoom); loop(); for (int i = 0; i < numShops; i++) if (mouseX < shopName[i].length() * 8 + 15 && mouseY > 15 * i && mouseY < 15 * (i + 1)) shopIds[i] = !shopIds[i]; my_pos = mouseY; } void mouseReleased() { noLoop(); } void mouseDragged() { if (mouseButton == LEFT) { offset_x = (mouseX - mx_start) / zoom; offset_y = (mouseY - my_start) / zoom; } else if (mouseButton == RIGHT) { if (mouseY - my_pos > 4) { float zoom_out = 9.8 / 10.0; mapShape.scale(zoom_out); zoom *= zoom_out; center_x = int(width * (1.0 - zoom) * 0.5); center_y = int(height * (1.0 - zoom) * 0.5); my_pos = mouseY; } else if (mouseY - my_pos < -4) { float zoom_in = 10.0 / 9.8; mapShape.scale(zoom_in); zoom *= zoom_in; center_x = int(width * (1.0 - zoom) * 0.5); center_y = int(height * (1.0 - zoom) * 0.5); my_pos = mouseY; } } } void readData() { new Slurper(); } Place parsePlace(String line) { String pieces[] = split(line, '\t'); int id = int(pieces[0]); String name = pieces[1]; float x = float(pieces[2]); float y = float(pieces[3]); return new Place(id, name, x, y); }

Place.pde

class Place { int id; String name; float x, y; public Place(int id, String name, float x, float y) { this.id = id; this.name = name; this.x = x; this.y = y; } public void draw() { if (shopIds[this.id]) { int xx = (int)TX(this.x) + int(offset_x * zoom); int yy = (int)TY(this.y) + int(offset_y * zoom); set(xx, yy, shopColor[this.id]); } } }

Slurper.pde

class Slurper implements Runnable { Slurper() { Thread thread = new Thread(this); thread.start(); } public void run() { try { BufferedReader reader = createReader(shopData); String line = reader.readLine(); totalCount = int(line); places = new Place[totalCount]; while ((line = reader.readLine()) != null) { places[placeCount] = parsePlace(line); placeCount++; } } catch (IOException e) { e.printStackTrace(); } noLoop(); } }

コメント