プログラムでおかえしできるかな

定年を過ぎて何かの役に立てないかなと始めた元SEのブログです

foliumのChoroplethで色分け地図を作成【Python】

このエントリーをはてなブックマークに追加

Python の folium パッケージを使用した色分け地図の作成方法を紹介します。
ライブラリの使い方やデータの作成方法などをソースコードも添えて説明をします。
感染症の定点当たりの患者数の色分け地図を題材にしています。
新型コロナとインフルエンザの患者数の違いを地図で比較できます。


▽アプリの結果の HTML ブラウザ出力と画面

 

アプリはお使いいただけます 📖 新型コロナとインフルエンザの流行を知る 🔗

目次

◆地図のみの表示

folium なら単に地図を作成するだけなら1命令で済みます。
見るためには、もう1命令でブラウザに表示します。
地図作成時、最低限、地図の位置と大きさを指定します。

◇手順

  1. 地図の作成:Map インスタンスを作成
    ・・・Map コンストラクタの説明は⤵
  2. 地図の表示:Map オブジェクトの show_in_browser() メソッドでブラウザに表示

◇コード:地図表示

import folium
map = folium.Map(location=[35.69, 139.70]
                 , zoom_start=10)
map.show_in_browser()

都道府県で区分けした地図の表示(GeoJSON使用)

folium では、マップタイルセットを変更することで、いろいろな見た目の地図を作成することができます。 マップタイルセットに白地図のような「Cartodb Positron」を使って都道府県の境界を分かりやすくします。
都道府県の境界用のデータに GeoJSON 型式のデータを使用します。・・・GeoJson データの取得方法は⤵

地図を作成し、都道府県の境界線を作成し、それらを重ねるイメージです。



◇手順(GeoJSON使用)

  1. 地図の作成:Map インスタンスを作成
  2. 境界線の作成:GeoJson データを指定して GeoJson インスタンスを作成、Map オブジェクトに追加
    ・・・GeoJson コンストラクタの説明は⤵
  3. 地図の表示:Map オブジェクトの show_in_browser() メソッドでブラウザに表示

◇コード:都道府県で区分けしたの表示(GeoJSON使用)

import folium

def basic_map_geo():
    # 単純な地図の表示
    map = folium.Map(location=[35.69, 139.70]
                    , zoom_start=10
                    , tiles='Cartodb Positron')

    # GeoJSON の利用
    _url = "https://raw.githubusercontent.com/smartnews-smri/japan-topography/main/data/municipality/geojson/s0010/prefectures.json"  # 全国都道府県 
    folium.GeoJson(_url).add_to(map)
    map.show_in_browser()

basic_map_geo()

都道府県で区分けした地図の表示(TopoJSON使用)

folium では、マップタイルセットを変更することで、いろいろな見た目の地図を作成することができます。
マップタイルセットに白地図のような「Cartodb Positron」を使って都道府県の境界を分かりやすくします。

都道府県の境界用のデータに TopoJSON 型式のデータを使用します。・・・TopoJSON データの取得方法は⤵

GeoJSON のネット上のデータは GeoJson コンストラクタで直接読めますが、TopoJSON のネット上のデータは TopoJson コンストラクタで直接読めないので requets.get() メソッドで先に読みます。
また、TopoJSON コンストラクタでは、TopoJSON データ内の geometries を求めるパスを指定します。・・・TopoJson コンストラクタの説明は⤵

全体としては、GeoJSON を使用した時と同様に、地図を作成し、都道府県の境界線を作成し、それらを重ねるイメージです。

出力結果は、GeoJSON を使った時と同じです。


◇手順(TopoJSON使用)

  1. 地図の作成:Map インスタンスを作成
  2. 境界線データの読み込み:requests.get() メソッドで TopoJSON データの読み込み
  3. 境界線の作成:TopoJson データを指定して TopoJson インスタンスを作成、Map オブジェクトに追加
  4. 地図の表示:Map オブジェクトの show_in_browser() メソッドで表示

◇コード:都道府県で区分けした地図の表示(TopoJSON使用)

import folium
import requests

def basic_map_topo():
    # 単純な地図の表示
    map = folium.Map(location=[35.69, 139.70]
                    , zoom_start=10
                    , tiles='Cartodb Positron')

    # TopoJSON の利用
    _url = "https://raw.githubusercontent.com/smartnews-smri/japan-topography/main/data/municipality/topojson/s0010/prefectures.json"  # 全国都道府県 
    topo_json_data = requests.get(_url).json()
    folium.TopoJson(topo_json_data
                    , "objects.prefectures").add_to(map)
    map.show_in_browser()

