|
BLOG
|
The real treasure is the friends we make along the way 🙂
... View more
07-31-2022
06:24 AM
|
3
|
0
|
1215
|
|
POST
|
I'm trying to figure out how to extract the feature class associated with the $feature instead of hardcoding it. AFAIK, that's not possible. You'll have to hardcode that. Ideally, it would be able to extract all the non-readonly fields and dump them into the copy_fields variable. That does sound like a better way... You'll have to hardcode the readonly fields, but they should be the same for all feature classes, so you only have to do it once. The list in the code is not complete! var readonly_fields = ["OBJECTID", "GlobalID", "Shape__Area", "Shape__Length", "created_by", "created_on", "GDB_ARCHIVE_OID", "GDB_IS_DELETE"] // exclude readonly fields (OBJECTID, GlobalID, editor tracking, versioning, etc.)
var old_attributes = Dictionary(Text($feature)).attributes
var new_attributes = Dictionary()
for(var field in old_attributes) {
if(!Includes(readonly_fields, field)) {
new_attributes[field] = old_attributes[field]
}
}
... View more
07-29-2022
02:51 AM
|
1
|
1
|
2741
|
|
POST
|
A and B are floats, "/" is a string. In Python, addition between float and str isn't defined, so the Field Calculator doesn't know what to do. You have to convert the floats to strings using one of these methods: # explicitly cast the floats to strings
str(!A!) + "/" + str(!B!)
# implicitly cast to string with str.format()
"{}/{}".format(!A!, !B!)
# implicitly cast to string with format string
f"{!A!}/{!B!}"
... View more
07-29-2022
02:29 AM
|
2
|
0
|
3104
|
|
IDEA
|
I just want the views to present data. For example: I have a feature class "Buildings" which stores information about buildings. I have a table "Contacts" which stores contact information. Buildings store the key to the contact information of their maintainers. In my map, I want to show the contact info in the building's popup. So I create a database view: SELECT b.GDB_ARCHIVE_OID, b.Shape, b.SomeAttribute, c.Name, c.Telephone
FROM db.do.Buildings b
LEFT JOIN db.do.Contacts c
ON b.ContactID = c.ContactID This works fine for unedited buildings and contacts. But let's say I edit a contact. Because a branch versioned table contains its own archive, the same ContactID is now in the table twice. The database view now contains two objects at the same position: one with the old contact information, one with the new. If I delete the building, the view will still show it. Basically, I see the whole archive of Buildings and Contacts for this object. I can circumvent that by selecting the most current entry for each OBJCETID in each table: SELECT b.GDB_ARCHIVE_OID, b.Shape, b.SomeAttribute, c.Name, c.Telephone
FROM (
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY OBJECTID ORDER BY GDB_FROM_DATE DESC) AS rank
FROM db.do.Buildings
) ranked_buildings
WHERE rank = 1 AND GDB_IS_DELETE = 0
) b
LEFT JOIN (
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY OBJECTID ORDER BY GDB_FROM_DATE DESC) AS rank
FROM db.do.Contacts
) ranked_contacts
WHERE rank = 1 AND GDB_IS_DELETE = 0
) c
ON b.ContactID = c.ContactID This is difficult to read, difficult to write, error prone, and probably inefficient. Especially as I often join multiple tables. And it seems like this could be dome automatically by the geodatabase, analogous to the versioned views in traditional versioning. From a user's perspective, I want to be able to use the first query, just with Buildings_evw instead of Buildings.
... View more
07-29-2022
02:15 AM
|
0
|
0
|
9400
|
|
POST
|
When validating your expression, Arcade will return empty FeatureSets with functions like Intersects(). Calling First() on an empty FeatureSet returns null. So xs_feat is null, thus you can't call a member method on null. You have to check for null before you continue: var other_layer = ...
var xs_feat = First(Intersects($feature, other_layer))
if(xs_feat == null) { return "Some default value" }
return xs_feat.Project
... View more
07-27-2022
09:15 AM
|
1
|
0
|
1222
|
|
POST
|
Multipart To Singlepart (Data Management)—ArcGIS Pro | Documentation
... View more
07-26-2022
10:33 PM
|
2
|
0
|
2093
|
|
POST
|
Yeah, I didn't test before posting... It tries to remove sublayers from the list, but they aren't in the list because you removed them in line 39 above. Just let it fail silently: try:
layer_list.remove(sub_layer)
except ValueError:
pass # sub_layer not in layer_list
... View more
07-26-2022
10:30 PM
|
0
|
1
|
7134
|
|
POST
|
I'm severely limited by IT restrictions. No chance to get an IDE or even Notepad++. I only have access to Python because it comes with ArcGIS, I can't get packages other than the ones that are preinstalled... So, I use the expression window in ArcGIS Pro, even for really long expressions. It needs a button to maximize it, but else it's doable.
... View more
07-26-2022
12:56 AM
|
1
|
2
|
6345
|
|
POST
|
You should be able to copy from SDE to FGDB using the XML Workspace Document: Export XML Workspace Document (Data Management)—ArcGIS Pro | Documentation Import XML Workspace Document (Data Management)—ArcGIS Pro | Documentation If this doesn't work, there is a script here: arcgis 10.1 - Copying ArcSDE geodatabase to file geodatabase using ArcPy? - Geographic Information Systems Stack Exchange I'm interested in your script (and why it doesn't work for SDEs). Could you post it, please?
... View more
07-26-2022
12:42 AM
|
1
|
6
|
10093
|
|
POST
|
You can use the Round() function. Other stuff: it's better to just load the fields you need to use less bandwidth, especially for large datasets if you fill an array and concatenate it, you won't have the empty first line if you restructure a bit, you can get rid of the nested code blocks var fs = FeatureSetByRelationshipName($feature,"qry_HUC_USEGROUP_RET" , ["YearNumber", "SumOfReturnMG"], false);
var result = []; //array
// start loop through related records
for (var f in fs) {
// for each f (=feature) in related features, add attendee to the result
Push(result, f.YearNumber + TextFormatting.NewLine + Round(f.SumOfReturnMG, 2);
}
// if result is empty, return a default value, else return the concatenated array
return IIF(Count(result) == 0, "", Concatenate(result, TextFormatting.NewLine))
... View more
07-26-2022
12:29 AM
|
0
|
0
|
927
|
|
POST
|
Something like this could do what you want: create a point feature class, add GlobalID create a field in that fc that will work as a foreign key to the table you wish to edit edit and add this attribute rule // Calculation Attribute Rule on your point FC
// Field: empty
// Triggers: Insert
// Exclude from application evaluation
// get the rows that will be updated
var key = $feature.KeyField
var table = FeatureSetByName($datastore, "Database.Dataowner.TableYouWantToEdit", ["GlobalID", "KeyField"], false)
var rows = Filter(table, "KeyField = @key")
// create and fill the update array
var lat_long_attributes = {"LAT": Geometry($feature).y, "LONG": Geometry($feature).x}
var updates = []
for(var row in rows) {
Push(updates, {"globalID": row.GlobalID, "attributes": lat_long_attributes}
}
// tell ArcGIS to edit the table
return {
"edit" [{
"className": "Database.Dataowner.TableYouWantToEdit",
"updates": updates
}]
} The workflow for this would be copy the key of the feature you want to edit create point feature --> paste key into the feature template, create the point in the correct location the attribute rule will trigger and write the coordinates of the new point into the lat/long fields of the row(s) you specified with the key
... View more
07-26-2022
12:00 AM
|
0
|
5
|
5239
|
|
POST
|
I am not sure why I am unable to see such granularity in terms of properties under Legend Hmm, no idea, but you can also do it with Python (see line 22). I would also like to know how I can specify which layers I would like to export, instead of all the layers on the map. listLayers() has an optional string argument which lets you search for layer name patterns. You could mabe rig something up with listLayers("*Stats"), but the far easier and more expandable way is to add a second step that only keeps the layers with the names you specify. See lines 32 and 39. from pathlib import Path
def export_layout_for_each_layer(layer_list, layout, save_folder):
save_folder = Path(save_folder)
# turn all layers off
for layer in layer_list:
layer.visible = False
# while there are still layers in the list
while layer_list:
# remove the first layer from the list and make it visible
layer = layer_list.pop(0)
layer.visible = True
# special treatment for group layers
if layer.isGroupLayer:
# recursively call this function on its sub layers (this exports all the sub layers on their own
export_layout_for_each_layer(layer.listLayers(), layout, save_folder)
# make the sub layers visible (so we can export the group layer) and remove the sub layers from the master layer list (because we already exported them)
for sub_layer in layer.listLayers():
layer_list.remove(sub_layer)
sub_layer.visible = True
# make sure the legend only shows active layers
layout.listElements("LEGEND_ELEMENT")[0].syncLayerVisibility = True
# set title and export, then make layer invisible
print(f"Exporting layout for {layer.name}")
layout.listElements("TEXT_ELEMENT")[0].text = layer.name
layout.exportToPDF(save_folder/f"{layer.name}.pdf")
layer.visible = False
# define your save location and export layerrs
save_folder = Path(arcpy.env.workspace).parent
export_layer_names = ["Money Stats" , "House Stats", "Car Stats", "Travel Stats"]
# get the elements you need
aprx = arcpy.mp.ArcGISProject("current")
layout = aprx.listLayouts("Layout")[0]
map_frame = layout.listElements('MAPFRAME_ELEMENT')[0]
all_layers = map_frame.map.listLayers()
export_layers = [layer for layer in all_layers if layer.name in export_layer_names]
# run it
export_layout_for_each_layer(export_layers, layout, save_folder)
... View more
07-25-2022
11:20 PM
|
0
|
3
|
7151
|
|
POST
|
According to your working query, 2022 should be provided as string, but it's an integer. Try these approaches: // convert this_year to string
var CB_gid = $feature.GlobalID;
var this_year= Text(Year(Now()));
var filter_statement = 'guid = @CB_gid AND last_cleaned IS NOT Null AND YEAR(last_cleaned) = @this_year)' // take care of the types yourself
var filter_statement = `guid = '${$feature.GlobalID}' AND last_cleaned IS NOT Null AND YEAR(last_cleaned) = '${Year(Now())}')`
... View more
07-25-2022
11:03 PM
|
0
|
0
|
1024
|
|
IDEA
|
No. The versioned views would show the current state of the version I'm currently connected to. Basically, they would look exactly like what you see when you open a branch versioned feature class in ArcGIS Pro: For each ObjectID, show the entry with the most recent GDB_FROM_DATE, except when GDB_IS_DELETE = 1. Hide all the versioning fields. ArcGIS Pro does all that, but apparently only in the application. I want exactly that behavior as an automatic, queriable view in the database. In traditional versioning, we have the base table, the a and d tables, and the archive table. ArcGIS provides a versioned view that pieces together the base, a, and d tables. This way, you can easily query the current state with SQL for database views, without having to worry about all the versioning stuff. SELECT * FROM TraditionallyVersionedTable_evw In branch versioning, we have only one table that contains versioning info and the archive. Now we don't have to fuss with a and d tables, but we have to take care to remove archived features from our database views (eg using the approach in my question). I don't want to have to do that myself. ArcGIS is capable of doing it, I just want to write my database views without having to worry about all the versioning stuff. SELECT * FROM BranchVersionedTable_evw
... View more
07-25-2022
10:52 PM
|
0
|
0
|
9444
|
|
IDEA
|
I recently made the switch to branch versioning and am now stumbling over the lack of versioned views (like the automatically created Featureclass_evw views for traditionally versioning). I have a typical relational database (SQL Server), mostly in third normal form. Of course, users of my maps don't care how the data is structured behind the scenes, they want to have all the info for an object in one place. So my workflow up to now has been to create database views that take care of all the joins and then publish these views to our Portal and consume them in my web maps. Now I have branch versioning in place, published the raw feature classes and tables to the Portal, users can use those to edit the database, cool. But now my database views are all messed up. With traditional versioning, I would use the automatically provided versioned views like this: SELECT t1.OBJECTID, t1.Shape, t2.Field
FROM database.dataowner.Table1_evw t1
LEFT JOIN database.dataowner.Table2_evw t2 ON t1.Key = t2.Key If I use that approach with branch versioned tables (without the _evw), the whole archive of both tables is pulled into the database view. If I edit a feature in Table1 and edit a related row in Table2 two times, I will get 6 output rows for the same feature. If I move the feature, it will have both the old and the new location in the view. If I delete it, it will still be shown in the view. I can circumvent that by creating versioned views for each table myself and then use those views for the other database views: /*Table1_evw*/
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY OBJECTID ORDER BY GDB_FROM_DATE DESC) AS rank
FROM database.dataowner.Table1
) AS ranked_table
WHERE rank = 1 AND GDB_IS_DELETE = 0 But this seems clunky and error prone and is probably quite computationally wasteful. And ArcGIS Pro already does this: If you look at a branch versioned table, it shows the current state of the table in the selected version, and it hides all the versioning fields. All "Add Archive" seems to do is add the raw table to the map. So, my suggestion: Give us automatically created versioned views for branch versioned tables. These would show the current state of the selected version, and they would be addressable by SQL.
... View more
07-25-2022
07:54 AM
|
22
|
12
|
10437
|
| 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
|