Select to view content in your preferred language

Issues with Geodesic Buffer function.

514
2
Jump to solution
08-29-2024 11:07 AM
Labels (3)
PeterPurnyn
Emerging Contributor

Python Version: 3.11.8

Using arcgis python I just want to create 5mi circle around point (in the US) using Point.buffer(), but because I covert from 4326 to 3857 and back to 4326 the distortion results in a smaller and squashed circle. So I decided to look into arcgis geodesic buffers but the documentation seems wrong and I keep getting errors. It seems pretty straitforward, give a geometry, set a buffer distance, provide the starting crs and get a "geometry job" back (although I would really prefer a Polygon that I can actually use directly).

I tried searching through previous threads but it seems while lots of people have this issue there is no straightforward example or solution to copy.

Is there anyone here who knows how do do this correctly? 

Code:
import arcgis.geometry
from arcgis.geometry import Geometry, Point, Polygon
from typing import List, NewType
from geopandas import GeoDataFrame
from arcgis.gis import GIS
from arcgis.geocoding import geocode, reverse_geocode
from arcgis.features import Feature, FeatureSet, FeatureLayer, FeatureCollection, use_proximity
import logging
from config import config
 
def get_coordinates(addresses: List[str]) -> List:
    """Get the coordinates of an address using the ArcGIS API.

    Args:
        addresses (List[str]): List of addresses to convert to lat/longs

    Returns:
        List[arcgis.geometry.Point]: List of ArcGIS points (x,y, spatial_reference) corresponding to address.
    """
    coordinates_list = []
    for address in addresses:
        try:
            response = geocode(address = address, as_featureset=True)
            coordinates = Point(response.features[0].geometry)
            coordinates_list.append(coordinates)
        except Exception as e:
            raise Exception(f"Could not find coordinates for {address}")
    return coordinates_list
   
def create_circle(points: List[Point], radius: List[float], gis: arcgis.GIS) -> Polygon:
    return arcgis.geometry.buffer(geometries=points, distances=radius, unit="Meters", in_sr={"wkid": 4326}, geodesic=True, gis=gis)

gis = GIS('home')
address = #insert str address here
p_list = get_coordinates([address])
c = create_circle(p_list, [1000], gis)

but I get this error:
 