basic_map_topo()

◆色分け地図の表示(TopoJSON使用)

色分け地図は、folium の Choropleth オブジェクトを作成し、Map オブジェクトに追加して作成します。
Choropleth オブジェクトを作成する際に、色分け用のデータを用意する必要があります。・・・データの作り方は ⤵
Choropleth コンストラクタでは、必要に応じ、色分け用の色の指定などが可能です。・・・Choropleth コンストラクタの説明は⤵

◇色分け用のデータをTopoJSONに指定

色分け用のデータをChoropleth コンストラクタで使用するには、DateFrame 型、Series 型、または辞書に変換可能なデータである必要があります。
Pandas を使えば、データの取得が簡単で、かつ DataFrame 型のデータができるので扱いやすいのですが、ここでは、辞書に変換可能なデータを用意しました。

辞書に変換可能なデータとして、キーと値のタプルのリストを用意します。

 例:[('key1',1), ('key2', 2), ('key3', 3)]

この時、キーは TopoJSON データでキーとして使用しているデータ(今回は都道府県名)にあわせます。
これを、Choropleth コンストラクタの data 引数に指定し、さらに、key_on 引数で GeoJSON(TopoJSON) データのどの要素とマッチングさせるかを指定します。

ツールチップの表示

色分けした根拠となる数字を見せる対応方法として、ツールチップがあります。
ツールチップを表示するためには、色分け用のデータを TopoJSON データにも追加する必要があります。
追加位置は、TopoJSON データの objects オブジェクトの中です。objects オブジェクトは階層構造になっており、その子孫は次の通りです。

objectsprefecturesgeometriesproperties

geometries が配列で都道府県ごとにあり、色分け用のデータは、properties オブジェクトに追加します。
properties オブジェクトには、既にキーN03_001、値が都道府県名の要素が存在します。
そこに都道府県名が一致するように色分け用データを追加します。・・・データの構造は⤵

ツールチップは、GeoJsonTooltip コンストラクタで作成します。・・・GeoJsonTooltip コンストラクタの説明は⤵

今回作成するツールチップは次のように出力します。

     地域  ○○県
        人数  12.34

◇手順

  1. 地図の作成:Map インスタンスを作成
  2. 境界線データの読み込み:requests.get() メソッドで TopoJSON データを読み込み
  3. 境界線の作成:TopoJson データを指定し TopoJson インスタンスを作成、Map オブジェクトに追加
  4. 地図の色分け:Choropleth インスタンスを作成し、Map オブジェクトに追加
    • geo_date 引数で TopoJSON データを指定
    • topojson 引数で TopoJSON データ内の geometries オブジェクトの位置を指定
    • data 引数で色分けするデータを指定
    • key_on 引数で data で指定した値を特定する TopoJSON データ内のキーを指定
  5. ツールチップの作成
    • TopoJSON データの編集
      • 色分け用データの辞書を作成 :(キー, 値) のタプルを要素としたリストを辞書に
      • 辞書の内容を TopoJSON データの properties オブジェクトに teito として追加
    • ツールチップの作成:GeoJsonTooltip インスタンスを作成し、Choropleth オブジェクトに追加
  6. 地図の表示:Map オブジェクトの show_in_browser() メソッドで表示

◇コード:色分け地図の表示

import folium
import requests

