Example #1
0
def break_lines_on_points(lineShp, pointShp, lineIdInPntShp,
                         splitedShp, srsEpsgCode):
    """
    Break lines on points location
    
    The points should be contained by the lines;
    The points table should have a column with the id of the
    line that contains the point.
    """
    
    from shapely.ops      import split
    from shapely.geometry import Point, LineString
    from gasp.fm          import tbl_to_obj
    from gasp.mng.df      import col_list_val_to_row
    from gasp.to.obj      import dict_to_df
    from gasp.to.shp      import df_to_shp
    
    # Sanitize line geometry
    def fix_line(line, point):
        buff = point.buffer(0.0001)
        
        splitLine = split(line, buff)
        
        nline = LineString(
            list(splitLine[0].coords) + list(point.coords) +
            list(splitLine[-1].coords)
        )
        
        return nline
    
    pnts  = tbl_to_obj(pointShp, fields='ALL', output='array')
    lines = tbl_to_obj(lineShp, fields='ALL', output='dict')
    
    for point in pnts:
        rel_line = lines[point[lineIdInPntShp]]
        
        if type(rel_line["GEOM"]) != list:
            line_geom = fix_line(rel_line["GEOM"], point["GEOM"])
            
            split_lines = split(line_geom, point["GEOM"])
            
            lines[point[lineIdInPntShp]]["GEOM"] = [l for l in split_lines]
        
        else:
            for i in range(len(rel_line["GEOM"])):
                if rel_line["GEOM"][i].distance(point["GEOM"]) < 1e-8:
                    line_geom = fix_line(rel_line["GEOM"][i], point["GEOM"])
                    split_lines = split(line_geom, point["GEOM"])
                    split_lines = [l for l in split_lines]
                    
                    lines[point[lineIdInPntShp]]["GEOM"][i] = split_lines[0]
                    lines[point[lineIdInPntShp]]["GEOM"] += split_lines[1:]
                    
                    break
                
                else:
                    continue
    
    # Result to Dataframe
    linesDf = dict_to_df(lines)
    
    # Where GEOM is a List, create a new row for each element in list
    linesDf = col_list_val_to_row(
        linesDf, "GEOM", geomCol="GEOM", epsg=srsEpsgCode
    )
    
    # Save result
    return df_to_shp(linesDf, splitedShp)
