Select to view content in your preferred language

How to list all polylines within any one polygon!?

1073
10
04-13-2023 01:48 PM
nsidaniel
Regular Contributor

I am trying to see what polylines are within any one polygon. That is, I'd like to print a list of what circuits a county contains.

To do this, I'm trying to iterate through some KMZs (after converting them to layers).

I then intersect the polygons (counties) with the polylines (circuits) and create a temp layer that should contain all the counties that contain lines in them.

I then use Search Cursor to print what polygons (counties) contain polylines (circuits).

Unfortunately, instead of combining all the polygon and polyline data into one attribute table, it iterates through each KMZ, creates a temp layer, then deletes it. It then prints the final temp layer KMZ comparison.

aprx = arcpy.mp.ArcGISProject("CURRENT")
m = aprx.listMaps("Map")[0]

county = ["Dude County"]
projectfilepath = "C:\\Users\\User\\Documents\\ArcGIS\\Projects\\ARCPY_test\\"
datafilepath = "C:\\Users\\User\\Documents\\ArcGIS\Data\\"
to_KMZs_filepath = "Circuits_KMZs\\"
parcel = "Counties_(v17a)"

gdb = datafilepath + to_KMZs_filepath
counties = m.listLayers(parcel)

import os 

for dirpath, dirnames, filenames in os.walk(rootdir):
    for file in filenames:
        if file.endswith("kmz"):
            try:
                arcpy.conversion.KMLToLayer(
                    in_kml_file = m.addDataFromPath(os.path.join(gdb,file)),
                    output_folder = projectfilepath,
                    output_data = file + "_LAYER",
                    include_groundoverlay="NO_GROUNDOVERLAY"
                )
                line = m.listLayers(file + "\Polylines")
                arcpy.analysis.Intersect(
                    in_features = [counties, line], 
                    out_feature_class = r"memory\temp_intersect",
                    output_type = "POINT"
                )
            except Exception:
                arcpy.AddMessage(os.path.join(rootdir,file))

fields = ["LABEL", "NAME_1"]
with arcpy.da.SearchCursor(r"memory\temp_intersect", fields) as u_cursor:
    for label, name_1 in u_cursor:
        if label in county:
            rows = arcpy.SearchCursor(r"memory\temp_intersect", fields="NAME_1")
            for row in rows:
                print("{0}".format(row.getValue("NAME_1")))

 

Tags (1)
0 Kudos
10 Replies
JoshuaSharp-Heward
Frequent Contributor

Hi,

Do you just need to indent from the "fields" line down? With the search cursor outside of the for loop it'll keep overwriting the "memory\temp_intersect" output for each KML and then just run the search cursor over the final KML layer that is intersected. Although this would print out the values for each KML separately which it doesn't sound like you want the output to be.

