POST
|
I'm not quite sure what you mean by combine. Do you want to also get the colors from a symbology with grouped unique values? Or do you have layers with grouped values from multiple fields? Eh, let's do both... To extract the item dict for different combinations of (multiple fields) and (grouped values), we have to generalize a bit. Let's take a look at how these combinations are represented in Python: # 4 layers with different Unique Value symbologies
layer_names = [
"unique", # just a plain UV symbology
"unique_grouped", # UV from a single field, but in groups
"unique_multiple", # UV from multiple fields, ungrouped
"unique_multiple_grouped", # UV from multiple fields, grouped
]
aprx = arcpy.mp.ArcGISProject("current")
for name in layer_names:
layer = aprx.activeMap.listLayers(name)[0]
renderer = layer.symbology.renderer
first_item = renderer.groups[0].items[0]
print(f"layer:\t{layer.name}\nfields:\t{renderer.fields}\nvalues:\t{first_item.values}\n\n") layer: unique
fields: ['TextField1']
values: [['A']]
layer: unique_grouped
fields: ['TextField1']
values: [['A'], ['B']]
layer: unique_multiple
fields: ['TextField1', 'IntegerField1']
values: [['A', '12345']]
layer: unique_multiple_grouped
fields: ['TextField1', 'IntegerField1']
values: [['A', '12345'], ['C', '2']] values is a list of lists. There is an inner list for each value in the group. In these lists, there is a (string!) value for each field. We want to use these lists as dictionary keys, but that's impossible, because keys have to be immutable, and lists are mutable, so we change them to immutable tuples. Also, we have to have a separate key for each value in a group. def get_item_dict(symbology):
if symbology.renderer.type != "UniqueValueRenderer":
raise ValueError("symbology has to be Unique Value!")
item_dict = dict()
for group in symbology.renderer.groups:
for item in group.items:
for value_group in item.values:
item_dict[tuple(value_group)] = item
return item_dict Also, let's put the color conversion into a separate function to make the code a bit cleaner... def convert_to_hex(color):
color_type = list(color.keys())[0]
if color_type == "RGB":
rgb = color["RGB"][:3]
return "#%02x%02x%02x" % tuple(rgb)
else:
return None And with these two functions, we can concentrate on the actual workflow: layer_names = ["TestPolygons"]
aprx = arcpy.mp.ArcGISProject("current")
for name in layer_names:
# get the layer
layer = aprx.activeMap.listLayers(name)[0]
# create a dict {values: item}
item_dict = get_item_dict(layer.symbology)
# add a new field
arcpy.management.AddField(layer, "PW_Zoning_Designation", "TEXT")
arcpy.management.AddField(layer, "ColorRaw", "TEXT")
arcpy.management.AddField(layer, "ColorHex", "TEXT")
# insert the label and color values
with arcpy.da.UpdateCursor(layer, ["PW_Zoning_Designation", "ColorRaw", "ColorHex"] + layer.symbology.renderer.fields) as cursor:
for row in cursor:
# get the item
key = tuple([str(x) for x in row[3:]]) # item.values stores values as string
try:
item = item_dict[key]
# no item found -> default value and skip to the next feature
except KeyError:
row[0] = "No Symbol"
cursor.updateRow(row)
continue
# store the item's label
row[0] = item.label
# store the raw color
row[1] = str(item.symbol.color)
# store the hex value
row[2] = convert_to_hex(item.symbol.color)
# write values
cursor.updateRow(row)
... View more
01-25-2024
09:37 AM
|
0
|
0
|
1063
|
POST
|
Glad to help 🙂 If your question is answered, please mark the solution so that this thread shows as answered.
... View more
01-25-2024
08:27 AM
|
0
|
0
|
640
|
POST
|
Yes, I used test data here... Your expression would look like this: var portail = Portal('https://xxxxx.ca/portal');
var fs = FeatureSetByPortalItem(
portail,
//itemid layer jobsignalisation
'250b512105df48169e8d01xxxxxxxxxx',
//layer id
0,
[
'nojob'
],
false);
return GroupBy(fs,
[{name: "test", expression: "SUBSTRING(nojob, 1, 4)"}],
[{name: "test_count", statistic: "COUNT", expression: "1"}]
)
... View more
01-25-2024
05:33 AM
|
0
|
2
|
648
|
POST
|
The original script was for Unique Values from multiple fields. You have Unique Values from one field in groups. These are represented differently in Python. This should work: layer_names = ["TestPolygons"]
aprx = arcpy.mp.ArcGISProject("current")
for name in layer_names:
# get the layer
layer = aprx.activeMap.listLayers(name)[0]
# get the symbology fields and items
renderer = layer.symbology.renderer
fields = renderer.fields
items = renderer.groups[0].items
# create a dict {values: label}
item_dict = dict()
for item in items:
for v in item.values:
item_dict[v[0]] = item.label
# add a new field
arcpy.management.AddField(layer, "LandUseDesignation1", "TEXT")
# insert the label values
with arcpy.da.UpdateCursor(layer, ["LandUseDesignation1"] + fields) as cursor:
for row in cursor:
key = row[-1]
try:
row[0] = item_dict[key]
cursor.updateRow(row)
except KeyError: # no symbology found
pass We have to change how we build the item_dict (lines 12-15) and how to get values from it (line 21).
... View more
01-25-2024
05:26 AM
|
2
|
3
|
1080
|
POST
|
Hmm, works in Pro and AGOL for me... Your PM_TOT_VAL looks like a text field. Throw a Number() in there: var x = "12345"
return Text(Number(x), "$#,###")
... View more
01-24-2024
02:35 PM
|
1
|
0
|
609
|
POST
|
var fs = Featureset({
fields: [{name:"nojob", type:"esriFieldTypeString"}],
features:[
{attributes: {nojob: "abcdefg"}},
{attributes: {nojob: "abcdabc"}},
{attributes: {nojob: "abcd"}},
{attributes: {nojob: "uvwx"}},
{attributes: {nojob: "uvwxabc"}},
]
})
return GroupBy(fs,
[{name: "test", expression: "SUBSTRING(nojob, 1, 4)"}],
[{name: "test_count", statistic: "COUNT", expression: "1"}]
)
... View more
01-24-2024
02:23 PM
|
0
|
4
|
672
|
POST
|
As it turns out, getting a symbol's color is easy, but there's no built-in way to get the hex value... If you have defined all your symbol colors in the RGB system, you're good to go: layer_names = ["TestPolygons"]
aprx = arcpy.mp.ArcGISProject("current")
for name in layer_names:
# get the layer
layer = aprx.activeMap.listLayers(name)[0]
# get the symbology fields and items
renderer = layer.symbology.renderer
fields = renderer.fields
items = renderer.groups[0].items
# create a dict {values: iteml}
item_dict = {tuple(item.values[0]): item for item in items}
# add a new field
arcpy.management.AddField(layer, "PW_Zoning_Designation", "TEXT")
arcpy.management.AddField(layer, "ColorRaw", "TEXT")
arcpy.management.AddField(layer, "ColorHex", "TEXT")
# insert the label and color values
with arcpy.da.UpdateCursor(layer, ["PW_Zoning_Designation", "ColorRaw", "ColorHex"] + fields) as cursor:
for row in cursor:
# get the item
key = tuple([str(x) for x in row[3:]]) # item.values stores values as string
try:
item = item_dict[key]
# no item found -> default value and skip to the next feature
except KeyError:
row[0] = "No Symbol"
cursor.updateRow(row)
continue
# store the item's label
row[0] = item.label
# get the symbol color
color = item.symbol.color
color_type = list(color.keys())[0]
# if it's rgb, convert to hex
if color_type == "RGB":
rgb = color["RGB"][:3]
row[2] = '#%02x%02x%02x' % tuple(rgb)
# if it's something else (hsv, hsl, cmyk), you have to convert that in other ways... here I just don't convert
else:
row[2] = None
# store the color value as string for documentation
row[1] = str(color)
# write values
cursor.updateRow(row) Note that we're storing the whole symbology item in the dictionary (line 12), not only the label. This way, we can access the item's symbol color in the for-loop (line 33). Colors can be defined in different systems (RGB, HSV, HSL, CMYK, ...). Converting from RGB to hex is pretty straightforward (line 38). If you have other color systems, you probably have to convert those values into RGB first (line 41). A good start could be the module colorsys, which is part of the default Python installation. It might be easier to go through your symbology and just switch the system there.
... View more
01-24-2024
02:08 PM
|
2
|
1
|
1106
|
POST
|
You either have an error in the construction of the secondary contact info or the Filter() errors out when you search for null. Try something like this: // load the data
var fs = Featureset({
fields: [{name: "contact_name", type: "esriFieldTypeString"}, {name: "contact_phone", type: "esriFieldTypeString"}, {name: "contact_address1", type: "esriFieldTypeString"}, {name: "contact_address2", type: "esriFieldTypeString"}, {name: "contact_city", type: "esriFieldTypeString"}, {name: "contact_state", type: "esriFieldTypeString"}, {name: "contact_zip", type: "esriFieldTypeString"}, {name: "contact_email", type: "esriFieldTypeString"}, ],
features: [
{attributes: {contact_name: "James Bond", contact_address1: "SIS Building", contact_city: "London", contact_state: "United Kingdom", contact_phone: "007", contact_zip: "99999", contact_email: "bond@sis.gov.uk"}},
{attributes: {contact_name: "Sherlock Holmes", contact_address1: "221B Baker Street", contact_address2: "First Floor", contact_city: "London", contact_state: "United Kingdom", contact_phone: "98765", contact_zip: "11111", contact_email: "sherlock@holmes-pi.co.uk"}},
],
geometryType: ""
})
//var fs = FeaturesetByPortalItem(...)
// return a default value if no primary contact is given
var prim_phone = "007"//$feature.prim_phone
if(prim_phone == null) { return "No contact information given." }
// find the primary contact
var primary = First(Filter(fs, "contact_phone = @prim_phone"))
// return a default value if no contact was found
if(primary == null) { return "No contact information found." }
// assemble the primary contact information
var prim_type = Proper("secret service agent")//Proper($feature.prim_contact_type)
var prim_address = primary.contact_address1 + IIf(IsEmpty(primary.contact_address2), "", TextFormatting.NewLine + primary.contact_address2)
var prim_contact_info = `Primary Contact Name: ${primary.contact_name} (${prim_type})
${prim_address}
${primary.contact_city}
${primary.contact_state} ${primary.contact_zip}
${primary.contact_phone}
${primary.contact_email}`
// find the secondary contact
// return the primary contact info if no secondary contact was found
var sec_phone = "98765"//$feature.sec_phone
if(sec_phone == null) { return prim_contact_info }
var secondary = First(Filter(fs, "contact_phone = @sec_phone"))
if(secondary == null) { return prim_contact_info }
// assemble the secondary contact information
var sec_type = Proper("private investigator")//Proper($feature.sec_contact_type)
var sec_address = secondary.contact_address1 + IIf(IsEmpty(secondary.contact_address2), "", TextFormatting.NewLine + secondary.contact_address2)
var sec_contact_info = `Secondary Contact Name: ${secondary.contact_name} (${sec_type})
${sec_address}
${secondary.contact_city}
${secondary.contact_state} ${secondary.contact_zip}
${secondary.contact_phone}
${secondary.contact_email}`
// return both contact information
return `${prim_contact_info}
${sec_contact_info}` Primary Contact Name: James Bond (Secret Service Agent)
SIS Building
London
United Kingdom 99999
007
bond@sis.gov.uk
Secondary Contact Name: Sherlock Holmes (Private Investigator)
221B Baker Street
First Floor
London
United Kingdom 11111
98765
sherlock@holmes-pi.co.uk
... View more
01-24-2024
11:34 AM
|
0
|
1
|
860
|
POST
|
Is there any reason to use an f-string here? Does this work? whereclause='1=1'
gis_payload = {
'token': portaltoken,
'f': 'json',
'where': whereclause
}
print(gis_payload)
response = requests.request("POST", url=url, data=gis_payload)
... View more
01-19-2024
09:15 AM
|
0
|
1
|
557
|
POST
|
If the expression returns true, however, nothing is written. The condition is true when step7Phone is null. In that case, you try to call attributes (eg contact_name) on a null (non-existing) object in lines 14-16, which results in an error, the expression doesn't return anything. Instead, you want to check if step7Phone is null before you use it. Something like this: var step7Phone = First(Filter(...))
// if no secondary contact info is found, only return the primary info
if(step7Phone == null) { return step4Phone }
// create the secondary info
var step8Phone = ...
// return both primary and secondary info
return step4Phone + TextFormatting.NewLine + TextFormatting.NewLine + step8Phone
... View more
01-19-2024
09:08 AM
|
1
|
1
|
1002
|
POST
|
You can search the closest line feature and then use the new-ish NearestCoordinate function to snap the point to that line. // Calculation attribute rule on the point fc
// field: empty
function closest_feature(test_feature, compare_feature_set) {
// returns the feature of compare_feature_set that is closest to test_feature
var min_distance = 9999999
var closest_feature = null
for(var f in compare_feature_set) {
var d = Distance(test_feature, f)
if(d < min_distance) {
min_distance = d
closest_feature = f
}
}
return closest_feature
}
// load the other featureset
var fs = FeatureSetByName($datastore, "Highways.HIGHWAYMGR.NSG_Network")
// get the feature that is closest to the current $feature
fs = Intersects(fs, Buffer($feature, 100)) // only analyze close-ish features
var f = closest_feature($feature, fs)
// abort if we didn't find something
if(f == null) { return }
// return the intersecting feature's value and snap the point to the found feature
return {
result: {
geometry: NearestCoordinate(f, $feature).coordinate,
attributes: {StreetsUID: f.NSG_STREETS_UID}
}
} If you don't have access to NearestCoordinate yet, you can use the functions from my answer in this blog.
... View more
01-19-2024
08:55 AM
|
0
|
2
|
688
|
POST
|
NameError: name 'arcpy' is not defined The script is meant to be executed in the ArcGIS Pro Python Window, where arcpy is imported by default. If you want to execute arcpy code outside of the Python Window (eg in custom tools or standalone scripts), you have to import arcpy first. Your problem is a little different from the other ones in this thread. Your feature class basically already is a match table. You could probably run AddAttachments for each AttachmentField. To make it easier, you can transpose your table. So instead of ID Attachment1 Attachment2 1 a1 2 a2 a3 You get ID Attachment 1 a1 2 a2 2 a3 This script will take care of the transformation, the MatchID field will contain the ObjectIDs of your fc. in_table = "TestPoints"
out_match_table = r"memory\match"
attachment_fields = ["TextField1", "TextField2"]
import arcpy
from pathlib import Path
# create match table
p = Path(out_match_table)
match_table = arcpy.management.CreateTable(str(p.parent), str(p.name))
arcpy.management.AddField(match_table, "Filename", "TEXT")
arcpy.management.AddField(match_table, "MatchID", "LONG")
# for each row in in_table, insert all attachment names into match table
with arcpy.da.InsertCursor(out_match_table, ["FileName", "MatchID"]) as i_cursor:
with arcpy.da.SearchCursor(in_table, ["OID@"] + attachment_fields) as s_cursor:
for row in s_cursor:
oid = row[0]
for attachment_name in row[1:]:
if attachment_name is not None:
i_cursor.insertRow([attachment_name, oid]) Input fc: Output match table: Then use that match table in AddAttachments: Which should attach all specified files:
... View more
01-19-2024
08:10 AM
|
0
|
0
|
778
|
BLOG
|
Hah, 200 exactly, nice! Seems like I was extremely active in the first half of 2023. But sadly I don't get to use ArcGIS (or any GIS) in my new job, so I've been much less active since then... I'll have to step up in this year's contest 😅
... View more
01-08-2024
10:52 AM
|
4
|
0
|
840
|
POST
|
Hey Hlynur, this scenario is described in this blog: https://www.esri.com/arcgis-blog/products/arcgis-pro/data-management/advanced-gdb-attribute-rules-editing-external-features-with-attribute-rules/
... View more
12-26-2023
11:17 PM
|
0
|
1
|
706
|
POST
|
This was probably 2.8 or 2.9 Make sure you allow symbol property connections (top right of the image under option 3.
... View more
12-06-2023
10:02 AM
|
1
|
0
|
2062
|
Title | Kudos | Posted |
---|---|---|
1 | 08-31-2021 11:11 PM | |
1 | 02-16-2023 11:38 PM | |
1 | 08-29-2022 01:47 AM | |
1 | 03-22-2022 11:52 PM | |
2 | 05-18-2023 12:45 AM |
Online Status |
Offline
|
Date Last Visited |
02-03-2024
06:14 PM
|