How to divide raster into measured segments?

2467
13
12-19-2018 06:37 PM
ElanaBerlin
New Contributor

I am working on a project that analyzes the correlation between land use and food web connectance of aquatic invertebrates in certain streams. In order to accurately analyze the data, I was planning on dividing the streams into four parts based on the length: 500 meters, 1000 meters, 1500 meters, and 2000 meters. I converted the polylines of the streams into rasters so that the distance in meters can be accounted for, but I'm not too sure how to divide these into measured segments. I tried clipping them to buffer rings, but because the streams are not straight, the length of the segments are not exact. Is there a tool I'm overlooking?

0 Kudos
13 Replies
XanderBakker
Esri Esteemed Contributor

If you want to split the line up in segments of 500m you get this result:

Which looks OK, but there are two featureclasses that give wrong results due to the fact that they are multiparts (English and Foster):

What you see is that part 3 consists of more than 1 part and part 9 starts on the left and continues in the middle. To process these lines correctly, we first need to apply Multipart To Singlepart—Help | ArcGIS Desktop to correct the input. When we run this again it will become something like this:

0 Kudos
XanderBakker
Esri Esteemed Contributor

Below the code that I used in this sample:

def main():
    import arcpy
    import os

    ws = r'C:\GeoNet\StreamsDivide\streams.gdb'
    arcpy.env.workspace = ws
    arcpy.env.overwriteOutput = True

    div_length = 500.0
    postfix = "_div500m"

    fcs = arcpy.ListFeatureClasses()
    for fc_name in fcs:
        print fc_name
        fc_in = os.path.join(ws, fc_name)
        sr = arcpy.Describe(fc_in).spatialReference
        fc_name_out = "{}{}".format(fc_name, postfix)
        print " - ", fc_name_out
        fc_out = os.path.join(ws, fc_name_out)
        arcpy.CreateFeatureclass_management(ws, fc_name_out, "POLYLINE", fc_in, "SAME_AS_TEMPLATE", "SAME_AS_TEMPLATE", sr)
        flds = GetFields(fc_in)
        with arcpy.da.InsertCursor(fc_out, flds) as curs_in:
            with arcpy.da.SearchCursor(fc_in, flds) as curs:
                for row in curs:
                    polyline = row[0]
                    lst_row = list(row)
                    length = polyline.length
                    d1 = 0
                    while d1 <= length:
                        d2 = d1 + div_length
                        if d2 > length:
                            d2 = length
                        print " - ", d1, " a ", d2
                        polyline_i = polyline.segmentAlongLine(d1, d2, False)
                        lst_row[0] = polyline_i
                        row_out = tuple(lst_row)
                        curs_in.insertRow(row_out)
                        d1 += div_length
    print "ready"

def GetFields(fc):
    fld_length = arcpy.Describe(fc).lengthFieldName
    fld_shape = arcpy.Describe(fc).shapeFieldName
    fld_oid = arcpy.Describe(fc).OIDFieldName
    flds = [fld.name for fld in arcpy.ListFields(fc) if not fld.name in [fld_length, fld_shape, fld_oid]]
    flds.insert(0, 'SHAPE@')
    print " - ", flds
    return flds

if __name__ == '__main__':
    main()
0 Kudos
ElanaBerlin
New Contributor

Thank you for doing all this. When the stream branches out different ways like in the second and third photo, I would like to break the stream at a cumulative distance of 500m. So if the stream were to branch out two different ways, one branch will be divided in 250m and so will the other branch. Would that be possible?

Otherwise, this looks really good. 

0 Kudos
XanderBakker
Esri Esteemed Contributor

That could be done with some adjustments to the code. Although to make it a little more controlable I would suggest to run the Multipart to Singlepart tool and add a field to the result and tag those branches that you want to split with the appropriate distance. So the field would contain the value 500 or 250 depending the situation and the code could read that values to process correspondingly.