55

Are there functions for conversion between different coordinate systems?

For example, Matlab has [rho,phi] = cart2pol(x,y) for conversion from cartesian to polar coordinates. Seems like it should be in numpy or scipy.

Paolo
  • 16,171
  • 20
  • 78
  • 110
cpc333
  • 1,095
  • 1
  • 9
  • 10

7 Answers7

96

Using numpy, you can define the following:

import numpy as np

def cart2pol(x, y):
    rho = np.sqrt(x**2 + y**2)
    phi = np.arctan2(y, x)
    return(rho, phi)

def pol2cart(rho, phi):
    x = rho * np.cos(phi)
    y = rho * np.sin(phi)
    return(x, y)
strpeter
  • 1,772
  • 2
  • 21
  • 43
nzh
  • 1,213
  • 9
  • 9
19

The existing answers can be simplified:

from numpy import exp, abs, angle

def polar2z(r,theta):
    return r * exp( 1j * theta )

def z2polar(z):
    return ( abs(z), angle(z) )

Or even:

polar2z = lambda r,θ: r * exp( 1j * θ )
z2polar = lambda z: ( abs(z), angle(z) )

Note these also work on arrays!

rS, thetaS = z2polar( [z1,z2,z3] )
zS = polar2z( rS, thetaS )
P i
  • 25,182
  • 33
  • 133
  • 229
  • 3
    I like this, but since the question starts with x and y (not z), I would add the simple line `z = x + 1j * y` – jpobst Aug 14 '17 at 12:49
  • how does this work? polar2z returns a single argument! – john ktejik Sep 09 '17 at 01:06
  • 1
    @johnktejik `z = polar2z(r,theta)` then `x = np.real(z)` and `y = np.imag(z)` Also, `np.angle()` has a `deg` option which returns degrees instead of radians. You could just pass that through `z2polar()` if you want degrees. – travc Dec 21 '17 at 00:47
  • 1
    This seems to assume that `z` is expressed as a complex number. For other forms, you'd have to first convert to complex, then apply this function. – Acccumulation Jul 02 '18 at 16:39
  • `np.angle(z)` internally extracts the real and imaginary part of the complex number `z` and uses `np.arctan2(zimag, zreal)` on them. The answer by @nzh avoids unnecessary conversions – divenex Oct 30 '19 at 15:46
14

You can use the cmath module.

If the number is converted to a complex format, then it becomes easier to just call the polar method on the number.

import cmath
input_num = complex(1, 2) # stored as 1+2j
r, phi = cmath.polar(input_num)
CR Vinay Kumar
  • 141
  • 1
  • 5
11

If you can't find it in numpy or scipy, here are a couple of quick functions and a point class:

import math

def rect(r, theta):
    """theta in degrees

    returns tuple; (float, float); (x,y)
    """
    x = r * math.cos(math.radians(theta))
    y = r * math.sin(math.radians(theta))
    return x,y

def polar(x, y):
    """returns r, theta(degrees)
    """
    r = (x ** 2 + y ** 2) ** .5
    theta = math.degrees(math.atan2(y,x))
    return r, theta

class Point(object):
    def __init__(self, x=None, y=None, r=None, theta=None):
        """x and y or r and theta(degrees)
        """
        if x and y:
            self.c_polar(x, y)
        elif r and theta:
            self.c_rect(r, theta)
        else:
            raise ValueError('Must specify x and y or r and theta')
    def c_polar(self, x, y, f = polar):
        self._x = x
        self._y = y
        self._r, self._theta = f(self._x, self._y)
        self._theta_radians = math.radians(self._theta)
    def c_rect(self, r, theta, f = rect):
        """theta in degrees
        """
        self._r = r
        self._theta = theta
        self._theta_radians = math.radians(theta)
        self._x, self._y = f(self._r, self._theta)
    def setx(self, x):
        self.c_polar(x, self._y)
    def getx(self):
        return self._x
    x = property(fget = getx, fset = setx)
    def sety(self, y):
        self.c_polar(self._x, y)
    def gety(self):
        return self._y
    y = property(fget = gety, fset = sety)
    def setxy(self, x, y):
        self.c_polar(x, y)
    def getxy(self):
        return self._x, self._y
    xy = property(fget = getxy, fset = setxy)
    def setr(self, r):
        self.c_rect(r, self._theta)
    def getr(self):
        return self._r
    r = property(fget = getr, fset = setr)
    def settheta(self, theta):
        """theta in degrees
        """
        self.c_rect(self._r, theta)
    def gettheta(self):
        return self._theta
    theta = property(fget = gettheta, fset = settheta)
    def set_r_theta(self, r, theta):
        """theta in degrees
        """
        self.c_rect(r, theta)
    def get_r_theta(self):
        return self._r, self._theta
    r_theta = property(fget = get_r_theta, fset = set_r_theta)
    def __str__(self):
        return '({},{})'.format(self._x, self._y)
wwii
  • 19,802
  • 6
  • 32
  • 69
  • What happens with `polar()` when `x = 0`? – xOneca Feb 21 '16 at 22:22
  • You need to use "atan2(y, x)" instead of atan(y / x), as suggested below. This will fix your x=0 issue, and issues with x < 0. – dmon Jul 05 '19 at 12:32
  • Thank you. I knew that was there not sure why I didn't use it, tempted to update the extraneous class I threw in too. – wwii Jul 05 '19 at 14:57
7

There is a better way to write polar(), here it is:

def polar(x,y):
  `returns r, theta(degrees)`
  return math.hypot(x,y),math.degrees(math.atan2(y,x))
Murray Foxcroft
  • 10,865
  • 2
  • 52
  • 71
KeithB
  • 181
  • 1
  • 4
  • Why should it be better? It isn't vectorized. – enedil Jun 13 '18 at 10:07
  • 2
    Ok, then use np.hypot. The point is that you should never write sqrt(x**2+y**2). hypot exists for a reason. – KeithB Jun 14 '18 at 08:15
  • 3
    From KeithB's comment, `return np.hypot(x, y), np.arctan2(y, x)` – tpk May 10 '19 at 04:45
  • what is x and what is y? I'm given an angle in radians and distance. – mLstudent33 Mar 28 '20 at 04:32
  • 1
    @mLstudent33: Obviously `polar` converts Cartesian (x,y) into polar (rho theta), what you need if the function which converts (rho, theta) into (x,y), see other answers for sophisticated methods or just use simple cos/sin as in [this answer](https://stackoverflow.com/a/20926435/774575). – mins Mar 27 '21 at 14:33
4

If your coordinates are stored as complex numbers you can use cmath

alcio
  • 159
  • 1
  • 2
-5

Thinking about it in general, I would strongly consider hiding coordinate system behind well-designed abstraction. Quoting Uncle Bob and his book:

class Point(object)
    def setCartesian(self, x, y)
    def setPolar(self, rho, theta)
    def getX(self)
    def getY(self)
    def getRho(self)
    def setTheta(self)

With interface like that any user of Point class may choose convenient representation, no explicit conversions will be performed. All this ugly sines, cosines etc. will be hidden in one place. Point class. Only place where you should care which representation is used in computer memory.

Łukasz Rogalski
  • 18,883
  • 6
  • 53
  • 84
  • 3
    No need for getters and setters in Python. Just use properties. – K.-Michael Aye Feb 20 '16 at 05:26
  • @K.-MichaelAye, I think he's talking about overloading the initializer and using methods to convert the class attributes under the hood. I don't he realized the question is about converting the attributes under the hood. – user1717828 Aug 02 '17 at 17:38