前回:https://shikuuk.blogspot.com/2025/06/python-folium-relearning6-from-may.html
次はPopupです。FoliumHomePageはこちら(https://python-visualization.github.io/folium/latest/user_guide/ui_elements/popups.html)です。FoliumのContentsは少しSideにPutして、わたしなりにGemini先生に聞きながら、国土地理情報に格納されている国内のダムに関する情報(https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-W01.html)を使って、ダムの位置にMarkerをPlotし、DamのInfomaionをPopupさせてみます。
まず最初に国土数値情報からダムの情報をGetし、GeoDataFrameにTransformするCodeです。DamInformationのURLはChromeのその他ツールのデベロッパーツールを活用して調べました。
>Code<
>Output<
W01_001 | W01_002 | W01_003 | W01_004 | W01_005 | W01_006 | W01_007 | W01_008 | W01_009 | W01_010 | W01_011 | W01_012 | W01_013 | W01_014 | geometry | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 駒込 | 191 | 堤川 | 駒込川 | 7 | 1,2,6 | 84.5 | 270.0 | 320 | 7800 | 4 | - | 青森県青森市大字駒込 | 4 | POINT (140.88589 40.70977) |
1 | 下湯 | 192 | 堤川 | 堤川 | 12 | 1,2,4 | 70.0 | 783.5 | 3723 | 12600 | 4 | 1988 | 青森県青森市大字荒川字横倉 | 1 | POINT (140.77942 40.69178) |
2 | 浅虫 | 193 | 浅虫川 | 浅虫川 | 7 | 1,2 | 9.0 | 215.0 | 10 | 300 | 4 | 2002 | 青森県青森市大字浅虫字山下 | 1 | POINT (140.87188 40.88522) |
3 | 田の沢溜池 | 194 | 小湊川 | 小湊川 | 3 | 3 | 21.0 | 205.0 | 124 | 1174 | 5 | 1945 | 青森県東津軽郡平内町大字松野木 | 1 | POINT (140.99147 40.89848) |
4 | 清水目 | 195 | 野辺地川 | 野辺地川 | 7 | 1 | 33.5 | 195.0 | 75 | 2630 | 4 | 2000 | 青森県上北郡東北町字清水目 | 1 | POINT (141.07611 40.81095) |
今回はGemini先生に色々と聞きました。まずはGemini先生への1問目の質問です。
>Gemini先生へのQuestion<
国土数値情報のダム情報のShapeファイルをダウンロードして作成したGeoPandasDataFrame'gdf'があります。これらのダムの位置情報(緯度・経度)をもとにFoliumのOpenStreetMap上でマーカーを表示した上で、tooltipにダム名(ColumnName'W01_001')を、PopUpで、水系名(ColumnName'W01_003')、ダムの形式(ColumnName'W01_005')、ダムの目的(ColumnName'W01_006')、ダムの堤高(m)(ColumnName'W01_007')、ダムの総貯水容量(千m3)(ColumnName'W01_010'),所在地ColumnName'W01_013')を表示したいです。
なお、ダムの形式は以下のようなコードです。
コード対応する内容1アーチダム2バットレスダム3アースダム4アスファルトフェイシングダム5アスファルトコアダム6フローティングゲートダム(可動堰)7重力式コンクリートダム8重力式アーチダム9重力式コンクリートダム・フィルダム複合ダム10中空重力式コンクリートダム11マルティプルアーチダム12ロックフィルダム13台形CSGダム。さらに、ダムの目的コードは以下のようなコードです。
コード対応する内容1洪水調節、農地防災2不特定用水、河川維持用水3灌漑、特定(新規)灌漑用水4上水道用水5工業用水道用水6発電7消流雪用水8レクリエーション。
さらに、ダムの目的別にマーカーの色を変えたいです。
Actually、ThisCodeでOutputされたMapのPopupでは'ダムの種類’と'ダムの目的'がすべて不明と出力されました。ということで、TeacherGeminiに改善の質問です。
>Gemini先生へのQuestion<
引き続き、Popupでダムの形式と、ダムの目的が全て'不明'で出て来ます
>TeacherGeminiのAnswer<
ポップアップでダムの形式と目的がすべて「不明」と表示されるとのこと、承知いたしました。これは主に以下の2つの原因が考えられます。
Shapeファイルの読み込み時のエンコーディングの問題: 国土数値情報のShapeファイルは、しばしばShift-JISでエンコードされています。もし読み込み時に正しいエンコーディングを指定できていない場合、文字化けが発生し、数値データであるはずの
W01_005
やW01_006
カラムが正しく読み込まれず、その結果、辞書によるマッピングが機能せずfillna('不明')
が適用されてしまいます。W01_005
やW01_006
カラムのデータ型が文字列になっている: Shapeファイルの読み込み方によっては、数値として扱われるべきカラムが文字列として読み込まれてしまうことがあります。この場合、辞書のマッピングは数値(整数)キーで行われるため、文字列として読み込まれたカラムの値とは一致せず、「不明」となってしまいます。...
以下、Answerは続くのですが、これまでの経験から2.の可能性が高いと判断して、MasterGeminiのSuggesting Codeを活用して、以下の通りCodeをFixします。
>Gemini先生にOfferいただいたCode< わたくしが少し手を加えてますが、ほぼママです。
>Output<
dam_type_map
とdam_purpose_map
は、提供されたコードと対応する内容をマッピングするための辞書です。purpose_colors
は、ダムの目的コードに対応するマーカーの色を定義するための辞書です。目的に応じて好きな色を設定してください。
変換した内容を新しいカラムとして追加:
gdf['W01_005'].map(dam_type_map).fillna('不明')
を使って、W01_005
(ダム形式コード)を対応する文字列に変換し、新しいカラム'ダム形式'
としてgdf
に追加します。fillna('不明')
は、マッピングできなかったコードがある場合に「不明」と表示するためのものです。- 同様に、
W01_006
(ダム目的コード)も'ダム目的'
カラムに追加します。
Folium マップの作成 (folium.Map
):
folium.Map(location=[center_lat, center_lon], zoom_start=6)
でベースとなる地図を作成します。location
には地図の中心となる緯度と経度を指定します。ここではgdf
のデータの平均値を使用しています。データがない場合のデフォルト値も設定しています。zoom_start
は初期のズームレベルです。
各ダムに対してマーカーを追加 (folium.Marker
):
gdf.iterrows()
を使って、gdf
の各行(つまり各ダム)をループ処理します。row.geometry.y
で緯度、row.geometry.x
で経度を取得します。- ツールチップ (
tooltip
):tooltip_text = row['W01_001']
でダム名をツールチップに設定します。 - ポップアップ (
popup
):popup_html
にf-stringを使ってHTML形式で情報を記述します。ここに水系名、ダムの形式、目的、堤高、総貯水容量、所在地を表示します。 - マーカーの色 (
icon=folium.Icon(color=marker_color)
):purpose_colors.get(purpose_code, 'gray')
を使って、ダムの目的コードに対応する色を取得します。もし対応するコードがない場合は'gray'
(灰色)が使われます。folium.Icon
のcolor
引数にこの色を渡し、マーカーの色を変更します。icon='info-sign'
はマーカー内のアイコンの例です。Foliumで利用可能な他のアイコンも試すことができます。 - 作成したマーカーは
add_to(m)
で地図に追加します。
マップの保存または表示:
m.save('dam_map.html')
で作成した地図をHTMLファイルとして保存します。このファイルをウェブブラウザで開くことで地図を確認できます。- Jupyter NotebookやJupyterLabの環境であれば、最後に
m
とだけ書くと、セルに出力された地図が直接表示されます。
TeacherGemini、ここまでPolitelyにExplainしてくれるとはExcellentでございます。
でも、こんなにMarkerでFillUpされると、HardToSeeなので、MarkerClasterというMethodを使って、EasyToSeeにしたいと思います。ここでもMasterGeminiの登場です。
>MasterGeminiへのQuestion<
完璧です。さらに2点改良を加えたいです。
①マーカーの数が多すぎてみづらいので、zoomが小さいときはマーカーをまとめて表示するようにできませんか?
②'ダムの目的'ごとにマーカーをfeatureGroupに設定して、個別のLayerに格納し、LayerControlで表示・非表示を切り替えできるようにできないでしょうか?
>MasterGeminiへのAnswer<
承知いたしました!Foliumで大量のマーカーを効率的に表示し、かつ目的別にレイヤーを切り替えるための2つの重要な改良点ですね。
- マーカークラスタリング (Marker Clustering):
folium.plugins.MarkerCluster
を使用します。これにより、ズームアウト時にはマーカーがグループ化され、ズームインすると個々のマーカーが表示されるようになります。 - FeatureGroup と LayerControl:
folium.FeatureGroup
を使用して目的ごとのダムを個別のレイヤーにまとめ、folium.LayerControl
でそれらの表示/非表示を切り替えられるようにします。
これらの改良を加えたコードを以下に示します。
>MasterGeminiのAnswer<
マーカーが表示されなくなったとのこと、承知いたしました。エラーが出ないのに表示されない場合、いくつか考えられる原因があります。
最も一般的なのは、マーカークラスタリングとFeatureGroupの両方に同じマーカーを追加していることで、内部的に競合が発生しているケースです。Foliumでは、マーカーは一つの親グループにのみ属するのが原則です。
今回は、レイヤーコントロールで表示を切り替えたいので、FeatureGroupにマーカーを追加し、そのFeatureGroup自体をMarkerClusterに追加する、というアプローチを取るのが適切です。
以下の修正案で、マーカーが表示されるようになるかお試しください。
修正のポイント
前回のコードでは、各folium.Marker
オブジェクトをmarker_cluster
と対応するfolium.FeatureGroup
の両方にadd_to()
していました。これが問題の原因と考えられます。
正しいアプローチは次の通りです。
- 各
FeatureGroup
自体をMarkerCluster
のメンバーにする。 - 個々のマーカーは、それぞれの
FeatureGroup
にのみ追加する。
これにより、LayerControlでFeatureGroupの表示/非表示を切り替えられ、かつFeatureGroupに含まれるマーカーが自動的にクラスタリングされます。
>Code<
>OutputMap< ▼DynamicMap▼
ダムの種類ごとにClasteringしたかったのですが、今回はここまでにして、次に進もうと思います。
前回:https://shikuuk.blogspot.com/2025/06/python-folium-relearning6-from-may.html
次回:https://shikuuk.blogspot.com/2025/06/python-folium-relearning8-from-may.html
コメント
コメントを投稿