Hello!
I have a large dataset that I want to be able to create a polygons from it to visualize what survey area a person is observing. The dataset consists of:
- Location Data (UTM's, NAD 1983)
- Left Bearing
- Right Bearing
- Visible Distance (in meters)
Can anyone point me in the right direction on how I can do this? I'm very new to mapping so if you can use basic terminology it would be appreciated!
Solved! Go to Solution.
So, assuming you have a table like this:
Display the locations
Display the view polygons
This is a little more complicated.
You could probably do that using a combination of geoprocessing tools, but I didn't find an easy one.
This is a case where a small Python script gets the job done faster.
def circle_section(x, y, start, end, radius, wkid):
"""Creates a circle section.
x, y: float, coordinates of the center
start, end: int, start and end of the section in degrees, Nort=0°, East=90°
radius: float, radius of the section
wkid: int, well-known id of the coordinate system
returns an arcpy.Polygon in the chosen coordinate system
"""
start = int(start)
end = int(end)
center = arcpy.Point(x, y)
center_geo = arcpy.PointGeometry(center, wkid)
angles = range(start, end, 1)
if start > end:
angles = list(range(start, 360, 1)) + list(range(0, end, 1))
arc_geos = [center_geo.pointFromAngleAndDistance(angle, radius, "PLANAR") for angle in angles]
points = [center] + [ag.firstPoint for ag in arc_geos] + [center]
return arcpy.Polygon(arcpy.Array(points), spatial_reference=wkid)
def create_view_sheds(in_table, out_features, x_field, y_field, bearing_left_field, bearing_right_field, distance_field, wkid):
"""Creates a polygon feature class with circle sections.
in_table: str, path to the input table or name of the table in the active map
out_features: str, path to the output feature class
*_field: str, names of the fields in the input table
wkid: int, well-known id of the coordinate system
"""
# create output feature class
from pathlib import Path
folder = str(Path(out_features).parent)
name = str(Path(out_features).name)
arcpy.management.CreateFeatureclass(folder, name, "POLYGON", spatial_reference=wkid)
arcpy.management.AddField(out_features, "FID", "LONG")
with arcpy.da.InsertCursor(out_features, ["SHAPE@", "FID"]) as i_cursor:
with arcpy.da.SearchCursor(in_table, ["OID@", x_field, y_field, bearing_left_field, bearing_right_field, distance_field]) as s_cursor:
# for each table row
for oid, x, y, bearing_left, bearing_right, distance in s_cursor:
# create a circle section
poly = circle_section(x, y, bearing_left, bearing_right, distance, wkid)
# write the polygon and the table row's objectid into the feature class
i_cursor.insertRow([poly, oid])
create_view_sheds("Observations", "memory/Viewsheds", "X", "Y", "BearingLeft", "BearingRight", "Distance", 25832)
So, assuming you have a table like this:
Display the locations
Display the view polygons
This is a little more complicated.
You could probably do that using a combination of geoprocessing tools, but I didn't find an easy one.
This is a case where a small Python script gets the job done faster.
def circle_section(x, y, start, end, radius, wkid):
"""Creates a circle section.
x, y: float, coordinates of the center
start, end: int, start and end of the section in degrees, Nort=0°, East=90°
radius: float, radius of the section
wkid: int, well-known id of the coordinate system
returns an arcpy.Polygon in the chosen coordinate system
"""
start = int(start)
end = int(end)
center = arcpy.Point(x, y)
center_geo = arcpy.PointGeometry(center, wkid)
angles = range(start, end, 1)
if start > end:
angles = list(range(start, 360, 1)) + list(range(0, end, 1))
arc_geos = [center_geo.pointFromAngleAndDistance(angle, radius, "PLANAR") for angle in angles]
points = [center] + [ag.firstPoint for ag in arc_geos] + [center]
return arcpy.Polygon(arcpy.Array(points), spatial_reference=wkid)
def create_view_sheds(in_table, out_features, x_field, y_field, bearing_left_field, bearing_right_field, distance_field, wkid):
"""Creates a polygon feature class with circle sections.
in_table: str, path to the input table or name of the table in the active map
out_features: str, path to the output feature class
*_field: str, names of the fields in the input table
wkid: int, well-known id of the coordinate system
"""
# create output feature class
from pathlib import Path
folder = str(Path(out_features).parent)
name = str(Path(out_features).name)
arcpy.management.CreateFeatureclass(folder, name, "POLYGON", spatial_reference=wkid)
arcpy.management.AddField(out_features, "FID", "LONG")
with arcpy.da.InsertCursor(out_features, ["SHAPE@", "FID"]) as i_cursor:
with arcpy.da.SearchCursor(in_table, ["OID@", x_field, y_field, bearing_left_field, bearing_right_field, distance_field]) as s_cursor:
# for each table row
for oid, x, y, bearing_left, bearing_right, distance in s_cursor:
# create a circle section
poly = circle_section(x, y, bearing_left, bearing_right, distance, wkid)
# write the polygon and the table row's objectid into the feature class
i_cursor.insertRow([poly, oid])
create_view_sheds("Observations", "memory/Viewsheds", "X", "Y", "BearingLeft", "BearingRight", "Distance", 25832)
Wow, I would have never been able to put this together on my own - thank you so very much for your detailed response! I constructed my tables as you outlined, and copy/pasted the first section and it appears to be accepted. However when I paste the second bit of code into it, I get this error:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "<string>", line 35, in create_view_sheds
RuntimeError: cannot open 'Observations'
I am sure I am missing something obvious here, does this tell me what I'm going wrong? Seeing these kinds of capabilities on ArcGIS is both intimidating and exciting! I think this will keep me busy and learning for quite awhile.
Update!
I was able to use 'Export Table' to take the .csv file and it will assign a genuine OID to it. However the code still creates a viewfield that is empty. I feel like I'm missing something super obvious here!
Does the code generate features, you just can't see them? Then you probably still work with the 25832 as your coordinate system. That was my coordinate system for testing, you should replace that with the well-known id of your coordinate system.
If that doesn't work, please post the csv, either here or in a private message.
That worked! For some reason it does it to 95% of the original points, but for a few points it still doesn't generate anything. I'm going to try and narrow down which ones to see if I can find a trend with them.
Wow, I learned an immense amount about ArcGIS and Python with this process! I can't say thank you enough for giving me some of your time to help me with this.
Glad you got it (mostly) working.
Off the top of my head, possible reasons for the missing polygons:
does this tell me what I'm going wrong?
Kind of. It tells you what problem it encountered (can't open "Observations") and where the error is (line35), from that you have to deduce what you did wrong.
In this case, it couldn't open the table "Observations". This is probably because your table has a different name. Either rename your table (click on it in the table of contents, press F2) or change the function call to reflect your table's name.
Seeing these kinds of capabilities on ArcGIS is both intimidating and exciting!
Yeah, I know that feeling... The neat part is, that doesn't really stop. The more you learn, the more specific your problems and questions get. Google and of course the Community are a big help in my ArcGIS journey...
It's like a never ending sudoku problem!
Ok, so I adjusted the title of my table and it now looks like this:
I now have an error that says:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "<string>", line 37, in create_view_sheds
RuntimeError: Cannot find field 'OID@'
If I try and break it down, is it saying that for this line:
for oid, x, y, bearing_left, bearing_right, distance in s_cursor:
It cannot find a field labelled 'OID@"?
I cannot say thank you enough to reflect my gratitude for the help on this. Hopefully one day my skills will be good enough to help someone else out!
Edit: I think the issue might be because I'm using a simple.csv file from Excel to upload the data. I'll have to figure out how to properly assign it an ObjectID.
Yes. OID@ is a placeholder for an ObjectID field. If you load a csv, you probably don't have that.
Even though I see it in your table. Did you just name your field "OBJECTID*" or is that a real ObjectID?
You actually don't need the ObjectID. It was just a way to be able to join the polygons to the observation table via Observations.OBJECTID = Polygons.FID
If you're creating the table with Excel, just create a field ID (or some other name) and let the values in that column increment automatically. In line 35, change "OID@" to "ID".