Ejemplo n.º 1
0
def overlap_summary(groupbydata, valuedata, fieldmapping=[]):
    # prep
    data1,data2 = groupbydata,valuedata
    if fieldmapping: aggfields,aggtypes = zip(*fieldmapping)
    aggfunctions = dict([("count",len),
                         ("sum",sum),
                         ("max",max),
                         ("min",min),
                         ("average",lambda seq: sum(seq)/float(len(seq)) ) ])

    # create spatial index
    if not hasattr(data1, "spindex"): data1.create_spatial_index()
    if not hasattr(data2, "spindex"): data2.create_spatial_index()

    # create new
    new = GeoTable()
    new.fields = list(data1.fields)
    if fieldmapping: 
        for aggfield,aggtype in fieldmapping:
            new.fields.append(aggfield)

    # for each groupby feature
    for i,feat in enumerate(data1.quick_overlap(data2.bbox)):
        geom = geoj2shapely(feat.geometry)
        geom = supershapely(geom)
        matches = []

        # get all value features that intersect
        for otherfeat in data2.quick_overlap(feat.bbox):        
            othergeom = geoj2shapely(otherfeat.geometry)
            if geom.intersects(othergeom):
                matches.append(otherfeat)

        # make newrow from original row
        newrow = list(feat.row)

        # if any matches
        if matches:
            def make_number(value):
                try: return float(value)
                except: return None
                
            # add summary values to newrow based on fieldmapping
            for aggfield,aggtype in fieldmapping:
                values = [otherfeat[aggfield] for otherfeat in matches]
                if aggtype in ("sum","max","min","average"):
                    # only consider number values if numeric stats
                    values = [make_number(value) for value in values if make_number(value) != None]
                aggregatefunc = aggfunctions[aggtype]
                summaryvalue = aggregatefunc(values)
                newrow.append(summaryvalue)

        # otherwise, add empty values
        else:
            newrow.extend(("" for _ in fieldmapping))

        # write feature to output
        new.add_feature(newrow, feat.geometry)

    return new
Ejemplo n.º 2
0
def vector_clean(data, tolerance=0):
    """Cleans the vector data of unnecessary clutter such as repeat
    points or closely related points within the distance specified in the
    'tolerance' parameter. Also tries to fix any broken geometries, dropping
    any unfixable ones.

    Adds the resulting cleaned data to the layers list.
    """
    # create new file
    outfile = GeoTable()
    outfile.fields = list(data.fields)

    # clean
    for feat in data:
        shapelyobj = geoj2shapely(feat.geometry)
        
        # try fixing invalid geoms
        if not shapelyobj.is_valid:
            if "Polygon" in shapelyobj.type:
                # fix bowtie polygons
                shapelyobj = shapelyobj.buffer(0.0)

        # remove repeat points (tolerance=0)
        # (and optionally smooth out complex shapes, tolerance >= 1)
        shapelyobj = shapelyobj.simplify(tolerance)
            
        # if still invalid, do not add to output
        if not shapelyobj.is_valid:
            continue

        # write to file
        geoj = shapely2geoj(shapelyobj)
        outfile.add_feature(feat.row, geoj)

    return outfile
Ejemplo n.º 3
0
def vector_spatialjoin(data1, data2, joincondition, radius=None):
    """Possible joinconditions:
        intersects, within, contains, crosses, touches, equals
       Also:
        distance
    """
    # create spatial index
    if not hasattr(data1, "spindex"): data1.create_spatial_index()
    if not hasattr(data2, "spindex"): data2.create_spatial_index()
    # create new
    new = GeoTable()
    new.fields = list(data1.fields)
    new.fields.extend(data2.fields)
    # intersect each feat in first with all others
    if joincondition in ("distance", ):
        new.fields.append("DISTANCE")
        if joincondition == "distance" and radius is None:
            raise Exception("radius arg must be set when using distance mode")
        maxnum = 9223372036854775807
        for feat in data1.quick_nearest(data2.bbox, n=maxnum):
            geom = geoj2shapely(feat.geometry)
            matchtest = getattr(geom, "distance")
            for otherfeat in data2.quick_nearest(feat.bbox, n=maxnum):
                othergeom = geoj2shapely(otherfeat.geometry)
                match = matchtest(othergeom)
                if match <= radius:
                    joined = list(feat.row)
                    joined.extend(otherfeat.row)
                    joined.append(match)
                    print "match", match
                    new.add_feature(joined, feat.geometry)
    else:
        for feat in data1.quick_overlap(data2.bbox):
            geom = geoj2shapely(feat.geometry)
            matchtest = getattr(geom, joincondition)
            for otherfeat in data2.quick_overlap(feat.bbox):
                othergeom = geoj2shapely(otherfeat.geometry)
                match = matchtest(othergeom)
                if match:
                    joined = list(feat.row)
                    joined.extend(otherfeat.row)
                    print "match", len(joined)
                    new.add_feature(joined, feat.geometry)

    return new