def Choropleth_map_topo(rows, max_value):
    """
    階級区分図の作成(TopoJSONを使用)
    Args:
        list:   報告数データ(都道府県と報告数のタプルのリスト)
        int:    報告数の最大値
    Returns:
        Map:    作成した地図のMapオブジェクト
    """
    # Mapオブジェクトの作成(日本地図全体が表示されるような位置と倍率を指定)
    map = folium.Map(location=[39.00, 137.00], tiles='Cartodb Positron', zoom_start=6)

    # TopoJSON の利用
    _url = "https://raw.githubusercontent.com/smartnews-smri/japan-topography/main/data/municipality/topojson/s0010/prefectures.json"  # 全国都道府県 
    topo_json_data = requests.get(_url).json()

    # MapオブジェクトにTopoJSONデータを追加
    folium.TopoJson(topo_json_data, "objects.prefectures").add_to(map)

    # Choroplethの作成
    cp = folium.Choropleth(geo_data=topo_json_data
                            , topojson='objects.prefectures'    # GeoJSONへ変換するデータの位置
                            , data=rows                             # 地域区分するデータ
                            , key_on='properties.N03_001'           # 地域を特定するキー
                            , bins=range(0, int(max_value + 2), 1)  # カラーマップ
                            , fill_color='PuRd'                     # カラーマップの色
                            , fill_opacity=0.3                      # 透明度
                            , line_weight=2,                        # 境界線の幅
                            )
    cp.add_to(map)          # Mapオブジェクトに追加

    # TopoJSONの地域データに定当データを追加(ツールチップに表示するため)
    # TopoJSONのgeometriesに都道府県のデータがあるのでそこのpropertisに要素追加
    teito = dict(rows)  # リストを辞書化
    for d in topo_json_data["objects"]["prefectures"]["geometries"]:
        # "properties"の辞書に定当のキーと値を追加(都道府県名をキーにして定当を取得)
        d["properties"]["teito"] = teito[d["properties"]["N03_001"]]
    # ツールチップの追加
    folium.GeoJsonTooltip(['N03_001', 'teito'], ['地域', '人数']).add_to(cp.geojson)
    # カラーマップの幅を指定(地図を並べて表示した時に長くなるため)
    cp.color_scale.width = 200

    # ブログ埋め込み用iframeの作成 作成したテキストを埋め込めば地図が表示される(色分けされなかった)
    # iframe = map._repr_html_()
    # with open("ifram.txt", "w", encoding='utf-8') as f:
    #     f.write(iframe)

    map.show_in_browser()               # こちらなら表示できるけど添付ファイルが残る

    return map

rows_c, rows_i, name_c, name_i, title, max_value = get_csv_from_web()
Choropleth_map_topo(rows_c, max([x[1] for x in rows_c]))







◆定点把握疾患の定点あたりの報告数をwebから取得

定点把握疾患の定点あたりの報告数は、NIID国立感染症研究所が出している「IDWR速報データ」(リンク:速報データ )から取得します。データは CSV ファイルです。
このサイトの「定点把握疾患(週報告)、報告数、定点当たり報告数、都道府県別」に貼られているリンクからダウンロードできます。
ここでは、 urllib.request.urlopen() メソッドを使用してネットワーク上から取得します。
定点当たり報告数は定当と略されています。

CSV の URL は次のような構成をしています。

https://www.niid.go.jp/niid/images/idwr/sokuho/idwr-年/年週/年-週-teiten.csv

年は西暦の下2ケタ、週はその年の何週目かを指定します。
データは約2週間後に公開されます。
そのためデータが取得できないことを考慮する必要があります。
データが取得できない場合、urlopen() メソッドの戻り値の url 属性に指定した url と異なる値が返るのでそれで判断します。

取得後、
・新型コロナデータ(都道府県名と定当のタプルのリスト)
・インフルエンザデータ(都道府県名と定当のタプルのリスト)
を作成します。
CSV データには見出し行が複数行設定されているのでそれらを考慮します。
作成したデータを folium で使用します。

新型コロナのデータは 2023年5月8日以降から追加されました。
それ以前はデータがないのでそのことを考慮します。
また、都道府県によっては、報告がない場合があります。こちらも考慮します。
考慮の方法はコードで確認してください。

CSVデータ

NIID国立感染症研究所のサイトから取得するデータは次のような構成です。

 
※こちらの記事のアプリで表示しています・・・CSV viewerアプリの作り方(ドラッグアンドドロップ)【Python】 🔗

CSVの構成】

    • 1行目  :見出し(データ名)
    • 2行目  :見出し(データの期間、作成日)
    • 3行目  :見出し(列名:感染症名)
    • 4行目  :見出し(列名:報告数か定当か)
    • 5行目  :データ(総数)
    • 6行目以降:データ(都道府県)
    • 1列目:都道府県名
    • 2列目:インフルエンザの報告数
    • 3列目:インフルエンザの定当数
    • 38列目:COVID-19の報告数
    • 39列目:COVID-19の定当数