Example #2
0
def shp_from_address(inTbl, idAddr, addrCol, outShp,
                     epsg_out=4326, sheet_name=None,
                     doorNumber=None, zip4=None, zip3=None,
                     city=None, language=None, useComponents=None,
                     country=None):
    """
    Receive a table with a list of addresses and use the Google Maps API
    to get their position
    
    Preferred Address Structure:
    Rua+dos+Combatentes+da+Grande+Guerra,+14,+3030-185,+Coimbra
    
    Table Structure:
    idAddr | addrCol | doorNumber | zip4 | zip3 | city
    idAddr field and address field are demandatory
    
    For now, The input table must be a excel file or a dbf table
    
    # TODO: Some of the rows could not have Geometry
    """
    
    from gasp.web.glg.geocod import get_position
    from gasp.fm             import tbl_to_obj
    from gasp.to.geom        import pnt_dfwxy_to_geodf
    from gasp.oss            import get_fileformat
    from gasp.mng.fld.df     import fld_types
    from gasp.to.obj         import df_to_dict, dict_to_df
    from gasp.to.shp         import df_to_shp
    
    # Get Addresses
    tblFormat = get_fileformat(inTbl)
    
    tblAdr = tbl_to_obj(inTbl, sheet=sheet_name)
    
    # Check if given columns are in table
    fields = [idAddr, addrCol, doorNumber, zip4, zip3, city]
    for f in fields:
        if f:
            if f not in tblAdr.columns.values:
                raise ValueError("{} column not in {}".format(f, inTbl))
    
    # Convert numeric fields to unicode
    colTypes = fld_types(tblAdr)
    for col in colTypes:
        if colTypes[col] != 'object':
            if colTypes[col] == 'float32' or colTypes[col] == 'float64':
                tblAdr[col] = tblAdr[col].astype(int)
            
        tblAdr[col] = tblAdr[col].astype(unicode, 'utf-8')
    
    # Create search field
    if not useComponents:
        if doorNumber and zip4 and zip3 and city:
            tblAdr["search"] = tblAdr[addrCol] + unicode(",", "utf-8") + \
                tblAdr[doorNumber].astype(unicode, "utf-8") + unicode(",", "utf-8") + \
                tblAdr[zip4] + unicode("-", "utf-8") + \
                tblAdr[zip3] + unicode(",", "utf-8") + tblAdr[city]
    
        elif not doorNumber and zip4 and zip3 and city:
            tblAdr["search"] = tblAdr[addrCol] + unicode(",", "utf-8") + \
                tblAdr[zip4] + unicode("-", "utf-8") + \
                tblAdr[zip3] + unicode(",", "utf-8") + tblAdr[city]
    
        elif doorNumber and not zip4 and not zip3 and not city:
            tblAdr["search"] = tblAdr[addrCol] + unicode(",", "utf-8") + \
                tblAdr[doorNumber]
    
        elif not doorNumber and not zip4 and not zip3 and not city:
            tblAdr["search"] = tblAdr[addrCol]
    
        elif doorNumber and zip4 and not zip3 and city:
            tblAdr = tblAdr[addrCol] + unicode(",", "utf-8") + \
                tblAdr[doorNumber] + unicode(",", "utf-8") + \
                tblAdr[zip4] + unicode(",", "utf-8") + tblAdr[city]
    
        elif doorNumber and not zip4 and not zip3 and city:
            tblAdr["search"] = tblAdr[addrCol] + unicode(",", "utf-8") + \
                tblAdr[doorNumber] + unicode(",", "utf-8") + tblAdr[city]
    
        elif not doorNumber and zip4 and not zip3 and city:
            tblAdr["search"] = tblAdr[addrCol] + unicode(",", "utf-8") + \
                tblAdr[city]
    
        elif not doorNumber and zip4 and zip3 and not city:
            tblAdr["search"] = tblAdr[addrCol] + unicode(",", "utf-8") + \
                tblAdr[zip4] + unicode("-", "utf-8") + tblAdr[zip3]
    
        elif doorNumber and zip4 and not zip3 and not city:
            tblAdr["search"] = tblAdr[addrCol] + unicode(",", "utf-8") + \
                tblAdr[doorNumber] + unicode(",", "utf-8") + tblAdr[zip4]
    
        elif doorNumber and zip4 and zip3 and not city:
            tblAdr["search"] = tblAdr[addrCol] + unicode(",", "utf-8") + \
                tblAdr[doorNumber] + unicode(",", "utf-8") + tblAdr[zip4] + \
                unicode("-", "utf-8") + tblAdr[zip3]
    
        elif not doorNumber and zip4 and not zip3 and not city:
            tblAdr["search"] = tblAdr[addrCol] + unicode(",", "utf-8") + \
                tblAdr[zip4]
    
        elif not doorNumber and not zip4 and not zip3 and city:
            tblAdr["search"] = tblAdr[addrCol] + unicode(",", "utf-8") + \
                tblAdr[city]
    
        else:
            raise ValueError('Parameters are not valid')
    
        # Sanitize search string
        tblAdr["search"] = tblAdr.search.str.replace(' ', '+')
    tblAdr = df_to_dict(tblAdr)
    
    # Geocode Addresses
    for idx in tblAdr:
        if not useComponents:
            glg_response = get_position(
                tblAdr[idx]["search"], country=None,
                language=None, locality=None, postal_code=None
            )
        else:
            if zip4 and zip3:
                _postal = u'{}-{}'.format(tblAdr[idx][zip4], tblAdr[idx][zip3])
            
            elif zip4 and not zip3:
                _postal = u'{}'.format(tblAdr[idx][zip4])
            
            else:
                _postal = None
            
            glg_response = get_position(
                u"{}{}".format(
                    tblAdr[idx][addrCol], u",{}".format(
                        tblAdr[idx][doorNumber]
                    ) if doorNumber else u""
                ),
                country=country, language=language,
                locality=tblAdr[idx][city].replace(" ", "+") if city else None,
                postal_code=_postal.replace(" ", "+")
            )
        
        if not glg_response: continue
        
        tblAdr[idx]["x"] = glg_response[0]['geometry']['location']['lng']
        tblAdr[idx]["y"] = glg_response[0]['geometry']['location']['lat']
        
        tblAdr[idx]["G_ADRS"] = glg_response[0]["formatted_address"]
        
        for i in glg_response[0]["address_components"]:
            if   i["types"][0] == 'street_number' : F = "G_PORT"
            elif i["types"][0] == 'route'         : F = "G_STREET"
            elif i["types"][0] == 'postal_code'   : F = "G_ZIPCODE"
            else: continue
            
            tblAdr[idx][F] = i["long_name"]
    
    # Convert Dataframe to GeoDataframe
    geoAdr = pnt_dfwxy_to_geodf(dict_to_df(tblAdr), "x", "y", 4326)
    
    # Reproject if user wants it
    if epsg_out != 4326:
        from gasp.mng.prj import project
        geoAdr = project(geoAdr, None, epsg_out, gisApi='pandas')
    
    # To Shapefile
    df_to_shp(geoAdr, outShp)
    
    return geoAdr
