def photos_to_shp(buffer_shp, epsg_in, outshp, keyword=None, epsg_out=4326, apikey=None, onlyInsideInput=True): """ Search for data in Flickr and return a Shapefile with the data. """ from gasp.to.shp import df_to_shp photos = photos_location(buffer_shp, epsg_in, keyword=keyword, epsg_out=epsg_out, keyToUse=apikey, onlySearchAreaContained=onlyInsideInput) try: if not photos: return 0 except: pass df_to_shp(photos, outshp) return outshp
def orig_dest_to_polyline(srcPoints, srcField, destPoints, destField, outShp): """ Connect origins to destinations with a polyline which length is the minimum distance between the origin related with a specific destination. One origin should be related with one destination. These relations should be expressed in srcField and destField """ from geopandas import GeoDataFrame from shapely.geometry import LineString from gasp.fm import tbl_to_obj from gasp.to.shp import df_to_shp srcPnt = tbl_to_obj(srcPoints) desPnt = tbl_to_obj(destPoints) joinDf = srcPnt.merge(destPnt, how='inner', left_on=srcField, right_on=destField) joinDf["geometry"] = joinDf.apply( lambda x: LineString(x["geometry_x"], x["geometry_y"]), axis=1) joinDf.drop(["geometry_x", "geometry_y"], axis=1, inplace=True) a = GeoDataFrame(joinDf) df_to_shp(joinDf, outShp) return outShp
def tweets_to_shp(buffer_shp, epsg_in, outshp, keyword=None, epsg_out=4326, __encoding__='plain_str', keyAPI=None): """ Search data in Twitter and create a vectorial file with that data """ from gasp.to.shp import df_to_shp tweets = geotweets_location(buffer_shp, epsg_in, keyword=keyword, epsg_out=epsg_out, keyToUse=keyAPI, onlySearchAreaContained=None) try: if not tweets: return 0 except: pass df_to_shp(tweets, outshp) return outshp
def find_places(inShp, epsg, radius, output, keyword=None, type=None): """ Extract places from Google Maps """ import pandas import time from gasp.fm import tbl_to_obj from gasp.to.geom import pnt_dfwxy_to_geodf from gasp.mng.prj import project from gasp.mng.fld.df import listval_to_newcols from gasp.to.shp import df_to_shp pntDf = tbl_to_obj(inShp) pntDf = project(pntDf, None, 4326, gisApi='pandas') if epsg != 4326 else pntDf pntDf['latitude'] = pntDf.geometry.y.astype(str) pntDf['longitude'] = pntDf.geometry.x.astype(str) DATA = 1 def get_places(row): places = get_places_by_radius(row.latitude, row.longitude, radius, keyword, type) if type(DATA) == int: DATA = pandas.DataFrame(places['results']) else: DATA = DATA.append(pandas.DataFrame(places['results']), ignore_index=True) a = pntDf.apply(lambda x: get_places(x), axis=1) DATA = listval_to_newcols(DATA, 'geometry') fldsToDelete = ['viewport', 'opening_hours', 'icon', 'plus_code', 'photos'] realDeletion = [x for x in fldsToDelete if x in DATA.columns.values] DATA.drop(realDeletion, axis=1, inplace=True) DATA = listval_to_newcols(DATA, 'location') DATA = pnt_dfwxy_to_geodf(DATA, 'lng', 'lat', 4326) if epsg != 4326: DATA = project(DATA, None, epsg, gisApi='pandas') DATA["types"] = DATA.types.astype(str) df_to_shp(DATA, output) return output
def join_bgrishp_with_bgridata(bgriShp, bgriCsv, outShp, shpJoinField="BGRI11", dataJoinField="GEO_COD", joinFieldsMantain=None, newNames=None): """ Join BGRI ESRI Shapefile with the CSV with the BGRI Data """ from gasp import goToList from gasp.fm import tbl_to_obj from gasp.to.shp import df_to_shp # Read main_table mainDf = tbl_to_obj(bgriShp) # Read join table joinDf = tbl_to_obj(bgriCsv, _delimiter=';', encoding_='utf-8') # Sanitize GEO_COD of bgriCsv joinDf[dataJoinField] = joinDf[dataJoinField].str.replace("'", "") if joinFieldsMantain: joinFieldsMantain = goToList(joinFieldsMantain) dropCols = [] for col in joinDf.columns.values: if col not in [dataJoinField] + joinFieldsMantain: dropCols.append(col) joinDf.drop(dropCols, axis=1, inplace=True) resultDf = mainDf.merge(joinDf, how='inner', left_on=shpJoinField, right_on=dataJoinField) if newNames: newNames = goToList(newNames) renDict = { joinFieldsMantain[n]: newNames[n] for n in range(len(joinFieldsMantain)) } resultDf.rename(columns=renDict, inplace=True) df_to_shp(resultDf, outShp) return outShp
def intersection(inShp, intersectShp, outShp, api='geopandas'): """ Intersection between ESRI Shapefile 'API's Available: * geopandas * saga; * pygrass """ if api == 'geopandas': import geopandas from gasp.fm import tbl_to_obj from gasp.to.shp import df_to_shp dfShp = tbl_to_obj(inShp) dfIntersect = tbl_to_obj(intersectShp) res_interse = geopandas.overlay(dfShp, dfIntersect, how='intersection') df_to_shp(res_interse, outShp) elif api == 'saga': from gasp import exec_cmd cmdout = exec_cmd( ("saga_cmd shapes_polygons 14 -A {} -B {} -RESULT {} -SPLIT 1" ).format(inShp, intersectShp, outShp)) elif api == 'pygrass': from grass.pygrass.modules import Module clip = Module("v.overlay", ainput=inShp, atype="area", binput=intersectShp, btype="area", operator="and", output=outShp, overwrite=True, run_=False, quiet=True) clip() else: raise ValueError("{} is not available!".format(api)) return outShp
def merge_feat(shps, outShp, api="ogr2ogr"): """ Get all features in several Shapefiles and save them in one file """ if api == "ogr2ogr": from gasp import exec_cmd from gasp.prop.ff import drv_name out_drv = drv_name(outShp) # Create output and copy some features of one layer (first in shps) cmdout = exec_cmd('ogr2ogr -f "{}" {} {}'.format( out_drv, outShp, shps[0] )) # Append remaining layers lcmd = [exec_cmd( 'ogr2ogr -f "{}" -update -append {} {}'.format( out_drv, outShp, shps[i] ) ) for i in range(1, len(shps))] elif api == 'pandas': """ Merge SHP using pandas """ from gasp.fm import tbl_to_obj from gasp.to.shp import df_to_shp if type(shps) != list: raise ValueError('shps should be a list with paths for Feature Classes') dfs = [tbl_to_obj(shp) for shp in shps] result = dfs[0] for df in dfs[1:]: result = result.append(df, ignore_index=True, sort=True) df_to_shp(result, outShp) else: raise ValueError( "{} API is not available" ) return outShp
def split_shp_by_attr(inShp, attr, outDir, _format='.shp'): """ Create a new shapefile for each value in a column """ import os from gasp.fm import shp_to_df from gasp.oss import get_filename from gasp.mng.fld.df import col_distinct from gasp.to.shp import df_to_shp # Sanitize format FFF = _format if _format[0] == '.' else '.' + _format # SHP TO DF dataDf = tbl_to_obj(inShp) # Get values in attr uniqueAttr = col_distinct(dataDf, attr) # Export Features with the same value in attr to a new File BASENAME = get_filename(inShp, forceLower=True) SHPS_RESULT = {} i = 1 for val in uniqueAttr: df = dataDf[dataDf[attr] == val] newShp = df_to_shp( df, os.path.join(outDir, "{}_{}{}".format(BASENAME, str(i), FFF))) SHPS_RESULT[val] = newShp i += 1 return SHPS_RESULT
def path_from_coords_to_shp(latOrigin, lngOrigin, latDest, lngDest, outshp, transmod='foot-walking', outepsg=4326): """ Receive coords and get path. Save path as Feature Class """ import pandas from gasp.web.orouteserv import directions from gasp.to.geom import regulardf_to_geodf, json_obj_to_geodf from gasp.to.shp import df_to_shp path = directions( latOrigin, lngOrigin, latDest, lngDest, modeTransportation=transmod ) geodf = json_obj_to_geodf(path, 4326) geodf.drop(['segments', 'bbox', 'way_points'], axis=1, inplace=True) geodf["summary"] = geodf['summary'][0] geodf = pandas.concat([ geodf.drop(['summary'], axis=1), geodf['summary'].apply(pandas.Series) ], axis=1) geodf = regulardf_to_geodf(geodf, "geometry", 4326) if outepsg != 4326: from gasp.mng.prj import project geodf = project(geodf, None, outepsg, gisApi='pandas') return df_to_shp(geodf, outshp)
def geodf_buffer_to_shp(geoDf, dist, outfile, colgeom='geometry'): """ Execute the Buffer Function of GeoPandas and export the result to a new shp """ from gasp.to.shp import df_to_shp __geoDf = geoDf.copy() __geoDf["buffer_geom"] = __geoDf[colgeom].buffer(dist, resolution=16) __geoDf.drop(colgeom, axis=1, inplace=True) __geoDf.rename(columns={"buffer_geom": colgeom}, inplace=True) df_to_shp(__geoDf, outfile) return outfile
def pointXls_to_shp(xlsFile, outShp, x_col, y_col, epsg, sheet=None): """ Excel table with Point information to ESRI Shapefile """ from gasp.fm import tbl_to_obj from gasp.to.geom import pnt_dfwxy_to_geodf from gasp.to.shp import df_to_shp # XLS TO PANDAS DATAFRAME dataDf = tbl_to_obj(xlsFile, sheet=sheet) # DATAFRAME TO GEO DATAFRAME geoDataDf = pnt_dfwxy_to_geodf(dataDf, x_col, y_col, epsg) # GEODATAFRAME TO ESRI SHAPEFILE df_to_shp(geoDataDf, outShp) return outShp
def places_to_shp(searchArea, epsgIn, epsgOut, outShp, keyword_=None, onlySearchArea=True): """ Get Locations From Facebook and Write data in a Vetorial File """ from gasp.to.shp import df_to_shp places = places_by_query( searchArea, epsgIn, keyword=keyword_, epsgOut=epsgOut, onlySearchAreaContained=onlySearchArea ) try: if not places: return 0 except: pass df_to_shp(places, outShp) return outShp
def pnd_dissolve(shp, field, outShp): """ Dissolve using GeoPandas """ from gasp.fm import tbl_to_obj from gasp.to.shp import df_to_shp df = tbl_to_obj(shp) dissDf = df.dissolve(by=field) return df_to_shp(df, outShp)
def psql_to_shp(conParam, table, outshp, api='pandas', epsg=None, geom_col='geom', tableIsQuery=None): """ PostgreSQL table to ESRI Shapefile using Pandas or PGSQL2SHP """ if api == 'pandas': from gasp.fm.sql import psql_to_geodf from gasp.to.shp import df_to_shp q = "SELECT * FROM {}".format(table) if not tableIsQuery else table df = psql_to_geodf(conParam, q, geomCol=geom_col, epsg=epsg) outsh = df_to_shp(df, outshp) elif api == 'pgsql2shp': from gasp import exec_cmd cmd = ('pgsql2shp -f {out} -h {hst} -u {usr} -p {pt} -P {pas}{geom} ' '{bd} {t}').format( hst=conParam['HOST'], usr=conParam['USER'], pt=conParam['PORT'], pas=conParam['PASSWORD'], bd=conParam['DATABASE'], t=table if not tableIsQuery else '"{}"'.format(table), out=outshp, geom="" if not geom_col else " -g {}".format(geom_col)) outcmd = exec_cmd(cmd) else: raise ValueError('api value must be \'pandas\' or \'pgsql2shp\'') return outshp
def same_attr_to_shp(inShps, interestCol, outFolder, basename="data_", resultDict=None): """ For several SHPS with the same field, this program will list all values in such field and will create a new shp for all values with the respective geometry regardeless the origin shp. """ import os from gasp import goToList from gasp.fm import tbl_to_obj from gasp.mng.gen import merge_df from gasp.to.shp import df_to_shp EXT = os.path.splitext(inShps[0])[1] shpDfs = [tbl_to_obj(shp) for shp in inShps] DF = merge_df(shpDfs, ignIndex=True) #DF.dropna(axis=0, how='any', inplace=True) uniqueVal = DF[interestCol].unique() nShps = [] if not resultDict else {} for val in uniqueVal: ndf = DF[DF[interestCol] == val] KEY = str(val).split('.')[0] if '.' in str(val) else str(val) nshp = df_to_shp(ndf, os.path.join( outFolder, '{}{}{}'.format(basename, KEY, EXT) )) if not resultDict: nShps.append(nshp) else: nShps[KEY] = nshp return nShps
def df_buffer_extent(inShp, inEpsg, meterTolerance, outShp): """ For all geometries, calculate the boundary given by the sum between the feature extent and the Tolerance variable """ from shapely.geometry import Polygon from geopandas import GeoDataFrame from gasp.fm import tbl_to_obj from gasp.to.shp import df_to_shp inDf = tbl_to_obj(inShp) inDf = df_add_ext(inDf, "geometry") inDf['minx'] = inDf.minx - meterTolerance inDf['miny'] = inDf.miny - meterTolerance inDf['maxx'] = inDf.maxx + meterTolerance inDf['maxy'] = inDf.maxy + meterTolerance # Produce new geometries geoms = [ Polygon([[ext[0], ext[3]], [ext[1], ext[3]], [ext[1], ext[2]], [ext[0], ext[2]], [ext[0], ext[3]]]) for ext in zip(inDf.minx, inDf.maxx, inDf.miny, inDf.maxy) ] inDf.drop(['minx', 'miny', 'maxx', 'maxy', 'geometry'], axis=1, inplace=True) result = GeoDataFrame(inDf, crs={'init': 'epsg:{}'.format(inEpsg)}, geometry=geoms) return df_to_shp(inDf, outShp)
def matrix_od(originsShp, destinationShp, originsEpsg, destinationEpsg, resultShp, modeTrans="driving"): """ Use Pandas to Retrieve data from MapBox Matrix OD Service """ import time from threading import Thread from gasp.web.mapbx import get_keys, matrix from gasp.fm import tbl_to_obj from gasp.mng.split import split_df, split_df_inN from gasp.mng.fld.df import listval_to_newcols from gasp.fm.geom import pointxy_to_cols from gasp.mng.prj import project from gasp.mng.gen import merge_df from gasp.prop.feat import get_geom_type from gasp.to.shp import df_to_shp # Data to GeoDataFrame origens = tbl_to_obj( originsShp) destinos = tbl_to_obj(destinationShp) # Check if SHPs are points inGeomType = get_geom_type(origens, geomCol="geometry", gisApi='pandas') if inGeomType != 'Point' and inGeomType != 'MultiPoint': raise ValueError('The input geometry must be of type point') inGeomType = get_geom_type(destinos, geomCol="geometry", gisApi='pandas') if inGeomType != 'Point' and inGeomType != 'MultiPoint': raise ValueError('The input geometry must be of type point') # Re-Project data to WGS if originsEpsg != 4326: origens = project(origens, None, 4326, gisApi='pandas') if destinationEpsg != 4326: destinos = project(destinos, None, 4326, gisApi='pandas') origens = pointxy_to_cols( origens, geomCol="geometry", colX="longitude", colY="latitude" ); destinos = pointxy_to_cols( destinos, geomCol="geometry", colX="longitude", colY="latitude" ) # Prepare coordinates Str origens["location"] = origens.longitude.astype(str) \ + "," + origens.latitude.astype(str) destinos["location"] = destinos.longitude.astype(str) \ + "," + destinos.latitude.astype(str) # Split destinations DataFrame into Dafaframes with # 24 rows lst_destinos = split_df(destinos, 24) # Get Keys to use KEYS = get_keys() # Split origins by key origensByKey = split_df_inN(origens, KEYS.shape[0]) lst_keys= KEYS["key"].tolist() # Produce matrix results = [] def get_matrix(origins, key): def def_apply(row): rowResults = [] for df in lst_destinos: strDest = df.location.str.cat(sep=";") strLocations = row["location"] + ";" + strDest dados = matrix( strLocations, idxSources="0", idxDestinations=";".join([str(i) for i in range(1, df.shape[0] + 1)]), useKey=key, modeTransportation=modeTrans ) time.sleep(5) rowResults += dados["durations"][0] row["od_matrix"] = rowResults return row newOrigins = origins.apply( lambda x: def_apply(x), axis=1 ) results.append(newOrigins) # Create threads thrds = [] i = 1 for df in origensByKey: thrds.append(Thread( name="tk{}".format(str(i)), target=get_matrix, args=(df, lst_keys[i - 1]) )) i += 1 # Start all threads for thr in thrds: thr.start() # Wait for all threads to finish for thr in thrds: thr.join() # Join all dataframes RESULT = merge_df(results, ignIndex=False) RESULT = listval_to_newcols(RESULT, "od_matrix") RESULT.rename( columns={ c: "dest_{}".format(c) for c in RESULT.columns.values if type(c) == int or type(c) == long }, inplace=True ) if originsEpsg != 4326: RESULT = project(RESULT, None, originsEpsg, gisApi='pandas') return df_to_shp(RESULT, resultShp) return results
def pop_less_dist_x2(net_dataset, rdv_name, locations, interval, unities, fld_groups, fld_pop, w, output, useOneway=None): """ Network processing - executar service area de modo a conhecer as areas a menos de x minutos de qualquer coisa """ import arcpy import numpy import os import pandas from gasp.cpu.arcg.lyr import feat_lyr from gasp.mng.genze import dissolve from gasp.cpu.arcg.anls.ovlay import intersect from gasp.cpu.arcg.mng.fld import calc_fld from gasp.mob.arctbx.svarea import service_area_polygon from gasp.fm import tbl_to_obj from gasp.oss import get_filename from gasp.to.shp import df_to_shp from gasp.cpu.arcg.mng.fld import del_field if arcpy.CheckExtension("Network") == "Available": arcpy.CheckOutExtension("Network") # Procedure # # Generate Service Area svArea = service_area_polygon(net_dataset, rdv_name, interval, locations, os.path.join(w, "servarea.shp"), ONEWAY_RESTRICTION=useOneway) # Dissolve Service Area svArea = dissolve(svArea, os.path.join(w, 'svarea_diss.shp'), "FID", api="arcpy") # Intersect unities with Service Area lyr_unities = feat_lyr(unities) unities_servarea = intersect([lyr_unities, svArea], os.path.join(w, "unidades_mx.shp")) # In the original Unities SHP, create a col with the population # only for the unities intersected with service area intersectDf = tbl_to_obj(unities_servarea) unities_less_than = intersectDf[fld_pop].unique() unities_less_than = pandas.DataFrame(unities_less_than, columns=['cod_']) popDf = tbl_to_obj(unities) popDf = popDf.merge(unities_less_than, how='outer', left_on=fld_pop, right_on="cod_") popDf["less_than"] = popDf.cod_.fillna(value='0') popDf["less_than"] = numpy.where(popDf["less_than"] != '0', '1', '0') popDf["population"] = numpy.where(popDf["less_than"] == '1', popDf[fld_pop], 0) popDf["original"] = popDf[fld_pop] newUnities = df_to_shp(popDf, os.path.join(w, 'unities_pop.shp')) # Dissolve and Get result result = dissolve(newUnities, output, fld_groups, statistics="original SUM;population SUM", api="arcpy") calc_fld(result, "pop_{}".format(interval), "[SUM_popula]", { "TYPE": "INTEGER", "LENGTH": "10", "PRECISION": "" }) calc_fld(result, fld_pop, "[SUM_origin]", { "TYPE": "INTEGER", "LENGTH": "10", "PRECISION": "" }) calc_fld(result, "pop_{}_p".format(interval), "([pop_{}] / [{}]) *100".format(interval, fld_pop), { "TYPE": "DOUBLE", "LENGTH": "6", "PRECISION": "2" }) del_field(result, "SUM_popula") del_field(result, "SUM_origin") return result
def servarea_from_points(pntShp, inEPSG, range, outShp, mode='foot-walking', intervals=None): """ Calculate isochrones for all points in a Point Feature Class """ import time from shapely.geometry import shape from threading import Thread from gasp.web.orouteserv import get_keys, isochrones from gasp.fm import tbl_to_obj from gasp.mng.split import split_df_inN from gasp.fm.geom import pointxy_to_cols from gasp.mng.gen import merge_df from gasp.prop.feat import get_geom_type from gasp.mng.prj import project from gasp.to.geom import dict_to_geodf from gasp.to.obj import df_to_dict from gasp.to.shp import df_to_shp # SHP TO GEODATAFRAME pntDf = tbl_to_obj(pntShp) # Check if SHPs are points inGeomType = get_geom_type(pntDf, geomCol="geometry", gisApi='pandas') if inGeomType != 'Point' and inGeomType != 'MultiPoint': raise ValueError('The input geometry must be of type point') # Reproject geodf if necessary if inEPSG != 4326: pntDf = project(pntDf, None, 4326, gisApi='pandas') pntDf["old_fid"] = pntDf.index pntDf = pointxy_to_cols( pntDf, geomCol="geometry", colX="longitude", colY="latitude" ) # Get Keys KEYS = get_keys() df_by_key = split_df_inN(pntDf, KEYS.shape[0]) keys_list = KEYS['key'].tolist() results = [] def get_isochrones(df, key): pntDict = df_to_dict(df) for k in pntDict: iso = isochrones( "{},{}".format(pntDict[k]["longitude"], pntDict[k]["latitude"]), range, range_type='time', modeTransportation=mode, intervals=intervals ) pntDict[k]["geometry"] = shape(iso["features"][0]["geometry"]) time.sleep(5) pntDf = dict_to_geodf(pntDict, "geometry", 4326) results.append(pntDf) # Create threads thrds = [] i = 1 for df in df_by_key: thrds.append(Thread( name='tk{}'.format(str(i)), target=get_isochrones, args=(df, keys_list[i - 1]) )) i += 1 # Start all threads for thr in thrds: thr.start() # Wait for all threads to finish for thr in thrds: thr.join() # Join all dataframes pntDf = merge_df(results, ignIndex=False) if inEPSG != 4326: pntDf = project(pntDf, None, inEPSG, gisApi='pandas') return df_to_shp(pntDf, outShp)
def population_within_point_buffer(netDataset, rdvName, pointShp, populationShp, popField, bufferDist, epsg, output, workspace=None, bufferIsTimeMinutes=None, useOneway=None): """ Assign to points the population within a certain distance (metric or time) * Creates a Service Area Polygon for each point in pointShp; * Intersect the Service Area Polygons with the populationShp; * Count the number of persons within each Service Area Polygon (this number will be weighted by the area % of the statistic unit intersected with the Service Area Polygon). """ import arcpy import os from geopandas import GeoDataFrame from gasp.cpu.arcg.lyr import feat_lyr from gasp.cpu.arcg.anls.ovlay import intersect from gasp.mng.gen import copy_feat from gasp.cpu.arcg.mng.fld import add_geom_attr from gasp.cpu.arcg.mng.fld import add_field from gasp.cpu.arcg.mng.fld import calc_fld from gasp.mng.genze import dissolve from gasp.mob.arctbx.svarea import service_area_use_meters from gasp.mob.arctbx.svarea import service_area_polygon from gasp.fm import tbl_to_obj from gasp.to.shp import df_to_shp workspace = os.path.dirname(pointShp) if not workspace else workspace if not os.path.exists(workspace): from gasp.oss.ops import create_folder workspace = create_folder(workspace, overwrite=False) # Copy population layer populationShp = copy_feat( populationShp, os.path.join(workspace, 'cop_{}'.format(os.path.basename(populationShp))), gisApi='arcpy') # Create layer pntLyr = feat_lyr(pointShp) popLyr = feat_lyr(populationShp) # Create Service Area if not bufferIsTimeMinutes: servArea = service_area_use_meters( netDataset, rdvName, bufferDist, pointShp, os.path.join(workspace, 'servare_{}'.format(os.path.basename(pointShp))), OVERLAP=False, ONEWAY=useOneway) else: servArea = service_area_polygon( netDataset, rdvName, bufferDist, pointShp, os.path.join(workspace, "servare_{}".format(os.path.basename(pointShp))), ONEWAY_RESTRICTION=useOneway, OVERLAP=None) servAreaLyr = feat_lyr(servArea) # Add Column with Polygons area to Feature Class population add_geom_attr(popLyr, "total", geom_attr="AREA") # Intersect buffer and Population Feature Class intSrc = intersect([servAreaLyr, popLyr], os.path.join(workspace, "int_servarea_pop.shp")) intLyr = feat_lyr(intSrc) # Get area of intersected statistical unities with population add_geom_attr(intLyr, "partarea", geom_attr="AREA") # Get population weighted by area intersected calc_fld(intLyr, "population", "((([partarea] * 100) / [total]) * [{}]) / 100".format(popField), { "TYPE": "DOUBLE", "LENGTH": "10", "PRECISION": "3" }) # Dissolve service area by Facility ID diss = dissolve(intLyr, os.path.join(workspace, 'diss_servpop.shp'), "FacilityID", statistics="population SUM") # Get original Point FID from FacilityID calc_fld(diss, "pnt_fid", "[FacilityID] - 1", { "TYPE": "INTEGER", "LENGTH": "5", "PRECISION": None }) dfPnt = tbl_to_obj(pointShp) dfDiss = tbl_to_obj(diss) dfDiss.rename(columns={"SUM_popula": "n_pessoas"}, inplace=True) resultDf = dfPnt.merge(dfDiss, how='inner', left_index=True, right_on="pnt_fid") resultDf.drop('geometry_y', axis=1, inplace=True) resultDf = GeoDataFrame(resultDf, crs={'init': 'epsg:{}'.format(epsg)}, geometry='geometry_x') df_to_shp(resultDf, output) return output
def project(inShp, outShp, outEPSG, inEPSG=None, gisApi='ogr', sql=None): """ Project Geodata using GIS API's Available: * arcpy * ogr * ogr2ogr; * pandas """ import os if gisApi == 'arcpy': """ Execute Data Management > Data Transformations > Projection """ import arcpy from gasp.cpu.arcg.lyr import feat_lyr from gasp.web.srorg import get_wkt_esri layer = feat_lyr(inShp) srs_obj = get_wkt_esri(outEPSG) arcpy.Project_management(layer, outShp, srs_obj) elif gisApi == 'ogr': """ Using ogr Python API """ if not inEPSG: raise ValueError( 'To use ogr API, you should specify the EPSG Code of the' ' input data using inEPSG parameter' ) from osgeo import ogr from gasp.prop.feat import get_geom_type from gasp.prop.ff import drv_name from gasp.mng.fld import ogr_copy_fields from gasp.prop.prj import get_sref_from_epsg from gasp.oss import get_filename def copyShp(out, outDefn, lyr_in, trans): for f in lyr_in: g = f.GetGeometryRef() g.Transform(trans) new = ogr.Feature(outDefn) new.SetGeometry(g) for i in range(0, outDefn.GetFieldCount()): new.SetField(outDefn.GetFieldDefn(i).GetNameRef(), f.GetField(i)) out.CreateFeature(new) new.Destroy() f.Destroy() # ####### # # Project # # ####### # transP = get_trans_param(inEPSG, outEPSG) inData = ogr.GetDriverByName( drv_name(inShp)).Open(inShp, 0) inLyr = inData.GetLayer() out = ogr.GetDriverByName( drv_name(outShp)).CreateDataSource(outShp) outlyr = out.CreateLayer( get_filename(outShp), get_sref_from_epsg(outEPSG), geom_type=get_geom_type( inShp, name=None, py_cls=True, gisApi='ogr' ) ) # Copy fields to the output ogr_copy_fields(inLyr, outlyr) # Copy/transform features from the input to the output outlyrDefn = outlyr.GetLayerDefn() copyShp(outlyr, outlyrDefn, inLyr, transP) inData.Destroy() out.Destroy() elif gisApi == 'ogr2ogr': """ Transform SRS of any OGR Compilant Data. Save the transformed data in a new file TODO: DB - only works with sqlite """ if not inEPSG: raise ValueError('To use ogr2ogr, you must specify inEPSG') from gasp import exec_cmd from gasp.prop.ff import drv_name cmd = ( 'ogr2ogr -f "{}" {} {}{} -s_srs EPSG:{} -t_srs:{}' ).format( drv_name(outShp), outShp, inShp, '' if not sql else ' -dialect sqlite -sql "{}"'.format(sql), str(inEpsg), str(outEpsg) ) outcmd = exec_cmd(cmd) elif gisApi == 'pandas': # Test if input Shp is GeoDataframe from geopandas import GeoDataFrame as gdf if type(inShp) == gdf: # Is DataFrame df = inShp else: # Assuming is file if os.path.exists(inShp): # Is File from gasp.fm import tbl_to_obj df = tbl_to_obj(inShp) else: raise ValueError(( "For pandas API, inShp must be file or GeoDataFrame" )) # Project df newDf = df.to_crs({'init' : 'epsg:{}'.format(str(outEPSG))}) if outShp: # Try to save as file from gasp.to.shp import df_to_shp return df_to_shp(df, outShp) else: return newDf else: raise ValueError('Sorry, API {} is not available'.format(gisApi)) return outShp
def obj_to_shp(dd, geomkey, srs, outshp): from gasp.to.obj import obj_to_geodf geodf = obj_to_geodf(dd, geomkey, srs) return df_to_shp(geodf, outshp)
def snap_points_to_near_line(lineShp, pointShp, epsg, workGrass, outPoints, location='overlap_pnts', api='grass', movesShp=None): """ Move points to overlap near line API's Available: * grass; * saga. """ if api == 'grass': """ Uses GRASS GIS to find near lines. """ import os; import numpy from geopandas import GeoDataFrame from gasp.oss import get_filename from gasp.session import run_grass from gasp.fm import shp_to_df from gasp.to.shp import df_to_shp # Create GRASS GIS Location grassBase = run_grass(workGrass, location=location, srs=epsg) import grass.script as grass import grass.script.setup as gsetup gsetup.init(grassBase, workGrass, location, 'PERMANENT') # Import some GRASS GIS tools from gasp.anls.prox import grs_near as near from gasp.cpu.grs.mng.feat import geomattr_to_db from gasp.to.shp.grs import shp_to_grs, grs_to_shp # Import data into GRASS GIS grsLines = shp_to_grs( lineShp, get_filename(lineShp, forceLower=True) ) grsPoint = shp_to_grs( pointShp, get_filename(pointShp, forceLower=True) ) # Get distance from points to near line near(grsPoint, grsLines, nearCatCol="tocat", nearDistCol="todistance") # Get coord of start/end points of polylines geomattr_to_db(grsLines, ['sta_pnt_x', 'sta_pnt_y'], 'start', 'line') geomattr_to_db(grsLines, ['end_pnt_x', 'end_pnt_y'], 'end', 'line') # Export data from GRASS GIS ogrPoint = grs_to_shp(grsPoint, os.path.join( workGrass, grsPoint + '.shp', 'point', asMultiPart=True )) ogrLine = grs_to_shp(grsLines, os.path.join( workGrass, grsLines + '.shp', 'point', asMultiPart=True )) # Points to GeoDataFrame pntDf = tbl_to_obj(ogrPoint) # Lines to GeoDataFrame lnhDf = tbl_to_obj(ogrLine) # Erase unecessary fields pntDf.drop(["todistance"], axis=1, inplace=True) lnhDf.drop([c for c in lnhDf.columns.values if c != 'geometry' and c != 'cat' and c != 'sta_pnt_x' and c != 'sta_pnt_y' and c != 'end_pnt_x' and c != 'end_pnt_y'], axis=1, inplace=True) # Join Geometries - Table with Point Geometry and Geometry of the # nearest line resultDf = pntDf.merge( lnhDf, how='inner', left_on='tocat', right_on='cat') # Move points resultDf['geometry'] = [geoms[0].interpolate( geoms[0].project(geoms[1]) ) for geoms in zip(resultDf.geometry_y, resultDf.geometry_x)] resultDf.drop(["geometry_x", "geometry_y", "cat_x", "cat_y"], axis=1, inplace=True) resultDf = GeoDataFrame( resultDf, crs={"init" : 'epsg:{}'.format(epsg)}, geometry="geometry" ) # Check if points are equal to any start/end points resultDf["x"] = resultDf.geometry.x resultDf["y"] = resultDf.geometry.y resultDf["check"] = numpy.where( (resultDf["x"] == resultDf["sta_pnt_x"]) & (resultDf["y"] == resultDf["sta_pnt_y"]), 1, 0 ) resultDf["check"] = numpy.where( (resultDf["x"] == resultDf["end_pnt_x"]) & (resultDf["y"] == resultDf["end_pnt_y"]), 1, 0 ) # To file df_to_shp(resultDf, outPoints) elif api == 'saga': """ Snap Points to Lines using SAGA GIS """ from gasp import exec_cmd cmd = ( "saga_cmd shapes_points 19 -INPUT {pnt} -SNAP {lnh} " "-OUTPUT {out}{mv}" ).format( pnt=pointShp, lnh=lineShp, out=outPoints, mv="" if not movesShp else " -MOVES {}".format(movesShp) ) outcmd = exec_cmd(cmd) else: raise ValueError("{} is not available!".format(api)) return outPoints
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 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 count_rows_by_entity_and_shpJoin(conPSQL, PG_TABLE, PG_ENTITY, PG_PIVOT_COL, SHP_TABLE, SHP_ENTITY, RESULT_SHP, WHERE=None): """ Select and GROUP BY attrs generating a table as: ENTITY | ATTR_N | COUNT 1 | 12ECIR | X 2 | 12ECIR | X 1 | 15ECIR | X 2 | 15ECIR | X Then convert this table to the following ENTITY | 12ECIR | 15ECIR 1 | X | X 2 | X | X The last table will be joined with a given Shapefile TODO: See if PGSQL crosstab works to solve this problem """ from gasp.to.obj import series_to_list from gasp.mng.joins import combine_dfs from gasp.fm.sql import query_to_df from gasp.fm import tbl_to_obj from gasp.sql.mng.tbl import del_tables from gasp.sql.mng.qw import ntbl_by_query from gasp.to.shp import df_to_shp # Get GROUP BYed data # Get row counting using GROUPBY with ENTITY AND PIVOT_COL q = ("SELECT {entity}, {pivc}, COUNT({entity}) AS n{entity} " "FROM {tbl} {whr}GROUP BY {entity}, {pivc}").format( entity=PG_ENTITY, tbl=PG_TABLE, pivc=PG_PIVOT_COL, whr="" if not WHERE else "WHERE {} ".format(WHERE) ) selData = ntbl_by_query(conPSQL, "seldata", q, api='psql') # Get columns of the output table pivotCols = query_to_df(conPSQL, "SELECT {piv} FROM {tb} GROUP BY {piv}".format( tb=selData, piv=PG_PIVOT_COL ), db_api='psql' ) pivotCols = series_to_list(pivotCols[PG_PIVOT_COL]) # Get data for each new column - new column data in one dataframe pre_pivot = [query_to_df(conPSQL, "SELECT {entity}, n{entity} FROM {t} WHERE {c}='{pivcol}'".format( entity=PG_ENTITY, t=selData, c=PG_PIVOT_COL, pivcol=col ), db_api='psql' ) for col in pivotCols] # In pre_pivot DF, give the correct name to the n{entity} column for i in range(len(pre_pivot)): pre_pivot[i].rename(columns={ "n{}".format(PG_ENTITY) : pivotCols[i] }, inplace=True) # Join all dataframes into one pivot_df = pre_pivot[0] pivot_df = combine_dfs(pivot_df, pre_pivot[1:], PG_ENTITY) # Join pivot_df to the Given ESRI Shapefile shpDf = tbl_to_obj(SHP_TABLE) shpDf = shpDf.merge(pivot_df, how='outer', left_on=SHP_ENTITY, right_on=PG_ENTITY) df_to_shp(shpDf, RESULT_SHP) del_tables(conPSQL, selData) return RESULT_SHP
def join_attr_by_distance(mainTable, joinTable, workGrass, epsg_code, output): """ Find nearest feature and join attributes of the nearest feature to the mainTable Uses GRASS GIS to find near lines. """ import os from gasp.session import run_grass from gasp.fm import tbl_to_obj from gasp.to.geom import regulardf_to_geodf from gasp.to.shp import df_to_shp from gasp.oss import get_filename # Create GRASS GIS Location grassBase = run_grass(workGrass, location='join_loc', srs=epsg_code) import grass.script as grass import grass.script.setup as gsetup gsetup.init(grassBase, workGrass, 'join_loc', 'PERMANENT') # Import some GRASS GIS tools from gasp.anls.prox import grs_near as near from gasp.cpu.grs.mng.feat import geomattr_to_db from gasp.to.shp.grs import shp_to_grs, grs_to_shp # Import data into GRASS GIS grsMain = shp_to_grs(mainTable, get_filename( mainTable, forceLower=True) ); grsJoin = shp_to_grs(joinTable, get_filename( joinTable, forceLower=True) ) # Get distance from each feature of mainTable to the nearest feature # of the join table near(grsMain, grsJoin, nearCatCol="tocat", nearDistCol="todistance") # Export data from GRASS GIS ogrMain = grs_to_shp(grsMain, os.path.join( workGrass, 'join_loc', grsMain + '_grs.shp'), None, asMultiPart=True ); ogrJoin = grs_to_shp(grsJoin, os.path.join( workGrass, 'join_loc', grsJoin + '_grs.shp'), None, asMultiPart=True) dfMain = tbl_to_obj(ogrMain) dfJoin = tbl_to_obj(ogrJoin) dfResult = dfMain.merge(dfJoin, how='inner', left_on='tocat', right_on='cat') dfResult.drop(["geometry_y", "cat_y"], axis=1, inplace=True) dfResult.rename(columns={"cat_x" : "cat_grass"}, inplace=True) dfResult["tocat"] = dfResult["tocat"] - 1 dfResult["cat_grass"] = dfResult["cat_grass"] - 1 dfResult = regulardf_to_geodf(dfResult, "geometry_x", epsg_code) df_to_shp(dfResult, output) return output
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 joinLines_by_spatial_rel_raster(mainLines, mainId, joinLines, joinCol, outfile, epsg): """ Join Attributes based on a spatial overlap. An raster based approach """ import os; import pandas from geopandas import GeoDataFrame from gasp.to.geom import regulardf_to_geodf from gasp.session import run_grass from gasp.oss import get_filename from gasp.oss.ops import create_folder from gasp.mng.ext import shpextent_to_boundary from gasp.mng.joins import join_dfs from gasp.mng.df import df_groupBy from gasp.to.rst import shp_to_raster from gasp.fm import tbl_to_obj from gasp.to.shp import df_to_shp workspace = create_folder(os.path.join( os.path.dirname(mainLines, 'tmp_dt') )) # Create boundary file boundary = shpextent_to_boundary( mainLines, os.path.join(workspace, "bound.shp"), epsg ) boundRst = shp_to_raster(boundary, None, 5, -99, os.path.join( workspace, "rst_base.tif"), epsg=epsg, api='gdal') # Start GRASS GIS Session gbase = run_grass(workspace, location="grs_loc", srs=boundRst) import grass.script as grass import grass.script.setup as gsetup gsetup.init(gbase, workspace, "grs_loc", "PERMANENT") from gasp.spanlst.local import combine from gasp.cpu.grs.spanlst import get_rst_report_data from gasp.to.shp.grs import shp_to_grs, grs_to_shp from gasp.to.rst import shp_to_raster # Add data to GRASS GIS mainVector = shp_to_grs( mainLines, get_filename(mainLines, forceLower=True)) joinVector = shp_to_grs( joinLines, get_filename(joinLines, forceLower=True)) mainRst = shp_to_raster( mainVector, mainId, None, None, "rst_" + mainVector, api='pygrass' ); joinRst = shp_to_raster( joinVector, joinCol, None, None, "rst_" + joinVector, api='pygrass' ) combRst = combine(mainRst, joinRst, "combine_rst", api="pygrass") combine_data = get_rst_report_data(combRst, UNITS="c") combDf = pandas.DataFrame(combine_data, columns=[ "comb_cat", "rst_1", "rst_2", "ncells" ]) combDf = combDf[combDf["rst_2"] != '0'] combDf["ncells"] = combDf["ncells"].astype(int) gbdata = df_groupBy(combDf, ["rst_1"], "MAX", "ncells") fTable = join_dfs(gbdata, combDf, ["rst_1", "ncells"], ["rst_1", "ncells"]) fTable["rst_2"] = fTable["rst_2"].astype(int) fTable = df_groupBy( fTable, ["rst_1", "ncells"], STAT='MIN', STAT_FIELD="rst_2" ) mainLinesCat = grs_to_shp( mainVector, os.path.join(workspace, mainVector + '.shp'), 'line') mainLinesDf = tbl_to_obj(mainLinesCat) resultDf = join_dfs( mainLinesDf, fTable, "cat", "rst_1", onlyCombinations=None ) resultDf.rename(columns={"rst_2" : joinCol}, inplace=True) resultDf = regulardf_to_geodf(resultDf, "geometry", epsg) df_to_shp(resultDf, outfile) return outfile
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