|
IDEA
|
That would be good, yes. As a workaround, you can leave the field empty and return a dictionary instead of a single value: var len = Length($feature)
//return len
return {
// in the result object, you can change the geometry and attributes of the $feature
"result": {
"attributes": {"Arcade_Shape_Length": len}
}
} For the full kyeyword documentation, see Attribute rule dictionary keywords—ArcGIS Pro | Documentation
... View more
03-01-2022
11:17 PM
|
0
|
0
|
2123
|
|
POST
|
I did a quick test, your rule works for me, both in FGDB and SDE. Possible workarounds: You can use the $editcontext.editType global The includeGeometry flag of FeatureSetByName should probably be true. I'm actually surprised it works when set to false, because (if I understand it correctly) there shouldn't be any geometry for the Intersects... There's nothing wrong with using separate rules for insert and update. Yes, code duplication can be a bit troublesome, but having (different) insert and update procedures in the same rule can also get confusing. // only compare with original geometry when you update, not on insert
if ($editcontext.editType == "UPDATE" && Equals(Geometry($originalFeature),Geometry($feature))) {
return $feature.SBPI_ID_NO
}
// set includeGeometry to true
var parcels = Filter(Intersects(FeatureSetByName($datastore, "Parcel", ["RETIREDBYRECORD", "SBPI_ID_NO"], true), Centroid($feature)),'RETIREDBYRECORD IS NULL')
if (Count(parcels) > 0) {
var select = first(parcels)
return select.SBPI_ID_NO;
}
return null
... View more
03-01-2022
03:58 AM
|
1
|
0
|
3333
|
|
POST
|
Or you could execute SQL statements using the ArcSDESQLExecute ArcPy class That's a good point. I find this class quite useful for reading user tables, because it's faster than arcpy.da.SearchCursor reading system tables (e.g. listing all tables, listing fields, listing all states), because it's either faster than the arcpy equivalents or not possible in arcpy I tried using it for writing user tables (again, because using SQL is faster than the arcpy cursors), but it didn't trigger Editor Tracking and, far worse for me, it didn't trigger Attribute Rules. I didn't have versioning in place then, so I don't know how it interacts with that. The documentation page you linked raises some interesting points which seem to apply to SQL in general, too: Do not alter enterprise geodatabase system tables using SQL. Corruption can occur if these system tables are edited directly using SQL. Edits on traditional versioned data performed using SQL should only be made through versioned views. Do not edit branch versioned data using SQL. [...] [...] Be aware, though, that SQL access to the geodatabase bypasses geodatabase functionality, such as topology, networks, terrains, or other class or workspace extensions and bypasses triggers and stored procedures used to maintain the relationships between tables needed for certain geodatabase functionality. Circumventing geodatabase functionality can corrupt the relationships between data in your geodatabase. Before attempting to access or modify any enterprise geodatabase objects, read all enterprise geodatabase documentation about using SQL against geodatabase objects in the DBMS.
... View more
02-28-2022
11:25 PM
|
0
|
0
|
8193
|
|
POST
|
Attribute Rules do trigger Editor Tracking, the respective tracking fields are set. Depending on your setup, you maybe won't get the time of the actual insert/update, but the time these changes got saved.
... View more
02-28-2022
11:11 PM
|
0
|
0
|
8194
|
|
POST
|
Just tested a little: In ArcGIS Pro, you can see the class breaks in the field histograms of the symbology pane: If you publish that layer and view its symbology in MapViewer Classic, it reveals that bivariate symbology actually uses an Arcade expression to symbolize, you can get the values out of that: You can either use these values in the expression above, or you can just copy/paste the symbology expression into a popup expression. In my case (X and Y values of the geometry's centroid), it looks like this: Of course, you should probably edit the expression a bit to show more descriptive text... Can't test with Map Viewer, but there's probably a way to get to the values there, too.
... View more
02-28-2022
10:51 PM
|
1
|
0
|
2509
|
|
POST
|
Disclaimer: I have never worked with SQL triggers. SQL triggers need additional software / SQL developers in the IT department. In my organization, server management software is not available for non-IT staff. So I would have to coordinate with IT staff to get what I want. AFAIK, nobody in our IT department knows enough about SQL to write the triggers. I need lots of automatic edits in my database, and during development, my requirements frequently change. In that case it's much easier to learn about Arcade and implement Attribute Rules myself than wait forever for IT to find the time. With Attribute Rules, you can view, create, and edit the data structures, triggers, and data in the same application. You can use Arcade to do other stuff (e.g. popups, labels, visualization, dashboards), so it's actually quite useful to learn. With SQL triggers, you lose all geodatabase functionality. Things like Editor Tracking, Versioning, Archiving are all done automatically with Attribute Rules, while you have to implement that yourself with SQL Triggers. For example, if you edit a versioned table with SQL Triggers and want to emulate the versioning, you have to edit at least the two delta tables, maybe also some geodatabase system tables. Attribute Rules tell you when something is wrong. If you made obvious errors, it won't even let you save the Rule. If you made less obvious errors that only emerge at runtime, you get an error message telling you where the error occured, which is of course extremely helpful for development. I don't know if that is the case with SQL Triggers. Constraint Attribute Rules are a helpful tool. For example, you can reject edits that change a value to be out of some arbitrary bounds, or you can reject edits if the geometry falls inside/outside of a specific area. You can probably do something like that with SQL Triggers, too, but with Constraint Attribute Rules you can define a custom error message to tell the user what is wrong. Validation Attribute Rules let you define some rules that are checked on demand, so that you can do manual quality assurance. Deprecation: Of course this is always a possibility. But Arcade is a new feature that is under constant development and is meant as a language for the whole ArcGIS environment, so I doubt it is going away any time soon. Attribute Rules are a feature of the Geodatabase, whereas Python addons were a feature of the application, that probably also makes a (favorable) difference in regard to deprecation. Locking: Yes, that can suck. In my case, I have only one coworker with write access, all others have only read access. And they don't see (and therefore don't lock) the actual tables, but database views. Another way is to disallow connections as geodatabase admin and then ask the database/server admin to close all existing connections. Limited functionality: I think all the basic stuff is there, and they add new functionality quite frequently. Of course, it isn't as extensive as older languages (and probably never will, as it's developed for very specific purposes). Performance: Rules that only affect the edited feature are quite fast. If you do huge chunks of edits at once, you will notice it. If you do single manual edits, probably not. More complex rules (filter tables, intersection, edit other tables) have a higher performance impact. Manual edits on some of my feature classes can take up to 3 seconds to evaluate the rules. But they are filtering 2-4 tables, do at least multiple intersections and send edit requests to multiple tables that trigger rules on those tables. Accessing vertices: Polylines and Polygons are modelled as array of arrays of points (multipart features). You can access vertices like this: // polyline
var geo = Geometry($feature)
var multipart_path = geo.paths // [ [Point] ]
var singlepart_path = geo.paths[0] // [Point]
// polygon
var geo = Geometry($feature)
var multipart_path = geo.rings // [ [Point] ]
var singlepart_path = geo.rings[0] // [Point]
for(var i in singlepart_path) {
var p = singlepart_path[i]
Console(p.X + "/" + p.Y)
} All in all, I'm a big fan of Attribute Rules and Arcade. It has enabled me to do stuff that I couldn't do with Attribute Assistant and Python Addins. My IT department would hate me if I would come to them asking to change SQL triggers all the time, and I can use the Arcade knowledge I gained to create good-looking popups and do some light label and symbol customization. If you don't do constant automated edits of huge chunks of data, I'd go for Attribute Rules.
... View more
02-28-2022
04:32 AM
|
3
|
5
|
8232
|
|
POST
|
Huh, seems like I wrongly remembered my struggles with changing field length... That's good to know, thanks for the tip!
... View more
02-28-2022
01:44 AM
|
0
|
1
|
2377
|
|
POST
|
AFAIK, there's no way to access the symbology information. You have to do it yourself: function categorize(value, thresholds) {
// takes a value and an array of numbers
// returns the array index of the highest number that is less or equal to the value
// categorize(6, [0, 5, 10]) --> 1
if(value == null) { return 0 } // treat empty goal as low
thresholds = Sort(thresholds)
for(var i = Count(thresholds)-1; i >= 0; i--) { // iterate backwards through the array
if(thresholds[i] <= value) {
return i
}
}
}
if($feature.ProtectionGoal == null && $feature.RestorationGoal == null) {
return "No Protection or Restoration Goals"
}
var protection_thresholds = [0, xxx, yyy] // ha
var protection_goal = categorize($feature.ProtectionGoal, protection_thresholds)
var restoration_thresholds = [0, xxx, yyy] // ha
var restoration_goal = categorize($feature.RestorationGoal, restoration_thresholds)
var status = When(
protection_goal == 0 && restoration_goal == 0, "low protection and restoration need",
protection_goal == 1 && restoration_goal == 0, "medium protection need",
protection_goal == 2 && restoration_goal == 0, "high protection need",
protection_goal == 0 && restoration_goal == 1, "medium restoration need",
protection_goal == 1 && restoration_goal == 1, "bla",
protection_goal == 2 && restoration_goal == 1, "bla",
protection_goal == 0 && restoration_goal == 2, "bla",
protection_goal == 1 && restoration_goal == 2, "bla",
protection_goal == 2 && restoration_goal == 2, "bla",
"uncategorized"
)
return status
... View more
02-28-2022
12:50 AM
|
1
|
0
|
2534
|
|
POST
|
I don't know how to do it in AGOL, but here's how you would do it in the Desktop environments, maybe it's similar... create a temporary text field with at least the size of the original text field copy all values from the text field to the temporary text field recreate the text field with the new size copy all values from the temporary text field to the recreated text field delete the temporary text field republish
... View more
02-27-2022
10:33 PM
|
0
|
3
|
2384
|
|
IDEA
|
Curiously, I don't see Min behaving that way when using a FeatureSet I'm not sure how to feel about that. On the one hand, it shows that it is absolutely possible to ignore the nulls. On the other hand, I'd much rather have the same (albeit wrong) result with both methods. It gets worse: Calling Abs($feature.NullValue) still returns 0, so even that isn't consistent. I retract my previous statment: I'm sure how I feel about this, it's bad. var fs = FeatureSet(Text(
{
fields: [{name: 'ints', type: 'esriFieldTypeInteger'}],
geometryType: '',
features: [{attributes: {ints: Null}}, {attributes: {ints: 1}}, {attributes: {ints: 2}}, {attributes: {ints: 3}}]
}
))
var values = []
for(var f in fs) { Push(values, f.ints) }
Console("Min")
Console("fs: " + Min(fs, "ints"))
Console("array: " + Min(values))
Console("\nAverage")
Console("fs: " + Average(fs, "ints"))
Console("array: " + Average(values))
Console("\nAbs")
var fs_abs = []
for(var f in fs) { Push(fs_abs, Abs(f.ints)) }
var array_abs = Map(values, Abs)
Console("fs: " + fs_abs)
Console("array: " + array_abs) Min
fs: 1
array: 0
Average
fs: 2
array: 1.5
Abs
fs: [0,1,2,3]
array: [0,1,2,3]
... View more
02-24-2022
06:17 AM
|
0
|
0
|
3617
|
|
IDEA
|
Mathematical Functions | ArcGIS Arcade | ArcGIS Developer While answering a question, I realized that Arcade treats null values as zero in the mathematical functions: var data = [1, 2, 3]
var data_z = [1, 2, 3, 0]
var data_n = [1, 2, 3, null]
function print(f, d, z, n) {
Console("\n" + f)
Console("data: " + d)
Console("data_z: " + z)
Console("data_n: " + n)
}
print("Average", Average(data), Average(data_z), Average(data_n))
print("StDev", StDev(data), StDev(data_z), StDev(data_n))
print("Variance", Variance(data), Variance(data_z), Variance(data_n))
print("Min", Min(data), Min(data_z), Min(data_n))
Console("\nAbs(null): " + Abs(null)) Average
data: 2
data_z: 1.5
data_n: 1.5
StDev
data: 0.816496580927726
data_z: 1.118033988749895
data_n: 1.118033988749895
Variance
data: 0.6666666666666666
data_z: 1.25
data_n: 1.25
Min
data: 1
data_z: 0
data_n: 0 Abs(null): 0 In my opinion, this is wrong. Null means something very different from zero: "The temperature today was 0°C" vs. "The thermometer broke, we couldn't measure" "I counted 0 cars driving through that street in the last hour" vs. "I was on my lunch break" In general: "I know the value, it is zero" vs. "I don't know the value" I think, null values should not be treated as zero. Instead, array functions (like Average, Min, etc.) should ignore them, so that Min([1, 2, 3]) == Min([1, 2, 3, null]) single-value functions should return null, so that Abs(null) == null
... View more
02-23-2022
11:53 PM
|
7
|
7
|
3668
|
|
POST
|
function non_zero_average(values) {
var non_zero = []
for(var i in values) {
var v = values[i]
if(!IsEmpty(v) && v != 0) {
Push(non_zero, v)
}
}
return Average(non_zero)
}
return non_zero_average([1, 2, 3, 0, null])
... View more
02-23-2022
11:16 PM
|
1
|
1
|
5811
|
|
POST
|
Attribute Rules can do stuff like that. Introduction to attribute rules—ArcGIS Pro | Documentation
... View more
02-23-2022
10:25 PM
|
1
|
1
|
1678
|
|
POST
|
So you want to see the tools in the geoprocessing history? This is already the case (at least for me): go to the geoprocessing history Hovering over the completed tools should give you a window with the tool's parameters, environment, messages and elapsed time: This works for both scripts and custom tools (python toolbox, haven't tested script tools). My code snippet gets the log messages of the tool you ran last (which should include start time, end time, elapsed time, warnings, and errors) and prints them or adds them to your script tool's messages.
... View more
02-23-2022
06:57 AM
|
0
|
0
|
3949
|
|
POST
|
GetMessages—ArcGIS Pro | Documentation import arcpy
fc = arcpy.GetParameterAsText(0)
arcpy.GetCount_management(fc)
# Print all of the geoprocessing messages returned by the
# last tool (GetCount)
print(arcpy.GetMessages())
arcpy.AddMessage(arcpy.GetMessages())
... View more
02-22-2022
11:31 PM
|
0
|
3
|
3962
|
| 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
|