Example #3
0
File: dmx.py Project: zonakre/gasp
def pnt_to_facility(pnt, pntSrs, facilities, facSrs, transMode="driving"):
    """
    Calculate distance between points and the nearest facility.
    
    # TODO: Add the possibility to save the path between origins and
    destinations
    """

    import os
    import time
    from gasp.fm import tbl_to_obj
    from gasp.to.geom import regulardf_to_geodf
    from gasp.mng.prj import project_df
    from gasp.prop.feat import get_geom_type
    from gasp.oss import get_filename
    from gasp.to.obj import df_to_dict, dict_to_df
    from gasp.to.shp import df_to_shp
    from gasp.web.glg.distmx import dist_matrix

    # Convert SHPs to GeoDataFrame
    pntDf = tbl_to_obj(pnt)
    tbl_to_obj(facilities)

    # Check if SHPs are points
    originsGeom = get_geom_type(pntDf, geomCol="geometry", gisApi='pandas')
    if originsGeom != 'Point' and originsGeom != 'MultiPoint':
        raise ValueError('All input geometry must be of type point')

    destGeom = get_geom_type(facil, geomCol="geometry", gisApi='pandas')
    if destGeom != 'Point' and destGeom != 'MultiPoint':
        raise ValueError('All input geometry must be of type point')

    # Re-Project if necessary
    pntDf = pntDf if pntSrs == 4326 else project(
        pntDf, None, 4326, gisApi='pandas')
    facil = facil if facSrs == 4326 else project(
        facil, None, 4326, gisApi='pandas')

    # Coords to cols as str
    pntDf["geom"] = pntDf["geometry"].y.astype(str) + "," + \
        pntDf["geometry"].x.astype(str)

    facil["geom"] = facil["geometry"].y.astype(str) + "," + \
        facil["geometry"].y.astype(str)

    # Get distance between points and nearest facility
    pntDict = df_to_dict(pntDf)

    for idx in pntDict:
        destStr = str(facil["geom"].str.cat(sep="|"))

        glg_resp = dist_matrix(pntDict[idx]["geom"],
                               destStr,
                               1,
                               int(facil.shape[0]),
                               transport_mode=transMode)

        matrix = pandas.DataFrame(glg_resp[0]["elements"])

        matrix.drop(["status", "distance"], axis=1, inplace=True)
        matrix = pandas.concat([
            matrix.drop(["duration"], axis=1), matrix["duration"].apply(
                pandas.Series)
        ],
                               axis=1)

        matrix.drop("text", axis=1, inplace=True)
        matrix.rename(columns={"value": "duration"}, inplace=True)

        pntDict[idx]["duration"] = matrix.duration.min() / 60.0

    pntDf = dict_to_df(pntDict)
    pntDf = regulardf_to_geodf(pntDf, "geometry", 4326)

    if pntSrs != 4326:
        pntDf = project(pntDf, None, pntSrs, gisApi='pandas')

    df_to_shp(
        pntDf,
        os.path.join(os.path.dirname(pnt),
                     "{}_{}.shp".format(get_filename(pnt), "result")))

    return pntDf
