鳥取県オープンデータで自転車事故の発生場所マップを作ってみたの巻

# はじめに

[鳥取県オープンデータカタログ](http://db.pref.tottori.jp/opendataResearch.nsf)では[交通事故情報](http://db.pref.tottori.jp/opendataResearch.nsf)がオープンデータで公開されています。

今回はこのオープンデータを使って自転車事故の発生場所マップを作ってみたいと思います(๑˃̵ᴗ˂̵)و 

2015年6月1日の道路交通法改正に伴い自転車の取り締まりも厳しくなったので、どんな場所で自転車事故が起こっているのか気になるところです。

まずは先に、完成したマップのスクリーンショットをお見せします。

![image](https://qiita-image-store.s3.amazonaws.com/0/32894/15bc6656-a2ee-2ece-b3a1-c2dabdb81f29.png)

こんな感じです。

平成26年度に発生した自転車に関する事故の場所を、

- 死亡事故
- 軽傷事故
- 重傷事故

に色分けしてあります。

この地図はGistで公開 https://gist.github.com/mh61503891/a2572598fa40f5bd0c08 しています。地図はもちろん拡大縮小したり動かせます(`･ω･´)

ピンをクリックすると詳細情報もみられます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/32894/63ff4f42-322a-b7b2-a86e-3e3877131088.png" width="320">

さて今回は、この作り方を簡単に説明したいと思います。主な読者はプログラミングを始めたて方を想定しつつ、プログラミングの前段階のUnix系のコマンドの使い方をもろもろメモしています。プログラミングされない方でも雰囲気は伝わるかと思います。

# プログラミング

## 環境

- OS: Mac OS X
- プログラミング言語: [Ruby](https://www.ruby-lang.org/ja/)
- テキストエディタ: [Atom](https://atom.io/)

という感じです。

## 作業ディレクトリの作成と移動

```bash
$ mkdir bicycle-accident && cd $_
```

`mkdir`コマンドでディレクトリを作成して`cd $_`コマンドで`$_`を指定すると`mkdir`したディレクトリに移動できます。`&&`は前（左）のコマンドが成功した場合に次（右）のコマンドを実行するという意味です。

## 現在のディレクトリの確認

```bash
$ pwd
/Users/masayuki/bicycle-accident
```

## データの取得

[交通事故情報](http://db.pref.tottori.jp/opendataResearch.nsf)では、

- 交通事故-(平成24年).csv
- 交通事故-(平成25年).csv
- 交通事故-(平成26年).csv

が公開されているようなので、とりあえずこれをダウンロードします。

```bash
$ wget 'http://db.pref.tottori.jp/opendataResearch.nsf/e92cd7f95a94c9c249257c92000236b8/5c2a1f59ec27a81a49257d630016cf34/$FILE/%E4%BA%A4%E9%80%9A%E4%BA%8B%E6%95%85-(%E5%B9%B3%E6%88%9024%E5%B9%B4).csv' -O crash24.csv
$ wget 'http://db.pref.tottori.jp/opendataResearch.nsf/e92cd7f95a94c9c249257c92000236b8/5c2a1f59ec27a81a49257d630016cf34/$FILE/%E4%BA%A4%E9%80%9A%E4%BA%8B%E6%95%85-(%E5%B9%B3%E6%88%9025%E5%B9%B4).csv' -O crash25.csv 
$ wget 'http://db.pref.tottori.jp/opendataResearch.nsf/e92cd7f95a94c9c249257c92000236b8/5c2a1f59ec27a81a49257d630016cf34/$FILE/%E4%BA%A4%E9%80%9A%E4%BA%8B%E6%95%85-(%E5%B9%B3%E6%88%9026%E5%B9%B4).csv' -O crash26.csv
```

- メモ
    - `wget`: ダウンロードするコマンド
    - `-O`: 保存先のファイル名を指定するオプション

## ファイル一覧

```bash
$ ls
crash24.csv crash25.csv crash26.csv
```

## 文字コードの確認

`nkf`コマンドに`--guess`オプションを付けると文字コードを判定してくれます。この結果によると文字コードは`Shift_JIS`で改行コードは`CRLF`のようです。

```bash
$ nkf --guess crash24.csv 
Shift_JIS (CRLF)
$ nkf --guess crash25.csv 
Shift_JIS (CRLF)
$ nkf --guess crash26.csv 
Shift_JIS (CRLF)
```

`ls`コマンドの標準出力をパイプ（`|`）で`xargs`コマンドに渡せば1行のコマンドで全てのファイルの文字コードを確認できます。

```bash
$ ls | xargs nkf --guess
crash24.csv: Shift_JIS (CRLF)
crash25.csv: Shift_JIS (CRLF)
crash26.csv: Shift_JIS (CRLF)
```

ファイルを絞り込みたい場合は`ls`コマンドよりも`find`コマンドを使った方が便利です。

```bash
$ find . -name "crash*.csv" | xargs nkf --guess
./crash24.csv: Shift_JIS (CRLF)
./crash25.csv: Shift_JIS (CRLF)
./crash26.csv: Shift_JIS (CRLF)
```

## データの中身の確認

Mac OS Xであれば、デフォルトの設定だと`nkf`コマンドの出力はUTF-8へ変換されてでてきます。これの先頭の数行を表示してみます。パイプ（`|`）を使って`head`コマンドに渡せばOKです。

```bash
$ nkf crash26.csv | head
名称,発生場所,発生年月日,当事者種別,事故内容,所轄警察署,事故類型,地点経度,地点緯度
全事故,東伯郡琴浦町大字出上,2013/10/30,軽貨物×相手なし,重傷事故,八橋署,車両単独,133.63196416700,35.50113361110
全事故,鳥取市三山口,2013/11/03,普通乗用×物件等,重傷事故,鳥取署,車両単独,134.15423333300,35.48269722220
全事故,米子市西福原一丁目,2013/11/21,普通乗用×普通乗用,軽傷事故,米子署,車両相互,133.34055833300,35.43853611110
全事故,鳥取市安長,2013/11/23,普通乗用×自転車,重傷事故,鳥取署,車両相互,134.20791666700,35.51267777780
全事故,鳥取市吉方温泉４丁目,2013/11/25,普通乗用×軽乗用×普通乗用,軽傷事故,鳥取署,車両相互,134.23786388900,35.48967222220
全事故,西伯郡南部町阿賀,2013/11/26,普通乗用×普通乗用,軽傷事故,米子署,車両相互,133.33130555600,35.36158611110
全事故,米子市上福原,2013/12/06,普通乗用×自転車,軽傷事故,米子署,車両相互,133.35246388900,35.44394166670
全事故,米子市宗像,2013/12/09,普通貨物×軽乗用,軽傷事故,米子署,車両相互,133.35307222200,35.41546388890
全事故,米子市日ノ出町二丁目,2013/12/12,軽貨物×自転車,軽傷事故,米子署,車両相互,133.33639027800,35.43667555560
```

どうやら1行目は列の意味を表す行になっているようです。この行はあった方が便利なので比較的良いデータ構造で助かります|･ω･´)

`column`コマンドを使ってもう少し見やすくしてましょう。
`-t`オプションは列数を自動判定してくれます。`-s`オプションは区切り文字を指定します。このデータはカンマ区切りなので`,`を指定しています。パイプ（`|`）で`nkf`コマンドと`head`コマンドの間に挟んでやれば、それぞれのコマンドがフィルターのようにデータを整形して受け渡してくれます。UNIX哲学というやつです。

```bash
$ nkf crash26.csv | column -t -s , | head
名称        発生場所                  発生年月日  当事者種別                                  事故内容  所轄警察署  事故類型  地点経度         地点緯度
全事故      東伯郡琴浦町大字出上      2013/10/30  軽貨物×相手なし                             重傷事故  八橋署      車両単独  133.63196416700  35.50113361110
全事故      鳥取市三山口              2013/11/03  普通乗用×物件等                             重傷事故  鳥取署      車両単独  134.15423333300  35.48269722220
全事故      米子市西福原一丁目        2013/11/21  普通乗用×普通乗用                           軽傷事故  米子署      車両相互  133.34055833300  35.43853611110
全事故      鳥取市安長                2013/11/23  普通乗用×自転車                             重傷事故  鳥取署      車両相互  134.20791666700  35.51267777780
全事故      鳥取市吉方温泉４丁目      2013/11/25  普通乗用×軽乗用×普通乗用                    軽傷事故  鳥取署      車両相互  134.23786388900  35.48967222220
全事故      西伯郡南部町阿賀          2013/11/26  普通乗用×普通乗用                           軽傷事故  米子署      車両相互  133.33130555600  35.36158611110
全事故      米子市上福原              2013/12/06  普通乗用×自転車                             軽傷事故  米子署      車両相互  133.35246388900  35.44394166670
全事故      米子市宗像                2013/12/09  普通貨物×軽乗用                             軽傷事故  米子署      車両相互  133.35307222200  35.41546388890
全事故      米子市日ノ出町二丁目      2013/12/12  軽貨物×自転車                               軽傷事故  米子署      車両相互  133.33639027800  35.43667555560
```

みやすくなりました|･ω･´)

## プログラミング

データの確認ができたところで、いよいよGeoJSONへ変換するプログラムを作りましょう。

## ソースコードのファイルの作成

空のファイルを作成するには`touch`を使います。まあ他の方法でも良いのですが私はこれをよく使っています。

```bash
$ touch crash_csv_to_crash_geojson.rb
```

さらに実行権限をつけましょう。

```
$ chmod +x crash_csv_to_crash_geojson.rb
```

こうすると以下のよう実行すれば、ソースコードをそのままコマンドのように実行することができます。

```
$ ./crash_csv_to_crash_geojson.rb
```

## ソースコード

いきなりですがソースコードはこんな感じです。説明は難しいので色々調べたりして読んでみてくだしあ…。

```crash_csv_to_crash_geojson.rb
#!/usr/bin/env ruby
require 'csv'
require 'json'

marker_colors = {
  '死亡事故' => '#FD7400',
  '軽傷事故' => '#BEDB39',
  '重傷事故' => '#004358'
}

map = {}
map['type'] = 'FeatureCollection'
map['features'] = []
CSV.new(STDIN, headers:true).read.each_with_index do |row, index|
  next if row['当事者種別'] !~ /自転車/
  feature = {
    id: index,
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [row['地点経度'].to_f, row['地点緯度'].to_f]
    },
    properties: row.to_h.merge({
      'marker-color': marker_colors[row['事故内容']]
    })
  }
  map['features'] << feature
end

puts JSON.pretty_generate(map)
```

実行するには以下のようにします。

```bash
$ nkf -S -w -Lu crash26.csv.csv | ./crash_csv_to_crash_geojson.rb > tottori-opendata-bicycle-accident-2014.geojson
```

`tottori-opendata-bicycle-accident-2014.geojson`というファイルが出力されるはずです。

## 事故種別による色分けについて

Mapboxによると`marker-color`で色のコードを指定するとピンの色を変更できるそうです。

色分けするにあたり、事故種別の種類をリストアップして確認します。

```bash
$ nkf -w -Lu crash26.csv | column -t -s , | sed 1d | awk '{print $5}' | sort | uniq -c
  32 死亡事故
 623 軽傷事故
 176 重傷事故
```

自転車だけを抜き出すならこう。

```bash
$ nkf -w -Lu crash26.csv | column -t -s , | sed 1d | grep '自転車' | awk '{print $5}' | sort | uniq -c
   6 死亡事故
 122 軽傷事故
  65 重傷事故
```

追記: ってなんか数があわねぇぇ。（※コメント欄参照）

`|`で繋がれた各コマンドの意味は以下のとおりです。

- `nkf -S -w -Lu crash26.csv`: 文字コードをShift_JISからUTF8、改行コードをUNIX形式にして出力
- `column -t -s ,`: カンマ区切りを表形式に変換して出力
- `sed 1d`: 1行目を削除して出力
- `grep '自転車'`: 自転車が含まれる行を抽出して出力
- `awk '{print $5}'`: 5列目を抽出して出力
- `sort`: ソートして出力
- `uniq -c`: 重複を排除しつつそれぞれの重複数を出力

Mac OS XのターミナルやLinuxを使う人は、簡単なデータであれば、こういうコマンドを組み合わせて処理してしまう場合が多いです。

ということで、3種類の事故があるようなので、3色に色分けしました。色の選定は[Adobe Color CC](https://color.adobe.com)というサイトから[Vitamin C](https://color.adobe.com/Vitamin-C-color-theme-492199/)というテーマを使うことにしました。

以下の3色をピックアップ。

- `#FD7400`
- `#BEDB39`
- `#004358`

という感じでコーディングしてあります。

## Gistへの公開

GitHubのGistというソースコードの断片を共有するサービスでは、GeoJSONという地理空間情報を表現するデータ形式のデータをアップロードすれば[Mapbox](https://www.mapbox.com/)というサービスと連携して自動的に地図表示してくれます。もちろんGistなのでデータの変更履歴も追跡できてなかなか便利です。

アップロードした地図は https://gist.github.com/mh61503891/a2572598fa40f5bd0c08 で公開しています。グリグリ動かしてみてください。

![image](https://qiita-image-store.s3.amazonaws.com/0/32894/15bc6656-a2ee-2ece-b3a1-c2dabdb81f29.png)

## おわりに

自転車事故の発生場所を見るとやっぱり交差点が多い感じですね。左右の確認しましょう…(´･ω･`)

いろいろコメントも募集しています。下部のコメント欄に何か書いてもらえると何か返信します。元気があれば、ですが…(´･ω･`)