【Snowflake】Streamlit in Snowflakeでポリゴン地図を表示

【Snowflake】Streamlit in Snowflakeでポリゴン地図を表示 | Tableau-id Press -タブロイド-
snowflake-logo-1200x630-960x504

こんにちは。ozawaです。

今回はStreamlit in Snowflakeでポリゴン地図を表示させてみます。

最近Streamlit in Snowflake では、マップ表示が使えるようになっています。

しかしながら、streamlitのデフォルト関数st.mapでは制約が多く、カスタマイズができない欠点があります。(なぜか、カラーやサイズ等を指定できない。。。)

また、st.mapではプロット地図のみ可能で、ヒートマップ地図やポリゴン地図を表示するには、他の手法を利用する必要があります。

 

そこで今回、pydeckライブラリを使用した別の手法でポリゴン地図を表示しようと思います。

 

実装!!

今回は、Prepper Open Data Bankの都道府県データを使って、人口の多い・少ないで色分けしたポリゴン地図を可視化してみます。

まずはソースコードを共有します。

# 必要なライブラリをインポート
import streamlit as st
from snowflake.snowpark.context import get_active_session
import json
#geo版のPandas
import geopandas as gpd
#geoデータの補正関数
from shapely.geometry import shape
from shapely.validation import make_valid
#geoデータの表示
import pydeck as pdk

# Snowflakeからデータを取得する関数をキャッシュ化
@st.cache_resource
def create_source():
    session = get_active_session()
    # Snowflakeからデータをクエリして取得
    df = session.sql('''
        SELECT
            PREF_NAME
            ,PREF_CODE
            ,POPULATION
            ,ST_ASGEOJSON(POLYGON_JP_PREF_LIGHT) AS GEO_JSON //GeographyからGeojsonに変換
        FROM
            PREPPER_OPEN_DATA_BANK__JAPANESE_PREFECTURE_DATA.E_PODB.E_PR_FD20
    ''').to_pandas()
    return df

# データの取得
df = create_source()

#GeojsonからGeometryに変換
def trans_shape(x):
    geometry = shape(json.loads(x))
    if geometry.is_valid:
        return geometry
    else:
        return make_valid(geometry)

# GeoDataFrameに都道府県名・人口・ポリゴン(GeojsonからGeometryに変換したもの)を格納
# COLORカラム:人口をもとにしたポリゴンの色
geometry = [trans_shape(row) for row in df['GEO_JSON'] ]
gdf = gpd.GeoDataFrame(df[['PREF_NAME', 'PREF_CODE', 'POPULATION']].reset_index(), geometry=geometry)
gdf["color"] = [[i*255, (1-i)*255, 0, 140] for i in gdf['POPULATION']/gdf['POPULATION'].max()]

# ポリゴン地図の可視化
layer = pdk.Layer(
    "GeoJsonLayer",
    data=gdf, # GeoDataFrameを指定
    get_polygon="geometry.coordinates", # Geometry辞書のgeometry.coodinatesの中に地理データが入っているので指定
    get_fill_color='color',  # ポリゴン色はCOLORカラムを指定
)

fig = pdk.Deck(
        layers=[layer],
        map_style="mapbox://styles/mapbox/light-v9", # ベースマップを指定
        initial_view_state=pdk.ViewState( # マップの初期表示の拡大度、中心を指定
            latitude=38,
            longitude=138,
            zoom=3.8,
        )
)

# 地図を表示
st.pydeck_chart(fig)

コードの詳細をピックアップして解説していきます。

1. ポリゴンデータをGeometryに変換

今回、Snowflake上のGeography型都道府県ポリゴンを、Geography→Geojson→Geometryに変換しています。

気持ちとしては、地図表示に使用するPydeckライブラリは、入力にGeoDataFrameデータを指定すると管理が楽であり、そのGeoDataFrameを作成するにはDataFrame型属性データ(都道府県名・人口…)とGeometry型かGeojson型ポリゴンデータが必要となるためです。