◇手順

  1. 引数で指定された日付から年と週を取得
    date クラスの strftime() メソッドで書式を指定して取得
    書式は、%Y:西暦4桁、%U %V:週番号
  2. web から CSV ファイルを開く:urllib.request.urlopen()
    • 戻り値のオブジェクトの url 属性が要求した url と異なっていたらエラーとして戻る
    • 1行目を読み飛ばし:next()
    • 2行目を読み地図のタイトルとして保存
      データは shift-JIS なのでデコードが必要:decode()
      カンマ区切りなのでカンマで分割して1つ目のデータを取得
      ダブルクォーテーションを削除:replace()
    • 3行目を読み感染症名として保存(データの扱いは同上)
    • 4行目、5行目を読み飛ばし:next()
    • 残りの行を一括で読み込み:read()
      • データは shift-JIS なのでデコード:decode()
      • 行ごとに分割:splitlines()
  3. 新型コロナのデータ作成
    都道府県名と定当のタプルを都道府県分のリストで作成:内包表記 [ for in if ]
    定当のデータがない時は作らない
    定当のデータは文字なので実数に変換
  4. インフルエンザのデータ作成(作成方法は同上)

◇コード:定点把握疾患の定点あたりの報告数をwebから取得

    def get_csv_from_web(self, today:date) -> Tuple[list, list, str, str, str, str]:
        """
        定点把握疾患の定点あたりの報告数をWebから取得
        Args:
            date:   初期表示日付
        Returns:
            list:   新型コロナデータ(都道府県と報告数のタプルのリスト)
            list:   インフルエンザデータ(都道府県と報告数のタプルのリスト)
            str:    感染症名
            str:    感染症名
            str:    期間
            str:    エラーメッセージ(エラーなしの時は空文字)
        """
        msg =""
        # today = datetime(2023, 10, 16)
        year = today.strftime('%Y')
        week = today.strftime('%V')
        # csvファイルのurl
        _url = f'https://www.niid.go.jp/niid/images/idwr/sokuho/idwr-{year}/{year}{week}/{year}-{week}-teiten.csv'
        # csvファイルの取得
        with urllib.request.urlopen(_url) as res:
            if res.url != _url:
                msg = "指定した日付の週にデータがありません"
                return None, None, None, None, None, None, msg
            # ヘッダに対する処理
            next(res)   # 1行目
            title = next(res).decode('cp932').split(',')[0].replace('"', '')   # 2行目 報告期間
            shippei = next(res).decode('cp932').split(',')  # 3行目 疾病
            if len(shippei) > 37:   # 2023/5/8以前のデータはない
                name_c = shippei[37].replace('"', '')            # 新型コロナ
            else:
                name_c = ""
            name_i = shippei[1].replace('"', '')             # インフルエンザ
            next(res)   # 4行目
            next(res)   # 5行目
            data = res.read()                       # 残りをすべて読む
            data = data.decode('cp932')             # urlopenで読んだ場合はデコードが必要
            data = data.splitlines()                # 行ごとに分ける
        # 新型コロナのデータ作成(データがあるものだけ、報告がないと「-」が設定されるので弾く)
        if len(shippei) > 37:   # 2023/5/8以前のデータはない
            rows_c = [(row[0], float(row[38])) for row in csv.reader(data) if row[38] and row[38] != "-"]   # 都道府県とCOVID-19定当を取得
        else:
            rows_c = []
        # インフルエンザのデータ作成(データがあるものだけ、報告がないと「-」が設定されるので弾く)
        rows_i = [(row[0], float(row[2])) for row in csv.reader(data) if row[2] and row[2] != "-"]   # 都道府県とインフルエンザ定当を取得
        return rows_c, rows_i, name_c, name_i, title, msg

◆地図を2つ並べて表示

地図を2つ作成し、並べて表示する方法を説明します。
folium のドキュメントにあるサンプルを元にしているだけなので、簡単に説明します。
サンプルでは、branca.element の Figure クラスを使用していますが、folium にも Figure クラスがあるのでそちらを使いました。多分同じだと思います。
まず、全体を描画する Figure オブジェクトを作成します。
次に、Figure オブジェクトに入れる Div オブジェクトを作成します。
Div オブジェクトは配置を指定して2つ作成します。
あわせて Div オブジェクトにタイトルを追加します。
タイトルは HTML を文字列で作成し、親となる地図に追加します。
追加は、get_root() メソッドで親を探し、html 属性の add_child() メソッドで行います。
html 属性については、詳細を調べていません。ご容赦ください。
ここで出てきた Figure や Div は、branca パッケージで提供されています。