Example #4
0
def address_from_featcls(inShp, outShp, epsg_in):
    """
    Read a point geometry and return a table with the addresses
    """
    
    from gasp.web.glg.geocod import get_address
    from gasp.fm             import tbl_to_obj
    from gasp.to.geom        import regulardf_to_geodf
    from gasp.fm.geom        import pointxy_to_cols
    from gasp.prop.feat      import get_geom_type
    from gasp.to.obj         import df_to_dict, dict_to_df
    from gasp.to.shp         import df_to_shp
    
    # Convert ESRI Shapefile to GeoDataFrame
    geoDf = tbl_to_obj(inShp)
    
    # Get Geometry field name
    for col in geoDf.columns.values:
        if col == 'geom' or col ==  'geometry':
            F_GEOM = col
            break
        else:
            continue
    
    # Check if inShp has a Geom of Type Point
    inGeomType = get_geom_type(geoDf, geomCol=F_GEOM, gisApi='pandas')
    
    if inGeomType != 'Point' and inGeomType != 'MultiPoint':
        raise ValueError('The input geometry must be of type point')
    
    # Reproject geodf if necessary
    if epsg_in != 4326:
        from gasp.mng.prj import project
        
        geoDf = project(geoDf, None, 4326, gisApi='pandas')
    
    # Get Coords of each point
    geoDf = pointxy_to_cols(geoDf, F_GEOM, colX="x", colY='y')
    
    # Search for addresses
    geoDict = df_to_dict(geoDf)
    for idx in geoDict:
        glg_response = get_address(geoDict[idx]["y"], geoDict[idx]["x"])
        
        geoDict[idx]["G_ADDRESS"] = glg_response[0]['formatted_address']
        
        for i in glg_response[0]["address_components"]:
            if   i["types"][0] == 'street_mumber' : F = "G_PORT"
            elif i["types"][0] == 'route'         : F = "G_STREET"
            elif i["types"][0] == 'postal_code'   : F = "G_ZIPCODE"
            else: continue
            
            geoDict[idx][F] = i["long_name"]
    
    # Save results in a new file
    geoDf = dict_to_df(geoDict)
    geoDf = regulardf_to_geodf(geoDf, F_GEOM, 4326)
    
    geoDf.drop(["x", "y"], axis=1, inplace=True)
    
    if epsg_in != 4326:
        geoDf = project(geoDf, None, epsg_in, gisApi='pandas')
    
    df_to_shp(geoDf, outShp)
    
    return geoDf