If you do want it all in one final search cursor, you could output each temp intersect layer with a different name (so it's not overwritten every time), then add a merge above the "fields" line to bring them all together, and use the merged layer as the input into your cursor?

by Anonymous User
Not applicable

@JoshuaSharp-Hewardis correct with nesting the code though I'd avoid nesting cursors that iterate over the same dataset. You could actually simplify this to use one cursor and utilize a dictionary.  I assume that you want to get a count for each county in the counties dataset so something like this will get a total:

aprx = arcpy.mp.ArcGISProject("CURRENT")
m = aprx.listMaps("Map")[0]

county = ["Dude County"]
projectfilepath = "C:\\Users\\User\\Documents\\ArcGIS\\Projects\\ARCPY_test\\"
datafilepath = "C:\\Users\\User\\Documents\\ArcGIS\Data\\"
to_KMZs_filepath = "Circuits_KMZs\\"
parcel = "Counties_(v17a)"

gdb = datafilepath + to_KMZs_filepath
counties = m.listLayers(parcel)

import os 
fields = ["LABEL", "NAME_1"]

totals = {}

for dirpath, dirnames, filenames in os.walk(rootdir):

    for file in filenames:
        if file.endswith("kmz"):
            try:
                arcpy.conversion.KMLToLayer(
                    in_kml_file = m.addDataFromPath(os.path.join(gdb,file)),
                    output_folder = projectfilepath,
                    output_data = file + "_LAYER",
                    include_groundoverlay="NO_GROUNDOVERLAY"
                )
                line = m.listLayers(file + "\Polylines")

                tmp_int = arcpy.analysis.Intersect(
                    in_features = [counties, line], 
                    out_feature_class = r"memory\temp_intersect",
                    output_type = "POINT"
                )

                with arcpy.da.SearchCursor(tmp_int, fields) as s_cursor:
                    for label, name_1 in s_cursor:
                        if label in county: # remove this conditional and adjust the indents below for it to include all counties in the intersect
                            print(f"{name_1}")
                            # add to dictionary for totals.
                            if not totals.get(label):
                                totals[label] = 1
                            else:
                                totals[label] = totals[label] + 1

            except Exception:
                arcpy.AddMessage(os.path.join(rootdir, file))

# print the final message
for k, v in totals.items():
    print(f'County: {k} has {v} polylines')

 

nsidaniel
Regular Contributor

Thank you @JoshuaSharp-Heward and @Anonymous User! Unfortunately, the code still writes over the "memory\temp_intersect" layer no matter how I modify it. The final "memory\temp_intersect"  layer is merely a copy of the counties layer.

I'm not trying to count the polylines, but list them out by name, per county.

So, if I enter the name of county (in the LABEL field), arcpy will spit out all the names of the circuits (in the NAME_1 field) that pass through that county.

0 Kudos
JoshuaSharp-Heward
Frequent Contributor

Have you confirmed that the intersect outputs what you want it to when you run it manually? I've updated the user above's code to store unique names for the input county/counties and print them at the end.

aprx = arcpy.mp.ArcGISProject("CURRENT")
m = aprx.listMaps("Map")[0]

county = ["Dude County"]
projectfilepath = "C:\\Users\\User\\Documents\\ArcGIS\\Projects\\ARCPY_test\\"
datafilepath = "C:\\Users\\User\\Documents\\ArcGIS\Data\\"
to_KMZs_filepath = "Circuits_KMZs\\"
parcel = "Counties_(v17a)"

gdb = datafilepath + to_KMZs_filepath
counties = m.listLayers(parcel)

import os 
fields = ["LABEL", "NAME_1"]

names = {}

for dirpath, dirnames, filenames in os.walk(rootdir):

    for file in filenames:
        if file.endswith("kmz"):
            try:
                arcpy.conversion.KMLToLayer(
                    in_kml_file = m.addDataFromPath(os.path.join(gdb,file)),
                    output_folder = projectfilepath,
                    output_data = file + "_LAYER",
                    include_groundoverlay="NO_GROUNDOVERLAY"
                )
                line = m.listLayers(file + "\Polylines")

                tmp_int = arcpy.analysis.Intersect(
                    in_features = [counties, line], 
                    out_feature_class = r"memory\temp_intersect",
                    output_type = "POINT"
                )

                with arcpy.da.SearchCursor(tmp_int, fields) as s_cursor:
                    for label, name_1 in s_cursor:
                        if label in county: # remove this conditional and adjust the indents below for it to include all counties in the intersect
                            print(f"{name_1}")
                            if label not in names: #if county not present as key in dictionary add it and add first name_1 value as a list
                                names[label]= [name_1]
                                print(f"Added {label} and {name_1} to names dictionary")
                            else:
                                if name_1 not in names[label]: #if county present as key and name_1 not in list of names, add it
                                    names[label].append(name_1)
                                    print(f"Adding {name_1} to {label} in dictionary")
                                else: #if name already in list of names for county key in dict, don't add it
                                    print(f"Not adding {name_1} as already present in dictionary")
 

            except Exception:
                arcpy.AddMessage(os.path.join(rootdir, file))

# print the final message
for k, v in totals.items():
    print(f'County: {k} | names: {v}')

The temp layers will always be overwritten with the above code because the output name is the same every time it's run, what we're doing here is extracting the information we want from the temporary layer, storing it to a dictionary outside of the for loop (so it's persisted) and then looping through the dictionary values at the end.

DavidPike
MVP Frequent Contributor

Can you not just merge all the features together and do a spatial join with a merge rule of 'join'? that would create a field which contains a list (you choose the delimiter also) of line attributes which intersect. 

nsidaniel
Regular Contributor

@JoshuaSharp-Hewardthank you! Your codes speeds things up, but still results in the same issue: the temp file is just a copy of the county files.

@DavidPikeI'm trying your idea, but coming up pretty short:

 

 

aprx = arcpy.mp.ArcGISProject("CURRENT")
m = aprx.listMaps("Map")[0]

county = ["Dude County"]
projectfilepath = "C:\\Users\\User\\Documents\\ArcGIS\\Projects\\ARCPY_test\\"
datafilepath = "C:\\Users\\User\\Documents\\ArcGIS\Data\\"
to_KMZs_filepath = "Circuits_KMZs\\"
parcel = "Counties_(v17a)"

gdb = datafilepath + to_KMZs_filepath
counties = m.listLayers(parcel)

import os 

for dirpath, dirnames, filenames in os.walk(gdb):
    
    for file in filenames:
        if file.endswith("kmz"):
            arcpy.conversion.KMLToLayer(
                in_kml_file = m.addDataFromPath(os.path.join(gdb,file)),
                output_folder = projectfilepath,
                output_data = file + "_LAYER",
                include_groundoverlay="NO_GROUNDOVERLAY")
            
            for lyr in m.listLayers(file + "_LAYER\Polylines"):
                m.moveLayer(lyr, counties, "BEFORE")
        
            if arcpy.Exists("group_for_merge") == False:
                m.createGroupLayer("group_for_merge")
            
            if arcpy.Exists("group_for_merge") == True:
                lyr_to_move = "*Polylines*"
                for lyr in m.listLayers(lyr_to_move):
                    groupLayer = "group_for_merge"
                    lyr =  m.listLayers(lyr_to_move)[0]
                    mapGroupLayer = m.listLayers(groupLayer)[0]
                    m.addLayerToGroup(mapGroupLayer, lyr)
                    arcpy.management.Delete(lyr_to_move, "lyr")
                    
                    # Create FieldMappings object to manage merge output fields
                    fieldMappings = arcpy.FieldMappings()

                    # Add all fields from both oldStreets and newStreets
                    fieldMappings.addTable(lyr_to_move)

                    # Add input fields "STREET_NAM" & "NM" into new output field
                    fldMap_circuitName = arcpy.FieldMap()
                    fldMap_circuitName.addInputField(lyr_to_move, "NAME")

                    # Set name of new output field "Street_Name"
                    circuitName = fldMap_circuitName.outputField
                    circuitName.name = "Circuit_Name"
                    fldMap_circuitName.outputField = circuitName

                    # Add output field to field mappings object
                    fieldMappings.addFieldMap(fldMap_circuitName)

                    # Remove all output fields from the field mappings, except fields 
                    # "Street_Class", "Street_Name", & "Distance"
                    for field in fieldMappings.fields:
                        if field.name not in ["Circuit_Name"]:
                            fieldMappings.removeFieldMap(fieldMappings.findFieldMapIndex(field.name))

                    # Use Merge tool to move features into single dataset
                    circuitsMerge = gdb 
                    arcpy.management.Merge(lyr_to_move, circuitsMerge, fieldMappings, 
                            addSourceInfo)

                    arcpy.analysis.SpatialJoin(counties, lyr_to_move,
                        out_feature_class="mergeSpatialJoin",
                        join_operation="JOIN_ONE_TO_MANY",
                        join_type="KEEP_ALL")

 

 

0 Kudos
by Anonymous User
Not applicable

From your code, there isnt really any other indication what your intention is for this temp layer so is there more code to this that is using the tmp_int? If you want to save each temp file that is created in your iteration, you need to give them unique names so they don't overwrite each iteration.

iter = 0
for file in filenames:
        if file.endswith("kmz"):
            try:
                arcpy.conversion.KMLToLayer(
                    in_kml_file = m.addDataFromPath(os.path.join(gdb,file)),
                    output_folder = projectfilepath,
                    output_data = file + "_LAYER",
                    include_groundoverlay="NO_GROUNDOVERLAY"
                )
                line = m.listLayers(file + "\Polylines")

                tmp_int = arcpy.analysis.Intersect(
                    in_features = [counties, line], 
                    out_feature_class = fr"memory\temp_intersect_{iter}",
                    output_type = "POINT"
                )
                ...
                iter += 1

 

0 Kudos
nsidaniel
Regular Contributor

Thank you Jeff, I'm trying to see what polylines are within any one polygon. (I'd like to print a list of what circuits any one county contains.)

0 Kudos
by Anonymous User
Not applicable

ok, if you want more than one county, you need to remove this conditional, which is limiting to "Dude County"

 if label in county: # remove this conditional and adjust the indents below for it to include all counties in the intersect

 

0 Kudos