Ejemplo n.º 4
0
def vector_spatialjoin(data1, data2, joincondition, radius=None):
    """Possible joinconditions:
        intersects, within, contains, crosses, touches, equals
       Also:
        distance
    """
    # create spatial index
    if not hasattr(data1, "spindex"): data1.create_spatial_index()
    if not hasattr(data2, "spindex"): data2.create_spatial_index()
    # create new
    new = GeoTable()
    new.fields = list(data1.fields)
    new.fields.extend(data2.fields)
    # intersect each feat in first with all others
    if joincondition in ("distance",):
        new.fields.append("DISTANCE")
        if joincondition == "distance" and radius is None: raise Exception("radius arg must be set when using distance mode")
        maxnum = 9223372036854775807
        for feat in data1.quick_nearest(data2.bbox, n=maxnum):
            geom = geoj2shapely(feat.geometry)
            matchtest = getattr(geom, "distance")
            for otherfeat in data2.quick_nearest(feat.bbox, n=maxnum):
                othergeom = geoj2shapely(otherfeat.geometry)
                match = matchtest(othergeom)
                if match <= radius:
                    joined = list(feat.row)
                    joined.extend(otherfeat.row)
                    joined.append(match)
                    print "match", match
                    new.add_feature(joined, feat.geometry)
    else:
        for feat in data1.quick_overlap(data2.bbox):
            geom = geoj2shapely(feat.geometry)
            matchtest = getattr(geom, joincondition)
            for otherfeat in data2.quick_overlap(feat.bbox):
                othergeom = geoj2shapely(otherfeat.geometry)
                match = matchtest(othergeom)
                if match:
                    joined = list(feat.row)
                    joined.extend(otherfeat.row)
                    print "match", len(joined)
                    new.add_feature(joined, feat.geometry)

    return new
Ejemplo n.º 5
0
def _to_centroids(data):
    """create one centroid point for each multi geometry part"""
    
    # create new file
    outfile = GeoTable()
    outfile.fields = list(data.fields)
    
    # loop features
    for feat in data:
        if feat.geometry["type"] != "Point":
            shapelypoint = geoj2shapely(feat.geometry).centroid
            geoj = shapely2geoj(shapelypoint)
            outfile.add_feature(feat.row, geoj)
    return outfile
Ejemplo n.º 6
0
def vector_buffer(data, dist_expression):
    # buffer and change each geojson dict in-place
    new = GeoTable()
    new.fields = list(data.fields)
    for feat in data:
        geom = geoj2shapely(feat.geometry)
        dist = eval(dist_expression)
        buffered = geom.buffer(dist)
        if not buffered.is_empty:
            geoj = shapely2geoj(buffered)
            geoj["type"] = buffered.type
            new.add_feature(feat.row, geoj)
    # change data type to polygon
    new.type = "Polygon"
    return new
Ejemplo n.º 7
0
def vector_buffer(data, dist_expression):
    # buffer and change each geojson dict in-place
    new = GeoTable()
    new.fields = list(data.fields)
    for feat in data:
        geom = geoj2shapely(feat.geometry)
        dist = eval(dist_expression)
        buffered = geom.buffer(dist)
        if not buffered.is_empty:
            geoj = shapely2geoj(buffered)
            geoj["type"] = buffered.type
            new.add_feature(feat.row, geoj)
    # change data type to polygon
    new.type = "Polygon"
    return new
Ejemplo n.º 8
0
def _to_multicentroids(data):
    """create multiple centroid points for each multi geometry part"""
    
    # create new file
    outfile = GeoTable()
    outfile.fields = list(data.fields)
    
    # loop features
    if "LineString" in data.type or "Polygon" in data.type:
        for feat in data:
            if "Multi" in feat.geometry["type"]:
                multishape = geoj2shapely(feat.geometry)
                for geom in multishape.geoms:
                    shapelypoint = geom.centroid
                    geoj = shapely2geoj(shapelypoint)
                    outfile.add_feature(feat.row, geoj)
            else:
                shapelypoint = geoj2shapely(feat.geometry).centroid
                geoj = shapely2geoj(shapelypoint)
                outfile.add_feature(feat.row, geoj)
        return outfile
    
    else:
        return data.copy()
