Source code for app.models.community

"""
Community
====================================
The Community module
"""
import os
import shapefile
import pygeoif

from .. import db
from geoalchemy2 import WKTElement
from geoalchemy2 import Geometry
from sqlalchemy import Column, String, Integer, func

[docs]class Community(db.Model): __tablename__ = "community" id = Column(Integer, primary_key=True) name = Column(String(64), nullable=False) boundaries = Column(Geometry('MULTIPOLYGON', srid=4326), nullable=False)
[docs] def to_dict(self): """Return a dictionary representation of this Community object.""" return { "id": self.id, "name": self.name, "boundaries": self.boundaries }
[docs] @classmethod def from_dict(cls, data): """Create a Community object from a dict.""" return cls(**data)
[docs] @classmethod def get_all_communities (cls): """Query the database and return a list of all Communities with their id, name and boundaries in GeoJSON format. """ return db.session.query(Community, func.ST_AsGeoJSON(Community.boundaries)).all()
[docs] @classmethod def get_community_surrounding(cls, longitude, latitude): """Get a Community with boundaries surrounding a given point specified by longitude and latitude. Returns the Community id, name and boundaries. """ return db.session.query( Community, func.ST_AsGeoJSON(Community.boundaries) ).filter( func.ST_Contains( Community.boundaries, WKTElement("POINT({} {})".format(longitude, latitude), 4326)) ).first()
[docs] @classmethod def add_comunity(cls, community): """Add a given Community to the database. If there is a conflict, the existing object in the database is overwritten. """ existing_community = cls.query.filter_by(id=community.id).first() if existing_community is None: db.session.add(community) else: existing_community = community db.session.commit() return community
[docs] @staticmethod def populate_db(): """Populate database with default community data.""" Community._parse_shapefile_and_populate_db("/db_info/communities/NEIGHBORHOODS_WGS84.shp")
@staticmethod def _parse_shapefile_and_populate_db(file_path): """Given a path to a shapefile containing Community information, parse the file and add each Community to the database. """ if not os.path.exists(file_path): print(file_path + " does not exist") else: sf = shapefile.Reader(file_path) # Create a dict of {<field>: <index>} field_dict = {} for field in sf.fields: field_dict[field[0]] = sf.fields.index(field) - 1 for shapeRecord in sf.shapeRecords(): Community.add_comunity(Community.from_dict({ "id": shapeRecord.record[field_dict['AREA_S_CD']], "name": ' '.join(shapeRecord.record[field_dict['AREA_NAME']].split(' ')[:-1]), "boundaries": WKTElement(str(pygeoif.MultiPolygon(pygeoif.as_shape(Community._longlat_to_latlong(shapeRecord.shape.__geo_interface__)))), 4326) })) @staticmethod def _longlat_to_latlong(geojson): """Given a GeoJSON in dict form, reverses the order of the coordinates. """ coordinates = geojson['coordinates'] new_coordinates = () for polygon in coordinates: new_polygon = (()) for point in polygon: new_point = (point[1], point[0]) new_polygon += (new_point), new_coordinates += (new_polygon), return { 'type': 'Polygon', 'coordinates': new_coordinates }