経県値マップをmatplotlibで実装してみる


最近日本の色んなところに行って経験したので、自分の行ってきた場所について纏めたいと思って、そしたら『経県値マップ』というサイトを見つけました。これを気に入ったので自分でもpythonで同じようなことを作ってみました。簡単なmatplotlibで描いたものです。

この記事ではその書いたpythonのコードについて説明します。

# できたもの
まず結果から始めたいです。

以下のコードで作った経県値マップはこういうものです。

![keikenchi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202903/2515a6c5-318f-a1a7-2119-40869c123e8d.png)

行ったことがある都道府県に点数をつけるものです。
点数の意味は
* 0: まだ全然行ったことも通り過ぎたこともない
* 1: 電車などで通ったことがあるが、足で踏んだことない
* 2: 乗り換えで行ってきたことがあるが、特に何もしていない
* 3: 用事や旅行などで行ったことがある
* 4: ホテルなどで泊まったことがある
* 5: 居住したことがある

そして全部合わせて総点数を計算するのです。


# きっかけ

元となったのはこのサイトです https://uub.jp/j.cgi/

ただしこのサイトでは本物に近い地図を使っていてちょっと見えにくい気もします。

そこでzhungさんという台湾人はもっと使いやすいものを作ったのです。このサイト https://zhung.com.tw/japanex/

このサイトの地図はsvgによって作られて綺麗に見えます。各都道府県の境界線は大雑把なx,yの座標で書いてあります。

今回私が作っているものは元の経県値マップよりも、zhungさんの経県値マップに近いものです。色々参考にしました。


# 実装

## シェープの情報

まず準備する必要があるのは各都道府県のシェープの情報です。ここでは`.json`という形で保存しておいて後でpythonから読み込みます。数字はzhungさんのサイトを元にしたものなので、できた地図はほとんど同じ形になります。