Example #5
0
def dist_onedest_network(pntShp, pntRouteId, networkShp, netRouteId, netOrder,
                         netDuration, srs, output):
    """
    Imagine-se uma rede cujos arcos levam a um unico destino
    Este programa calcula a distancia entre um ponto e esse destino
    em duas fases:
    * calculo da distancia ao ponto de entrada na rede mais proximo;
    * distancia entre essa entrada o destino da rede.
    
    A rede e composta por circuitos, e suposto partir-se de um ponto,
    entrar num circuito e nunca sair dele ate ao destino. O circuito
    associado a cada ponto deve constar na tabela dos pontos.
    """

    import pandas
    import time
    from geopandas import GeoDataFrame
    from gasp.fm import tbl_to_obj
    from gasp.web.glg.direct import pnt_to_pnt_duration
    from gasp.to.geom import regulardf_to_geodf, pnt_dfwxy_to_geodf
    from gasp.mng.df import df_groupBy
    from gasp.mng.prj import project
    from gasp.fm.geom import geom_endpoints_to_cols, pointxy_to_cols
    from gasp.mng.fld.df import distinct_of_distinct
    from gasp.to.obj import df_to_dict, dict_to_df
    from gasp.to.shp import df_to_shp

    netDataFrame = tbl_to_obj(networkShp)
    pntDataFrame = tbl_to_obj(pntShp)

    # Get entrance nodes
    netDataFrame = geom_endpoints_to_cols(netDataFrame, geomCol="geometry")
    geoEntrances = pnt_dfwxy_to_geodf(netDataFrame, "start_x", "start_y", srs)

    # To WGS
    if srs != 4326:
        geoEntrances = project(geoEntrances, None, 4326, gisApi='pandas')
        pntDataFrame = project(pntDataFrame, None, 4326, gisApi='pandas')

    # Get entrances by circuit
    routesEntrances = distinct_of_distinct(geoEntrances, netRouteId, netOrder)

    pntRelStops = pntDataFrame.merge(geoEntrances,
                                     how='inner',
                                     left_on=pntRouteId,
                                     right_on=netRouteId)

    pntRelStops = pointxy_to_cols(pntRelStops,
                                  geomCol="geometry",
                                  colX="start_x",
                                  colY="start_y")
    pntRelStops = pointxy_to_cols(pntRelStops,
                                  geomCol="geometry",
                                  colX="node_x",
                                  colY="node_y")

    pntRelStopsDict = df_to_dict(pntRelStops)

    for idx in pntRelStopsDict:
        ape = pnt_to_pnt_duration(pntRelStopsDict[idx]["start_y"],
                                  pntRelStopsDict[idx]["start_x"],
                                  pntRelStopsDict[idx]["node_y"],
                                  pntRelStopsDict[idx]["node_x"],
                                  mode="walking")

        time.sleep(5)

        pntRelStopsDict[idx]["gduration"] = ape

    pntRelStops = dict_to_df(pntRelStopsDict)

    pntRelStops_gp = df_groupBy(
        pntRelStops,
        [x for x in list(pntDataFrame.columns.values) if x != "geometry"],
        STAT='MIN',
        STAT_FIELD="gduration")

    pntRelStops_gp = pntRelStops_gp.merge(
        pntRelStops,
        how='inner',
        left_on=list(pntRelStops_gp.columns.values),
        right_on=list(pntRelStops_gp.columns.values))

    final_time = []
    for idx, row in pntRelStops_gp.iterrows():
        circ = row[pntRouteId]
        order = row[netOrder]

        for i in range(len(routesEntrances[circ])):
            if order == routesEntrances[circ][i]:
                checkpoints = routesEntrances[circ][i:]

            else:
                continue

        timedistance = []
        for check in checkpoints:
            val = int(netDataFrame.loc[(netDataFrame[netRouteId] == circ) &
                                       (netDataFrame[netOrder] == check),
                                       [netDuration]][netDuration])

            timedistance.append(val)

        final_time.append(row["gduration"] + sum(timedistance))

    pntRelStops_gp["final_time"] = pandas.Series(final_time)

    # Save result
    pntRelStops_gp.drop(["geometry_y"], axis=1, inplace=True)

    gd = regulardf_to_geodf(pntRelStops_gp, "geometry_x", 4326)

    if srs != 4326:
        gd = project(gd, None, srs, gisApi='pandas')

    df_to_shp(gd, output)

    return output