Select to view content in your preferred language

Viewing Survey Area of an Observation

1654
11
Jump to solution
08-16-2022 04:13 PM
PaintedSun
Emerging Contributor

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!

0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

So, assuming you have a table like this:

JohannesLindner_0-1660732749476.png

 

Display the locations

  • right-click the table in the table of contents, "Display XY Data"
    JohannesLindner_1-1660732849536.png
  • Choose where you want to save the point feature class, choose the appropriate coordinate fields and your coordinate system, click OK.
    JohannesLindner_2-1660732940244.png

 

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.

  • Open the Python window
    JohannesLindner_5-1660733624466.png

     

  • Copy/Paste these functions and hit enter twice

 

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])

 

 

  • Call the function

 

create_view_sheds("Observations", "memory/Viewsheds", "X", "Y", "BearingLeft", "BearingRight", "Distance", 25832)

 

 

JohannesLindner_6-1660734947024.png

 


Have a great day!
Johannes

View solution in original post

11 Replies
JohannesLindner
MVP Frequent Contributor

So, assuming you have a table like this:

JohannesLindner_0-1660732749476.png

 

Display the locations

  • right-click the table in the table of contents, "Display XY Data"
    JohannesLindner_1-1660732849536.png
  • Choose where you want to save the point feature class, choose the appropriate coordinate fields and your coordinate system, click OK.
    JohannesLindner_2-1660732940244.png

 

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.

  • Open the Python window
    JohannesLindner_5-1660733624466.png

     

  • Copy/Paste these functions and hit enter twice

 

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])

 

 

  • Call the function

 

create_view_sheds("Observations", "memory/Viewsheds", "X", "Y", "BearingLeft", "BearingRight", "Distance", 25832)

 

 

JohannesLindner_6-1660734947024.png

 


Have a great day!
Johannes
PaintedSun
Emerging Contributor

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. 

0 Kudos
PaintedSun
Emerging Contributor

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! 

0 Kudos
JohannesLindner
MVP Frequent Contributor

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.


Have a great day!
Johannes
0 Kudos
PaintedSun
Emerging Contributor

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. 

0 Kudos
JohannesLindner
MVP Frequent Contributor

Glad you got it (mostly) working.

Off the top of my head, possible reasons for the missing polygons:

  • make sure you don't have a selection in the table
  • make sure the coordinates are correct (are the missing rows correctly converted to points with Display XY Data?)
  • make sure there are values in the bearing and distance fields

Have a great day!
Johannes
JohannesLindner
MVP Frequent Contributor

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...


Have a great day!
Johannes
PaintedSun
Emerging Contributor

It's like a never ending sudoku problem! 

Ok, so I adjusted the title of my table and it now looks like this: 

PaintedSun_0-1660750352232.png

 

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. 

0 Kudos
JohannesLindner
MVP Frequent Contributor

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".


Have a great day!
Johannes