def gdb_to_shp(workspace, outworkspace): """ Export all feature classes in a Geodatabase to a single file. Do this for all Geodatabases in workspace. """ import os from glass.mng.gen import copy_feat # List GeoDatabases lst_gdb = arcpy.ListWorkspaces(workspace_type="FileGDB") dic_gdb = {} for gdb in lst_gdb: arcpy.env.workspace = gdb dic_gdb[gdb] = {} dts = arcpy.ListDatasets() for dt in dts: dic_gdb[gdb][dt] = arcpy.ListFeatureClasses(feature_dataset=dt) for gdb in dic_gdb: for dt in dic_gdb[gdb]: for fc in dic_gdb[gdb][dt]: copy_feat(os.path.join(gdb, dt, fc), os.path.join( outworkspace, "{}_{}.shp".format( os.path.splitext(os.path.basename(gdb))[0], fc)), gisApi='arcpy')
def round_table_values(table, decimal_by_col_file, outputFile): """ Round all column values using the number of decimal places written in a excel file COL_NAME | nr_decimal_places COL_1 | 1 COL_2 | 0 ... | ... COL_N | 2 """ from glass.cpu.arcg.lyr import feat_lyr from glass.mng.gen import copy_feat from glass.cpu.arcg.mng.fld import type_fields from glass.fm import tbl_to_obj arcpy.env.overwriteOutput = True # Get number of decimal places for the values of each column places_by_col = tbl_to_obj( decimal_by_col_file, sheet=0, output='dict', useFirstColAsIndex=True ) PLACES_FIELD = places_by_col[places_by_col.keys()[0]].keys()[0] # Copy table outTable = copy_feat(table, outputFile, gisApi='arcpy') # Edit copy putting the correct decimal places in each column lyr = feat_lyr(outTable) # List table fields fields = type_fields(lyr) cursor = arcpy.UpdateCursor(lyr) for lnh in cursor: for col in fields: if col in places_by_col: if fields[col] == 'Integer' or fields[col] == 'Double' \ or fields[col] == 'SmallInteger': value = lnh.getValue(col) lnh.setValue( col, round(value, int(places_by_col[col][PLACES_FIELD])) ) else: continue else: print("{} not in {}".format(col, decimal_by_col_file)) cursor.updateRow(lnh) del lyr return outputFile
def mean_rst_by_polygon(polygons, raster, work, resultShp): """ Mean of all cells intersect with the input polygon features """ import arcpy import os from glass.cpu.arcg.lyr import feat_lyr, rst_lyr from glass.prop.rst import rst_stats from glass.cpu.arcg.mng.fld import add_field from glass.mng.gen import copy_feat from glass.cpu.arcg.anls.exct import select_by_attr from glass.cpu.arcg.mng.rst.proc import clip_raster # ########### # # Environment # # ########### # arcpy.env.overwriteOutput = True arcpy.env.workspace = work # ###### # # Do it! # # ###### # # Copy the Input poly_copy = copy_feat(polygons, resultShp, gisApi='arcpy') # Create Layers lyrShp = feat_lyr(poly_copy) lyrRst = rst_lyr(raster) # Create field for register calculated statistics if len(os.path.basename(raster)) <= 10: fld_name = os.path.basename(raster) else: fld_name = os.path.basename(raster)[:10] add_field(lyrShp, fld_name, "DOUBLE", "20", "3") # Calculate mean c = arcpy.UpdateCursor(lyrShp) l = c.next() while l: fid = str(l.getValue("FID")) selection = select_by_attr(lyrShp, "FID={c}".format(c=fid), "poly_{c}.shp".format(c=fid)) sel_rst = clip_raster(lyrRst, selection, "clip_rst_{c}.img".format(c=fid)) mean = rst_stats(sel_rst, api='arcpy')["MEAN"] l.setValue(fld_name, mean) c.updateRow(l) l = c.next()
def arcg_mean_time_WByPop2(netDt, rdv, infraestruturas, unidades, conjuntos, popf, w, output, oneway=None): """ Tempo medio ponderado pela populacao residente a infra-estrutura mais proxima (min) * netDt = Path to Network Dataset * infraestruturas = Points of destiny * unidades = BGRI; Freg; Concelhos * conjuntos = Freg; Concelhos; NUT - field * popf = Field with the population of the statistic unity * w = Workspace * output = Path to store the final output * rdv = Name of feature class with the streets network """ import arcpy import os from glass.cpu.arcg.lyr import feat_lyr from glass.cpu.arcg.mng.feat import feat_to_pnt from glass.cpu.arcg.mng.fld import add_field, calc_fld from glass.cpu.arcg.mng.joins import join_table from glass.mng.genze import dissolve from glass.mng.gen import copy_feat from glass.mob.arctbx.closest import closest_facility from glass.dct import tbl_to_obj def get_freg_denominator(shp, groups, population, fld_time="Total_Minu"): cursor = arcpy.SearchCursor(shp) groups_sum = {} for lnh in cursor: group = lnh.getValue(groups) nrInd = float(lnh.getValue(population)) time = float(lnh.getValue(fld_time)) if group not in groups_sum.keys(): groups_sum[group] = time * nrInd else: groups_sum[group] += time * nrInd del cursor, lnh return groups_sum if not os.path.exists(w): from glass.oss.ops import create_folder w = create_folder(w, overwrite=False) arcpy.env.overwriteOutput = True arcpy.env.workspace = w # Start Procedure # # Create copy of statitic unities to preserve the original data copy_unities = copy_feat(unidades, os.path.join(w, os.path.basename(unidades)), gisApi='arcpy') # Generate centroids of the statistic unities - unidades lyr_unidades = feat_lyr(copy_unities) pnt_unidades = feat_to_pnt(lyr_unidades, 'pnt_unidades.shp') # Network Processing - Distance between CENTROID and Destiny points closest_facility(netDt, rdv, infraestruturas, pnt_unidades, os.path.join(w, "cls_table.dbf"), oneway_restriction=oneway) add_field("cls_table.dbf", 'j', "SHORT", "6") calc_fld("cls_table.dbf", 'j', "[IncidentID]-1") join_table(lyr_unidades, "FID", "cls_table.dbf", "j", "Total_Minu") del lyr_unidades # Calculo dos somatorios por freguesia (conjunto) # To GeoDf unidadesDf = tbl_to_obj(copy_unities) """ groups = get_freg_denominator(lyr_unidades, conjuntos, popf) add_field(lyr_unidades, "tm", "FLOAT", "10", "3") cs = arcpy.UpdateCursor(lyr_unidades) linha = cs.next() while linha: group = linha.getValue(conjuntos) t = float(linha.getValue("Total_Minu")) p = int(linha.getValue(popf)) total = groups[group] indi = ((t * p) / total) * t linha.setValue("tm", indi) cs.updateRow(linha) linha = cs.next() return dissolve(lyr_unidades, output, conjuntos, "tm SUM")""" return unidadesDf
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 glass.cpu.arcg.lyr import feat_lyr from glass.cpu.arcg.anls.ovlay import intersect from glass.mng.gen import copy_feat from glass.cpu.arcg.mng.fld import add_geom_attr from glass.cpu.arcg.mng.fld import add_field from glass.cpu.arcg.mng.fld import calc_fld from glass.mng.genze import dissolve from glass.mob.arctbx.svarea import service_area_use_meters from glass.mob.arctbx.svarea import service_area_polygon from glass.fm import tbl_to_obj from glass.toshp import df_to_shp workspace = os.path.dirname(pointShp) if not workspace else workspace if not os.path.exists(workspace): from glass.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 mean_time_in_povoated_areas(network, rdv_name, stat_units, popFld, destinations, output, workspace, ONEWAY=True, GRID_REF_CELLSIZE=10): """ Receive statistical units and some destinations. Estimates the mean distance to that destinations for each statistical unit. The mean for each statistical will be calculated using a point grid: -> Statistical unit to grid point; -> Distance from grid point to destination; -> Mean of these distances. This method will only do the math for areas (statistic units) with population. """ import os import arcpy from glass.cpu.arcg.lyr import feat_lyr from glass.cpu.arcg.anls.exct import select_by_attr from glass.cpu.arcg.mng.fld import field_statistics from glass.cpu.arcg.mng.fld import add_field from glass.cpu.arcg.mng.gen import merge from glass.mng.gen import copy_feat from glass.mob.arctbx.closest import closest_facility from glass.to.shp.arcg import rst_to_pnt from glass.to.rst import shp_to_raster if arcpy.CheckExtension("Network") == "Available": arcpy.CheckOutExtension("Network") else: raise ValueError('Network analyst extension is not avaiable') arcpy.env.overwriteOutput = True WORK = workspace # Add field stat_units = copy_feat(stat_units, os.path.join(WORK, os.path.basename(stat_units)), gisApi='arcpy') add_field(stat_units, "TIME", "DOUBLE", "10", precision="3") # Split stat_units into two layers # One with population # One with no population withPop = select_by_attr(stat_units, '{}>0'.format(popFld), os.path.join(WORK, 'with_pop.shp')) noPop = select_by_attr(stat_units, '{}=0'.format(popFld), os.path.join(WORK, 'no_pop.shp')) # For each statistic unit with population withLyr = feat_lyr(withPop) cursor = arcpy.UpdateCursor(withLyr) FID = 0 for feature in cursor: # Create a new file unity = select_by_attr( withLyr, 'FID = {}'.format(str(FID)), os.path.join(WORK, 'unit_{}.shp'.format(str(FID)))) # Convert to raster rst_unity = shp_to_raster(unity, "FID", GRID_REF_CELLSIZE, None, os.path.join(WORK, 'unit_{}.tif'.format(str(FID))), api='arcpy') # Convert to point pnt_unity = rst_to_pnt( rst_unity, os.path.join(WORK, 'pnt_un_{}.shp'.format(str(FID)))) # Execute closest facilitie CLOSEST_TABLE = os.path.join(WORK, 'cls_fac_{}.dbf'.format(str(FID))) closest_facility(network, rdv_name, destinations, pnt_unity, CLOSEST_TABLE, oneway_restriction=ONEWAY) # Get Mean MEAN_TIME = field_statistics(CLOSEST_TABLE, 'Total_Minu', 'MEAN')[0] # Record Mean feature.setValue("TIME", MEAN_TIME) cursor.updateRow(feature) FID += 1 merge([withPop, noPop], output) return output
def mean_time_by_influence_area(netDt, rdv, infraestruturas, fld_infraestruturas, unidades, id_unidade, conjuntos, popf, influence_areas_unities, w, output, oneway=True): """ Tempo medio ponderado pela populacao residente a infra-estrutura mais proxima (min), por area de influencia * netDt - Path to Network Dataset * infraestruturas - Points of destiny * fld_infraestruturas - Field on destiny points to relate with influence area * unidades - BGRI; Freg; Concelhos * conjuntos - Freg; Concelhos; NUT - field * popf - Field with the population of the statistic unity * influence_areas_unities - Field on statistic unities layer to relate with influence area * w = Workspace * output = Path to store the final output * rdv - Name of feature class with the streets network * junctions - Name of feature class with the junctions """ import arcpy import os from glass.cpu.arcg.lyr import feat_lyr from glass.cpu.arcg.mng.feat import feat_to_pnt from glass.cpu.arcg.mng.gen import merge from glass.mng.gen import copy_feat from glass.mng.genze import dissolve from glass.cpu.arcg.mng.fld import add_field from glass.cpu.arcg.mng.fld import calc_fld from glass.cpu.arcg.mng.fld import field_statistics from glass.cpu.arcg.mng.fld import type_fields from glass.cpu.arcg.mng.joins import join_table from glass.cpu.arcg.anls.exct import select_by_attr from glass.cpu.arcg.netanlst.closest import closest_facility """if arcpy.CheckExtension("Network") == "Available": arcpy.CheckOutExtension("Network") else: raise ValueError('Network analyst extension is not avaiable')""" def ListGroupArea(lyr, fld_ia, fld_grp): d = {} cs = arcpy.SearchCursor(lyr) for lnh in cs: id_group = lnh.getValue(fld_grp) id_ia = lnh.getValue(fld_ia) if id_group not in d.keys(): d[id_group] = [id_ia] else: if id_ia not in d[id_group]: d[id_group].append(id_ia) return d arcpy.env.overwriteOutput = True arcpy.env.workspace = w # Procedure # copy_unities = copy_feat(unidades, os.path.join(w, os.path.basename(unidades)), gisApi='arcpy') # Generate centroids of the statistic unities - unidades lyr_unidades = feat_lyr(copy_unities) pnt_unidades = feat_to_pnt(lyr_unidades, 'pnt_unidades.shp', pnt_position="INSIDE") # List all groups of unities (conjuntos) group_areas = ListGroupArea(lyr_unidades, influence_areas_unities, conjuntos) # Create Layers lyr_pnt_unidades = feat_lyr(pnt_unidades) lyr_pnt_facilities = feat_lyr(infraestruturas) result_list = [] fld_type_unities = type_fields(lyr_pnt_unidades, field=conjuntos) SELECT_UNITIES = '{fld}=\'{c}\'' if str(fld_type_unities) == 'String' \ else '{fld}={c}' fld_type_facilities = type_fields(lyr_pnt_facilities, field=fld_infraestruturas) SELECT_FACILITIES = '{fld}=\'{obj}\'' if str(fld_type_facilities) == 'String' \ else '{fld}={obj}' for group in group_areas.keys(): # Select centroids of interest interest_centroids = select_by_attr( lyr_pnt_unidades, SELECT_UNITIES.format(c=str(group), fld=conjuntos), 'pnt_{c}.shp'.format(c=str(group))) # Select facilities of interest expression = ' OR '.join([ SELECT_FACILITIES.format(fld=fld_infraestruturas, obj=str(group_areas[group][i])) for i in range(len(group_areas[group])) ]) interest_facilities = select_by_attr( lyr_pnt_facilities, expression, 'facilities_{c}.shp'.format(c=str(group))) # Run closest facilitie - Distance between selected CENTROID and selected facilities cls_fac_table = os.path.join(w, "clsf_{c}.dbf".format(c=str(group))) closest_facility(netDt, rdv, interest_facilities, interest_centroids, cls_fac_table, oneway_restriction=oneway) add_field(cls_fac_table, 'j', "SHORT", "6") calc_fld(cls_fac_table, 'j', "[IncidentID]-1") join_table(interest_centroids, "FID", cls_fac_table, "j", "Total_Minu") # Calculate sum of time x population add_field(interest_centroids, 'sum', "DOUBLE", "10", "3") calc_fld(interest_centroids, 'sum', "[{pop}]*[Total_Minu]".format(pop=popf)) denominador = field_statistics(interest_centroids, 'sum', 'SUM') add_field(interest_centroids, 'tm', "DOUBLE", "10", "3") calc_fld( interest_centroids, 'tm', "([sum]/{sumatorio})*[Total_Minu]".format( sumatorio=str(denominador))) result_list.append(interest_centroids) merge_shp = merge(result_list, "merge_centroids.shp") join_table(lyr_unidades, id_unidade, "merge_centroids.shp", id_unidade, "tm") return dissolve(lyr_unidades, output, conjuntos, statistics="tm SUM", api='arcpy')
def service_area_use_meters(net, rdv, distance, loc, out, OVERLAP=True, ONEWAY=None): """ Execute service area tool using metric distances """ from glass.mng.gen import copy_feat if arcpy.CheckExtension("Network") == "Available": arcpy.CheckOutExtension("Network") else: raise ValueError('Network analyst extension is not avaiable') network_name = str(os.path.basename(net)) JUNCTIONS = network_name + '_Junctions' oneway = "" if not ONEWAY else "Oneway" INTERVALS = str(distance) if type(distance) == int or \ type(distance) == float else distance if \ type(distance) == str or type(distance) == unicode \ else ' '.join([str(int(x)) for x in distance]) if \ type(distance) == list else None if not INTERVALS: raise ValueError(('distance format is not valid')) arcpy.MakeServiceAreaLayer_na( in_network_dataset=net, out_network_analysis_layer="servArea", impedance_attribute="Length", travel_from_to="TRAVEL_FROM", default_break_values=INTERVALS, polygon_type="DETAILED_POLYS", merge="NO_MERGE" if OVERLAP else "NO_OVERLAP", nesting_type="RINGS", line_type="NO_LINES", overlap="OVERLAP" if OVERLAP else "NON_OVERLAP", split="NO_SPLIT", excluded_source_name="", accumulate_attribute_name="", UTurn_policy="NO_UTURNS", restriction_attribute_name=oneway, polygon_trim="TRIM_POLYS", poly_trim_value="250 Meters", lines_source_fields="NO_LINES_SOURCE_FIELDS", hierarchy="NO_HIERARCHY", time_of_day="") # Add locations to the service area layer arcpy.AddLocations_na( "servArea", "Facilities", loc, "", "5000 Meters", "", "{_rdv} SHAPE;{j} NONE".format(_rdv=str(rdv), j=str(JUNCTIONS)), "MATCH_TO_CLOSEST", "APPEND", "NO_SNAP", "5 Meters", "INCLUDE", "{_rdv} #;{j} #".format(_rdv=str(rdv), j=str(JUNCTIONS))) # Solve arcpy.Solve_na("servArea", "SKIP", "TERMINATE", "") # Export to a shapefile save_servArea = copy_feat("servArea\\Polygons", out, gisApi='arcpy') return save_servArea