◇手順

  1. Figure インスタンスを作成
  2. Figure オブジェクトに Div オブジェクトを追加:add_subplot()
    2つ作成して表示位置を分ける
  3. 色分け地図を作成:Choropleth_map_topo() (自作メソッド)
    2種類の地図を作成
  4. 色分け地図を Div オブジェクトに追加:add_child()
  5. タイトルを作成
    • タイトル用 HTML 文字列を作成
    • 色分け地図の親の html 属性に追加:add_child()
  6. 地図の表示
    Figure オブジェクトは show_in_browser() メソッドを持たないので、ファイルに保存して表示
    • 保存:save()
    • ブラウザに表示:webbrowser.open()

◇コード:地図を2つ並べて表示

import folium
import webbrowser

def tow_choropleth(rows_c, rows_i, name_c, name_i, title, max_value):
    f = folium.Figure()
    sb1 = f.add_subplot(1, 2, 1)
    sb2 = f.add_subplot(1, 2, 2)
    m1 = Choropleth_map_topo(rows_c, max_value)
    m2 = Choropleth_map_topo(rows_i, max_value)
    # add_child タイトルより先じゃないとタイトルが出ない
    sb1.add_child(m1)
    sb2.add_child(m2)
    # タイトルを追加
    title_html = f'''
             <h3 align="center" style="font-size:20px"><b>{name_c}定点当たり報告数</b></h3>
             <h6 align="right";">{title}</h6>
             '''
    m1.get_root().html.add_child(folium.Element(title_html))
    title_html = f'''
             <h3 align="center" style="font-size:20px"><b>{name_i}定点当たり報告数</b></h3>
             <h6 align="right";">{title}</h6>
             '''
    m2.get_root().html.add_child(folium.Element(title_html))

    # 地図htmlをファイルに保存
    f.save('maptest.html')

    # HTMLファイルをブラウザで表示
    webbrowser.open('maptest.html')   # 開くのが早すぎで出てこないことがある

◆アプリとしての作り込み

アプリとしては次節のような機能、特長を設けました。

NIID国立感染症研究所が提供しているデータは、約2週間前のものが最新なので、カレンダーの初期値を16日前にしました。
過去の色分け地図を作成できるように日付の指定ができるようにするにあたり、tkcalendar パッケージを利用しました。
tkcalendar の使い方はコードで確認してください。・・・tkcalendar パッケージの説明は⤵

日付を指定後、地図作成ボタンが押されたら地図を作成します。

◇機能・特長

  • 新型コロナとインフルエンザの定点あたり報告数を色分け地図(階級区分図)でブラウザ表示します
  • 地図上にツールチップで報告数を表示します
  • 週(日付を指定)を指定して作成できます
  • 報告数の上限を固定して作成できます
  • 新型コロナ、インフルエンザの一方だけを作成することができます

◇手順

  1. 色分け用データの取得:get_csv_from_web()(自作メソッド)
  2. エラーがあったら戻る:msg が空でなければエラー
  3. 感染症名のチェックが一つも無かったら戻る
  4. 色分け用データの最大値を求める:max()
  5. 最大値を固定にするチェックが付いていたら固定にする
    ただし、色分けデータの最大値より小さくしない(エラー回避)
  6. 地図作成
    チェックされた状態に依りメソッドを変えて呼び出し

◇コード:地図作成

▽カレンダー、ボタンの作成(MyFrame クラスのコンストラクタ)

        # カレンダー    最新データは今日の16に前の週からなのでカレンダーの初期値とする
        latest_date = date.today() - timedelta(days=16)
        self.tkcal = DateEntry(self, year=latest_date.year
                            , month=latest_date.month
                            , day=latest_date.day
                            , date_pattern='y/m/d'
                            , locale='ja_JP')
        self.tkcal.pack()
        # 作成ボタン
        btn_exe = tk.Button(self, text='地図作成', command=self.create_map)
        btn_exe.pack()

▽MyFrame クラス

    def create_map(self):
        """
        地図作成(カレンダーから日付を取得して地図を作成)
        """
        self.var_msg.set("")
        self.update_idletasks()
        today = self.tkcal.get_date()
        msg = self.ctrl.create_map(today)
        self.var_msg.set(msg)

