Convert DD to DMS with Python

16731
7
Jump to solution
04-28-2011 05:22 PM
MichaelClarke
New Contributor III
Hi,

I'm trying to automate the "Calculate Geometry" interactive process in ArcMap10 using Python. Interactively this allows me to calculate the X or Y attribute as a DMS string.

I have used the arcpy.AddXY_management to create and populate Decimal Degree fields however I'm new to Python and I cant get my head around how I write an expression to convert this to DMS.

Can anyone help?

Thanks!
-Mick
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
curtvprice
MVP Esteemed Contributor
I got these two functions working pretty well so I thought I'd share them. These are fairly general purpose, so for example, say you want a string field you could format the results like this (Calculate Field, python):

"%4i %2i %5.3f %3i %2i %5.3f " % dd2dms(!LATDD!,!LONDD!)


def dd2dms(dd1,dd2,ndec=6):
    """Convert a decimal degree coordinate pair to a six-tuple of degrees, minutes seconds.
    
    The returned values are not rounded.
    
    Arguments
    
    dd1, dd2 - coordinate pair, in decimal degrees
      
    Example
    
      >>> dd2dms(-74.25,32.1)
      (-74, 15, 6.9444444444444444e-05, 32, 6, 2.7777777777778172e-05)
    """
    # Author: Curtis Price, http://profile.usgs.gov/cprice
    # Disclaimer: Not approved by USGS. (Provisional, subject to revision.)    
    def ToDMS(dd):
        dd1 = abs(float(dd))
        cdeg = int(dd1)
        minsec = dd1 - cdeg
        cmin = int(minsec * 60)
        csec = (minsec % 60) / float(3600)    
        if dd < 0: cdeg = cdeg * -1
        return cdeg,cmin,csec 
    
    try:
        # return a six-tuple
        return ToDMS(dd1) + ToDMS(dd2)           
    except:
        raise Exception, "Invalid input"            

def dms2dd(deg1,min1,sec1,deg2,min2,sec2):
    """Convert a degrees-minutes seconds coordinate pair to decimal degrees.
    
    The returned values are not rounded.
        
    Arguments
    
      deg1,min1,sec1,deg2,min2,sec2 - DMS coordinate pair (six values)
    
    Example
    
    >>> dms2deg(-74,45,0,34,10,20)
    (-74.75, 34.172222222222217)
    """
    # Author: Curtis Price, http://profile.usgs.gov/cprice
    # Disclaimer: Not approved by USGS. (Provisional, subject to revision.)    

    def ToDD(deg,min=0,sec=0):
        dd = abs(deg) + min / 60.0 + sec / 3600.0
        if deg < 0:
            dd = dd * -1.0
        return dd
    try:
        return ToDD(deg1,min1,sec1), ToDD(deg2,min2,sec2)
    except Exception:
        raise Exception, "Invalid input"

View solution in original post

0 Kudos
7 Replies
DanPatterson_Retired
MVP Emeritus
>>> lat = 45.543210
>>> deg = int(lat)
>>> min = int((lat-deg)*60)
>>> sec = ((lat-deg)*60) - min
>>> print deg, min, sec
45 32 0.5926

you need to create a text field to contain the DMS values or 3 separate numeric fields to store the values
0 Kudos
JakeSkinner
Esri Esteemed Contributor
Not the most elegant way, but I got the below code working.  Could be cleaned up a bit.

rows = arcpy.UpdateCursor(input)
for row in rows:
    Xcoord = str(row.X)
    Xcoord2 = Xcoord.split(".")
    XDegrees = Xcoord2[0]
    Xcoord3 = float("." + Xcoord2[1])
    Xcoord4 = Xcoord3 * 60
    Xcoord5 = str(Xcoord4)
    Xcoord6 = Xcoord5.split(".")
    XMinutes = Xcoord6[0]
    Xcoord7 = float("." + Xcoord6[1])
    Xcoord8 = Xcoord7 * 60
    Xcoord9 = str(Xcoord8)
    XSeconds = Xcoord9
    DMS = XDegrees + " " + XMinutes + "' " + XSeconds + "''"
    row.Lat = DMS
    rows.updateRow(row)

del row, rows


You can duplicate the code and run it for the Longitude value.
0 Kudos
DanPatterson_Retired
MVP Emeritus
or keep everything as numbers until the very end
rows = arcpy.UpdateCursor(input)
for row in rows:
    lat = int(row.X)
    deg = int(lat)
    minutes = int(lat-deg)*60
    sec = ((lat-deg)*60)    
    DMS = str(deg) + " " + str(minutes) + "' " + str(sec)+ "''"
    row.Lat = DMS
    rows.updateRow(row)
