Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a number non-georeferenced CAD layers (see this question) that have text annotation features. I have created a model to convert the text to points, but after converting the annotation to a Point featureclass, I see that the CAD text anchor points do not coincide with the center of the CAD text (which is where the points belong).

Therefore, I would like to programatically (using ModelBuilder or ArcPy) [move] a feature relative to its current location (delta x,y) using a measured X,Y value that I will provide.

This would allow me to move the GIS points back to where they belong, instead of the offset CAD anchor point. Any ideas on how I can accomplish this task?

UPDATE: @PolyGeo gave an excellent answer using SHAPE@XY IN 10.1, but currently I am running 10.0. Any 10.0 ideas?

share|improve this question
I have an issue with using shift values given in two fields in the attribute table: Delta X and Delta Y. Default values work but fail when reading values from the table. – user48779 Mar 11 '15 at 15:16
This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient reputation you will be able to comment on any post. – MAJ742 Mar 11 '15 at 15:43

This code should do it using the SHAPE@XY token that came with arcpy.da.UpdateCursor in ArcGIS 10.1.

import arcpy
# Set some variables
fc = r"C:\temp\test.gdb\testFC"
fc2 = r"C:\temp\test.gdb\testFCcopy"
xOffset = 0.001
yOffset = 0.001
# Code to make a copy which will have its coordinates moved (and can be compared with original)
if arcpy.Exists(fc2):
# Perform the move
with arcpy.da.UpdateCursor(fc2, ["SHAPE@XY"]) as cursor:
    for row in cursor:
        cursor.updateRow([[row[0][0] + xOffset,row[0][1] + yOffset]])

The coding pattern used here came from ArcPy Café.

share|improve this answer
Ugh! It took me until this morning to realize that SHAPE@XY is only available in 10.1, and my company is still using 10.0. This is a great answer (going forward), but I'm going to wait and see if anyone has any suggestions for 10.0. Thanks! – RyanDalton Jul 15 '13 at 14:20
More information on a similar process for anybody reading this. Still 10.1. – theJones Jul 15 '13 at 15:03
Is this actually setting the values anywhere? Never used the UpdateCursor like that before. Usually I do += and then update the row. Otherwise only thing I do different in my version is the UpdateCursor uses ['SHAPE@X', 'SHAPE@Y'] so you can access them as row[0] and row[1] instead of having to do the row[0][0] and row[0][1]. Think its just a bit easier to read for me. – eseglem Jul 15 '13 at 16:03
Yes, that is a valid way to update the rows. Actually, I had never seen a value passed in updateRow() until a few weeks ago. It was actually an example for updating the geometry. – Paul Jul 15 '13 at 17:34
up vote 5 down vote accepted

I credit @artwork21 for leading me to my final solution. I actually found a nearly complete script in the ArcGIS 10.0 online help article called "Calculate Field examples", listed under the subcategory "Code samples—geometry" and "For a point feature class, shift the x coordinate of each point by 100"

The final script that I used within the ModelBuilder "Calculate Field" tool was:

Expression: shiftXYCoordinates(!SHAPE!,%ShiftX%,%ShiftY%)

where ShiftX and ShiftY are variables (as parameters) defined on the ModelBuilder canvas.

Expression Type: PYTHON_9.3

Code Block:

def shiftXYCoordinates(shape,x_shift,y_shift):
   point = shape.getPart(0)
   point.X += float(x_shift)
   point.Y += float(y_shift)
   return point

Since all models work on a selected set, you should also be able to create this as a generic tool that will work in conjunction with other models/tools in other modelbuilder sessions. The very simple model I created (as a "plugin" to other models to shift coordinate values) looks like this. That way I can control the shift on a per-selection-set basis (as defined in other models):

ShiftXY Model

It worked like a charm, thank you all for your input!

share|improve this answer

You may also use this field calculator script to move feature locations:

def XYsetVALUE( shape, X_value, Y_value): 
  myMoveX = 0.001
  myMoveY = 0.001
  point = shape.getPart(0) 
  point.X = X_value + myMoveX
  point.Y = Y_value + myMoveY
  return point 


You could include an extra Calculate Field method within your model using the function above.

share|improve this answer
Thats an interesting way to do it, I didn't actually know you could field calculate on the shape field. This may actually be the easiest way to get it done if it is a set offset for all points. It would probably be faster to do point.X += myMoveX and point.Y += myMoveY instead of needing to pass in X and Y coordinates for it though. – eseglem Jul 15 '13 at 15:58

As you can see, it's a lot easier in 10.1 when you get access to cursor tokens.

import arcpy
# Code to move features in copy of same dataset
fc = r"C:\temp\test.gdb\testFC"
fc2 = r"C:\temp\test.gdb\testFCcopy"
xOffset = 0.001
yOffset = 0.001
if arcpy.Exists(fc2):
arcpy.Copy_management(fc, fc2)

shape = arcpy.Describe(fc2).ShapeFieldName

cursor = arcpy.UpdateCursor(fc2)
for row in cursor:    
    point = row.getValue(shape).getPart()
    row.setValue(shape, arcpy.Point(point.X + xOffset, point.Y + yOffset))

del point, row, cursor
share|improve this answer

I adapted the solution to move / shift points point into a certain direction (angle) and a given distance.

Looks like:

def shiftXYCoordinates(shape,angle,distance):
point = shape.getPart(0)
point.Y += distance * math.cos(math.radians(angle))
point.X += distance * math.sin(math.radians(angle))
return point

and be called like shiftXYCoordinates(!SHAPE!, !Angle! ,5000), if you have a field “angle” for your points features (or with a constant of course). Angle should be given in decimal degrees. 0 will shift “up”, 90 “right” etc. I got them after creating strip map index features and converting those to points.

Also make sure to select Field Name “Shape” before running :)

(Solution tested in ArcMap 10.0 SP5)

share|improve this answer

This works for 10.0:

# Featureclass here
FC = r'featureclass'

fcount = 0
shapefield = arcpy.Describe(FC).shapeFieldName
featureUpdate = arcpy.UpdateCursor(FC)
for f in featureUpdate:
    # Hard coded shifts but easy enough to set up a lookup function if needed
    sLon = 0.001
    sLat = 0.001
    # Optional but I like to count to see where it is at in the process
    if fcount % 1000 == 0:
        print('Updating feature %s...' %(fcount))
    # Get the original value
    cF = f.getValue(shapefield)
    cPNT = cF.getPart()
    # Create a new point with the shifted value
    sPNT = arcpy.Point(cPNT.X - sLon, cPNT.Y - sLAT)
    # Set the shapefield to the new point and update feature
    f.setValue(shapefield, sPNT)
    fcount += 1
del featureUpdate
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.