Ejemplo n.º 9
0
def overlap_summary(groupbydata, valuedata, fieldmapping=[]):
    # prep
    data1, data2 = groupbydata, valuedata
    if fieldmapping: aggfields, aggtypes = zip(*fieldmapping)
    aggfunctions = dict([("count", len), ("sum", sum), ("max", max),
                         ("min", min),
                         ("average", lambda seq: sum(seq) / float(len(seq)))])

    # create spatial index
    if not hasattr(data1, "spindex"): data1.create_spatial_index()
    if not hasattr(data2, "spindex"): data2.create_spatial_index()

    # create new
    new = GeoTable()
    new.fields = list(data1.fields)
    if fieldmapping:
        for aggfield, aggtype in fieldmapping:
            new.fields.append(aggfield)

    # for each groupby feature
    for i, feat in enumerate(data1.quick_overlap(data2.bbox)):
        geom = geoj2shapely(feat.geometry)
        geom = supershapely(geom)
        matches = []

        # get all value features that intersect
        for otherfeat in data2.quick_overlap(feat.bbox):
            othergeom = geoj2shapely(otherfeat.geometry)
            if geom.intersects(othergeom):
                matches.append(otherfeat)

        # make newrow from original row
        newrow = list(feat.row)

        # if any matches
        if matches:

            def make_number(value):
                try:
                    return float(value)
                except:
                    return None

            # add summary values to newrow based on fieldmapping
            for aggfield, aggtype in fieldmapping:
                values = [otherfeat[aggfield] for otherfeat in matches]
                if aggtype in ("sum", "max", "min", "average"):
                    # only consider number values if numeric stats
                    values = [
                        make_number(value) for value in values
                        if make_number(value) != None
                    ]
                aggregatefunc = aggfunctions[aggtype]
                summaryvalue = aggregatefunc(values)
                newrow.append(summaryvalue)

        # otherwise, add empty values
        else:
            newrow.extend(("" for _ in fieldmapping))

        # write feature to output
        new.add_feature(newrow, feat.geometry)

    return new
Ejemplo n.º 10
0
def vector_to_polygons(data, polytype="convex hull"):
    # create new file
    outfile = GeoTable()
    outfile.fields = list(data.fields)
        
    if polytype == "convex hull":
        for feat in data:
            shapelygeom = geoj2shapely(feat.geometry)
            convex = shapelygeom.convex_hull
            geoj = shapely2geoj(convex)
            # sometimes the convex hull is only a line or point
            # but we cannot mix shapetypes, so exclude those
            if geoj["type"] == "Polygon":
                outfile.add_feature(feat.row, geoj)
            
        return outfile

    elif polytype == "delauney triangles":
        if "Point" in data.type:
            def get_flattened_points():
                for feat in data:
                    if "Multi" in feat.geometry["type"]:
                        for point in feat.geometry["coordinates"]:
                            yield point
                    else: yield feat.geometry["coordinates"]
            triangles = pytess.triangulate(get_flattened_points())
            # triangle polygons are between multiple existing points,
            # so do not inherit any attributes
            for tri in triangles:
                geoj = {"type": "Polygon",
                        "coordinates": [tri] }
                row = ["" for field in outfile.fields]
                outfile.add_feature(row, geoj)

            return outfile

        else:
            raise Exception("Delauney triangles can only be made from point data")

    elif polytype == "voronoi polygons":
        if "Point" in data.type:
            def get_flattened_points():
                for feat in data:
                    if "Multi" in feat.geometry["type"]:
                        for point in feat.geometry["coordinates"]:
                            yield point
                    else: yield feat.geometry["coordinates"]
            results = pytess.voronoi(get_flattened_points())
            # return new file with polygon geometries
            for midpoint,polygon in results:
                geoj = {"type": "Polygon",
                        "coordinates": [polygon] }
                row = ["" for field in outfile.fields]
                outfile.add_feature(row, geoj)

            return outfile

        else:
            raise Exception("Voronoi polygons can only be made from point data")

    elif polytype == "enclose lines":
        if "LineString" in data.type:
            shapelylines = (geoj2shapely(feat.geometry) for feat in data)
            for polygon in shapely.ops.polygonize(shapelylines):
                geoj = shapely2geoj(polygon)
                row = ["" for field in outfile.fields]
                outfile.add_feature(row, geoj)

            return outfile
        
        else:
            raise Exception("Enclose lines can only be done on line data")