geoalchemyで位置情報をpythonから扱う
sqlalchemyでMySQLを使うで説明したsqlalchemyでは、ここで説明したMySQLの位置情報を利用できない。
そこで、geoalchemyを使う。
インストール
sudo pip install geoalchemy
以上。
マッピング
sqlalchemyではMySQLテーブルとマッピングするためのクラスを定義する。
その際に、geometry型のカラムをsqlalchemyでは扱えないため、geoalchemy.GeometryColumnを利用する
import文はsqlalchemyでMySQLを使うと同じ。
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DECIMAL, DATETIME, create_engine from sqlalchemy.orm import session maker, relationship from sqlalchemy.ext.declarative import declarative_base from geoalchemy import GeometryColumn, Point from geoalchemy.mysql import MySQLComparator class Place(Base): __tablename__ = "place" __table_args__ = {"mysql_engine": "MyISAM"} id = Column("id", Integer, primary_key=True, autoincrement=True) name = Column("name", String(255)) latlng = GeometryColumn("latlng", Point(dimension=2, srid=4326),\ nullable=False, comparator=MySQLComparator) def __init__(self, name, latlng): self.name = name self.latlng = latlng
これでマッピング用のクラスPlaceが定義出来た。
latlng = GeometryColumn("latlng", Point(dimension=2, srid=4326),\ nullable=False, comparator=MySQLComparator)
ではカラム自体をGeometryColumnで作成し、カラムのタイプを2次元のPointで(sridはよく分からないのでデフォルト値)、
MySQLを利用するのでcomparatorにMySQLComparatorをセットしています。
DBから位置情報の取得し、扱う
# これが使える import geoalchemy.functions as gf # echo=Trueでログを吐く engine = create_engin("mysql://[user]:[passwd]@[host]/[dbname]",\ encoding="utf-8", echo=False) Session = sessionmaker(bind=engine) session = Session() # 矩形範囲にあるPlaceを取得する margin = 0.01 lng, lat = 35.0, 135.0 left, right = lng - margin, lng + margin bottom, top = lat - margin, lat + margin # boxは(left, bottom), (right, bottom), (right, top), (left, top)の4点を結ぶ正方形となる box = "POLYGON(({left} {bottom}, {right} {bottom}, {right} {top}, {left} {top}, {left} {bottom})\ .format(left=left, right=right, bottom=bottom, top=top)" s = session.query(Place.id, Place.name, Place.latlng, \ gf.wkt(Place.latlng).label("point"), gf.x(Place.latlng).label("lat"), gf.y(Place.latlng).label("lng"))\ .filter(Place.latlng.within(box)).all() # dict化 return [place._asdict() for place in s]
こんな感じ
geometry.functionsでいろいろ出来そう。
ちなみに、sqlalchemyでは
from sqlalchemy import func
で、func.round(四捨五入)や.group_byしてfunc.avg(平均)が可能となる。
ジオコーディング
緯度経度を扱うために、googleが提供するジオコーディングのapiを叩いて結果を取得する
from urllib import url open import json url = "http://maps.googleapis.com/maps/api/geocode/json?address={landmark}&sensor=true" landmark = "京都駅" geo_json = json.load(urlopen(url.format(landmark=landmark))) latlng = geo_json["results"][0]["geometry"]["location"] result = {"lat": latlng["lat"], "lng": latlng["lng"]}
urlopen使っててエラー処理もしてないので、使うときはきちんと書きましょう...