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 clip_each_feature(rst, shp, feature_id, work, out_basename): """ Clip a raster dataset for each feature in a feature class """ import arcpy import os from glass.cpu.arcg.lyr import feat_lyr from glass.cpu.arcg.lyr import rst_lyr from glass.cpu.arcg.anls.exct import select_by_attr from glass.oss.ops import create_folder # ########### # # Environment # # ########### # arcpy.env.overwriteOutput = True arcpy.env.workspace = work # ###### # # Do it! # # ###### # # Open feature class lyr_shp = feat_lyr(shp) lyr_rst = rst_lyr(rst) # Create folder for some temporary files wTmp = create_folder(os.path.join(work, 'tmp')) # Get id's field type fields = arcpy.ListFields(lyr_shp) for f in fields: if str(f.name) == str(feature_id): fld_type = f.type break expression = '{fld}=\'{_id}\'' if str(fld_type) == 'String' else \ '{fld}={_id}' del fields, f # Run the clip tool for each feature in the shp input c = arcpy.SearchCursor(lyr_shp) l = c.next() while l: fid = str(l.getValue(feature_id)) selection = select_by_attr( lyr_shp, expression.format(fld=feature_id, _id=fid), os.path.join(wTmp, 'each_{}.shp'.format(fid))) clip_rst = clip_raster(lyr_rst, selection, '{b}_{_id}.tif'.format(b=out_basename, _id=fid)) l = c.next()
def TIN_nodata_interpolation(inRst, boundary, prj, cellsize, outRst, workspace=None, template=None): """ Preenche os valores NoData de uma imagem raster usando um TIN """ import os from glass.oss import get_filename from glass.cpu.arcg.lyr import rst_lyr from glass.cpu.arcg.lyr import feat_lyr from glass.cpu.to.shp.arcg import rst_to_pnt from glass.cpu.arcg._3D.mng.tin import create_tin from glass.cpu.to.rst.arcg import tin_to_raster workspace = workspace if workspace else \ os.path.dirname(outRst) # Convert Input Raster to a Point Feature Class rstLyr = rst_lyr(inRst) pntRst = rst_to_pnt( rstLyr, os.path.join(workspace, get_filename(inRstinRst) + '.shp')) # Create TIN pntrstLyr = feat_lyr(pntRst) lmtLyr = feat_lyr(boundary) tinInputs = ('{bound} <None> Soft_Clip <None>;' '{rst_pnt} GRID_CODE Mass_Points <None>') tinOutput = os.path.join(workspace, 'tin_' + get_filename(inRst)) create_tin(tinOutput, prj, tinInputs) return tin_to_raster(tinOutput, cellsize, outRst, template=template)
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 polygons_to_facility(netdataset, polygons, facilities, outTbl, oneway=None, rdv=None, junctions=None, save_result_input=None): """ Execute the Closest Facility tool after calculation of polygons centroids """ 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 from glass.cpu.arcg.mng.fld import calc_fld from glass.cpu.arcg.mng.joins import join_table arcpy.env.overwriteOutput = True # Polygons to Points polLyr = feat_lyr(polygons) pntShp = os.path.join( os.path.dirname(polygons), os.path.splitext(os.path.basename(polygons))[0] + '_pnt.shp') pntShp = feat_to_pnt(polLyr, pntShp, pnt_position='INSIDE') closest_facility(netdataset, facilities, pntShp, outTbl, oneway_restriction=oneway, rdv=rdv, junc=junctions) field_output = 'dst' + os.path.splitext(os.path.basename(facilities))[0] add_field(outTbl, field_output[:10], "FLOAT", "10", "3") calc_fld(outTbl, field_output[:10], "[Total_Minu]") if save_result_input: add_field(outTbl, 'j', "SHORT", "6") calc_fld(outTbl, 'j', "[IncidentID]-1") join_table(polLyr, "FID", outTbl, "j", field_output[:10])
def polygons_from_points(inputPnt, outputPol, prj, POLYGON_FIELD, ORDER_FIELD=None): """ Create a Polygon Table from a Point Table A given Point Table: FID | POLYGON_ID | ORDER_FIELD 0 | P1 | 1 1 | P1 | 2 2 | P1 | 3 3 | P1 | 4 4 | P2 | 1 5 | P2 | 2 6 | P2 | 3 7 | P2 | 4 Will be converted into a new Polygon Table: FID | POLYGON_ID 0 | P1 1 | P2 In the Point Table, the POLYGON_ID field identifies the Polygon of that point, the ORDER FIELD specifies the position (first point, second point, etc.) of the point in the polygon. If no ORDER field is specified, the points will be assigned to polygons by reading order. """ import os from glass.cpu.arcg.lyr import feat_lyr from glass.cpu.arcg.mng.featcls import create_feat_class from glass.cpu.arcg.mng.fld import add_field from glass.cpu.arcg.mng.fld import type_fields arcpy.env.overwriteOutput = True # TODO: Check Geometry of the Inputs # List all point pntLyr = feat_lyr(inputPnt) cursor = arcpy.SearchCursor(pntLyr) line = cursor.next() lPnt = {} cnt = 0 while line: # Get Point Geom pnt = line.Shape.centroid # Get Polygon Identification polygon = line.getValue(POLYGON_FIELD) # Get position in the polygon order = line.getValue(ORDER_FIELD) if ORDER_FIELD else cnt # Store data if polygon not in lPnt.keys(): lPnt[polygon] = {order: (pnt.X, pnt.Y)} else: lPnt[polygon].update({order: (pnt.X, pnt.Y)}) line = cursor.next() cnt += 1 del line del cursor # Write Output create_feat_class(outputPol, "POLYGON", prj) outLyr = feat_lyr(outputPol) # Add polygon ID fieldsPnt = type_fields(pntLyr) POLYGON_FIELD_TYPE = "TEXT" if fieldsPnt[POLYGON_FIELD] == 'String' \ else "SHORT" if fieldsPnt[POLYGON_FIELD] == 'Integer' else \ "TEXT" POLYGON_FIELD_PRECISION = 50 if POLYGON_FIELD_TYPE == "TEXT" else \ 15 add_field(outLyr, POLYGON_FIELD, POLYGON_FIELD_TYPE, POLYGON_FIELD_PRECISION) cursor = arcpy.InsertCursor(outLyr) # Add Polygons point = arcpy.CreateObject("Point") for polygon in lPnt: vector = arcpy.CreateObject("Array") pnt_order = lPnt[polygon].keys() pnt_order.sort() for p in pnt_order: point.ID = p point.X = lPnt[polygon][p][0] point.Y = lPnt[polygon][p][1] vector.add(point) # Add last point point.X = lPnt[polygon][pnt_order[0]][0] point.Y = lPnt[polygon][pnt_order[0]][1] vector.add(point) new_row = cursor.newRow() new_row.Shape = vector new_row.setValue(POLYGON_FIELD, str(polygon)) cursor.insertRow(new_row) vector = 0
def service_area_as_sup_cst(networkDataset, rdvName, extentLyr, originsLyr, output, epsg=3763, REF_DISTANCE=3000, NR_INTERVALS=20): """ Create a Cost Distance Surface using Service Area Tool Same result of the Cost Distance tool but using Service Area Tool Supported by Google Maps API PROBLEM: REF_DISTANCE should be greater if the extent is higher. """ import os from glass.prop.ext import get_extent from glass.cpu.arcg.lyr import feat_lyr from glass.to.shp.arcg import geomArray_to_fc from glass.mob.arctbx.svarea import service_area_polygon from glass.web.glg.distmatrix import get_max_dist if epsg != 4326: from glass.mng.prj import project arcpy.env.overwriteOutput = True # Get extent minX, maxX, minY, maxY = get_extent(extentLyr, gisApi='arcpy') # Get Reference points through the boundary # Get North West to East north_west_east = [(minX, maxY)] # Get South West to East south_west_east = [(minX, minY)] c = minX while c < maxX: north_west_east.append((c, maxY)) south_west_east.append((c, minY)) c += REF_DISTANCE north_west_east.append((maxX, maxY)) south_west_east.append((maxX, minY)) # Get West North to South west_north_to_south = [(minX, maxY)] # Get East North to South east_north_to_south = [(maxX, maxY)] c = maxY while c > minY: west_north_to_south.append((minX, c)) east_north_to_south.append((maxX, c)) c -= REF_DISTANCE west_north_to_south.append((minX, minY)) east_north_to_south.append((maxX, minY)) south_west_east.reverse() west_north_to_south.reverse() # Export Ref Points to a file only to see the result REF_GEOM = north_west_east + east_north_to_south + \ south_west_east + west_north_to_south line_array = [{'FID': 0, "GEOM": REF_GEOM}] REF_POINTS = os.path.join(os.path.dirname(output), 'extent.shp') geomArray_to_fc(line_array, REF_POINTS, "POLYLINE", epsg, overwrite=True) # Calculate time-distance between origins Lyr and reference points # Get Geom of originsLyr # Convert to WGS84 if epsg != 4326: originsWGS = project( originsLyr, os.path.join(os.path.dirname(output), 'origins_wgs84.shp'), 4326) else: originsWGS = originsLyr origLyr = feat_lyr(originsWGS) origPoint = [] for line in arcpy.SearchCursor(origLyr): pnt = line.Shape.centroid origPoint.append((pnt.X, pnt.Y)) # Get WGS REF POINTS if epsg != 4326: refWGS = project( REF_POINTS, os.path.join(os.path.dirname(output), 'extent_wgs.shp'), 4326) else: refWGS = REF_POINTS refPointsLyr = feat_lyr(refWGS) refPoints = [] for line in arcpy.SearchCursor(refPointsLyr): geom = line.getValue("Shape") for vector in geom: for pnt in vector: pnt_str = str(pnt).split(' ') refPoints.append((pnt_str[0], pnt_str[1])) # From that distances, get time intervals max_distance = get_max_dist(origPoint, refPoints) INTERVAL_RANGE = int(round(max_distance / NR_INTERVALS, 0)) c = 0 INTERVALS = [] for i in range(NR_INTERVALS): INTERVALS.append(c + INTERVAL_RANGE) c += INTERVAL_RANGE # Run Service Area Tool service_area_polygon(networkDataset, rdvName, INTERVALS, originsLyr, output) return output
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 clip_several_each_feature(rst_folder, shp, feature_id, work, template=None, rst_file_format='.tif'): """ Clip a folder of rasters by each feature in a feature class The rasters clipped for a feature will be in an individual folder """ import arcpy import os from glass.cpu.arcg.lyr import feat_lyr from glass.cpu.arcg.lyr import rst_lyr from glass.cpu.arcg.anls.exct import select_by_attr from glass.cpu.arcg.mng.fld import type_fields from glass.oss.ops import create_folder from glass.pys.oss import lst_ff # ########### # # Environment # # ########### # arcpy.env.overwriteOutput = True arcpy.env.workspace = work # ###### # # Do it! # # ###### # # Open feature class lyr_shp = feat_lyr(shp) # Create folder for some temporary files wTmp = create_folder(os.path.join(work, 'tmp')) # Split feature class in parts c = arcpy.SearchCursor(lyr_shp) l = c.next() features = {} # Get id's field type fld_type = type_fields(lyr_shp, field=feature_id) expression = '{fld}=\'{_id}\'' if str(fld_type) == 'String' else \ '{fld}={_id}' del fields, f while l: fid = str(l.getValue(feature_id)) selection = select_by_attr( lyr_shp, expression.format(fld=feature_id, _id=fid), os.path.join(wTmp, 'each_{}.shp'.format(fid))) f_lyr = feat_lyr(selection) features[fid] = f_lyr l = c.next() rasters = lst_ff(rst_folder, file_format='.tif') for raster in rasters: r_lyr = rst_lyr(raster) for feat in features: clip_rst = clip_raster( r_lyr, features[feat], os.path.join(work, os.path.splitext(os.path.basename(feat))[0], os.path.basename(raster)), template)
def euclidean_distance(shpRst, cellsize, outRst, template=None, boundary=None, snap=None): """ Euclidean distance from Spatial Analyst """ from arcpy import env from arcpy.sa import * import os arcpy.CheckOutExtension('Spatial') from glass.prop.ff import vector_formats, raster_formats from glass.cpu.arcg.lyr import feat_lyr, rst_lyr path_to_output = outRst if not boundary else \ os.path.join( os.path.dirname(outRst), '{n}_ext{f}'.format( n=os.path.splitext(os.path.basename(outRst))[0], f=os.path.splitext(os.path.basename(outRst))[1] ) ) inputFormat = os.path.splitext(shpRst)[1] if inputFormat in vector_formats(): inLyr = feat_lyr(shpRst) elif inputFormat in raster_formats(): inLyr = rst_lyr(shpRst) else: raise ValueError( 'Could not identify if shpRst is a feature class or a raster') if template: tempEnvironment0 = env.extent env.extent = template if snap: tempSnap = env.snapRaster env.snapRaster = snap outEucDistance = EucDistance(inLyr, "", cellsize, "") outEucDistance.save(path_to_output) if template: env.extent = tempEnvironment0 if snap: env.snapRaster = tempSnap if boundary: from glass.cpu.arcg.mng.rst.proc import clip_raster clipLyr = feat_lyr(boundary) clip_raster(path_to_output, clipLyr, outRst, template=template, snap=snap)
def geomArray_to_fc(array, output, GEOM_TYPE, EPSG, overwrite=True, fields=None): """ Convert a array as array = [ { "FID" : 0, "OTHER_FIELDS" : value "GEOM" : [(x1, y1), ..., (xn, yn)] }, ..., { "FID" : 1, "OTHER_FIELDS" : value "GEOM" : [(x1, y1), ..., (xn, yn)] }, ] to a new Feature Class If fields, it should have a value like: {name : [type, length], name: [type, length]} """ from glass.cpu.arcg.mng.featcls import create_feat_class from glass.cpu.arcg.lyr import feat_lyr from glass.cpu.arcg.mng.fld import add_field if overwrite: arcpy.env.overwriteOutput = True # Create a new Feature Class output = create_feat_class(output, GEOM_TYPE, EPSG) outLyr = feat_lyr(output) # Create fields if fields: if type(fields) != dict: raise ValueError('FIELDS should be a dict') else: for fld in fields: add_field(outLyr, fld, fields[fld][0], fields[fld][1]) # Add things to the feature class cursor = arcpy.InsertCursor(outLyr) point = arcpy.CreateObject("Point") for line in array: vector = arcpy.CreateObject("Array") c = 0 for pnt in line["GEOM"]: point.ID = c point.X = pnt[0] point.Y = pnt[1] vector.add(point) c += 1 new_row = cursor.newRow() new_row.Shape = vector # Add field values if fields: for fld in fields: if fld in line: new_row.setValue(fld, line[fld]) cursor.insertRow(new_row) vector = 0 return output
def viewshed_by_feat_class2(inRaster, observerDataset, feat_class_folder, output_folder, snapRst=None, visibilityRadius=20000, epsg=3763): """ See for each feature class in a folder if it is possible to see a interest object from all poins in each feature class Why this method is different from viewshed_by_feat_class? viewshed_by_feat_class uses viewshed tool of ArcGIS; This one will calculate the visibility point by point, when the script identifies that one point is observable from another, it stops. TO BE MANTAINED? """ import arcpy import numpy import os from glass.oss.ops import create_folder from glass.prop.ff import vector_formats, raster_formats from glass.cpu.arcg.lyr import feat_lyr from glass.prop.rst import get_cell_coord from glass.prop.ext import rst_ext from glass.prop.rst import rst_shape, rst_distinct, get_nodata, get_cellsize from glass.anls.prox.bf import _buffer from glass.cpu.arcg.mng.rst.proc import clip_raster from glass.cpu.arcg.spanlst.surf import viewshed from glass.cpu.arcg.spanlst.rcls import reclassify from glass.cpu.arcg._3D.view import line_of_sight from glass.to.rst import shp_to_raster from glass.to.rst.arcg import array_to_raster from glass.to.shp.arcg import geomArray_to_fc from glass.fm.rst import toarray_varcmap as rst_to_array arcpy.CheckOutExtension('Spatial') arcpy.env.overwriteOutput = True # Check if observerDataset is a Raster or a Feature Class RASTER_FORMATS = raster_formats() VECTOR_FORMATS = vector_formats() observerFormat = os.path.splitext(observerDataset)[1] if observerFormat in VECTOR_FORMATS: from glass.cpu.arcg.anls.exct import clip elif observerFormat in RASTER_FORMATS: from glass.to.shp.arcg import rst_to_pnt from glass.to.shp import rst_to_polyg # If raster, get CELLSIZE of the observer dataset CELLSIZE = get_cellsize(observerDataset, gisApi='arcpy') REF_CELLSIZE = 500 from glass.cpu.arcg.mng.sample import fishnet from glass.cpu.arcg.anls.ovlay import erase from glass.cpu.arcg.mng.feat import feat_to_pnt else: raise ValueError(('Could not identify if observerDataset is a raster ' 'or a feature class')) # Create workspace for temporary files wTmp = create_folder(os.path.join(output_folder, 'tempfiles')) # When clipping the observerDataset (when it is a raster), there is a change # of obtaining a raster with more values than the original raster # Check values of the observerDataset UNIQUEVALUES = [] if observerFormat in RASTER_FORMATS: for line in arcpy.SearchCursor(observerDataset): # TODO: Raster could not have attribute table value = int(line.getValue("Value")) if value not in UNIQUEVALUES: UNIQUEVALUES.append(value) else: continue # List feature classes arcpy.env.workspace = feat_class_folder fclasses = arcpy.ListFeatureClasses() for fc in fclasses: # Create Buffer fcBuffer = _buffer( fc, visibilityRadius, os.path.join(wTmp, os.path.basename(fc)), ) # Clip inRaster clipInRst = clip_raster(inRaster, fcBuffer, os.path.join( wTmp, 'dem_{}{}'.format( os.path.splitext( os.path.basename(fc))[0], os.path.splitext(inRaster)[1])), snap=snapRst, clipGeom=True) # Clip observerDataset # If Raster, convert to points if observerDataset in VECTOR_FORMATS: clipObs = clip( observerDataset, fcBuffer, os.path.join( wTmp, 'obs_{}{}'.format( os.path.splitext(os.path.basename(fc))[0], os.path.splitext(observerDataset)[1]))) elif observerFormat in RASTER_FORMATS: # Clip Raster clipTmp = clip_raster( observerDataset, fcBuffer, os.path.join( wTmp, 'obs_{}{}'.format( os.path.splitext(os.path.basename(fc))[0], os.path.splitext(observerDataset)[1])), snap=snapRst, clipGeom=True) # Check if clip has the same values that the original raster RST_UNIQUE = rst_distinct(clipTmp, gisApi='arcpy') if len(RST_UNIQUE) > len(UNIQUEVALUES): # Reclassify raster rules = {} for v in RST_UNIQUE: if v in UNIQUEVALUES: rules[v] = v else: rules[v] = 'NODATA' clipTmp = reclassify( clipTmp, 'Value', rules, os.path.join(wTmp, 'r_{}'.format(os.path.basename(clipTmp))), template=clipTmp) if CELLSIZE < REF_CELLSIZE: # if cellsize if less than REF_CELLSIZE # Change cellsize to REF_CELLSIZE: # 1) Create fishnet REF_CELLSIZE fishNet = fishnet(os.path.join( wTmp, 'fish_{}'.format(os.path.basename(fc))), clipTmp, cellWidth=REF_CELLSIZE, cellHeight=REF_CELLSIZE) # 2) Erase areas with NoData Values # Raster to shp cls_intPolygon = rst_to_polyg( clipTmp, os.path.join(wTmp, 'cls_int_{}'.format(os.path.basename(fc))), gisApi='arcpy') # - Erase areas of the fishnet that have nodata values # in the raster tmpErase = erase( fishNet, cls_intPolygon, os.path.join(wTmp, 'nozones_{}'.format(os.path.basename(fc)))) trueErase = erase( fishNet, tmpErase, os.path.join(wTmp, 'fishint_{}'.format(os.path.basename(fc)))) # 3) Convert erased fishnet to points clipObs = feat_to_pnt( trueErase, os.path.join(wTmp, 'obs_{}'.format(os.path.basename(fc))), pnt_position="INSIDE") else: clipObs = rst_to_pnt( clipTmp, os.path.join(wTmp, 'obs_{}'.format(os.path.basename(fc)))) # Calculate visibility # Boundary to raster boundRst = shp_to_raster( fc, 'FID', CELLSIZE, None, os.path.join( wTmp, '{}_{}'.format( os.path.splitext(os.path.basename(fc))[0], os.path.splitext(observerDataset)[1])), snap=clipInRst, api='arcpy') noDataVal = get_nodata(boundRst, gisApi='arcpy') boundArray = rst_to_array(boundRst) # Raster to array # For each cell, get cell position and create line of sight shape = rst_shape(boundRst, gisApi='arcpy') xmin, xmax, ymin, ymax = rst_ext(boundRst, gisApi='arcpy2') visibilityArray = numpy.zeros((shape[0], shape[1])) numpy.copyto(visibilityArray, boundArray, 'unsafe', boundArray == noDataVal) for l in range(len(visibilityArray)): for c in range(len(visibilityArray[l])): if visibilityArray[l][c] == noDataVal: continue # Get cell position x, y = get_cell_coord(l, c, xmin, ymin, CELLSIZE, CELLSIZE) # Get Line of sight cursor = arcpy.SearchCursor(clipObs) for line in cursor: FID = line.getValue("FID") geom = line.Shape.centroid sightArray = [ { "FID": 0, "GEOM": [(x, y), (geom.X, geom.Y)] }, ] lineSight = geomArray_to_fc( sightArray, os.path.join( wTmp, 'ls_{}_{}_{}_{}{}'.format( os.path.splitext(os.path.basename(fc))[0], str(l), str(c), str(FID), os.path.splitext(fc)[1])), "POLYLINE", epsg) lineSightRes = line_of_sight( clipInRst, lineSight, os.path.join( wTmp, 'lsr_{}_{}_{}_{}{}'.format( os.path.splitext(os.path.basename(fc))[0], str(l), str(c), str(FID), os.path.splitext(fc)[1]))) lyrLineSight = feat_lyr(lineSightRes) cs = arcpy.SearchCursor(lyrLineSight) lnh = cs.next() cnt = 0 while cnt == 0: try: vis = lnh.getValue("TarIsVis") except: pass cnt += 1 if vis == 1: visibilityArray[l][c] = 1 break else: continue # Generate Raster with visibility data visibilityRst = array_to_raster( visibilityArray, xmin, CELLSIZE, CELLSIZE, os.path.join( output_folder, 'vis_{}{}'.format( os.path.splitext(os.path.basename(fc))[0], os.path.splitext(clipInRst)[1]))) return output_folder