```shape.json
{
"北海道": [["p", [97.88,13.65], [97.88,22.35], [93.07,22.35], [86.86,25.71], [81.61,22.26], [78.4,22.26], [78.4,24.7], [71.87,24.7], [71.87,20.12], [76.39,16.73], [76.39,4.08], [82.29,4.08], [93.92,13.65]]],
"青森": [["p", [86.66,31.98], [86.66,34.18], [71.87,34.18], [71.87,28.35], [75.7,28.35], [75.7,29.83], [79.79,29.83], [79.79,26.0], [82.83,26.0], [82.83,29.33]]],
"岩手": [["p", [86.66,34.18], [86.66,39.55], [85.18,40.84], [85.18,41.32], [78.74,41.32], [78.74,34.18]]],
"宮城": [["r",78.74,41.32,6.44,7.66]],
"秋田": [["r",71.87,34.18,6.87,7.13]],
"山形": [["p", [78.74,41.32], [78.74,48.97], [73.09,48.97], [73.09,45.93], [72.3,45.93], [71.87,45.45], [71.87,41.32]]],
"福島": [["r",73.09,48.97,12.09,5.74]],
"茨城": [["p", [86.31,61.87], [86.31,62.46], [80.14,62.46], [80.14,54.71], [85.18,54.71], [85.18,60.83]]],
"栃木": [["r",74.57,54.71,5.57,6.09]],
"群馬": [["r",68.83,54.71,5.74,6.09]],
"埼玉": [["r",68.83,60.8,11.31,3.22]],
"千葉": [["p", [86.31,62.46], [86.31,71.77], [81.79,71.77], [81.79,67.5], [80.14,67.5], [80.14,62.46]]],
"東京": [["r",71.87,64.02,8.26,3.48]],
"神奈川": [["r",71.87,67.5,7.13,4.44]],
"新潟": [["p", [73.09,45.93], [73.09,54.71], [63.87,54.71], [63.87,51.68], [72.3,45.93]], ["p", [65.6,46.88], [63.25,48.62], [61.55,48.62], [63.88,46.88]]],
"富山": [["p", [63.87,51.68], [63.87,58.98], [56.56,58.98], [56.56,55.85], [59.46,55.85]]],
"石川": [["p", [56.56,52.97], [56.56,60.11], [49.16,60.11], [49.16,59.67], [52.99,57.17], [52.99,52.97]]],
"福井": [["p", [56.56,60.11], [56.56,64.55], [45.94,64.55], [45.94,63.15], [49.16,63.15], [49.16,60.11]]],
"山梨": [["r",67.61,64.02,4.26,6.09]],
"長野": [["p", [68.83,54.71], [68.83,64.02], [67.61,64.02], [67.61,70.11], [61.52,70.11], [61.52,58.98], [63.87,58.98], [63.87,54.71]]],
"岐阜": [["p", [61.52,58.98], [61.52,70.11], [55.51,70.11], [55.51,64.55], [56.56,64.55], [56.56,58.98]]],
"静岡": [["p", [73.7,71.94], [73.7,75.33], [71.0,75.33], [71.0,72.21], [67.65,75.25], [63.34,75.25], [63.34,70.11], [71.87,70.11], [71.87,71.94]]],
"愛知": [["p", [63.34,70.11], [63.34,75.25], [56.91,75.25], [56.91,72.64], [55.51,72.64], [55.51,70.11]]],
"三重": [["p", [55.51,70.11], [55.51,72.64], [54.38,72.64], [54.38,81.25], [50.99,81.25], [50.99,70.11]]],
"滋賀": [["r",50.99,64.55,4.52,5.57]],
"京都": [["p", [50.99,64.55], [50.99,70.11], [41.94,70.11], [41.94,62.37], [45.94,62.37], [45.94,64.55]]],
"大阪": [["p", [47.16,70.11], [47.16,75.68], [43.6,75.68], [43.6,71.94], [41.94,71.94], [41.94,70.11]]],
"兵庫": [["r",35.94,62.37,6.0,9.57], ["r",40.46,72.81,1.91,1.83]],
"奈良": [["r",47.16,70.11,3.83,7.92]],
"和歌山": [["p", [50.99,78.03], [50.99,81.25], [43.6,81.25], [43.6,75.68], [47.16,75.68], [47.16,78.03]]],
"鳥取": [["r",30.11,62.37,5.83,4.26]],
"島根": [["p", [30.11,62.37], [30.11,66.63], [23.85,66.63], [23.85,62.29], [24.31,62.37]]],
"岡山": [["r",30.11,66.63,5.83,5.31]],
"広島": [["r",23.85,66.63,6.26,5.31]],
"山口": [["p", [23.85,62.29], [23.85,71.94], [18.54,71.94], [18.54,65.42]]],
"徳島": [["p", [39.42,77.51], [39.42,82.22], [31.59,80.53], [31.59,77.51]]],
"香川": [["r",31.59,74.72,7.83,2.78]],
"愛媛": [["p", [31.59,76.64], [31.59,80.99], [21.6,80.99], [21.39,76.99], [27.94,74.27], [27.94,76.64]]],
"高知": [["p", [39.42,82.22], [39.42,85.25], [35.94,85.25], [34.24,83.42], [30.45,83.42], [28.66,85.25], [21.61,85.25], [21.6,80.99], [31.59,80.99], [31.59,80.53]]],
"福岡": [["p", [17.76,69.33], [17.76,71.59], [13.58,71.59], [13.58,76.38], [8.1,76.38], [8.1,74.81], [9.63,74.81], [9.6,69.33]]],
"佐賀": [["p", [9.63,74.81], [5.58,74.81], [5.58,69.33], [9.6,69.33]]],
"長崎": [["p", [5.58,74.81], [5.94,74.81], [5.94,77.16], [2.36,77.16], [2.36,69.33], [5.58,69.33]]],
"熊本": [["p", [13.58,76.38], [13.58,83.51], [6.45,83.51], [6.45,82.33], [8.1,81.07], [8.1,76.38]]],
"大分": [["r",13.58,71.59,4.18,6.0]],
"宮崎": [["p", [17.76,77.6], [17.76,78.41], [17.15,79.4], [17.15,85.08], [15.72,85.08], [13.58,85.08], [13.58,77.6]]],
"鹿児島": [["p", [17.15,85.08], [17.15,87.2], [13.81,90.3], [12.71,90.3], [12.71,87.17], [9.58,87.17], [9.58,88.91], [6.45,88.91], [6.45,83.51], [13.58,83.51], [13.58,85.08]]],
"沖縄": [["r",2.1,90.38,2.87,5.31]]
}
```

