|
POST
|
Issue: When attempting to calculate a field on a simple junction layer with a table join, I get an error stating that I have to be in an edit session. To recreate the issue: Create a trace network, including a point feature class as simple junctions. Add the junctions to a map. Add a field to the junctions. For this example, use type Double. Join another layer to the simple junction layer. Use the Calculate Field geoprocessing tool to calculate the new Double field. Or, just right-click the field name in the table window and click Field Calculator. Try to calculate any value. Even zero will suffice for this test. In pro 2.6.3, I then get an error saying: ERROR 999999: Something unexpected caused the tool to fail. Contact Esri Technical Support (http://esriurl.com/support) to Report a Bug, and refer to the error help for potential solutions or workarounds. An edit operation is required. [WRProxyMZ] Failed to execute (CalculateField). In ArcMap, the workaround would be to click Editor > Start Editing. I don't know how to do that in Pro. Instead, my current workaround is to click a cell in the attribute table and write some bogus value, in this case zero, so that the edit tab on the ribbon has the Save button enabled. I believe this is the equivalent of having an edit session open. Then, I can calculate the field as normal. But, that seems kludgy, so what's the proper way of handling this issue? Thanks!
... View more
12-13-2020
12:16 PM
|
2
|
1
|
1047
|
|
POST
|
Jon, About case b, I was placing a starting flag at the edge endpoint, and then using the WRProxyMZ layer as barriers. When I do this, the two edges that share that endpoint are selected in the downstream trace result, while no WRProxyMZ features are selected. Thanks for the tip about multiple flags being placed when I snap to an edge endpoint. I was able to zoom in and see this. It looks like one starting flag is placed exactly at the endpoint and associated with one of the edges, and another starting flag is placed a tiny distance away, and thus a tiny distance along, the other edge. So, one of the flags is spatially coincident with the WRProxyMZ point, and another is very close by. I did try two experiments, where in one case the second flag was just upstream of the junction, and in the other case the second flag was just downstream. In both cases, the result was the same for a downstream trace (with the two starting flags, and using WRProxyMZ as barriers): the two edges were selected, and no junction was selectd. That said, I'm not too worried about case b, because for an edge endpoint, I would just create a flag associatd with the WRProxyMZ point instead of any edges. By the way, I suspect the behavior most end users would prefer is for a single flag to be placed when snapping to edge endpoints, instead of two flags. Maybe that's one of the issues you mentioned that will be fixed in 2.7. The issue that I could still use help with, is getting the downstream WRProxyMZ point selected when the starting flag is in the middle of an edge upstream from the WRProxyMZ point. See the first screenshot in the OP. Basically, I'm trying to get the orange point labeled 1378 to be selected in a downstream trace using the green circle, which is partway up the upstream edge, as the starting point. When you set up a trace like that in the first post, do you get point 1378 selected? Thanks for those links about starting points and barriers. That is exactly the kind of documentation I was looking for, and I'm a little embarrassed that I didn't stumble across it on my own!
... View more
12-11-2020
08:23 AM
|
0
|
0
|
2971
|
|
POST
|
I manually installed the 2.6.3 patch and got the same result: the junction stopping the trace isn't selected. However, I discovered a couple of other curious behaviors: a. If I interactively place a barrier at the downstream endpoint of the edge, snapping to that WRProxyMZ point, and use TN_Temp_Barriers as the barriers, that WRProxyMZ point stopping the trace is selected in the trace results. Yay! This is the desired result. b. If I instead place the barrier by snapping to the edge endpoint, which is spatially coincident with that WRProxyMZ point (I turned off WRProxyMZ in the table of contents to help me snap to the edge endpoint), that WRProxyMZ point is NOT selected in the trace results. I suspect this behavior is related to what I discovered about setting flags as described in this other post, in which you need to include and populate SOURCEID and FEATUREGLOBALID attributes in the flag and barrier feature classes to get desired trace results. When you set flags and barriers interactively, those attributes are populated for you, which is why TN_Temp_Starting_Points and TN_Temp_Barriers tend to work as expected. If you're going to use different feature classes for flags or barriers, you've got to populate those attributes yourself. This makes me wonder why the software can't just figure it out for you when you provide your own flag or barrier feature class. I don't really know why those attributes are needed in the first place. Is there some use case in which you'd want to treat a flag at the endpoint of an edge differently from a flag at a junction located at the same endpoint? The software seems to be programmed that way, which is why the above case (a) works while case (b) does not. It would be wonderful to have some guidance on how to properly create your own flag and barrier feature classes, along with some explanation as to why things work the way they work.
... View more
12-06-2020
06:34 AM
|
0
|
2
|
2989
|
|
POST
|
My mistake was simply copying my selected junction to a separate flag feature class. To make this work, I also have to add and populate a couple of fields that you'll notice in the TN_Temp_Starting_Points feature class in your default geodatabase that stores the flags you create interactively (via Data tab on ribbon), namely, SOURCEID and FEATUREGLOBALID. The SOURCEID refers to the identifier given to the junction layer in the trace network. The FEATUREGLOBALID is the GLOBALID of the junction feature where you want the starting point placed. I discovered this when I noticed that traces initiated from a copy of TN_Temp_Starting_Points worked. I deleted fields one by one and ran traces to see which fields were actually required, leading me to just the two fields I mentioned above. I do not know if that works in all cases. It would be nice if an Esri guru could comment on how to properly make a starting flag feature class. I wish this information had been in a white paper that I had access to. Here's code that demonstrates how to trace upstream given a junction layer. import arcpy
def get_source_id(network, network_layer):
d = arcpy.Describe(network_layer)
fc_name = d.featureClass.name
d = arcpy.Describe(network)
for s in d.sources:
if s.name == fc_name:
return s.sourceID
arcpy.AddError(
'Could not determine network source ID for ' + network_layer.name)
raise arcpy.ExecuteError
def point_to_flag(shape_xy, spatial_ref, source_id, global_id):
flag_fc = arcpy.CreateFeatureclass_management(
out_path='memory',
out_name='flag',
geometry_type='POINT',
has_m='ENABLED',
has_z='ENABLED',
spatial_reference=spatial_ref)[0]
flag_fc = arcpy.management.AddField(flag_fc, 'SOURCEID', 'LONG')[0]
flag_fc = arcpy.management.AddField(flag_fc, 'FEATUREGLOBALID', 'GUID')[0]
fields = ['SHAPE@XY', 'SOURCEID', 'FEATUREGLOBALID']
with arcpy.da.InsertCursor(flag_fc, fields) as cursor:
cursor.insertRow((shape_xy, source_id, global_id))
return flag_fc
arcpy.env.overwriteOutput = True
network = arcpy.GetParameter(0)
junction_layer = arcpy.GetParameter(1)
spatial_ref = arcpy.Describe(junction_layer).spatialReference
source_id = get_source_id(network, junction_layer)
with arcpy.da.SearchCursor(junction_layer, ['SHAPE@XY', 'GLOBALID']) as cursor:
for i, row in enumerate(cursor):
flag = point_to_flag(row[0], spatial_ref, source_id, row[1])
Updated_Trace_Network = arcpy.tn.Trace(
in_trace_network=network,
trace_type='UPSTREAM',
starting_points=flag)[0]
arcpy.SetParameter(2, junction_layer)
... View more
12-02-2020
02:08 PM
|
0
|
1
|
1695
|
|
POST
|
I figured out how to prevent the downstream edge from being returned in the upstream trace. My mistake was simply copying my selected junction to a separate flag feature class. To make this work, I also have to add and populate a couple of fields that you'll notice in the TN_Temp_Starting_Points feature class in your default geodatabase that stores the flags you create interactively (via Data tab on ribbon), namely, SOURCEID and FEATUREGLOBALID. The SOURCEID refers to the identifier given to the junction layer in the trace network. The FEATUREGLOBALID is the GLOBALID of the junction feature where you want the starting point placed. I wish this information had been in a white paper that I had access to. Here's code that demonstrates how to trace upstream given a junction layer. import arcpy
def get_source_id(network, network_layer):
d = arcpy.Describe(network_layer)
fc_name = d.featureClass.name
d = arcpy.Describe(network)
for s in d.sources:
if s.name == fc_name:
return s.sourceID
arcpy.AddError(
'Could not determine network source ID for ' + network_layer.name)
raise arcpy.ExecuteError
def point_to_flag(shape_xy, spatial_ref, source_id, global_id):
flag_fc = arcpy.CreateFeatureclass_management(
out_path='memory',
out_name='flag',
geometry_type='POINT',
has_m='ENABLED',
has_z='ENABLED',
spatial_reference=spatial_ref)[0]
flag_fc = arcpy.management.AddField(flag_fc, 'SOURCEID', 'LONG')[0]
flag_fc = arcpy.management.AddField(flag_fc, 'FEATUREGLOBALID', 'GUID')[0]
fields = ['SHAPE@XY', 'SOURCEID', 'FEATUREGLOBALID']
with arcpy.da.InsertCursor(flag_fc, fields) as cursor:
cursor.insertRow((shape_xy, source_id, global_id))
return flag_fc
arcpy.env.overwriteOutput = True
network = arcpy.GetParameter(0)
junction_layer = arcpy.GetParameter(1)
spatial_ref = arcpy.Describe(junction_layer).spatialReference
source_id = get_source_id(network, junction_layer)
with arcpy.da.SearchCursor(junction_layer, ['SHAPE@XY', 'GLOBALID']) as cursor:
for i, row in enumerate(cursor):
flag = point_to_flag(row[0], spatial_ref, source_id, row[1])
Updated_Trace_Network = arcpy.tn.Trace(
in_trace_network=network,
trace_type='UPSTREAM',
starting_points=flag)[0]
arcpy.SetParameter(2, junction_layer) So, until Pro 2.7 is released in which the trace tools return selection layers, the keys to iterating traces are: Create a point feature class for your starting point(s), and populate SOURCEID and FEATUREGLOBALID attributes in that feature class. Return aggregated geometry, and use that geometry to select features from your network layer(s). If you're updating a network layer's attributes while iterating, when you call arcpy.tn.Trace remember to set validate_consistency='DO_NOT_VALIDATE_CONSISTENCY' so the tool executes even as you update features. Run arcpy.ValidateNetworkTopology_tn when you need to validate the network after updating it. I've implemented this via Python. It seems like it should also work via ModelBuilder iteration, but ModelBuilder iteration confuses me, so I haven't verified it works there. My id_to_edges.py script, and the utils.py script it relies on, are attached in case folks find it helpful.
... View more
12-02-2020
02:03 PM
|
0
|
3
|
6104
|
|
POST
|
I've got 2.6.0 currently. My Pro instance can't connect to the update server, so I'm unable to upgrade to 2.6.3.
... View more
12-02-2020
12:11 PM
|
1
|
0
|
2996
|
|
POST
|
I have a trace network with edges (NHDFlowline) and junctions (WRProxyMZ) that has been validated. When I trace downstream from a point along an edge (green circle in figures below), using all WRProxyMZ points as barriers, with Include Barrier Features checked, the barrier that stops the trace is not returned in the results. It seems like it should be returned if Include Barrier Features is checked. See the two screenshots below. The first shows the map layers and starting flag which I set interactively. The second shows the Trace tool inputs (no advanced options set) and the resulting map selection after running the trace. Example data and Pro project are attached. Starting flag (green) and junctions used as barriers (orange) Trace results -- note no downstream junction selected
... View more
11-22-2020
08:49 AM
|
0
|
6
|
3025
|
|
POST
|
I'm thinking the only recourse until 2.7 is released, is to output an aggregated feature and then use a spatial filter to select the appropriate edges That's what I wound up doing. I used Python rather than ModelBuilder because I find it easier to follow. Some example code is below. I also heard Arc Hydro is using trace networks now, so I will peak at their code later. For this to work, I have to deal with the fact that when I copy a given junction to a new feature class to use as a starting point, when I perform an upstream trace, the trace tends to also include the edge just downstream of that junction. Before running the code below, I precompute length downstream to the network outlet for each junction, and also from the downstream end of each edge. If an edge has a length downstream value less than the junction, then it is downstream from the junction. I only want upstream edges. Updated_Trace_Network = arcpy.tn.Trace(
in_trace_network=network,
trace_type='UPSTREAM',
starting_points=start_pt,
validate_consistency='DO_NOT_VALIDATE_CONSISTENCY', ## proceed even if we've updated other features
condition_barriers=[['HydroID', 'DOES_NOT_EQUAL', 'SPECIFIC_VALUE', hydro_id, 'OR']],
traversability_scope='JUNCTIONS_ONLY',
result_types=['AGGREGATED_GEOMETRY'],
trace_name=str(hydro_id),
aggregated_lines=agg_lines)[0]
if Updated_Trace_Network:
# Select the edges corresponding to the aggregated trace result
lyr = arcpy.SelectLayerByLocation_management(
edge_layer, 'SHARE_A_LINE_SEGMENT_WITH', agg_lines)[0]
edge_count = int(arcpy.GetCount_management(lyr)[0])
if edge_count > 0:
# Sometimes downstream edges are selected. Remove them.
arcpy.SelectLayerByAttribute_management(
lyr, 'SUBSET_SELECTION', 'LengthDown >= ' + str(length_down))
edge_count = int(arcpy.GetCount_management(lyr)[0])
if edge_count > 0:
arcpy.AddMessage('Upstream edge count: ' + str(edge_count))
arcpy.CalculateField_management(lyr, 'JunctionID', hydro_id)
else:
arcpy.AddMessage('No upstream edges found')
else:
arcpy.AddMessage('No upstream edges found')
... View more
11-07-2020
02:57 PM
|
0
|
0
|
6134
|
|
POST
|
hydro_id is a number, like 1392. It's used to create a whereclause like "HydroID = 1392". I use hydro_id to uniquely identify each feature in my feature class. It's unique like ObjectID, but I have control over it. In line 24, whereclause is one of the optional arguments in the FeatureClassToFeatureClass function that is called on line 20. There is a closing paren on line 24 that completes the function. Geoprocessing tools can return one or more outputs, so the [0] is grabbing the first output, which is the output feature class. The same thing goes for the [0] bracket at the end of the arcpy.tn.Trace call that starts on line 25. I think condition barriers is right. I created that code by exporting it as a Python script from a working GP Model in ModelBuilder, and then tweaking it to run as a script tool. Also, you can have multiple conditions, and each condition has a list of parameters, so the conditions argument is a list of conditions, i.e., a list of lists. In my case, I only have one condition, so the outer list only has one element in it (the inner list), and I can see how that looks funny. Even if those condition barriers were wrong, if it didn't cause an error, the worst it would do is to make all upstream edges be selected instead of just the ones between the starting point and the nearest upstream barriers. However, even downstream edges are included in that search cursor on line 32, so it's like the layer isn't yet seeing the selection from the network trace. I observed that as the tool executes, I do see the selections from each trace happening in the map, and when the tool finishes, the selection from the last trace is still there. But, the edge layer as seen by the code doesn't see that selection; ditto when run within an iterator in ModelBuilder.
... View more
11-06-2020
02:03 PM
|
0
|
1
|
6134
|
|
POST
|
I attempted the same task in a script tool and found the same result: The input edge layer does not have the trace results as a selection when arcpy.tn.Trace completes. I'm thinking the only recourse until 2.7 is released, is to output an aggregated feature and then use a spatial filter to select the appropriate edges, which will be very slow. I'm also worried about geometries not matching exactly since exported junctions don't seem to return the same results as an interactive starting point. import arcpy
arcpy.env.overwriteOutput = True
network = arcpy.GetParameter(0)
junction_layer = arcpy.GetParameter(1)
edge_layer = arcpy.GetParameter(2)
# Trace network overwrites selections, so grab HydroIDs before tracing
hydro_ids = []
with arcpy.da.SearchCursor(junction_layer, ['HydroID']) as cursor:
for row in cursor:
hydro_ids.append(row[0])
for hydro_id in hydro_ids:
# Using junction layer even with filter applied results in all points used,
# so send the junction to a temporary feature class for use in tracing
start_pt = arcpy.conversion.FeatureClassToFeatureClass(
in_features=junction_layer,
out_path='memory',
out_name='current_junction',
where_clause='HydroID = ' + str(hydro_id))[0]
Updated_Trace_Network = arcpy.tn.Trace(
in_trace_network=network,
trace_type='UPSTREAM',
starting_points=start_pt,
condition_barriers=[['HydroID', 'DOES_NOT_EQUAL', 'SPECIFIC_VALUE', hydro_id, 'OR']],
traversability_scope='JUNCTIONS_ONLY',)[0]
if Updated_Trace_Network:
with arcpy.da.SearchCursor(edge_layer, ['JunctionID']) as cursor:
count = 0
for row in cursor:
count += 1
# Should be a selected subset, but we're getting the entire feature class
arcpy.AddMessage('Edges: ' + str(count))
arcpy.SetParameter(3, edge_layer)
... View more
11-06-2020
09:22 AM
|
0
|
4
|
6134
|
|
POST
|
I don't think there is an output destination in _SingleJunctionoEdges. The input to that tool is a layer, and the tool calculates a field on the layer, so the output labeled Output Feature Class is actually the input layer. Or maybe I'm misunderstanding. I put the geodatabase and toolbox here in case you want to have a look: NetworkTest.zip - Box To test: 1. Add the Hydro network in the geodatabase to a map. 2. Select a single WRProxyMZ point (or more, but it just takes longer). 3. In the toolbox, run Junctions To Edges Iterator, with the Hydro network, WRProxyMZ, and NHDFlowline as inputs. The tool's job is to trace upstream from each selected point, using all other WRProxyMZ points as barriers. For each upstream edge found between the starting point and the upstream points, assign the JunctionID attribute of the edges to be equal to the HydroID of the starting point. The freshly unzipped geodatabase has all JunctionIDs as -1. When the tool finishes, the edges in the trace results for the final iteration are selected in the map. However, the calculate field task ran on the entire layer and not just the selection, as evidenced by all NHDFlowlines having the same JunctionID, e.g., 1392.
... View more
11-06-2020
07:25 AM
|
0
|
5
|
6134
|
|
POST
|
In theory, the trace network would serve your needs. I'm actually trying to do something similar. The general procedure would be to build a trace network with your snapped cities and rivers. Then you would iterate through each city, and do the following: 1. Set the city as a starting point. 2. Trace upstream. 3. Collect and names of the upstream cities that were returned in the trace. They would be returned in the form of a feature selection on the city layer. 4. Concatenate the names in a comma separated list and write to the Cities Upstream field in the city layer. 5. Trace downstream. 6. Collect the names downstream. 7. Write the names to the Cities Downstream field. (In fact, if you iterate through all cities and trace upstream, you can use that information to also build the list of cities downstream, but conceptually it's just easier to do steps 5, 6, and 7, albeit probably slower from a scripting standpoint). However, in practice I'm struggling to get the iteration working in ModelBuilder. I may wait a few days to see if any experts have solutions. Things may be better in Pro 2.7, but my client will be at 2.6 for a while so I'm stuck for now. If a ModelBuilder solution doesn't present itself, I'll try Python instead.
... View more
11-05-2020
12:49 PM
|
0
|
0
|
971
|
|
POST
|
I have a GP model that performs a trace and then assigns a long integer stored in the HydroID variable to a field in the edge layer. Calculate Field has the Updated Trace Network as a precondition, so it waits until the trace is finished and there is a selection. This works fine when I run the model. The model is shown below, and is named "_Single Junction To Edges". The problem arises when I encapsulate this model in another model with an iterator. I want to iterate through a selected set of junctions, and for each one, perform the trace and calculate the field. However, calculate field appears to be running on the entire edge layer rather than the selection. As the model runs, I can see the selections being made in the map, but the tool ignores them. The model with the iterator, which includes "_Single Junction To Edges" as one of the tools, is shown below. What do I need to do to get the iterator version to work like the standalone version with respect to using feature selections when it comes time to calculate the field? I do acknowledge that outputting a group layer with the selection from the Trace tool in Pro 2.7, as discussed in this thread on working with trace results, may be the solution. But it seems like the single model was working correctly, so I wonder if I'm just missing something that will make it work in the iterator. I'm on Pro 2.6.
... View more
11-05-2020
12:27 PM
|
0
|
11
|
6959
|
|
POST
|
As a workaround for the Trace tool not honoring feature selections, I am trying the following: 1. In Pro 2.6, select the junction feature I'm interested in. 2. Export the feature to a new feature class named Flag in my default geodatabase. Note that my trace network is in another geodatabase. 3. Clear the selection. 4. Run an upstream trace, using Flag as the Starting Points with all other parameters at defaults. However, in addition to the expected upstream edges, the resulting feature selection includes the edge just downstream of the junction (orange circle in image below). When I instead use the ribbon to interactively set a starting point at the desired junction (I made sure it snapped to that junction feature before clicking), and then run an upstream trace (initiated from the ribbon, so it's using the TN_Temp_Starting_Points and all defaults), I get the desired result, which is just the upstream set of edges. Why is my exported junction causing a downstream edge to be returned from an upstream trace? Note that interactively setting starting points isn't an option for me, because I'm trying to automate this for thousands of junctions via ModelBuilder.
... View more
11-05-2020
11:55 AM
|
0
|
2
|
1727
|
|
POST
|
I have a trace network built from a point feature class and a line feature class. Traces initiated using locations set by the Trace Locations functionality of the ribbon work fine. I'd like to be able to use a feature selection as my starting points instead of interactively clicking each point. I clear all trace locations via the ribbon. However, even if I select just a single point in my point layer, when I run a downstream trace and set the point layer as the Starting Points (leaving everything else as default), the trace completes using all the points in the layer as starting points rather than the selected point. I was under the impression that geoprocessing tools honor feature selections, but the Trace tool does not appear to be doing so. I'm in Pro 2.6.
... View more
11-05-2020
09:48 AM
|
0
|
1
|
1091
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 05-11-2020 11:56 AM | |
| 4 | 06-03-2021 09:16 AM | |
| 2 | 12-13-2020 12:16 PM | |
| 1 | 12-02-2020 12:11 PM | |
| 1 | 06-05-2019 06:55 AM |
| Online Status |
Offline
|
| Date Last Visited |
09-05-2024
06:00 PM
|