def _evaluate_spatial_input(input_points): """ Helper function to determine if the input is either a FeatureSet or Spatially Enabled DataFrame, and output to FeatureSet for subsequent processing. :param input_points: FeatureSet or Spatially Enabled DataFrame :return: FeatureSet """ try: from arcgis.features.geo._accessor import _is_geoenabled from pandas import DataFrame except ImportError as ie: _log.warning( "One or more of the libraries needed for this feature is not available. " "Please resolve the following error: " + str(ie)) raise ie if isinstance(input_points, FeatureSet): return input_points elif isinstance(input_points, DataFrame) and _is_geoenabled(input_points): return input_points.spatial.to_featureset() elif isinstance(input_points, DataFrame) and not _is_geoenabled(input_points): raise Exception( 'input_points is a DataFrame, but does not appear to be spatially enabled. Using the <df>.spatial.set_geometry(col, sr=None) may help. (https://esri.github.io/arcgis-python-api/apidoc/html/arcgis.features.toc.html#arcgis.features.GeoAccessor.set_geometry)' ) else: raise Exception( 'input_points must be either a FeatureSet or Spatially Enabled DataFrame instead of {}' .format(type(input_points)))
def within(sdf, other, relation="CLEMENTINI"): """ Indicates if the base geometry is within the comparison geometry. `within` is the opposite operator of `contains`. ========================= ========================================================= **Argument** **Description** ------------------------- --------------------------------------------------------- sdf Required Spatially Enabled DataFrame. The dataframe to have the operation performed on. ------------------------- --------------------------------------------------------- other Required Spatially Enabled DataFrame or arcgis.Geometry. This is the selecting data. ------------------------- --------------------------------------------------------- relation Optional String. The spatial relationship type. The allowed values are: BOUNDARY, CLEMENTINI, and PROPER. BOUNDARY - Relationship has no restrictions for interiors or boundaries. CLEMENTINI - Interiors of geometries must intersect. This is the default. PROPER - Boundaries of geometries must not intersect. ========================= ========================================================= :returns: pd.DataFrame (Spatially enabled DataFrame) """ global _HASARCPY, _HASSHAPELY if _HASARCPY == False and _HASSHAPELY == False: return None ud = pd.Series([False] * len(sdf)) if isinstance(other, (Point, Polygon, Polyline, MultiPoint)): sindex = sdf.spatial.sindex() q1 = sindex.intersect(bbox=other.extent) sub = sdf.iloc[q1] dj = sub[sdf.spatial.name].geom.within(other, relation) dj.index = sub.index ud = ud | dj return sdf[ud] elif _is_geoenabled(other): sindex = sdf.spatial.sindex() name = other.spatial.name for index, seg in other.iterrows(): g = seg[name] q1 = sindex.intersect(bbox=g.extent) sub = sdf.iloc[q1] if len(sub) > 0: dj = sub[sdf.spatial.name].geom.within(other, relation) dj.index = sub.index ud = ud | dj return sdf[ud] else: raise ValueError(("Invalid input, please verify that `other` " "is a Point, Polygon, Polyline, MultiPoint, " "or Spatially enabled DataFrame")) return None
def _evaluate_spatial_input(input_points): """ Helper function to determine if the input is either a FeatureSet or Spatially Enabled DataFrame, and output to FeatureSet for subsequent processing. :param input_points: FeatureSet or Spatially Enabled DataFrame :return: FeatureSet """ if isinstance(input_points, FeatureSet): return input_points elif isinstance(input_points, DataFrame) and _is_geoenabled(input_points): return input_points.spatial.to_featureset() elif isinstance(input_points, DataFrame) and not _is_geoenabled(input_points): raise Exception('input_points is a DataFrame, but does not appear to be spatially enabled. Using the <df>.spatial.set_geometry(col, sr=None) may help. (https://esri.github.io/arcgis-python-api/apidoc/html/arcgis.features.toc.html#arcgis.features.GeoAccessor.set_geometry)') else: raise Exception('input_points must be either a FeatureSet or Spatially Enabled DataFrame instead of {}'.format(type(input_points)))
def crosses(sdf, other): """ Indicates if the two geometries intersect in a geometry of a lesser shape type. Two polylines cross if they share only points in common, at least one of which is not an endpoint. A polyline and an polygon cross if they share a polyline or a point (for vertical line) in common on the interior of the polygon which is not equivalent to the entire polyline. ========================= ========================================================= **Argument** **Description** ------------------------- --------------------------------------------------------- sdf Required Spatially Enabled DataFrame. The dataframe to have the operation performed on. ------------------------- --------------------------------------------------------- other Required Spatially Enabled DataFrame or arcgis.Geometry. This is the selecting data. ========================= ========================================================= :returns: pd.DataFrame (Spatially enabled DataFrame) """ global _HASARCPY, _HASSHAPELY if _HASARCPY == False and _HASSHAPELY == False: return None ud = pd.Series([False] * len(sdf)) if isinstance(other, (Point, Polygon, Polyline, MultiPoint)): sindex = sdf.spatial.sindex() q1 = sindex.intersect(bbox=other.extent) sub = sdf.iloc[q1] dj = sub[sdf.spatial.name].geom.crosses(other) dj.index = sub.index ud = ud | dj return sdf[ud] elif _is_geoenabled(other): sindex = sdf.spatial.sindex() name = other.spatial.name for index, seg in other.iterrows(): g = seg[name] q1 = sindex.intersect(bbox=g.extent) sub = sdf.iloc[q1] if len(sub) > 0: dj = sub[sdf.spatial.name].geom.crosses(g) dj.index = sub.index ud = ud | dj return sdf[ud] else: raise ValueError(("Invalid input, please verify that `other` " "is a Point, Polygon, Polyline, MultiPoint, " "or Spatially enabled DataFrame")) return None
def touches(sdf, other): """ Indicates if the boundaries of the geometries intersect. Two geometries touch when the intersection of the geometries is not empty, but the intersection of their interiors is empty. For example, a point touches a polyline only if the point is coincident with one of the polyline end points. ========================= ========================================================= **Argument** **Description** ------------------------- --------------------------------------------------------- sdf Required Spatially Enabled DataFrame. The dataframe to have the operation performed on. ------------------------- --------------------------------------------------------- other Required Spatially Enabled DataFrame or arcgis.Geometry. This is the selecting data. ========================= ========================================================= :returns: pd.DataFrame (Spatially enabled DataFrame) """ global _HASARCPY, _HASSHAPELY if _HASARCPY == False and _HASSHAPELY == False: return None ud = pd.Series([False] * len(sdf)) if isinstance(other, (Point, Polygon, Polyline, MultiPoint)): sindex = sdf.spatial.sindex() q1 = sindex.intersect(bbox=other.extent) sub = sdf.iloc[q1] dj = sub[sdf.spatial.name].geom.touches(other) dj.index = sub.index ud = ud | dj return sdf[ud] elif _is_geoenabled(other): sindex = sdf.spatial.sindex() name = other.spatial.name for index, seg in other.iterrows(): g = seg[name] q1 = sindex.intersect(bbox=g.extent) sub = sdf.iloc[q1] if len(sub) > 0: dj = sub[sdf.spatial.name].geom.touches(g) dj.index = sub.index ud = ud | dj return sdf[ud] else: raise ValueError(("Invalid input, please verify that `other` " "is a Point, Polygon, Polyline, MultiPoint, " "or Spatially enabled DataFrame")) return None
def equals(sdf, other): """ Indicates if the base and comparison geometries are of the same shape type and define the same set of points in the plane. This is a 2D comparison only; M and Z values are ignored. ========================= ========================================================= **Argument** **Description** ------------------------- --------------------------------------------------------- sdf Required Spatially Enabled DataFrame. The dataframe to have the operation performed on. ------------------------- --------------------------------------------------------- other Required Spatially Enabled DataFrame or arcgis.Geometry. This is the selecting data. ========================= ========================================================= :returns: pd.DataFrame (Spatially enabled DataFrame) """ global _HASARCPY, _HASSHAPELY if _HASARCPY == False and _HASSHAPELY == False: return None ud = pd.Series([False] * len(sdf)) if isinstance(other, (Point, Polygon, Polyline, MultiPoint)): sindex = sdf.spatial.sindex() q1 = sindex.intersect(bbox=other.extent) sub = sdf.iloc[q1] dj = sub[sdf.spatial.name].geom.equals(other) dj.index = sub.index ud = ud | dj return sdf[ud] elif _is_geoenabled(other): sindex = sdf.spatial.sindex() name = other.spatial.name for index, seg in other.iterrows(): g = seg[name] q1 = sindex.intersect(bbox=g.extent) sub = sdf.iloc[q1] if len(sub) > 0: dj = sub[sdf.spatial.name].geom.equals(g) dj.index = sub.index ud = ud | dj return sdf[ud] else: raise ValueError(("Invalid input, please verify that `other` " "is a Point, Polygon, Polyline, MultiPoint, " "or Spatially enabled DataFrame")) return None
def select(sdf, other): """ Performs a select by location operation ========================= ========================================================= **Argument** **Description** ------------------------- --------------------------------------------------------- sdf Required Spatially Enabled DataFrame. The dataframe to have the operation performed on. ------------------------- --------------------------------------------------------- other Required Spatially Enabled DataFrame or arcgis.Geometry. This is the selecting data. ========================= ========================================================= :returns: pd.DataFrame (Spatially enabled DataFrame) """ ud = pd.Series([False] * len(sdf)) if isinstance(other, (Point, Polygon, Polyline, MultiPoint)): sindex = sdf.spatial.sindex() q1 = sindex.intersect(bbox=other.extent) sub = sdf.iloc[q1] dj = sub[sdf.spatial.name].geom.disjoint(other) == False dj.index = sub.index ud = ud | dj return sdf[ud] elif _is_geoenabled(other): sindex = sdf.spatial.sindex() name = other.spatial.name for index, seg in other.iterrows(): g = seg[name] q1 = sindex.intersect(bbox=g.extent) sub = sdf.iloc[q1] if len(sub) > 0: dj = sub[sdf.spatial.name].geom.disjoint(g) == False dj.index = sub.index ud = ud | dj return sdf[ud] else: raise ValueError(("Invalid input, please verify that `other` " "is a Point, Polygon, Polyline, MultiPoint, " "or Spatially enabled DataFrame")) return None
def _execute_gp_tool(gis, task_name, params, param_db, return_values, use_async, url, webtool=False, add_token=True, return_messages=False, future=False): if gis is None: gis = arcgis.env.active_gis gp_params = {"f": "json"} # ---------------------in---------------------# for param_name, param_value in params.items(): #print(param_name + " = " + str(param_value)) if param_name in param_db: py_type, gp_param_name = param_db[param_name] if param_value is None: param_value = '' gp_params[gp_param_name] = param_value if py_type == FeatureSet: if webtool: if isinstance(param_value, (tuple, list)): gp_params[gp_param_name] = [ _layer_input_gp(p) for p in param_value ] else: gp_params[gp_param_name] = _layer_input_gp(param_value) else: try: from arcgis.features.geo._accessor import _is_geoenabled except: def _is_geoenabled(o): return False if type(param_value) == FeatureSet: gp_params[gp_param_name] = param_value.to_dict() elif _is_geoenabled(param_value): gp_params[gp_param_name] = json.loads( json.dumps(param_value.spatial.__feature_set__, default=_date_handler)) elif type(param_value) == str: try: klass = py_type gp_params[gp_param_name] = klass.from_str( param_value) except: pass elif py_type in [LinearUnit, DataFile, RasterData]: if type(param_value) in [LinearUnit, DataFile, RasterData]: gp_params[gp_param_name] = param_value.to_dict() elif type(param_value) == str: try: klass = py_type gp_params[gp_param_name] = klass.from_str(param_value) except: pass elif isinstance(param_value, arcgis.gis.Layer): gp_params[gp_param_name] = param_value._lyr_dict elif py_type == datetime.datetime: gp_params[gp_param_name] = _date_handler(param_value) # --------------------------------------------# _set_env_params(gp_params, params) # for param_name, param_value in gp_params.items(): # print(param_name + " = " + str(param_value)) gptool = arcgis.gis._GISResource(url, gis) if use_async: task_url = "{}/{}".format(url, task_name) submit_url = "{}/submitJob".format(task_url) if add_token and submit_url.lower().find("arcgis.com") == -1: try: job_info = gptool._con.post(submit_url, gp_params, token=gptool._token) except: job_info = gptool._con.post(submit_url, gp_params) else: job_info = gptool._con.post(submit_url, gp_params) job_id = job_info['jobId'] if future: executor = concurrent.futures.ThreadPoolExecutor(1) future = executor.submit( _future_op, *(gptool, task_url, job_info, job_id, param_db, return_values, return_messages)) executor.shutdown(False) gpjob = GPJob(future=future, gptool=gptool, jobid=job_id, task_url=task_url, gis=gptool._gis, notify=arcgis.env.verbose) return gpjob job_info = _analysis_job_status(gptool, task_url, job_info) resp = _analysis_job_results(gptool, task_url, job_info, job_id) # ---------------------async-out---------------------# output_dict = {} for retParamName in resp.keys(): output_val = resp[retParamName] try: ret_param_name, ret_val = _get_output_value( gptool, output_val, param_db, retParamName) output_dict[ret_param_name] = ret_val except KeyError: pass # cannot handle unexpected output as return tuple will change # tools with output map service - add another output: # result_layer = '' #***self.properties.resultMapServerName if gptool.properties.resultMapServerName != '': job_id = job_info.get("jobId") result_layer_url = url.replace('/GPServer', '/MapServer') + '/jobs/' + job_id output_dict['result_layer'] = MapImageLayer( result_layer_url, gptool._gis) num_returns = len(resp) if return_messages: return _return_output(num_returns, output_dict, return_values), job_info return _return_output(num_returns, output_dict, return_values) else: # synchronous exec_url = url + "/" + task_name + "/execute" if add_token: resp = gptool._con.post(exec_url, gp_params, token=gptool._token) else: resp = gptool._con.post(exec_url, gp_params) output_dict = {} for result in resp['results']: retParamName = result['paramName'] output_val = result['value'] try: ret_param_name, ret_val = _get_output_value( gptool, output_val, param_db, retParamName) output_dict[ret_param_name] = ret_val except KeyError: pass # cannot handle unexpected output as return tuple will change num_returns = len(resp['results']) if return_messages: return _return_output(num_returns, output_dict, return_values), job_info return _return_output(num_returns, output_dict, return_values)