こんにちは!ozawaです!
Snowflake上やStreamlit in Snowflake上で地理データを扱っている中で、試行錯誤ながら地理データのベターな処理を確立できるようになってきました。
今回は、Snowflake上でのジオデータの作成方法、処理方法、可視化までをガイドとしてまとめてみようと思います。
全部で8項目あるので、興味がある項目があればぜひご覧になってください~!
Snowflakeの地理データ全体フロー
さっそく今回扱う地理データ処理の一覧です!これをもとに各項目の処理を確認していきましょう。
① ShapeからGeoJson・WKTへの変換
Snowflakeに地理データをアップする際には、Shapeで作られた地理データをGeoJsonかWKTといったファイル形式に変換する必要があります。
ステージに上げることができるファイル形式でShapeが対応していないからです。
ちなみに地理ソフトウェアQgisを使うことでShapeからGeoJsonに簡単に変換することができます。
今回GeoJsonでアップしてみますが、大きく2種類のGeoJson形式があり得ます。
a. 地理データとその属性データをGeoJson拡張子としてアップ
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"polygon_id": 1 //属性データ
},
"geometry": {
"coordinates": [ //ポリゴン
[
[
139.66269177823767,
35.725004794396696
],
[
139.78182309267356,
35.725004794396696
],
[
139.78182309267356,
35.78296021979881
],
[
139.66269177823767,
35.78296021979881
],
[
139.66269177823767,
35.725004794396696
]
]
],
"type": "Polygon"
}
}
]
}
b. csvの中に属性データと文字列型に変換したGeoJsonを格納しアップ
手法aの「geometry」の中身を文字列型の地理データとして格納しているイメージです。
② Stageを介してアップ
①で作成した手法a. GeoJson、手法b.GeoJsonを含んだcsvをStage上にアップしていきます。
手法b. GeoJsonを含んだcsvの場合は、GeoJsonカラムを文字列カラムとしてアップする必要があります。
個人的には、手法a. Json等のオブジェクトとしてアップするよりも、手法b. csvの中にGeoJsonをカラムの1つとして格納する手法のほうが扱いやすいと感じています。
(手法aでは半構造化の処理が必要となるためです。ただし、手法aの場合は、代わりに③④の地理データ変換作業は不必要になります。)
そのため、手順③と④では、手法b. GeoJsonを含んだcsvを使って説明していきます。
③ 文字列GeoJsonカラムからジオメトリ型のカラムを作成
TRY_TO_GEOMETRYを使うことで、文字型としてアップされたGeoJsonから、ジオメトリ型の地理データカラムを作成することができます。
TRY_TO_GEOMETRYでは文字型から地理型に変換できるものは変換、できない無効な形の場合はNullを返します。
ジオメトリ型を作成する関数として他にもTO_GEOMETRYがありますが、TO_GEOMETRYの場合はNullを返さずにエラーを返します。
CREATE OR REPLACE TABLE
as
SELECT ID, POLYGON(String), TRY_TO_GEOMETRY(POLYGON(String)POLYGON) POLYGON //文字列からジオメトリ型に変換
FROM TABLE_SRC
④ 文字列GeoJsonカラムからジオグラフィ型のカラムを作成
ジオメトリ型への変換と同様に、ジオグラフィ型への変換も行うことができ、TRY_TO_GEOGRAPHYやTO_GEOGRAPHY関数を使います。
CREATE OR REPLACE TABLE
as
SELECT ID, POLYGON(String), TRY_TO_GEOGRAPHY(POLYGON(String)POLYGON) POLYGON //文字列からジオグラフィ型に変換
FROM TABLE_SRC
ここで、ジオメトリ型やジオグラフィ型という2つの地理データ型が出てきていることに疑問を感じる方がいると思うので、次の⑤で2つの型の違いを解説します。
⑤ GeoJsonを介してジオメトリとジオグラフィを変換
GeoJsonを介してジオメトリとジオグラフィを変換することができます。
GeoJsonへの変換にはST_ASGEOJSONを使っています。
TO_GEOGRAPHY(ST_ASGEOJSON(GEOMETRY_DATA)) //ジオメトリ->ジオグラフィ
TO_GEOMETRY(ST_ASGEOJSON(GEOGRAPHY_DATA)) //ジオグラフィ->ジオメトリ
ちなみに、ジオメトリ型とジオグラフィ型とでは地理データとして設計思想が違っていて、以下のような思想の違いがあります。
ジオメトリ型:地図を平面と仮定して地理的な処理を実施(投影座標系)
ジオグラフィ型:地図を球体と仮定して地理的な処理を実施(地理座標系)
例えば、点Aから点Bまでの距離を求める場合、ジオメトリ型は想定通り点Aから点Bまでの距離を求めますが、ジオグラフィ型の場合は球の点Aと点Bを結ぶので、地中に入ることがあり、正確な距離とは言えません。実際に、ジオメトリ型とジオグラフィ型で距離を測ると、結果に差異が見られます。
一方で、ジオメトリ型は本来球体の地球を平面に直すことから、平面への投影に様々な解釈法があるという複雑さがあります。
参照:GEOGRAPHY と GEOMETRY の違いについて
⑥ 地理データと属性データをDataframe化
地理データと属性データをDataFrame化することで、そのあとの新規カラムの作成や、カラムの計算が簡単となります。
一般的にはPandasを使ってDataFrame化しますが、地理データを含める場合は、GeoPandasというライブラリを使います。
GeoPandasに入れることができる地理データがジオメトリ型であるため、ジオグラフィ型の場合は、⑤の手法でジオメトリ型に変換してからの作業になります。
import geopandas as gdf
gdf = gpd(df['ID'], geometry=df['POLYGON']) //属性データとポリゴンを指定し、GeoPandasを作成
⑦ 地理データを地理関数を使って加工
地理的処理に長けているShapelyライブラリや、Snwoflakeの「ST_」から始まる地理関数を使って、ジオメトリ型やジオグラフィ型の地理データを加工することができます。
ここで注意するのが、さきほどのジオメトリ型とジオグラフィ型の思想が異なる点です。
距離を取る「ST_DISTANCE」や、面積を求める「ST_AREA」場合は2つの型では値が異なってきます。
また、ジオメトリ型、ジオグラフィ型の片方にしか存在しない関数もあります。
例えば、ジオハッシュを作成する「ST_GEOHASH」は球体の地球をスライスする想定なのでジオグラフィ型でしか使えません。
一方で、バッファ・商圏を作成する「ST_BUFFER」は平面の地球上で2点の距離を比較することで領域が作成されるので、ジオメトリ型でしか使えません。
⑧ Dataframe化されたジオデータから可視化
Dataframe化されたポリゴンとその属性データから、Pydeckを使って可視化をしていきます。
import pydeck as pdk import streamlit as st layer = pdk.Layer( "GeoJsonLayer", data=gdf, get_polygon="geometry", //ポリゴンカラムを指定 ) fig = pdk.Deck( layers=[layer], map_style="mapbox://styles/mapbox/light-v9", //ベースマップ initial_view_state=pdk.ViewState( //初期表示の拡大度、緯度経度を指定 latitude=35.5, longitude=139.5, zoom=8, pitch=0 )
) st.pydeck_chart(fig) #streamlitでpydeck地図を表示
おわりに
truestarでは、Snowflake導入検討、導入支援や環境構築まで幅広くサポート可能です。
Snowflakeに゙興味がある、導入済みだけどもっとうまく活用したい等々ありましたら、ぜひこちらから相談ください!
これまでのSnowflakeに関する記事はこちら