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)
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
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
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
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