▽Mapping クラス

    def create_map(self, today:date) -> str:
        """
        地図作成
        Args:
            date:   報告者数報告日
        Returns:
            str:    実行結果のメッセージ
        """
        rows_c, rows_i, name_c, name_i, title, msg = self.get_csv_from_web(today)
        # エラーがあったら戻る
        if msg: return msg
        # 感染症にチェックが無かったら戻る
        if self.view.var_col.get() == False and self.view.var_flu.get() == False:
            return "感染症の両方か、どちらかにチェックを付けてください"
        # 定当の最大値
        max_c = max([x[1] for x in rows_c], default=0)
        max_i = max([x[1] for x in rows_i])
        # 最大値を固定にする場合
        if self.view.var_fix_max.get(): max_c = max_i = max(40, max_c, max_i)
        # どの感染症を対象にするかで出す地図を分ける
        if self.view.var_col.get() and self.view.var_flu.get(): # 新型コロナとインフルエンザ
            self.tow_choropleth(rows_c, rows_i, name_c, name_i, title, max_c, max_i)
        elif self.view.var_col.get():                           # 新型コロナ
            self.Choropleth_map_topo(rows_c, name_c, title, max_c, True)
        elif self.view.var_flu.get():                           # インフルエンザ
            self.Choropleth_map_topo(rows_i, name_i, title, max_i, True)
        print('finished')
        return "地図をブラウザに表示しました"

◆GeoJSONとTopoJSON

GeoJSON は、JSON を用いて GIS (地理情報システム)データを記述したファイルフォーマットです。
属性にはポイント(住所や座標)、ライン(各種道路や境界線)、 ポリゴン(国や地域)などが含まれます。
TopoJSON は、GeoJSON の拡張であり、トポロジー(連続性や収束性が定義可能な空間)を記述します。

GeoJSON は経度緯度の配列をデータとして持っていて、ポイントやライン、ポリゴンを描くことができます。
TopoJSON はアーク(弧線)の配列を持っています。 しかも境界線のデータを共有するなどして、GeoJSONに比べてデータ量が格段に少なくなります。

ここでは、データ量の少ない TopoJSON データを使います。
GeoJSON データを使う場合も簡単に触れます。

◇データの入手

データは、いろいろな方が作成して公開してくれています。
GitHub で公開されている場合は、データの raw を表示してその URL を使います。

公開されているデータのいくつかを紹介します。
いずれも GeoJSON、TopoJSON とも提供されています。

◇データの構造(TopoJSON)

色分け地図を作成する場合、データの構造を知っておく必要があります。
ここでは、前述の smartnews-smri から提供されている TopoJSON データの構造を紹介します。

   "type":"Topology",
    "arcs":[],
    "transform":{
        "scale":[],
        "translate":[]
    },
    "objects":{
        "prefectures":{
            "type":"GeometryCollection",
            "geometries":[
                {           これが県数分ある
                    "arcs":[],
                    "type":"MultiPolygon",
                    "properties":
                        {
                            "N03_001":"県名"
                        }
                },
                ...
            ]
        }
    }

◆foliumパッケージ

Python で地図を表示するために folium パッケージを使用します。
folium は、Leaflet.js という JavaScript ライブラリを利用する HTML を作成して地図を出力します。

◇GeoJsonクラス

◎コンストラク

  • 【構文】GeoJson(data, style_function, highlight_function, name, overlay, control, show, smooth_factor, tooltip, embed, popup, zoom_on_click, marker, **kwargs)
  • よく使う使い方(サンプル)
    【構文】GeoJson("https://raw.githubusercontent.com/???/geo.json")
  • 主な引数
    • data:プロットする GeoJSON データ。
      • ファイル:データはファイルを読み込み使用
      • dict:データは JSON に変換され使用
      • str
        • http, ftp, https:データをwebから取得
        • JSONの記述:JSONデータとして取得
        • その他:ファイルパスとして扱いJSONデータとしてロード

◇TopoJsonクラス

◎コンストラク

  • 【構文】TopoJson(data, object_path, style_function, name, overlay, control, show, smooth_factor, tooltip)
  • よく使う使い方(サンプル)
    【構文】TopoJson(topo_json_data, "objects.prefectures")
  • 主な引数
    • data:プロットする TopoJSON データ。必須
      GeoJSON のような web から読む機能なし
      • ファイル:データはファイルを読み込み使用
      • dict:データは JSON に変換され使用
      • str:データはそのまま使用
    • object_path:TopoJSON データの geometries を子に持つオブジェクトを示す objects からのパス。必須

◇Mapクラス