--------------------------------------------------------------------------- Exception Traceback (most recent call last) ~\AppData\Local\Temp\ipykernel_17428\702013528.py in <cell line: 0>() 26 print(f"::{type(p_list[0])}::") 27 print(f"::{[p for p in p_list]}::") ---> 28 c = create_circle(p_list, [1000], gis) 29 30 #map = GIS().map(p, zoomlevel=15) ~\AppData\Local\Temp\ipykernel_17428\702013528.py in create_circle(points, radius, gis) 19 20 def create_circle(points: List[Point], radius: List[float], gis: arcgis.GIS) -> Polygon: ---> 21 return arcgis.geometry.buffer(geometries=points, distances=radius, unit="Meters", in_sr={"wkid": config.LatLongCRS}, geodesic=True, gis=gis) 22 23 gis = GIS('home') c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\site-packages\arcgis\geometry\functions.py in buffer(geometries, in_sr, distances, unit, out_sr, buffer_sr, union_results, geodesic, gis, future) 438 if isinstance(distances, list): 439 distances = ",".join([str(d) for d in distances]) --> 440 return gis._tools.geometry.buffer( 441 geometries, 442 in_sr, c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\site-packages\arcgis\_impl\tools.py in buffer(self, geometries, inSR, distances, unit, outSR, bufferSR, unionResults, geodesic, future) 21411 params["outSR"] = outSR 21412 sr = outSR or inSR > 21413 return self._execute_by_chunk(url, params, 2, "buffer", sr, future) 21414 21415 # ---------------------------------------------------------------------- c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\site-packages\arcgis\_impl\tools.py in _execute_by_chunk(self, url, params, number_executors, task_name, sr, future) 21245 return job 21246 else: > 21247 results = job.result() 21248 if isinstance(results, dict): 21249 all_results.append(results) c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\site-packages\arcgis\_impl\_async\jobs.py in result(self) 232 elif self._wkid: # set the output sr to that wkid integer 233 sr = {"spatialReference": {"wkid": self._wkid}} --> 234 res = self._future.result() 235 if isinstance(res, (list, tuple)): 236 [g.update(sr) for g in res if not "spatialReference" in g] c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\concurrent\futures\_base.py in result(self, timeout) 454 raise CancelledError() 455 elif self._state == FINISHED: --> 456 return self.__get_result() 457 else: 458 raise TimeoutError() c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\concurrent\futures\_base.py in __get_result(self) 399 if self._exception: 400 try: --> 401 raise self._exception 402 finally: 403 # Break a reference cycle with the exception in self._exception c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\concurrent\futures\thread.py in run(self) 56 57 try: ---> 58 result = self.fn(*self.args, **self.kwargs) 59 except BaseException as exc: 60 self.future.set_exception(exc) c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\site-packages\arcgis\_impl\tools.py in _process_results(self, results, out_sr) 21152 21153 if isinstance(results, concurrent.futures.Future): > 21154 results = results.result() 21155 if "error" in results: 21156 return results c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\concurrent\futures\_base.py in result(self, timeout) 454 raise CancelledError() 455 elif self._state == FINISHED: --> 456 return self.__get_result() 457 else: 458 raise TimeoutError() c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\concurrent\futures\_base.py in __get_result(self) 399 if self._exception: 400 try: --> 401 raise self._exception 402 finally: 403 # Break a reference cycle with the exception in self._exception c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\concurrent\futures\thread.py in run(self) 56 57 try: ---> 58 result = self.fn(*self.args, **self.kwargs) 59 except BaseException as exc: 60 self.future.set_exception(exc) c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\site-packages\arcgis\gis\_impl\_con\_connection.py in post(self, path, params, files, **kwargs) 1524 if return_raw_response: 1525 return resp -> 1526 return self._handle_response( 1527 resp=resp, 1528 out_path=out_path, c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\site-packages\arcgis\gis\_impl\_con\_connection.py in _handle_response(self, resp, file_name, out_path, try_json, force_bytes, ignore_error_key) 999 return data 1000 errorcode = data["error"]["code"] if "code" in data["error"] else 0 -> 1001 self._handle_json_error(data["error"], errorcode) 1002 return data 1003 else: c:\Users\peter.purnyn\AppData\Local\ESRI\conda\envs\project_tbd\Lib\site-packages\arcgis\gis\_impl\_con\_connection.py in _handle_json_error(self, error, errorcode) 1022 1023 errormessage = errormessage + "\n(Error Code: " + str(errorcode) + ")" -> 1024 raise Exception(errormessage) 1025 1026 def post_multipart( Exception: Unable to complete operation. (Error Code: 400)
0 Kudos
1 Solution

Accepted Solutions
MarkTorrey
Esri Contributor

Hi Peter,

In your create_circle function try changing the unit parameter from the string "meters" to the arcgis.geometry.LengthUnits.METER enum or the enums value which is 9001.

def create_circle(points: List[Point], radius: List[float], gis: arcgis.GIS) -> Polygon:
    return arcgis.geometry.buffer(geometries=points, distances=radius, unit=arcgis.geometry.LengthUnits.METER, in_sr={"wkid": 4326}, geodesic=True, gis=gis)

 

View solution in original post

2 Replies
MarkTorrey
Esri Contributor

Hi Peter,

In your create_circle function try changing the unit parameter from the string "meters" to the arcgis.geometry.LengthUnits.METER enum or the enums value which is 9001.

def create_circle(points: List[Point], radius: List[float], gis: arcgis.GIS) -> Polygon:
    return arcgis.geometry.buffer(geometries=points, distances=radius, unit=arcgis.geometry.LengthUnits.METER, in_sr={"wkid": 4326}, geodesic=True, gis=gis)

 

PeterPurnyn
Emerging Contributor

Thank you.

0 Kudos