del row, rows

(totally untested)
0 Kudos
MichaelClarke
New Contributor III
Nice, I'll give it a go!

Many thanks!
0 Kudos
deleted-user-rmQdIupSdOqe
New Contributor III
Did you get this to work?  I am trying to use it in calculate field tool in a model and I can't get it to run. I am most likely not defining the inputs correctly.
What is the input in UpdateCursor(input)?
What is row.X?
0 Kudos
curtvprice
MVP Esteemed Contributor
Here's my shot at it:

def dd2dms(dd1,dd2):
    """Convert decimal degree value to a tuple of degrees, minutes seconds.
    
    Argument
    
    dd1, dd2 - value in decimal degrees
    
    Example:
    
    >>> deg2dms(-74.49999)
    (-74, 29, 3539.9639999999918)
    
    Author: Curtis Price, http://profile.usgs.gov/cprice
    Disclaimer: Not approved by USGS. (Provisional, subject to revision.)
    """
    def ToDMS(dd):
        deg = int(abs(dd))
        min = int((abs(dd) - deg) * 60)
        sec = (abs(dd) - (deg - (min / 60.0))) * 3600.0
        if dd < 0: deg = deg * -1
        return deg,min,sec 
    
    try:
        # return a six-tuple
        return ToDMS(dd1) + ToDMS(dd2)           
    except:
        raise Exception, "Invalid input"            

def dms2dd(deg1,min1,sec1,deg2,min2,sec2):
    """Convert degrees, minutes seconds to decimal degrees values.
    
    Argument
    
      deg1,min1,sec1,deg2,min2,sec2 - coordinate pair (2 x 3)
    
    Example
    
    >>> dms2deg(-74,45,0,34,10,20)
    (-74.75, 34.172222222222217)
    
    Author: Curtis Price, http://profile.usgs.gov/cprice
    Disclaimer: Not approved by USGS. (Provisional, subject to revision.)
    """
    def ToDD(deg,min=0,sec=0):
        dd = abs(deg) + min / 60.0 + sec / 3600.0
        if deg < 0:
            dd = dd * -1.0
        return dd
    try:
        return ToDD(deg1,min1,sec1), ToDD(deg2,min2,sec2)
    except Exception:
        raise Exception, "Invalid input"
0 Kudos
curtvprice
MVP Esteemed Contributor
I got these two functions working pretty well so I thought I'd share them. These are fairly general purpose, so for example, say you want a string field you could format the results like this (Calculate Field, python):

"%4i %2i %5.3f %3i %2i %5.3f " % dd2dms(!LATDD!,!LONDD!)


def dd2dms(dd1,dd2,ndec=6):
    """Convert a decimal degree coordinate pair to a six-tuple of degrees, minutes seconds.
    
    The returned values are not rounded.
    
    Arguments
    
    dd1, dd2 - coordinate pair, in decimal degrees
      
    Example
    
      >>> dd2dms(-74.25,32.1)
      (-74, 15, 6.9444444444444444e-05, 32, 6, 2.7777777777778172e-05)
    """
    # Author: Curtis Price, http://profile.usgs.gov/cprice
    # Disclaimer: Not approved by USGS. (Provisional, subject to revision.)    
    def ToDMS(dd):
        dd1 = abs(float(dd))
        cdeg = int(dd1)
        minsec = dd1 - cdeg
        cmin = int(minsec * 60)
        csec = (minsec % 60) / float(3600)    
        if dd < 0: cdeg = cdeg * -1
        return cdeg,cmin,csec 
    
    try:
        # return a six-tuple
        return ToDMS(dd1) + ToDMS(dd2)           
    except:
        raise Exception, "Invalid input"            

def dms2dd(deg1,min1,sec1,deg2,min2,sec2):
    """Convert a degrees-minutes seconds coordinate pair to decimal degrees.
    
    The returned values are not rounded.
        
    Arguments
    
      deg1,min1,sec1,deg2,min2,sec2 - DMS coordinate pair (six values)
    
    Example
    
    >>> dms2deg(-74,45,0,34,10,20)
    (-74.75, 34.172222222222217)
    """
    # Author: Curtis Price, http://profile.usgs.gov/cprice
    # Disclaimer: Not approved by USGS. (Provisional, subject to revision.)    

    def ToDD(deg,min=0,sec=0):
        dd = abs(deg) + min / 60.0 + sec / 3600.0
        if deg < 0:
            dd = dd * -1.0
        return dd
    try:
        return ToDD(deg1,min1,sec1), ToDD(deg2,min2,sec2)
    except Exception:
        raise Exception, "Invalid input"
0 Kudos