シェープは2種類あります。長方形で表現するものはrと書いて、多角形はpにしています。

* 長方形の場合、rの次に[x, y, width, height]。
* 多角形の場合、pの次には各頂点の[x, y]。

ほとんどは一つのシェープですが、兵庫県と新潟県は本土の部分と小さな島の部分があるので2つになっています。

## テクストの情報
次は都道府県の名前を書くテクストの位置と並び方です。シェープの形によって縦書きの方がいいと横書きの方がものに分けられているので、ここにも書いて区別しています。

```text.json
{
"北海道": [84.87,14.90,"横"],
"青森": [79.26,32.09,"横"],
"岩手": [82.7,37.75,"横"],
"宮城": [81.96,45.15,"横"],
"秋田": [75.30,37.74,"横"],
"山形": [75.30,45.14,"横"],
"福島": [79.13,51.84,"横"],
"茨城": [82.72,58.58,"横"],
"栃木": [77.35,57.75,"横"],
"群馬": [71.7,57.75,"横"],
"埼玉": [74.48,62.41,"横"],
"千葉": [83.22,66.11,"横"],
"東京": [76.0,65.76,"横"],
"神奈川": [75.43,69.72,"横"],
"新潟": [68.48,51.32,"横"],
"富山": [60.21,57.33,"横"],
"石川": [54.50,56.54,"縦"],
"福井": [52.75,62.33,"横"],
"山梨": [69.74,67.06,"縦"],
"長野": [65.17,62.41,"縦"],
"岐阜": [58.51,64.54,"縦"],
"静岡": [67.02,72.72,"横"],
"愛知": [59.42,72.68,"横"],
"三重": [52.75,75.68,"縦"],
"滋賀": [53.25,67.335,"横"],
"京都": [46.46,67.00,"横"],
"大阪": [45.55,72.89,"縦"],
"兵庫": [38.94,67.155,"縦"],
"奈良": [49.075,74.07,"縦"],
"和歌山": [47.3,79.47,"横"],
"鳥取": [33.02,64.50,"横"],
"島根": [26.98,64.46,"横"],
"岡山": [33.025,69.28,"横"],
"広島": [26.98,69.285,"横"],
"山口": [21.19,68.11,"縦"],
"徳島": [35.50,79.36,"横"],
"香川": [35.50,76.11,"横"],
"愛媛": [26.49,78.63,"横"],
"高知": [25.51,82.89,"横"],
"福岡": [11.90,72.85,"縦"],
"佐賀": [7.605,72.07,"縦"],
"長崎": [3.95,73.24,"縦"],
"熊本": [10.01,79.94,"縦"],
"大分": [15.67,74.59,"縦"],
"宮崎": [15.17,81.34,"縦"],
"鹿児島": [10.00,85.80,"横"],
"沖縄": [3.53,93.03,"縦"]
}
```

## 自分の経県値を記入する
この部分は人によって違うことになります。どの都道府県でどんな経験をしたか点数で書いておくのです。

私の場合はこうなっています。（この記事を書いた時点で）

