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