◎コンストラク

  • 【構文】Map(location, width, height, left, top, position, tiles, attr, min_zoom, max_zoom, zoom_start, min_lat, max_lat, min_lon, max_lon, max_bounds, crs, control_scale, prefer_canvas, no_touch, disable_3d, png_enabled, zoom_control, **kwargs)
  • 主な引数
    • location :地図の緯度と経度のタプルかリスト(北緯、東経)
    • zoom_start:地図の初期ズームレベル
    • tiles:使用するマップタイルセット。デフォルト:"OpenStreetMap"

◎メソッド

  • show_in_browser()
    デフォルトブラウザで表示。下記のようなファイルが作られる
    ユーザー/AppData/Local/Temp/folium_a8jdrfot.html
  • save(outfile, close_file=True)
    HTMLをoutfileファイルに保存
    • outfile:str, bytes, Path型の時は作成、それ以外(ファイル型)はそのまま使用

◇Choroplethクラス

◎コンストラク

  • 【構文】Choropleth(geo_data, data, columns, key_on, bins, fill_color, nan_fill_color, fill_opacity, nan_fill_opacity, line_color, line_weight, line_opacity, name, legend_name, overlay, control, show, topojson, smooth_factor, highlight, use_jenks, **kwargs)

  • 主な引数

    • geo_data:GeoJSON ジオメトリへの URL、ファイル パス、またはデータ (json、dict、geopandas など)
    • topojson:TopoJSON を使用する場合、「objects.yourfeature」を指定
      指定すると GeoJSON への変換が有効になる
      「objects.yourfeature」は JSON ファイルを確認して求める
    • data:GeoJSON にバインドするデータ
      • Pandas の DataFrame 型(2次元の型)
      • Series 型(1列分の型)
      • dict()で辞書にできるデータ(これだとpandasを使わない)
        • キーと値のペア(タプル (key, value) など)のリスト
          例:[('k1',1), ('k2', 2), ('k3', 3)]
        • キーのリストと値のリストから
          keys = ['k1', 'k2', 'k3'];values = [1, 2, 3];
          dict(zip(keys, values))
    • key_on:data とバインドする geo_data のキーを指定(feature の子孫)
    • fill_color:エリアの色
      "BuGn", "BuPu", "GnBu", "OrRd", "PuBu", "PuBuGn", "PuRd", "RdPu", "YlGn" , "YlGnBu", "YlOrBr", and "YlOrRd".
    • columns:データが Pandas DataFrame の場合、バインドされるデータの列をタプルで指定
      (キーになる列, 値になる列)
    • bins:色分けの仕方。デフォルト:6
      • int:何段階に色分けするかの値。最小値と最大値の間を等間隔に分ける
      • シーケンス:色分けする境界の値を直接定義
        例:[3, 4, 9, 11]
        データの範囲より指定が狭いと例外が発生
      • str"stone", "auto", "doane", "fd", "rice", "scott", "sqrt", "sturges"
        設定値はこちらを参照:numpy.histogram_bin_edges — NumPy v1.26 Manual

◇GeoJsonTooltipクラス

◎コンストラク

  • 【構文】GeoJsonTooltip(fields, aliases, labels, localize, style, class_name, sticky, **kwargs)
  • 主な引数
    • fields:表示したい GeoJson/TopoJson の「プロパティ」または GeoPandas GeoDataFrame 列のラベルのシーケンス
    • aliases:フィールドのキーの代わりにフィールド名としてツールヒントに表示するオプションのエイリアスのシーケンス

◇Figureクラス(brancaパッケージ)

描画する内容を入れるためのクラスです。

◎コンストラク

  • 【構文】Figure(width, height, ratio, title, figsize)
  • 主な引数
    • width:図の幅。パーセントかピクセルで指定。デフォルト:"100%"
    • height:図の高さ。パーセントかピクセルで指定。デフォルト:None

      ◎メソッド

  • add_subplot(x, y, n, margin=0.05)
    分割サブプロットの作成(matplotlibスタイル)
    • x:グリッドの行数
    • y:グリッドのカラム数
    • n:セル番号(1-x*y)
  • save(outfile, close_file=True)
    html ファイルに保存
    • outfile:ファイルまたはファイル名

Tkinterの使い方

Tkinter(ティーキンター)は Python が標準で提供している GUI パッケージです。
他のプログラムの開発ツールで提供されているようなルック&フィールな GUI ツールではありません。
従って、画面を構成するには、すべてコードを書く必要があります。

