Python conversion between coordinates
Asked Answered
S

13

88

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.

Sammiesammons answered 4/1, 2014 at 17:15 Comment(0)
F
137

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)
Fayefayette answered 5/11, 2014 at 12:31 Comment(3)
In case one doesn't have x and y separately, but inside one numpy array, numpy.linalg.norm(arr) comes in handy as alternative to np.sqrt(arr[:, 0]**2....)Wyn
Alternately arr**2 will square all the elements independently, next you np.sum(arr,axis=1) the rows, then finally **.5 to sqrt it as well.Deglutition
and then what? what do you do with x,y?Martica
F
27

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 )
Forgave answered 24/10, 2015 at 14:27 Comment(5)
I like this, but since the question starts with x and y (not z), I would add the simple line z = x + 1j * yFaldstool
how does this work? polar2z returns a single argument!Martica
@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.Ossy
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.Outreach
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 @Fayefayette avoids unnecessary conversionsOctangle
G
18

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)
Geez answered 23/4, 2018 at 17:15 Comment(0)
P
15

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)
Pacificia answered 4/1, 2014 at 20:36 Comment(0)
S
13

There is a better way to write a method to convert from Cartesian to polar coordinates; here it is:

import numpy as np
def polar(x, y) -> tuple:
  """returns rho, theta (degrees)"""
  return np.hypot(x, y), np.degrees(np.arctan2(y, x))
Stump answered 8/8, 2016 at 11:51 Comment(7)
Why should it be better? It isn't vectorized.Glacis
Ok, then use np.hypot. The point is that you should never write sqrt(x2+y2). hypot exists for a reason.Stump
From KeithB's comment, return np.hypot(x, y), np.arctan2(y, x)Distrait
what is x and what is y? I'm given an angle in radians and distance.Polymerization
@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.December
Sorry for the necro. Why "you should never write sqrt(x**2+y**2)"?. In my test sqrt(x**2+y**2) is more then 50% faster then np.hypot(x,y).Logrolling
@MitchellvanZuylen The danger of the naive expression is the risk of overflow of the intermediate value x**2+y**2. See [What’s so hard about finding a hypotenuse?][1] and [Pythagorean addition][2]. [1]: johndcook.com/blog/2010/06/02/… [2]: en.wikipedia.org/wiki/Pythagorean_addition#ImplementationTen
G
5

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

Gauzy answered 4/1, 2014 at 17:20 Comment(0)
L
3

Mix of all the above answers which suits me:

import numpy as np

def pol2cart(r,theta):
    '''
    Parameters:
    - r: float, vector amplitude
    - theta: float, vector angle
    Returns:
    - x: float, x coord. of vector end
    - y: float, y coord. of vector end
    '''

    z = r * np.exp(1j * theta)
    x, y = z.real, z.imag

    return x, y

def cart2pol(x, y):
    '''
    Parameters:
    - x: float, x coord. of vector end
    - y: float, y coord. of vector end
    Returns:
    - r: float, vector amplitude
    - theta: float, vector angle
    '''

    z = x + y * 1j
    r,theta = np.abs(z), np.angle(z)

    return r,theta
Louis answered 11/6, 2021 at 15:44 Comment(0)
A
3

In case, like me, you're trying to control a robot that accepts a speed and heading value based off of a joystick value, use this instead (it converts the radians to degrees:

def cart2pol(x, y):
    rho = np.sqrt(x**2 + y**2)
    phi = np.arctan2(y, x)
    return(rho, math.degrees(phi))
Anorthosite answered 21/8, 2021 at 21:44 Comment(0)
B
0

If you have an array of (x,y) coordinates or (rho, phi) coordinates you can transform them all at once with numpy.

The functions return an array of converted coordinates.

import numpy as np

def combine2Coord(c1, c2):
    return np.concatenate((c1.reshape(-1, 1), c2.reshape(-1, 1)), axis=1)

def cart2pol(xyArr):
    rho = np.sqrt((xyArr**2).sum(1))
    phi = np.arctan2(xyArr[:,1], xyArr[:,0])
    return combine2Coord(rho, phi)

def pol2cart(rhoPhiArr):
    x = rhoPhiArr[:,0] * np.cos(rhoPhiArr[:,1])
    y = rhoPhiArr[:,0] * np.sin(rhoPhiArr[:,1])
    return combine2Coord(x, y)
Burgoo answered 17/6, 2022 at 23:15 Comment(0)
R
0

Do you care about speed? Use cmath, it's an order faster than numpy. And it's already included in any python since python 2!

Using ipython:

import cmath, numpy as np

def polar2z(polar):
    rho, phi = polar
    return rho * np.exp( 1j * phi )

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


def cart2polC(xy):
    x, y = xy
    return(cmath.polar(complex(x, y))) # rho, phi

def pol2cartC(polar):
    rho, phi = polar
    z = rho * cmath.exp(1j * phi)
    return z.real, z.imag

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

def pol2cartNP(polar):
    rho, phi = polar
    x = rho * np.cos(phi)
    y = rho * np.sin(phi)
    return(x, y)

xy = (100,100)
polar = (100,0)

%timeit cart2polC(xy)
%timeit pol2cartC(polar)

%timeit cart2polNP(xy)
%timeit pol2cartNP(polar)

%timeit z2polar(complex(*xy))
%timeit polar2z(polar)

373 ns ± 4.76 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
337 ns ± 0.976 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
4.3 µs ± 34.2 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
3.41 µs ± 5.78 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
3.4 µs ± 5.4 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
1.39 µs ± 3.86 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
Reggie answered 1/11, 2022 at 8:33 Comment(0)
M
0

You can use the built-in function spherical_to_cartesian from astropy.

Here the docs: https://docs.astropy.org/en/stable/api/astropy.coordinates.spherical_to_cartesian.html

Mezereum answered 17/12, 2023 at 8:5 Comment(0)
N
0

You can use hyperspherical package. It works for any dimension.

import numpy as np
from hyperspherical import cartesian2spherical, spherical2cartesian

xy = np.random.rand(3000000,2)
%timeit r_theta = cartesian2spherical(xy)

The time:

81.5 ms ± 2.96 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Nevernever answered 28/6 at 8:56 Comment(0)
L
-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.

Leff answered 5/11, 2014 at 13:11 Comment(2)
No need for getters and setters in Python. Just use properties.Wyn
@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.Greasepaint

© 2022 - 2024 — McMap. All rights reserved.