また、GeoDataFrameにGeojson型が使えそうならGeojson→Geometryの変換が不要だと思われますが、Geometry型では正常なポリゴンかどうかを判定する関数と補正する関数があるため、ポリゴン表示をより正確に行うためにGeometry型への変換を実施します。

 

まず、Snwoflake上のGeographyからGeojsonへと変換するためには、SnowflakSQL上でST_ASGEOSON関数を使用します。

//GeographyからGeojsonに変換
ST_ASGEOJSON(POLYGON_JP_PREF_LIGHT) AS GEO_JSON

次にGeojsonからGeometryに変換するためには、地理データを処理するShapelyライブラリを使用します。

入力をGeojsonとして、shape関数でGeometry型に変換します。

shape関数で変換したGeometry型には、表示できない形状があります。

is_validで使用できるかの判定を行い、make_valid関数を使って補正をします。

#GeojsonからGeometryに変換
def trans_shape(x):
    geometry = shape(json.loads(x))
    if geometry.is_valid: #ポリゴンが使用できるか?
        return geometry
    else:
        return make_valid(geometry) #ポリゴン補正

geometry = [trans_shape(row) for row in df['GEO_JSON'] ] #47都道府県のポリゴンリストを作成

ここまで行い、Geometry型の正常な47都道府県ポリゴンが完成します。

 

2. DataFrame から GeoDataFrameを作成

47都道府県の属性データを格納した47レコードのDataFrameと、Geometry型の47都道府県ポリゴンリストを入力にして、GeoDataFrameを作成します。

geometry = [trans_shape(row) for row in df['GEO_JSON'] ] #47都道府県のポリゴンリスト

#GeoDataFrameの作成
gdf = gpd.GeoDataFrame(df[['PREF_NAME', 'PREF_CODE', 'POPULATION']].reset_index(), geometry=geometry)

3. GeoDataFrameをPydeckに入れて地図出力

Pydeckライブラリを使ってポリゴン地図を表示します。

layer変数では、人口が多い・少ないに応じた色分け都道府県ポリゴンデータが格納されています。(Tableauのマップレイヤーみたいですね。)

fig変数では、地図全体の設定を行っています。map_styleでは、ベースマップを指定しています。衛星地図とかも表示できるようです。initial_view_stateでは、初期地図の拡大度や中心を指定しています。

最後に、st.pydeck_chart関数で、Pydeckで作成した地図をStreamlit画面に表示します。

# ポリゴン地図の可視化
layer = pdk.Layer(
    "GeoJsonLayer",
    data=gdf, # GeoDataFrameを指定
    get_polygon="geometry.coordinates", # Geometry辞書のgeometry.coodinatesの中に地理データが入っているので指定
    get_fill_color='color',  # ポリゴン色はCOLORカラムを指定
)

fig = pdk.Deck(
        layers=[layer], #表示する地図レイヤーを指定
        map_style="mapbox://styles/mapbox/light-v9", # ベースマップを指定
        initial_view_state=pdk.ViewState( # マップの初期表示の拡大度、中心を指定
            latitude=38,
            longitude=138,
            zoom=3.8,
        )
)

# タイトルを表示
st.title('ポリゴン地図を表示できたよ~')
# 地図を表示
st.pydeck_chart(fig)

完成図

人口が多い・少ないで色分けしてStreamlit in Snowflakeでポリゴン地図表示できました!

おわりに

今回使用したPrepper Open Data Bankは、都道府県データ・ポリゴンだけではなく、カレンダーデータや、気象予報データ等があります。ぜひお使いください。

truestarでは、Streamlit画面開発だけではなく、Snowflake導入検討、導入支援や環境構築まで幅広くサポート可能です。

Snowflakeに゙興味がある、導入済みだけどもっとうまく活用したい等々ありましたら、ぜひこちらから相談ください!

これまでのSnowflakeに関する記事はこちら