Tkinter を使用するには import が必要です。

  • インポート:import tkinter as tk

慣例的に tk と別名を付けるようです。

Tkinterの使用ウィジェット

Tkinter がサポートする GUI の部品をウィジェット (widget) と呼びます。

ここでは次のウィジェットを使用しています。

◇使用ウィジェット

ウィジェットは基本的にインスタンスを作成し、表示テキストや表示方法などを指定して使用します。

今回使用しているウィジェットです。

パッケージ ウィジェット 用途 見た目
tkinter Frame
フレーム
ウィジェットの受け皿
tkinter Label
ラベル
文字、画像の表示
tkinter Button
ボタン
押すと処理が動くボタン
tkinter Checkbutton
チェックボックス
チェックでオン/オフを設定
tkcalender DateEntry
日付選択エントリ
日付を設定

◇画面構成 - フレーム構造

プログラムを作るにあたって、どのような画面にするか決めなくてはなりません。画面構成を考えるということですね。
画面を構成するというのは、GUI 部品(ウィジェット)を画面に配置することです。
ウィジェットは設定したテキストに合わせてサイズが決まるので、そのまま使用しても画面構成上問題ないものと、広げないと見栄えが良くないものが出てきます。

今回の画面構成です。

  • lbl_title (Label)    :タイトル表示
  • tk_cal (DateEntry)    :日付指定エントリー
  • btn_exe (Button)     :画像作成ボタン
  • chb_fix_max (CheckButton) :最大値を固定するチェックボックス
  • chb_col (CheckButton)  :新型コロナ出力チェックボックス
  • chb_flu (CheckButton)  :インフルエンザ出力チェックボックス
  • lbl_msg (Label)     :メッセージ表示

※「lbl_strings」などはプログラムで使用した変数名です。()内はクラス名です。

ウィジェットの配置 - pack

▶説明は別記事を参照してください
 📖 ウィジェットの配置 - pack - SQLクライアントアプリの作り方(Tkinterで表)【Python】 🔗

◇動作をウィジェットに割り当てる - バインド

▶説明は別記事を参照してください
 📖 動作をウィジェットに割り当てる - Excel viewerアプリの作り方(Tkinterでタブと表)【Python】 🔗

◆tkcalendarパッケージ

Tkinterで使えるカレンダーダイアログです。
Tkinterで使える Calendar と DateEntry ウィジェットを提供しています。

  • インストール:pip install tkcalendar
  • インポート :from tkcalendar import Calendar, DateEntry

◇Calendarウィジェット

◎コンストラク

  • 【構文】Calendar(master=None, **kw)
  • 主な引数
    • master   :親ウィジェット
    • font    :カレンダーのフォント
    • borderwidth:カレンダーの周囲の境界線の幅
    • year    :初期表示する年
    • month   :初期表示する月
    • day    :初期表示する日
    • firstweekday:週の始まり“monday” or “sunday”
    • locale   :ロケール(日付の表示形式が変わる)。例:"en_US", "ja_JP"
    • date_pattern:日付フォーマット d, dd:日、m, mm:月、yy:西暦

      ◎メソッド

  • get_date():選択されている日付を文字列で返す

◇DateEntryウィジェット

ドロップダウンカレンダーを使用した日付選択エントリです。

◎コンストラク

  • 【構文】DateEntry(master=None, **kw)
  • 引数

◎メソッド

  • get_date():表示されている日付をDate型で返す

◆ソースの取得

全体のソースはこちらから取得できます。

◇ご注意

本記事は次のバージョンの下で動作した内容を基に記述しています。

  • Python   3.8.5
  • folium   0.14.0
  • tkcalendar 1.6.1

◇免責事項

ご利用に際しては、『免責事項』をご確認ください。
お気づきの点がございましたら『お問い合わせ』からお問い合わせください。

◆さいごに

アプリの記事を投稿してから本記事を投稿するまでに時間が掛かってしまいました。
もし、お待ちいただいている方がいらっしゃいましたら申し訳ございませんでした。
予想以上にてこずってしまいました。
folium の使い方とかを調査していると GeoPandas と言うパッケージの存在に気が付きます。
次は、GeoPandas を使ったものを作ってみようかと思っています。


あわせて読みたい 📖 GeoPandasで色分け地図を作成【Python】 🔗

◆参考

投稿: 、更新: