Date: 2015-10-08 Modified: 2017-04-19 new ***
Included:
Purpose:
Many posts on GeoNet come from people looking to write a script or produce a tool which can be handled in a much simpler fashion. This is first in a series of posts that will address how to use the field calculator to its fullest. The use, and perhaps the limitations to using, the field calculator should be guided by the following considerations:
Notes:
Useage:
For all functions, do the following:
----------------------------------------------------------------------------------------------------------------------------------------
For use in tables, to retrieve the X or Y coordinates in an appropriate field. See the header for requirements.
Pre-logic Script Code:
def pnt_along(shape, value=0.0, use_fraction=False, XorY="X"):
"""Position X or Y coordinate, x/y meters or decimal fraction along a line.
:Requires:
:--------
: shape field: python parser use !Shape!
: value: (distance or decimal fraction, 0-1)
: use_fraction: (True/False)
: XorY: specify X or Y coordinates
:
:Returns: the specified coordinate (X or Y) meters or % along line or boundary
:-------
:
:Useage: pnt_along(!Shape!, 100, False, "X") # X, 100 m from start point
:
"""
XorY = XorY.upper()
if use_fraction and (value > 1.0):
value = value/100.0
if shape.type.lower() == "polygon":
shape = shape.boundary()
pnt = shape.positionAlongLine(value,use_fraction)
if XorY == 'X':
return pnt.centroid.X
else:
return pnt.centroid.Y
pnt_along(!Shape!, 100, False, "X") # X, 100 m from start point
Calculate the distance to a specific point within a dataset. For example, you can determine the distance from a point cloud's center to other points. Features not in the file can be obtained by other means. Useful to get summary information on inter-point distances as a prelude to a full clustering or KD-means study.
For example, the potential workflow to get the distance of every point to the point clouds center might include the following steps:
Pre-logic Script Code:
""" dist_to(shape, from_x, from_y)
input: shape field, origin x,y
returns: distance to the specified point
expression: dist_to(!Shape!, x, y)
"""
def dist_to(shape, from_x, from_y):
x = shape.centroid.X
y = shape.centroid.Y
distance = math.sqrt((x - from_x)**2 + (y - from_y)**2)
return distance
expression =
dist_to(!Shape!, x, y)
-----------------------------------------------------------------------------------------------------------------------------------------
Pre-logic Script Code:
""" input shape field: returns cumulative distance between points
dist_cumu(!Shape!) #enter into the expression box"""
x0 = 0.0
y0 = 0.0
distance = 0.0
def dist_cumu(shape):
global x0
global y0
global distance
x = shape.centroid.X
y = shape.centroid.Y
if x0 == 0.0 and y0 == 0.0:
x0 = x
y0 = y
distance += math.sqrt((x - x0)**2 + (y - y0)**2)
x0 = x
y0 = y
return distance
expression =
dist_cum(!Shape!)
----------------------------------------------------------------------------------------------------------------------------------------
Determine distances between sequential point pairs (not cumulative).
Pre-logic Script Code:
""" dist_between(shape)
input: shape field
returns: distance between successive points
expression: dist_between(!Shape!)
"""
x0 = 0.0
y0 = 0.0
def dist_between(shape):
global x0
global y0
x = shape.centroid.X
y = shape.centroid.Y
if x0 == 0.0 and y0 == 0.0:
x0 = x
y0 = y
distance = math.sqrt((x - x0)**2 + (y - y0)**2)
x0 = x
y0 = y
return distance
expression =
dist_between(!Shape!)
-----------------------------------------------------------------------------------------------------------------------------------------
Determine the azimuth to a specific point, for example, a point cloud's center.
Pre-logic Script Code:
""" azimuth_to(shape, from_x, from_y)
input: shape field, from_x, from_y
returns: angle between 0 and <360 between a specified point and others
expression: azimuth_to(!Shape!, from_x, from_y)
"""
def azimuth_to(shape, from_x, from_y):
radian = math.atan((shape.centroid.X - from_x)/(shape.centroid.Y - from_y))
degrees = math.degrees(radian)
if degrees < 0:
return degrees + 360.0
else:
return degrees
expression =
azimuth_to(!Shape!,from_x, from_y)
-----------------------------------------------------------------------------------------------------------------------------------------
Determine the angle between points, for example, angle changes between waypoints.
Pre-logic Script Code:
""" angle_between(shape)
input: shape field
returns: angle between successive points,
NE +ve 0 to 90, NW +ve 90 to 180,
SE -ve <0 to -90, SW -ve <-90 to -180
expression: angle_between(!Shape!)
"""
x0 = 0.0
y0 = 0.0
angle = 0.0
def angle_between(shape):
global x0
global y0
x = shape.centroid.X
y = shape.centroid.Y
if x0 == 0.0 and y0 == 0.0:
x0 = x
y0 = y
return 0.0
radian = math.atan2((shape.centroid.Y - y0),(shape.centroid.X - x0))
angle = math.degrees(radian)
x0 = x
y0 = y
return angle
expression =
angle_between(!Shape!)
-----------------------------------------------------------------------------------------------------------------------------------------
Line direction or Azimuth to Compass Bearing
Can be used to determine the direction/orientation between two points which may or may not be on a polyline. Provide the origin and destination points. The origin may be the 0,0 origin or the beginning of a polyline or a polyline segment.
def line_dir(orig, dest, fromNorth=False):
"""Direction of a line given 2 points
: orig, dest - two points representing the start and end of a line.
: fromNorth - True or False gives angle relative to x-axis)
:
"""
orig = np.asarray(orig)
dest = np.asarray(dest)
dx, dy = dest - orig
ang = np.degrees(np.arctan2(dy, dx))
if fromNorth:
ang = np.mod((450.0 - ang), 360.)
return ang
-----------------------------------------------------------------------------------------------------------------------------------------
Once the Azimuth to a particular point is determined, this can be converted to a compass direction, centered in 22.5 degree bands. The type of compass can be altered to suit... see script header.
import numpy as np
global a
global c
c = np.array(['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE',
'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N'])
a = np.arange(11.25, 360., 22.5)
def compass(angle):
"""Return the compass direction based on supplied angle.
:Requires:
:--------
: angle - angle(s) in degrees, no check made for other formats.
: - a single value, list or np.ndarray can be used as input.
: - angles are assumed to be from compass north, alter to suit.
:
:Returns: The compass direction.
:-------
:
:Notes:
:-----
: Compass ranges can be altered to suit the desired format.
: See various wiki's for other options. This incarnation uses 22.5
: degree ranges with the compass centered on the range.
: ie. N between 348.75 and 11.25 degrees, range equals 22.5)
:
:----------------------------------------------------------------------
"""
if isinstance(angle, (float, int, list, np.ndarray)):
angle = np.atleast_1d(angle)
comp_dir = c[np.digitize(angle, a)]
if len(comp_dir) == 1:
comp_dir[0]
return comp_dir
expression =
compass(!Azimuth_Field_Name!) # python parser, field name enclosed in quotes
:--------------------------------------------------------------------------------------------------------------------------------------------------------------
Degrees decimal minutes to decimal degrees
def ddm_ddd(a, sep=" "):
""" convert decimal minute string to decimal degrees
: a - degree, decimal minute string
: sep - usually a space, but check
"""
d, m = [abs(float(i)) for i in a.split(sep)]
sign = [-1, 1][d < 0]
dd = sign*(d + m/60.)
return dd
For example ddm_ddd(!YourStringField!, sep=" ") will convert a string/text field into a double in your new field
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.