|
POST
|
the line is multiple parts (features? Sections?) I'd vote for "features". "parts" makes it sound like you're working with multipart geometries, and the expression should work as expected there. To do what you want, you need to modify Josh's expression a bit: load the line layer (the same layer for which you define this expression) filter it to get all lines with the same name as the current $feature create an outer loop that iterates over those lines, do the intersection for each line // get the states layer
var portal = Portal('https://arcgis.com')
var states = FeatureSetByPortalItem(
portal,
'a454cf97c4264cd2b77f27175e01d3ba',
3,
['ABBRV']
)
// get the lines layer
var lines = FeatureSetByPortalItem(
portal,
'id',
0,
['NAME']
)
// get all lines that have the same NAME as the current $feature
var name = $feature.NAME
var filtered_lines = Filter(lines, "NAME = @name")
// create array of intersected state names
var c_array = []
// iterate over the filtered lines
for(var f in filtered_lines) {
// intersect that line with the states
var xs = Intersects(f, states)
// get the intersected states' names
for (var c in xs){
Push(c_array, c['ABBRV'])
}
}
// remove duplicates
var unique_states = Distinct(c_array)
// concatenate array, return string
return Concatenate(unique_states, ', ')
... View more
04-21-2023
02:26 PM
|
1
|
0
|
1857
|
|
POST
|
Ah. In that case, you would need to do the unique symbology on an Arcade expression. Click on the expression button to open the editor: Use this expression (modify it to fit your actual field names and values): var asset_group = $feature.AssetGroup
// if this is not a FlowControlDevice, just return the asset group
if(asset_group != 300) {
return asset_group
}
// if this is a FlowControlDevice, return 301 if the switch is open, else 302
if($feature.SwitchIsOpen == 1) {
return 301
}
return 302
... View more
04-18-2023
12:49 AM
|
0
|
0
|
1584
|
|
POST
|
That sounds like you want to symbolize with Unique Values.
... View more
04-17-2023
07:54 AM
|
1
|
2
|
1626
|
|
POST
|
Ah OK. You have to do just a little bit more. Intersect the fc with itself delete all features of the intersection where FID1 = FID2 use Join Field to copy the Shape_Area field into the intersection. Do this twice (join with FID1 and with FID2). use Calculate Field to calculate how much the intersection covers the respective features Percentage_1 = Area_Intersection / Area_1 * 100 Percentage_2 = Area_Intersection / Area_2 * 100 Select Layer By Attribute to select those features where both percentages are above a certain threshold, eg 90% export those features. The OBJECTID is the GroupID, the two FID fields are the OBJECTIDs of the features that are part of the group. You can use Join Field to get the GroupID Into the original feature class use Delete Identical on the exported fc with the Shape field fc = "TestPolygons"
out_folder = "memory"
out_name = "Groups"
# read fc as {oid: geometry}
geo = dict([row for row in arcpy.da.SearchCursor(fc, ["OID@", "SHAPE@"])])
# intersect the fc with itself and read the result as [ [ geometry, fid_1, fid_2 ] ]
intersection = arcpy.analysis.Intersect([fc, fc], "memory/intersect", "ONLY_FID")
fid_fields = [f.name for f in arcpy.ListFields(intersection) if f.type=="Integer"]
intersect = [row for row in arcpy.da.SearchCursor(intersection, ["SHAPE@"] + fid_fields)]
# create output
out_table = arcpy.management.CreateFeatureclass(out_folder, out_name, "POLYGON", spatial_reference=fc)
arcpy.management.AddField(out_table, "FID_1", "LONG")
arcpy.management.AddField(out_table, "FID_2", "LONG")
with arcpy.da.InsertCursor(out_table, ["SHAPE@", "FID_1", "FID_2"]) as cursor:
for shp, fid_1, fid_2 in intersect:
# skip if fids are the same
if fid_1 == fid_2:
continue
# get the corresponding original polygons
shp_1 = geo[fid_1]
shp_2 = geo[fid_2]
# if they are sufficiently same-ish, write the fids into the output table
if (shp.area / shp_1.area > 0.9) and (shp.area / shp_2.area > 0.9):
cursor.insertRow([shp, fid_1, fid_2])
arcpy.management.DeleteIdentical(out_table, "Shape")
... View more
04-16-2023
01:36 AM
|
0
|
1
|
3712
|
|
POST
|
With tools: Intersect the both feature classes use Join Field to copy the !Shape_Area! fields from the fcs into the intersection use Calculate Field to calculate how much the intersection covers the respective features Percentage_1 = Area_Intersection / Area_FC1 * 100 Percentage_2 = Area_Intersection / Area_FC2 * 100 Select Layer By Attribute to select those features where both percentages are above a certain threshold, eg 90% export those features. The OBJECTID is the GroupID, the two FID fields are the OBJECTIDs of the features that are part of the group. You can use Join Field to get the GroupID Into the original feature classes Example (yellow polygons labeled with yellow OBJECTIDs, black outlined Polygons labeled with black OBJECTIDs, groups not symbolized but labeled with red OBJECTIDs. Polygons without group don't have enough overlap.) You can do the same with arcpy, but the field mappings are a hassle. It's easier using Cursors: fc_1 = "TestPolygons"
fc_2 = "TestPolygons_1"
out_folder = "memory"
out_name = "Groups"
# read fcs as {oid: geometry}
geo_1 = dict([row for row in arcpy.da.SearchCursor(fc_1, ["OID@", "SHAPE@"])])
geo_2 = dict([row for row in arcpy.da.SearchCursor(fc_2, ["OID@", "SHAPE@"])])
# intersect the fcs and read the result as [ [ geometry, fid_1, fid_2 ] ]
intersection = arcpy.analysis.Intersect([fc_1, fc_2], "memory/intersect", "ONLY_FID")
fid_fields = [f.name for f in arcpy.ListFields(intersection) if f.type=="Integer"]
intersect = [row for row in arcpy.da.SearchCursor(intersection, ["SHAPE@"] + fid_fields)]
# create output
out_table = arcpy.management.CreateFeatureclass(out_folder, out_name, "POLYGON", spatial_reference=fc_1)
for fid in fid_fields:
arcpy.management.AddField(out_table, fid, "LONG")
with arcpy.da.InsertCursor(out_table, ["SHAPE@"] + fid_fields) as cursor:
for shp, fid_1, fid_2 in intersect:
# get the corresponding original polygons
shp_1 = geo_1[fid_1]
shp_2 = geo_2[fid_2]
# if they are sufficiently same-ish, write the fids into the output table
if (shp.area / shp_1.area > 0.9) and (shp.area / shp_2.area > 0.9):
cursor.insertRow([shp, fid_1, fid_2])
... View more
04-15-2023
04:11 PM
|
0
|
3
|
3732
|
|
POST
|
Arcade: Add a function to merge multiple Featuresets Arcade: Add a function that quickly converts a Featureset into an Array
... View more
04-15-2023
05:02 AM
|
0
|
0
|
2558
|
|
IDEA
|
Please add a function that quickly converts a Featureset into an Array. As discussed in this thread, it's sometimes necessary to convert a Featureset into an Array, but loading the Featureset takes a long time, especially accessing it for the first time. So instead of this: var fs = FeaturesetByPortalItem(Portal("https://arcgis.com"), "2b93b06dc0dc4e809d3c8db5cb96ba69", 0)
var fs_arr = []
for(var f in fs) {
Push(fs_arr, Dictionary(Text(f)))
}
return fs_arr It would be helpful (and hopefully much faster) to have a function like this: var fs = FeaturesetByPortalItem(Portal("https://arcgis.com"), "2b93b06dc0dc4e809d3c8db5cb96ba69", 0)
var fs_arr = FeaturesetToArray(fs)
return fs_arr
... View more
04-15-2023
05:00 AM
|
32
|
5
|
3511
|
|
IDEA
|
Please add a function to merge multiple Featuresets together, analogous to the geoprocessing tool Merge. Example case: Sometimes you have multiple services for the same problem (eg scheduled work projects) in different domains (eg wastewater, stormwater, water, gas, road). If you want to display these different Featuresets in a single table/list/chart, you have to create the output featureset, go through the featuresets and push each feature into the output featureset. It would be helpful to have a function like this: // same fields -> without field map
var fs_1 = FeaturesetByPortalItem(..., ["Project", "StartDate", "EndDate"], false)
var fs_2 = FeaturesetByPortalItem(..., ["Project", "StartDate", "EndDate"], false)
var merged_fs = Merge([fs_1, fs_2])
// different fields -> with field map
var fs_1 = FeaturesetByPortalItem(..., ["Project", "StartDate", "EndDate"], false)
var fs_2 = FeaturesetByPortalItem(..., ["ProjectName", "Start", "End"], false)
var merged_fs = Merge([fs_1, fs_2], {"Project": ["Project", "ProjectName"], "Start": ["StartDate", "Start"}, "End": ["EndDate", "End"]})
... View more
04-15-2023
04:51 AM
|
11
|
0
|
951
|
|
POST
|
Hey Josh, thanks that's good stuff! I should note, I'm not timing individual feature loads in the last step, just how long it takes to do a for loop onallfeatures. Yeah, I did that too, which makes the time discrepancy even starker. After you spent a lot of time getting the first feature, it's not nearly instantaneous to access a feature, but all features. when multiple functions are chained together, the Arcade compiler actually combines them into a single request. That's good to know! If you have to extensively use a single FeatureSet, you can load the whole thing into memory by looping through and pushing each feature into a new FeatureSet. [...] What Arcade really needs is a function to quickly convert a FeatureSet into an Array... Yeah, that's the way I went in this case. I had to merge three featuresets and then compare each feature to each other feature. Pushing the features into the array is where this question cropped up, because it took a long time. I'm gonna open ideas for an Array conversion and Merge. Pinging the World Atlas is a good idea and raises two other interesting points: If you load a layer form the Living Atlas in the Arcade Playground, the FeaturesetBy* function returns instantly. Loading the First() feature takes much less time for a layer from the Living Atlas compared to a service from my AGOL: The time to load the layer is approximately the same. But the expression loads the First() feature from the World Atlas in 10 milliseconds, and from my AGOL in 460 milliseconds. That's a somewhat extreme difference.
... View more
04-15-2023
04:33 AM
|
1
|
1
|
2560
|
|
POST
|
That's the same error as in your previous reply. Did you actually change the fc path to include the databas?
... View more
04-14-2023
06:35 AM
|
0
|
0
|
1592
|
|
POST
|
While trying to optimize a data expression for Dashboard with @ChrisSpadi , I realized that the first time you access a feature of a featureset, it takes a very long time. A quick example: var times_load = []
var times_read_first = []
var times_read_all = []
var start
for(var i = 0; i < 10; i++) {
// load the layer
start = Now()
var fs = FeaturesetByPortalItem(Portal("https://arcgis.com"), "78ea2a77985743abb7e83b021da2f728", 0, ["OBJECTID"], false)
Push(times_load, DateDiff(Now(), start))
// access the first feature
start = Now()
var oid = First(fs).OBJECTID
Push(times_read_first, DateDiff(Now(), start))
// acccess all features
start = Now()
for(var f in fs) {
var oid = f.OBJECTID
}
Push(times_read_all, DateDiff(Now(), start))
}
Console(`Loading the layer: ${Round(Average(times_load), 0)} milliseconds. ${times_load}`)
Console(`Reading the first element: ${Round(Average(times_read_first), 0)} milliseconds. ${times_read_first}`)
Console(`Reading all elements: ${Round(Average(times_read_all), 0)} milliseconds. ${times_read_all}`) Loading the layer: 274 milliseconds. [485,255,254,250,246,254,247,247,247,253]
Reading the first element: 588 milliseconds. [1202,479,678,446,546,350,1126,349,340,361]
Reading all elements: 0 milliseconds. [1,0,0,0,0,0,0,0,0,0] This layer has only 8 features. As you can see, getting the layer reference with FeaturesetByPortalItem takes ~0.25 seconds. Accessing the first feature takes ~0.6 seconds (with widely varying times). After that first time, accessing features is instantaneous. Until now, I assumed that FeaturesetBy* loads the layer into the RAM. But this makes it seems as if FeaturesetBy* only establishes a connection to the layer and the first data access reads the whole layer into RAM. Is this interpretation correct? Is there anything we can do to optimize these times (besides specifying fields and not loading geometries, both of which I did here)? @jcarlson , @XanderBakker
... View more
04-14-2023
05:13 AM
|
0
|
4
|
2627
|
|
POST
|
Literally anything. You just want to trigger the Attribute Rule, and the rule will calculate a new value for the Parish field. //Parish =
"abc"
... View more
04-14-2023
04:39 AM
|
0
|
0
|
1601
|
|
POST
|
You forgot the path to the database. fc = "path:/to/your/database.sde/CorGIS.CORMGR.Blablabla"
... View more
04-14-2023
04:37 AM
|
0
|
0
|
1601
|
|
POST
|
Yeah, you can't just take that expression and use it in the field calculator. The Attribute Rule calculates multiple fields at once, you can't do that in the calculator. To apply the rule on an existing feature: create the rule, be sure that it triggers on update make any edit to the feature For bulk updates, just use the field calculator to update a field (let's call it Field1) to the value that is alread in that field: // Field1 =
return $feature.Field1
... View more
04-14-2023
02:19 AM
|
0
|
2
|
4070
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 01-30-2023 09:57 AM | |
| 1 | 05-18-2023 12:51 AM | |
| 1 | 03-05-2023 12:46 PM | |
| 1 | 12-07-2022 07:01 AM | |
| 1 | 06-21-2022 08:27 AM |
| Online Status |
Offline
|
| Date Last Visited |
02-03-2024
06:14 PM
|