How to determine quadrant given x- and y-coordinate columns in Pandas DataFrame

Viewed 200

Dataframe format:

tooth_id x_center y_center width height quadrant
1 0.309643 0.082520 0.072325 0.169476
2 -0.211200 -0.057675 0.071321 0.199645
3 -0.307634 -0.127773 0.081366 0.187223
4 -0.262933 -0.093611 0.065294 0.211180
5 0.253139 0.136646 0.096936 0.190772

Question: how to write a loop to deliver the following outcome? In each roll:

if x_center >=0 and y_center >= 0, quadrant = 1
if x_center <0 and y_center >= 0,  quadrant = 2 
if x_center <0 and y_center <0,    quadrant = 3
if x_center >0 and y_center <0,    quadrant = 4  
2 Answers

Use np.select:

# Update: change 'df.x_center > 0' to 'df.x_center >= 0'
# See comment of @ddejohn below

df['quadrant'] = np.select([(df.x_center >= 0) & (df.y_center >= 0),
                            (df.x_center < 0) & (df.y_center >= 0),
                            (df.x_center < 0) & (df.y_center < 0),
                            (df.x_center >= 0) & (df.y_center < 0)],
                           choicelist=[1, 2, 3, 4])

Output:

>>> df
   tooth_id  x_center  y_center     width    height  quadrant
0         1  0.309643  0.082520  0.072325  0.169476         1
1         2 -0.211200 -0.057675  0.071321  0.199645         3
2         3 -0.307634 -0.127773  0.081366  0.187223         3
3         4 -0.262933 -0.093611  0.065294  0.211180         3
4         5  0.253139  0.136646  0.096936  0.190772         1

Solution

Here's another solution, using arctan2 and a little modular arithmetic. Note that Corralien's approach is much more generalizable. What follows is very specific to this use-case.

import numpy as np

deg = np.round(180 * np.arctan2(df.y_center, df.x_center) / np.pi).astype(int)
df["quadrant"] = 1 + ((deg + 360) % 360) // 90

Output:

>>> df
   tooth_id  x_center  y_center     width    height  quadrant
0         1  0.309643  0.082520  0.072325  0.169476         1
1         2 -0.211200 -0.057675  0.071321  0.199645         3
2         3 -0.307634 -0.127773  0.081366  0.187223         3
3         4 -0.262933 -0.093611  0.065294  0.211180         3
4         5  0.253139  0.136646  0.096936  0.190772         1

Note, points on the axes are "rolled over" into the neighboring quadrant in the anti-clockwise direction, e.g., the point (0, 0.631), which lies at 90° is considered quadrant 2; (-0.578, 0), which lies at 180° is considered quadrant 3, etc.

Steps

Use np.arctan2() to get the angle (in degrees) formed by each (x, y) point:

>>> deg = np.round(180 * np.arctan2(df.y_center, df.x_center) / np.pi).astype(int)
>>> deg
0     15
1   -165
2   -157
3   -160
4     28
dtype: int32

Now, convert (-180°, 180°] to [0°, 360°):

>>> deg = (deg + 360) % 360
>>> deg
0     15
1    195
2    203
3    200
4     28
dtype: int32

Floor divide by 90 to get the quadrant (which'll return 0, 1, 2, 3 -- so also add 1):

>>> quadrant = 1 + (deg // 90)
>>> quadrant
0    1
1    3
2    3
3    3
4    1
dtype: int32
Related