読者です 読者をやめる 読者になる 読者になる

Graph::Gvizで大阪市営地下鉄を描いてみた

perl graphviz

東京の地下鉄の路線サインをGviz(Ruby Graphviz Wrapper)で描く


を参考に Graph::Gvizを使って、大阪市営地下鉄を描いてみました。

関連リポジトリ

大して探していないんですが、緯度・経度の正規化に適したモジュールが
なかったので、適当にでっちあげました。

コード

#!perl
use strict;
use warnings;

use Graph::Gviz;
use Math::Normalize::Range;
use Text::CSV_XS;
use Math::Round qw/nearest/;

use utf8;

my $csv_file = 'old20121010_utf8.csv ';

my $csv = Text::CSV_XS->new;
open my $fh, '<:encoding(utf8)', $csv_file or die "Can't open $csv_file: $!";

my %rail_line;
$csv->getline($fh); # remove header

my (@longtudes, @latitudes);
while (my $row = $csv->getline($fh)) {
    my $line = $row->[8];
    next unless $line =~ m{大阪市営地下鉄};

    push @longtudes, $row->[11];
    push @latitudes, $row->[12];
    push @{$rail_line{$line}}, $row;
}

close $fh;

my ($lon_min, $lon_max) = minmax(@longtudes);
my ($lat_min, $lat_max) = minmax(@latitudes);

my $svg_normalizer = Math::Normalize::Range->new(target_min => 10, target_max => 60);

my @line_colors = (
    ["御堂筋線" => '#e5171f'], ["谷町線"   => '#522886'], ["四つ橋線" => '#0078ba'],
    ["中央線"   => '#019a66'], ["千日前線" => '#e44d93'], ["堺筋線"   => '#814721'],
    ["今里筋線" => '#ee7b1a'], ["長堀鶴見緑地線" => '#a9cc51'],
);

my $graph = graph {
    name 'Osaka_Subway';
    global label => 'Osaka Municipal Subway', size => 16, layout => 'neato';

    edges arrowhead => 'none', penwidth => 2;
    nodes style => 'filled', fontcolor => 'white';

    while (my ($line, $stations) = each %rail_line) {
        global label => $line;

        my $index = 1;
        my $length = scalar @{$stations};
        for my $station (@{$stations}) {
            my ($id, $name, $seq) = @{$station}[2, 9, 4];
            my $next_id = $seq + 1;

            my $color = '#999999';
            for my $line_color (@line_colors) {
                my $n = $line_color->[0];
                if ($line =~ m{$n}) {
                    $color = $line_color->[1];
                    last;
                }
            }

            my $pos_x = $svg_normalizer->normalize($station->[11], {
                min => $lon_min, max => $lon_max,
            });

            my $pos_y = $svg_normalizer->normalize($station->[12], {
                min => $lat_min, max => $lat_max,
            });

            my $pos = sprintf "%d,%d!", nearest(0.1, $pos_x), nearest(0.1, $pos_y);

            edge "${id}_${next_id}", color => $color if $index < $length;
            node $id, label => $name, color => $color, pos => $pos;

            $index++;
        }
    }
};

$graph->save(path => "osaka_subway", type => 'svg');

sub minmax {
    my $init = shift;
    my ($min, $max) = ($init, $init);
    for (@_) {
        $min = $_ if $min > $_;
        $max = $_ if $max < $_;
    }
    return ($min, $max);
}

実行結果

結果の SVGを以下にアップしました。
(SVGなので拡大しまくっても問題なく見れます。)

http://syohex.github.com/graph-gviz/osaka_subway.svg

おわりに

駅に設置されている料金を書いた図ぐらいしか見たことなかったので
知らなかったんですが、実際の駅の配置はこんな感じになっていたん
ですね。全然知りませんでした。西梅田と梅田が近いとか、御堂筋線
四つ橋線のなんばはやっぱり離れているんだなとかも知ることが
できました。大阪に馴染みがある人でないとわからないと思いますが・・・。