|
POST
|
// Calculation Attribute Rule on the maintenance table
// field: ExpireDate
// triggers: insert
var maintenance_date = $feature.MaintenanceDate
if(maintenance_date == null) {
// if there is no date value in the field, you have two options:
// return null (no expire date)
// use the current date
// return null // uncomment this line to return null
maintenance_date = Today()
}
var expire_date = DateAdd(maintenance_date, 10, "days")
return expire_date
... View more
03-22-2023
11:53 PM
|
0
|
0
|
1109
|
|
POST
|
var codes = {
"Very bad": 0,
"Bad": 1,
"Good": 2,
"Very good": 3,
}
if(HasKey(codes, $feature.StringField)) {
return codes[$feature.StringField]
}
return 999 // default value if you forgot a code
... View more
03-22-2023
11:59 AM
|
0
|
0
|
1218
|
|
POST
|
Labels only show strings, s you have to return a string. I can' test right now, maybe it works with the DataFrame method: def FindLabel():
table = getTable()
return table.to_string() If it doesn't, you can try constructing it yourself (untested): def FindLabel():
d = {"DATE": ["Fall 2018", "Spring 2019"], "RESULTS": [7.1, 8.4]}
# get the column names and the max row count
columns = k in d.keys()
num_rows = max([len(d[c]) for c in columns])
# header in bold
rows = [
"\t".join([f"<BOL>{c}</BOL>" for c in columns]),
]
# append the values
for r in range(num_rows):
row = []
for c in columns:
# get the value of current r and c, or default empty string
try:
row.append(str(d[c][r]))
except IndexError:
row.append(" ")
rows.append("\t".join(row))
# concatenate the rows with line breaks
return "\n".join(rows)
... View more
03-22-2023
11:48 AM
|
1
|
0
|
3090
|
|
POST
|
You created the rule on the basin fc. This rule will only be executed if you change a basin feature. It will do nothing when you change the related table. To do what you want, you have to create an Attribute Rule on the related table that changes the basin fc. You can do that by returning a dictionary instead of a single value. Documentation of that dictionary can be found here: Attribute rule dictionary keywords—ArcGIS Pro | Documentation Something like this should work (untested!). Edit lines 7&8 to use the actual field you use for the relationship instead of BasinID! // Calculation Attribute Rule on the customer table
// field: leave empty
// triggers: insert, update, delete
// exclude from application evaluation
// get all features belonging to the same basin
var basin_id = $feature.BasinID
var query = "BasinID = @basin_id"
if($editcontext.editType == "DELETE") {
// exclude this feature if we're deleting it
var oid = $feature.OBJECTID
query += " AND OBJECTID <> @oid"
}
var wastewater_loads = Filter($featureset, query)
// get the total
var total_gallons = Sum(wastewater_loads, "gallons")
// get the related basin
var basin = First(FeaturesetByRelationshipName("Basins_Pop_Employ_2021_22_TESTENV")
if(basin == null) { return }
// return the dictionary to edit the basin fc
return {
edit: [{
className: "Basins_Pop_Employ_2021_22_TESTENV",
updates: [{
objectID: basin.OBJECTID,
attributes: {TGallons: total_gallons}
}]
}]
}
... View more
03-22-2023
11:28 AM
|
1
|
4
|
3247
|
|
POST
|
If you post a screenshot of the tool parameters and of the error message, I and other users might find out why.
... View more
03-20-2023
02:42 PM
|
0
|
0
|
1817
|
|
POST
|
So you converted a raster to polygons, ran Zonal Statistics on the raster and now want those statistics in the polygons? You used Add Join. This tool virtually adds all fields from the join table to the target table, based on the specified relationship. The fields aren't really in the table (in the database). ArcGIS just displays them inside the current project. As they aren't really there, you can't delete them. Multiple options: Hide the fields Export the layer to a new feature class. That fc actually has all those fields, so you can delete them Use Join Field and choose the fields you want to append to the polygon fc
... View more
03-20-2023
01:56 PM
|
1
|
2
|
1831
|
|
POST
|
Since I switched to Pro 3 years or so ago, I have used Attribute Rules heavily in my database. Things I do include Automatic primary key maintain topological relationships stream segments and their junctions create a junction: snap to closest segment, split that segment at the junction create a segment: look for junctions close to end points (snap to the junctions or create new ones) move a junction: move the segment vertices and vice versa streams and buildings (bridges, culverts, weirs, etc) create/edit building: snap to nearest segment move segment: re-snap buildings get attributes from related tables (relationships via location and/or attributes) edit other tables Constraint rules Validation Rules Some answers to your questions (of course, only from my experience, your mileage may vary): Many rules vs huge rules: I tend to huge. cons: unwieldy to work with, especially in the default Arcade editor. pros: you don't have to do the same steps (eg load the same featureset) in multiple rules, which is good for writing and changing the rule/database schema and for execution time. If multiple rules trigger on the same table, you have no control over the execution order, which can give unwanted results if a rule depends on a field that is calculated by another rule. If you calculate both fields in the same rule, you have full control. if you have to debug, you only have one rule to check vs two or three or even more. of course, working through a huge rule can also be more cumbersome than working through several small ones... other geodatabase features: I haven't worked with contingent values. But for default values I found that it is just as easy to check a field for null and return the default value with the other calculated values. alternative mechanisms: bulk inserts/edits with attribute rules that load other tables are really slow, because the other tables get loaded for each feature. if you have to do that often, a python script is better (just read the other table once, store it in a list/dict and work with that). same goes for field calculation with related tables same goes for validation rules. I wanted to validate my topological relationships (I know, there's the topology dataset, but I have attributes based on topology, too). But that took hours for my relatively small database, while a simple Python tool does the same in under 10 minutes. Other things I did to make my rules manageable: You may want to use an external editor (I wanted to but couldn't because of IT restrictions) Have your rules saved somewhere (could already be solved with an external editor). That is good for version control and for quickly taking a look at the rule without opening Pro, navigating to the table, opening the Attribute Rules view, and opening and resizing the editor. Personally, I developed my rule in the default editor until it worked, then I ran a tool that exported all attribute rules to text files. Personally, I find the separation into Calculation/Constraint/Validation somewhat cumbersome, because I kept on forgetting that some tables had constraint rules. So I just converted my constraint rules to calculation rules (or incorporated them in existing ones). To reject an edit, you can return a dict with the key errorMessage (see here). Mostly, I just used a default value if some error occured to let the edit through.
... View more
03-20-2023
01:44 PM
|
6
|
7
|
10878
|
|
POST
|
Yeah, if you want to access another table in attribute rules, it has to be in the same database. In other profiles (eg field calculation or popup), you can also access fetauresets from the map or from Portal/AGOL.
... View more
03-20-2023
12:47 PM
|
0
|
0
|
2729
|
|
POST
|
Is that the actual name? Check it in the layer's properties, could be an alias. Is the Land_grid fc in the same database as the fc for which you are creating the attribute rule?
... View more
03-20-2023
12:31 PM
|
1
|
0
|
2737
|
|
POST
|
To post code: You have to make the field that gets updated dependent on the value in InspectionReason. You're correct, you can do this with in if/else. Here, I use When(), which is multiple if/elses chained together, so you can even add more inspection reasons later on. I also removed the unused loading of the parent table. var update_field = When(
$feature.InspectionReason == "Condition Rating", "LastConditionRatingInspectDate",
$feature.InspectionReason == "Maintenance Activity", "LastMaintenanceActivityDate",
null // some other inspection reason
)
var parent_id = $feature.ParentGUID
if (IsEmpty(parent_id) || IsEmpty(update_field)) { return parent_id }
var update = {"globalID": parent_id, "attributes": {}}
update.attributes[update_field] = $feature.InspectionDate
return {
'edit': [{
'className': 'CTDOT_Planning_OtherDrainage',
'updates': [update]
}]
}
... View more
03-20-2023
12:21 PM
|
0
|
0
|
2866
|
|
POST
|
Making a method parameter final is mostly a safety feature for the programmer of the method. It doesn't have any effect on calling the method, because (as you demonstrated) changing a parameter inside a method doesn't change it outside the method's scope. So, why make a parameter final? It prevents easily made errors like this: public class Test {
static class MyObject {
private int id;
public void set_id(int id) {
id = id; // Oops, I wanted to set this.id, but I reassigned the parameter!
}
public int get_id() {
return this.id;
}
}
public static void main(String args[]) {
MyObject obj = new MyObject();
obj.set_id(123);
System.out.println(obj.get_id());
}
} ID: 0 Now, this is an easy example, and you would find the error rather quickly, but in long methods it can easily become more complex. If we make the parameter final, we will get a compile time error, so we can fix the error right away: public class Test {
static class MyObject {
private int id;
public void set_id(final int id) {
id = id; // Oops, I wanted to set this.id, but I reassigned the parameter!
}
public int get_id() {
return this.id;
}
}
public static void main(String args[]) {
MyObject obj = new MyObject();
obj.set_id(123);
System.out.println("ID: " + obj.get_id());
}
} /Test.java:6: error: final parameter id may not be assigned
id = id; // Oops, I wanted to set this.id, but I reassigned the parameter!
^
1 error Apart from obvious errors like that, reassigning parameters inside the method can be seen as bad practice in general (especially in long, convoluted methods). The final keyword helps the programmer to avoid that. As a side note: Your pojo example doesn't apply to the question, because you're not changing the value the parameter points to, but an internal value of the parameter. The final keyword does not prevent this. A somewhat better example (I hope nobody programs something like this in practice...) would be this, demonstrating again how making a parameter final (and not reassigning parameters to new values) can avoid confusion and errors: public class Test {
static class MyObject {
private int id;
public void set_id(final int id) {
this.id = id;
}
public int get_id() {
return this.id;
}
}
static MyObject set_object_id(MyObject obj, int id) {
obj = new MyObject();
obj.set_id(id);
return obj;
}
public static void main(String args[]) {
MyObject obj = new MyObject();
set_object_id(obj, 123);
System.out.println("ID: " + obj.get_id());
}
} ID: 0 If line 14 is hidden somewhere in a long and complex method, you or your successor will have to search for a long time to find out why the internal value didn't change. Now, if we make the parameters in line 13 final, we will get a compile time error. We look at that, realize what we did wrong, and fix it. Making parameters final helps to avoid errors. public class Test {
// ...
static MyObject set_object_id(final MyObject obj, final int id) {
//obj = new MyObject();
obj.set_id(id);
return obj;
}
public static void main(String args[]) {
MyObject obj = new MyObject();
set_object_id(obj, 123);
System.out.println("ID: " + obj.get_id());
}
} ID: 123
... View more
03-15-2023
06:55 AM
|
1
|
1
|
1633
|
|
POST
|
If you have a unique id field with the same values in the wrong and correct layers, you can use a little Python script: # parameters
wrong_geometries_fc = "TestPoints" # layer name or path to the shapefile
wrong_geometries_id_field = "IntegerField2" # name of the id field
correct_geometries_fc = "TestPointsAGOL"
correct_geometries_id_field = "IntegerField2"
# read the correct geometries
correct_geometries = {i: shp for i, shp in arcpy.da.SearchCursor(correct_geometries_fc, [correct_geometries_id_field, "SHAPE@"])}
# iterate over the wrong geometries
with arcpy.da.UpdateCursor(wrong_geometries_fc, [wrong_geometries_id_field, "SHAPE@"]) as cursor:
for i, shp in cursor:
# find the correct geometry and update
try:
correct_geometry = correct_geometries[i]
cursor.updateRow([i, correct_geometry])
except KeyError:
print(f"No correct geometry found for {wrong_geometries_id_field} = {i}")
... View more
03-15-2023
03:01 AM
|
0
|
0
|
1304
|
|
IDEA
|
This already exists. There is a button: Or you can press Ctr+Shift+A
... View more
03-15-2023
02:36 AM
|
0
|
0
|
721
|
|
POST
|
Seems like you're working with an Arcade Element. These are slightly different from "normal" Arcade expressions. An Expression in a popup behaves somewhat like a field. You can show it in the field list, and you can use it's return value in text elements. But an expression can only return one value and it has to be a basic data type (string, integer, float, date). Elements can do more advanced stuff like returning multiple values, displaying charts, or evaluating HTML. But to be able to do that, the popup has to know what you're returning, that's why you have to specify that with the dictionary. You see few examples of Arcade Elements because they're still quite new (Arcade 1.16, which corresponds to ArcGIS Pro 2.9 and ArcGIS Enterprise 11.0). Most people still work with Arcade Expressions. The docs for the Arcade Element (the docs call it Popup Element, but I believe in the Map Viewer its actually Arcade Element) is here: https://developers.arcgis.com/arcade/profiles/popup-element/ And here are some examples of return dictionaries: https://developers.arcgis.com/web-map-specification/objects/popupElement/
... View more
03-14-2023
04:06 PM
|
0
|
1
|
2282
|
|
POST
|
Your last line is wrong. You're returning city_fields, which is an Array: ['CITYNAME'] When you test the expression, it will successfully return that array (or more probably the default value). I would argue that it is not a valid response, though, as you want the actual field value... In the popup, it tries to return the array, but it's only allowed to display a string, so it displays nothing. var fac = FeatureSetByName($map, "City Boundaries", ["CITYNAME"])
var intfac = First(Intersects($feature, fac))
If(IsEmpty(intfac)){
return 'Jurisdiction: Unincorporated Washington County'
}
return intfac.CITYNAME
... View more
03-14-2023
03:48 AM
|
0
|
3
|
2294
|
| 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
|