```keikenchi.json
{
"北海道": 4,
"青森": 1,
"岩手": 3,
"宮城": 5,
"秋田": 4,
"山形": 3,
"福島": 4,
"茨城": 3,
"栃木": 1,
"群馬": 3,
"埼玉": 4,
"千葉": 2,
"東京": 4,
"神奈川": 4,
"新潟": 1,
"富山": 1,
"石川": 4,
"福井": 3,
"山梨": 3,
"長野": 1,
"岐阜": 3,
"静岡": 2,
"愛知": 4,
"三重": 3,
"滋賀": 3,
"京都": 4,
"大阪": 3,
"兵庫": 3,
"奈良": 3,
"和歌山": 3,
"鳥取": 0,
"島根": 0,
"岡山": 3,
"広島": 4,
"山口": 3,
"徳島": 0,
"香川": 0,
"愛媛": 0,
"高知": 0,
"福岡": 0,
"佐賀": 0,
"長崎": 0,
"熊本": 0,
"大分": 0,
"宮崎": 0,
"鹿児島": 0,
"沖縄": 0
}
```

## コード
必要な情報の準備が整ったら次は実装のpythonコードです。

```python
import matplotlib.pyplot as plt
import json

plt.figure(figsize=[12,12],dpi=100)
ax = plt.axes([0,0,1,1],xlim=[0,100],ylim=[0,100],aspect=1)
ax.invert_yaxis() # 0は上から
ax.add_patch(plt.Rectangle([0,0],100,100,fc='#c3d8f7')) # 海の背景

# 各情報のファイルを開ける
dic_sh = json.load(open('shape.json',encoding='utf-8')) # 都道府県の形
dic_kk = json.load(open('keikenchi.json',encoding='utf-8')) # 自分の経県値
dic_text = json.load(open('text.json',encoding='utf-8')) # 名前の位置と並び方
lis_iro = ['#ffffff','#bbfeb9','#92dc1f','#fcff00','#e19045','#de4c25'] # 各点数の色

tensuu = 0 # 累計点数
for tdfk,lis_sh in dic_sh.items(): # 各都道府県でループする
    tensuu += dic_kk[tdfk] # この都道府県の点数
    for sh in lis_sh:
        if(sh[0]=='r'): # 長方形の場合
            p = plt.Rectangle((sh[1],sh[2]),sh[3],sh[4],fc=lis_iro[dic_kk[tdfk]],ec='#000000',lw=1)
            ax.add_patch(p)
        elif(sh[0]=='p'): # 多角形の場合
            p = plt.Polygon(sh[1:],fc=lis_iro[dic_kk[tdfk]],ec='#000000',lw=1)
            ax.add_patch(p)
    
    # 都道府県の名前を書く
    if(dic_text[tdfk][2]=='横'): # 文字が横に並ぶ場合
        tdfk_ = tdfk
    elif(dic_text[tdfk][2]=='縦'): # 文字が縦に並ぶ場合
        tdfk_ = '\n'.join(tdfk)
    plt.text(dic_text[tdfk][0],dic_text[tdfk][1],tdfk_,fontname='MS Gothic',size=18,va='center',ha='center',color='#5f1e8d')

# 点数について説明する部分
level = ['未訪問','通過した','降り立った','歩いた','泊まった','住んだ'] # 各点数の意味
plt.text(4,8,'%d点'%tensuu,fontname='MS Gothic',size=52) # 総点数
for i,iro in enumerate(lis_iro):
    n_tdfk = list(dic_kk.values()).count(i) # その点数を持つ都道府県の数
    ax.add_patch(plt.Rectangle([8,37.5-i*5],6,3,fc=iro))
    plt.text(15,40-i*5,level[i],fontname='MS Gothic',size=25)
    plt.text(32,40-i*5,'+%d (×%d)'%(i,n_tdfk),fontname='MS Gothic',size=25)

plt.axis('off')
plt.savefig('keikenchi.png') # 画像を保存する
plt.close()
```

これを実行したら以上の経県値マップができます。

# 終わりに

以上pythonで経県値マップを生成するコードを書いてみました。

みんなさんもよろしければこのコードを使って自分の経県値マップを描いてみましょう。