|
POST
|
The really easy way: Create a database sequence // Calculation Attribute Rule
// trigger: Insert
// field:CW_ID
var seq = NextSequenceValue("SequenceName")
return "SAN" + seq If for some reason you can't create sequences, you'll have to do it the harder way: // Calculation Attribute Rule
// trigger: Insert
// field:CW_ID
// get the latest feature with a CW_ID
var last_feature = First(OrderBy(Filter($featureset, "CW_ID IS NOT NULL"), "OBJECTID DESC"))
// get the last CW_ID and add 1
var seq = IIf(last_feature == null, 0, last_feature.CW_ID) + 1
return "SAN" + seq
... View more
08-18-2023
02:53 PM
|
3
|
0
|
4557
|
|
POST
|
Another way to do this, showing both field aliases / names and the values (edit lines 3,4,5,8): // define the fields that should be displayed
var display_fields = {
"Autotroph": ["Field1", "Field2", "Field3"],
"Heterotroph": ["Field4", "Field5", "Field6", "Field7"],
"Abiotic": ["Field8", "Field9"],
}
// get the requested fields based on your condition
var requested_fields = display_fields[$feature.Condition]
// Calling fields by variable instead of string literal can be icky,
// so we should tell Arcade that we expect all fields to be loaded
Expects($feature, "*")
// create a dictionary of {field_name: field_alias}
var fields = Schema($feature).fields
var aliases = {}
for(var f in fields) {
aliases[fields[f].name] = fields[f].alias
}
// define an empty array that stores the output lines
var popup_lines = []
// loop over the requested field names
for(var f in requested_fields) {
// get the name, alias, and value of the field
var name = requested_fields [f]
var alias = aliases[name]
var value = $feature[name]
// append to the lines
Push(popup_lines, `${alias}: ${value}`)
}
// concatenate and return
return Concatenate(popup_lines, TextFormatting.NewLine)
... View more
08-18-2023
02:28 PM
|
0
|
0
|
3966
|
|
POST
|
That's a really clean solution, but you need the $ signs in front of the curly braces in the string literals, and you need the parantheses behind the function names in the When call.
... View more
08-18-2023
02:13 PM
|
1
|
1
|
3968
|
|
POST
|
I am curious about how you got the 2835 number? Trial-and-error. I knew that screen_dist / real_dist = 1 / scale -> screen_dist = real_dist / scale The lines weren't long enough, but they were proportional to the buffer distance, so I was on the right track. I figured I'd have to convert from "meters on screen" to "pixels", so I started putting in some common dpi values, but they ere all too small, so I just started iterating until I got something that looked right. I think I just found out what that value is. Go to scale 1:1, place a point, symbolize it with the line symbol, make it really wide to reduce the relative error (I used 1500pt). Measure the distance / create a line feature over the symbol and get it's length (0.5292 meters in my case). 1500 pt / 0.5292 m = x / 1m -> x = 2835 pt So it's the points needed to display one meter at scale 1:1.
... View more
08-18-2023
02:02 PM
|
0
|
0
|
4019
|
|
POST
|
Your expression can be simplified: var time1 = Date($feature.enddate)
var dd = DateDiff(time1, Now(), "days")
return When(
dd <= 0, "Inactive",
dd <= 5, "5 days or less to expire",
"Active"
) You have a few possibilities: Just don't symbolize expired points. They will still be in the table, but won't show up in the map. If your actual data is in a database, you can use an Attribute Rule (doesn't work for layers hosted in AGOL). You could create an Attribute Rule on your point featureclass like the script below. That will delete all expired points every time you add a new point. // Calculation Attribute Rule on your poit fc
// triggers: Insert
// field: empty
// exclude from application evaluation
var deletes = []
for(var f in $featureset) {
var dd = DateDiff(f.DateField1, Now(), "days") // replace with the name of your date field
if(dd <= 0) {
Push(deletes, {globalID: f.GlobalID})
}
}
return {
edit: [{
className: "TestPoints", // replace with the name of your point fc
deletes: deletes
}]
} You could also write a Python script that deletes all expired points. You can run that script manually or have it run automatically every day or so.
... View more
08-18-2023
03:59 AM
|
1
|
1
|
2981
|
|
POST
|
You can do it with symbol property connections and Arcade, using the $view global. In your polygon symbology, add a marker layer Set it to this shape, deactivate proportional scaling Set the placement and position parameters Allow symbol property connections Switch to the text element, set the angle to 0°, set the text properties to appropriate values (I'm using centered, 12 pt, some vertical offset) Activate the attribute mapping for the Text string parameter, enter a custom Arcade expression. Use this script, switch to your units // If you don't have a distance attribute, calculate the radius yourself
// This will be inexact!
var a = Area($feature, "square-meters")
var r = Sqrt(a / PI)
// Else just use your distance field
//var r = $feature.BUFF_DIST
return Round(r, 1) + " m" Switch to the line element, activate the attribute mapping for the Size parameter, use this expression // Like before
//var a = Area($feature, "square-meters")
//var r = Sqrt(a / PI)
var r = $feature.BUFF_DIST
return r / $view.scale * 2835
// I have no idea where the 2835 is coming from. I guess it has something to do with my map's / monitor's DPI.
// It might be a different number for your units and setup. Scale 1:20.000 Scale 1:50.000 Scale 1:10.000 Note that the displayed radius is not exact. I used 500, 750, and 1000 meters. But the Area() function densifies the COGO lines of the buffers to like 35 vertices, which shaves off some area around the rim.
... View more
08-18-2023
03:24 AM
|
1
|
2
|
4043
|
|
POST
|
fixed the ZeroDivisionError fixed the behavior for nearly horizontal lines here, the angle can switch from 180°/359° to 0°. this is a small angle difference, but the tool would split the line, because it saw a difference of 179°... now it works correctly. Added some fields in the output fc, mostly for debugging, but maybe it's useful... fixed in script and reuploaded the tool it seems as though once the problem gets bigger, it is not capable of handling the curves and nicks This is something I can't test without actual data. Can you send me your point and/or line feature classes here or in a private message? Thanks for the data. After fixing the error, the tool works fine for me. It takes some time (3 to 4 minutes), but that's to be expected, because it does it does expensive geometry computations on 39.000 features... I took a look at some of the more complex regions, but I couldn't find anywhere where it wasn't "capable of handling the curves and nicks". Can you try again and send me coordinates of places here it doesn't work? Just to be sure: The Angle Tolerance parameter controls how the "curves and nicks" are handled. If the difference between angles of two consecutive segments of an input line is bigger than that value (in degrees), then these segments will be in different output lines. If the angle difference is smaller than the tolerance, they will be part of the same output line. So if you want greater differentiation, set the tolerance to a smaller value. For example, this is the split with an Angle Tolerance of 10°: When I use 50°, there are less splits:
... View more
08-17-2023
01:09 PM
|
0
|
0
|
4812
|
|
POST
|
Select the unwanted rows with Select Layer By Attribute or with a definition query Use this with Calculate Field (This changes the data, make a backup!) # ID =
next_sas_02_sequence()
# Code Block
sas_counter = 5700
def next_sas_02_sequence():
global sas_counter
sas_02_sequence = f"SAS-02-{sas_counter:05}"
sas_counter += 1
return sas_02_sequence
... View more
08-16-2023
02:46 PM
|
1
|
0
|
1715
|
|
POST
|
Just to give you the sort of errors I am getting, here it is: Haha, I thought about this possible error when writing the code but decided against writing checks that would make the code more complicated because I thought it wasn't very probable that the error actually occurs... I will fix it later. Is there a way to combine the lines with one another? Dissolve without specifying a Dissolve Field should combine all lines into one huge multipart line. it seems as though once the problem gets bigger, it is not capable of handling the curves and nicks This is something I can't test without actual data. Can you send me your point and/or line feature classes here or in a private message?
... View more
08-16-2023
01:24 PM
|
1
|
0
|
4836
|
|
POST
|
I can't test on an SDE, but this code has worked before: import arcpy, pandas
domains = arcpy.da.ListDomains("C:/bla/database.sde")
# create an empty to-dimensional list to store the domain data
rows = []
column_names = ["DomainName", "DomainType", "Index", "Code", "Description", "Min", "Max"]
# fill the list
for domain in domains:
if domain.domainType == "Range":
row = [domain.name, domain.domainType, 0, None, None, domain.range[0], domain.range[1]]
rows.append(row)
else:
for i, (k, v) in enumerate(domain.codedValues.items()):
row = [domain.name, domain.domainType, i, k, v, None, None]
rows.append(row)
# convert to DataFrame
dataframe = pandas.DataFrame(rows, columns=column_names)
# export
dataframe.to_csv("C:/bla/domains.csv", index=False)
dataframe.to_excel("C:/bla/domains.xlsx", index=False)
... View more
08-16-2023
10:19 AM
|
1
|
0
|
4050
|
|
POST
|
Your first two examples don't return the data you expect because you take the first feature of the layer, not the feature you clicked on. To access the current feature, use the $feature global, like you did in your third example. I think your third example doesn't work because Arcade only loads fields if they are used in the expression. This works great if you explicitly call your fields by using $feature["Field"] or $feature.Field . It doesn't work when you access fields by variable like $feature[fieldName]. In cases like this, you should tell Arcade to load all fields using Expects(). // define the requested field names
var fieldsToInclude = ["objectid", "TextField1"]
// Calling fields by variable instead of string literal can be icky,
// so we should tell Arcade that we expect all fields to be loaded
Expects($feature, "*")
// create a dictionary of {fieldName: fieldAlias}
var fieldData = Schema($feature).fields
var aliases = {}
for(var f in fieldData) {
aliases[fieldData[f].name] = fieldData[f].alias
}
// define an empty array that stores the output lines
var popupLines = []
// loop over the requested field names
for(var f in fieldsToInclude) {
// get the name, alias, and value of the field
var fName = fieldsToInclude[f]
var fAlias = aliases[fName]
var fValue = $feature[fName]
// if value is valid, append it to the array
if(!Includes([null, 0, "", " "], fValue)) {
Push(popupLines, `${fAlias}: ${fValue}`)
}
}
// concatenate and return
return Concatenate(popupLines, TextFormatting.NewLine)
... View more
08-16-2023
09:59 AM
|
2
|
0
|
2879
|
|
POST
|
Oh god, please don't rename these imports. You, your successor, and people trying to help you are going to have a really bad time trying to figure out where eg "ReplicateFeature" is coming from and what it does. But we do know where to look up the docs for "arcpy.management.CopyFeatures". Just import arcpy and leave it at that. In line 15, you're checking for ".gdb" in the database path, and only if it's there do you actually get the domain values. If you input a .sde, the if block will be skipped and the function will return None.
... View more
08-16-2023
09:20 AM
|
2
|
2
|
4062
|
|
POST
|
Hmm... The tool has no problem dividing this structure, but it's programmed to work with lines, not points. If you input this multipart line (it also works for multiple single-part lines): It returns the correct splits: The problem then becomes "How to get the points into the correct line shape(s)", which is easy for simple point chains (Points To Line), but might be more complicated here. Points To Line has a Line Field parameter. If the points have an attribute that differs between the line parts, you can use that. If you don't have such a field, then you might be stuck doing these corners manually. I could probably rewrite the tool to work with points instead of lines, but I have no idea how I would tackle this case, so it wouldn't do you any good...
... View more
08-16-2023
09:07 AM
|
0
|
0
|
4851
|
|
POST
|
Yes. If it can't convert the string into a number, the conversion will fail. You need to strip out the character: # NewField =
convert(!OldField!)
# Code Block
def convert(x):
try:
x = x.replace('"', '')
return float(x)
except:
return None
... View more
08-16-2023
08:45 AM
|
0
|
1
|
3490
|
|
POST
|
Assuming your points are ordered: Run Points To Line Copy/Paste the script below into your Python Window (without lines 79 and after) and call divide_lines_into_straight_lines alternatively, turn the script into a script tool and run that (also enclosed at end of this post) import arcpy
import math
from pathlib import Path
# function to divide a list of vertices
def divide_path_into_straight_paths(path, angle_tolerance):
""" Divides an arcpy line path into straight parts.
path: [arcpy.Point], the vertices of the path
angle_tolerance: float, difference of consecutive angles (in degrees)
between vertices smaller than this value are considered to be straight
Returns the split paths as [[arcpy.Point]]
"""
segments = [
[path[i-1], path[i]]
for i in range(1, len(path))
]
angles = [
math.degrees(math.atan2(s[0].Y - s[1].Y, s[0].X - s[1].X)) % 180 # % 180 to get the same angle regardless of vertex order
for s in segments
]
split_paths = []
split_path_angles = []
for i, (segment, angle) in enumerate(zip(segments, angles)):
if i == 0:
split_paths.append(segment)
split_path_angles.append([angle])
continue
angle_difference = abs(angle - angles[i-1])
if angle_difference > 90:
angle_difference = abs(angle_difference - 180) # to make 179° comparable to 1°
if angle_difference <= angle_tolerance:
split_paths[-1].append(segment[-1])
split_path_angles[-1].append(angle)
else:
split_paths.append(segment)
split_path_angles.append([angle])
return split_paths, split_path_angles
# function to divide a line geometry
def divide_line_into_straight_lines(line, angle_tolerance):
""" Divides an arcpy line geometry into straight parts.
line: arcpy.Polyline, the line geometry
angle_tolerance: float, difference of consecutive angles (in degrees)
between vertices smaller than this value are considered to be straight
Returns the split lines as [arcpy.Polyline]
"""
split_lines = []
for part in line:
split_paths, split_path_angles = divide_path_into_straight_paths(part, angle_tolerance)
for path in split_paths:
split_lines.append(arcpy.Polyline(arcpy.Array([path]), spatial_reference=line.spatialReference))
return split_lines, split_path_angles
# function to divide all lines in a fc and write the output into a new fc
def divide_lines_into_straight_lines(input_lines, output_lines, angle_tolerance):
""" Divides all polylines in a featureclass or layer (honors selection)
into straight parts.
input_lines: str, path to the input featureclass / name of the layer
output_lines: str, path of the output featureclass
angle_tolerance: float, difference of consecutive angles (in degrees)
between vertices smaller than this value are considered to be straight
"""
lines = [row for row in arcpy.da.SearchCursor(input_lines, ["OID@", "SHAPE@"])]
out_path = Path(output_lines)
out_fc = arcpy.management.CreateFeatureclass(str(out_path.parent), str(out_path.stem), "POLYLINE", spatial_reference=lines[0][1].spatialReference)
arcpy.management.AddField(out_fc, "FID", "LONG")
arcpy.management.AddField(out_fc, "LENGTH", "DOUBLE")
arcpy.management.AddField(out_fc, "ANGLE_START", "DOUBLE")
arcpy.management.AddField(out_fc, "ANGLE_MIN", "DOUBLE")
arcpy.management.AddField(out_fc, "ANGLE_MAX", "DOUBLE")
arcpy.management.AddField(out_fc, "ANGLE_RANGE", "DOUBLE")
arcpy.management.AddField(out_fc, "VERTEX_COUNT", "LONG")
with arcpy.da.InsertCursor(out_fc, ["FID", "SHAPE@", "LENGTH", "ANGLE_START", "ANGLE_MIN", "ANGLE_MAX", "ANGLE_RANGE", "VERTEX_COUNT"]) as cursor:
for oid, shp in lines:
split_shapes, split_angles = divide_line_into_straight_lines(shp, angle_tolerance)
for shape, angles in zip(split_shapes, split_angles):
a_start = angles[0]
a_min = min(angles)
a_max = max(angles)
a_range = a_max - a_min
if a_range > angle_tolerance:
a_range = abs(a_range - 180)
v_count = len(angles) + 1
cursor.insertRow([oid, shape, shape.length, a_start, a_min, a_max, a_range, v_count])
# you can use the script as tool, parameters:
# Feature Layer, Required, Input, Filter for Polylines
# Feature Layer, Required, Output, Filter for Polylines
# Double, Required, Input
if __name__ == "__main__":
input_lines = arcpy.GetParameterAsText(0)
output_lines = arcpy.GetParameterAsText(1)
angle_tolerance = arcpy.GetParameter(2)
divide_lines_into_straight_lines(input_lines, output_lines, angle_tolerance) Points: Points To Line: Straight Lines:
... View more
08-16-2023
02:35 AM
|
0
|
0
|
4869
|
| 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
|