Source code for plotastrodata.coord_utils

import numpy as np
from astropy import units
from astropy.coordinates import FK4, FK5, SkyCoord


def _updateframe(frame: str | None) -> str:
    """Internal function to str frame to astropy frame.

    Args:
        frame (str): This should be one of 'J2000', 'B1950', 'FK5', 'FK4', and 'ICRS'.

    Returns:
        str: frame as is, FK5(equinox='J2000'), FK4(equinox='B1950'), or 'icrs'.
    """
    if 'ICRS' in frame:
        a = 'icrs'
    elif 'J2000' in frame or 'FK5' in frame:
        a = FK5(equinox='J2000')
    elif 'B1950' in frame or 'FK4' in frame:
        a = FK4(equinox='B1950')
    elif isinstance(frame, str):
        print(f'Unknown frame ({frame}) was found. Use ICRS instead.')
        a = 'icrs'
    else:
        a = frame
    return a


def _getframe(coord: str | list) -> tuple:
    """Internal function to pick up the frame name from the coordinates. When coord is a list, frame and framename are picked up from the first element.

    Args:
        coord (str): something like "J2000 01h23m45.6s 01d23m45.6s" or a list of them.

    Returns:
        tuple: updated coord and frame. frame is FK5(equinox='J2000), FK4(equinox='B1950'), or 'icrs'.
    """
    def getframe_single(s: str) -> tuple:
        c = s.split()
        hasframe = len(c) == 3
        hmsdms = f'{c[1]} {c[2]}' if hasframe else s
        frame = _updateframe(c[0]) if hasframe else None
        framename = c[0] if hasframe else None
        return hmsdms, frame, framename

    if isinstance(coord, str):
        return getframe_single(coord)
    else:
        outlist = [getframe_single(c) for c in coord]
        hmsdms = [a[0] for a in outlist]
        frame = outlist[0][1]
        framename = outlist[0][2]
        return hmsdms, frame, framename


[docs] def coord2xy(coords: str | list, coordorg: str = '00h00m00s 00d00m00s', frame: str | None = None, frameorg: str | None = None, ) -> np.ndarray: """Transform R.A.-Dec. to relative (deg, deg). Args: coords (str, list): something like '01h23m45.6s 01d23m45.6s'. The input can be a list of str in an arbitrary shape. coordorg (str, optional): something like '01h23m45.6s 01d23m45.6s'. The origin of the relative (deg, deg). Defaults to '00h00m00s 00d00m00s'. frame (str, optional): coordinate frame. Defaults to None. frameorg (str, optional): coordinate frame of the origin. Defaults to None. Returns: np.ndarray: [(array of) alphas, (array of) deltas] in degree. The shape of alphas and deltas is the input shape. With a single input, the output is [alpha0, delta0]. """ coordorg, frameorg_in, _ = _getframe(coordorg) frameorg = frameorg_in if frameorg is None else _updateframe(frameorg) coords, frame_in, _ = _getframe(coords) frame = frame_in if frame is None else _updateframe(frame) if frame is None: frame = frameorg elif frameorg is None: frameorg = frame c0 = SkyCoord(coordorg, frame=frameorg) # frame=None means ICRS. if frame is not None: c0 = c0.transform_to(frame=frame) clist = SkyCoord(coords, frame=frame) # frame=None means ICRS. xy = c0.spherical_offsets_to(clist) xy = np.array([xy[0].degree, xy[1].degree]) return xy
[docs] def xy2coord(xy: list, coordorg: str = '00h00m00s 00d00m00s', frame: str | None = None, frameorg: str | None = None, ) -> str | np.ndarray: """Transform relative (deg, deg) to R.A.-Dec. Args: xy (list): [(array of) alphas, (array of) deltas] in degree. alphas and deltas can have an arbitrary shape. coordorg (str): something like '01h23m45.6s 01d23m45.6s'. The origin of the relative (deg, deg). Defaults to '00h00m00s 00d00m00s'. frame (str): coordinate frame. Defaults to None. frameorg (str): coordinate frame of the origin. Defaults to None. Returns: str: something like '01h23m45.6s 01d23m45.6s'. With multiple inputs, the output has the input shape. """ coordorg, frameorg_in, framenameorg = _getframe(coordorg) frameorg = frameorg_in if frameorg is None else _updateframe(frameorg) framename = framenameorg if frame is None else frame frame = frameorg if frame is None else _updateframe(frame) c0 = SkyCoord(coordorg, frame=frameorg) # frame=None means ICRS. coords = c0.spherical_offsets_by(*xy * units.degree) if frame is not None: coords = coords.transform_to(frame=frame) coords = coords.to_string('hmsdms') if framename is not None: if isinstance(coords, str): coords = f'{framename} {coords}' else: coords = np.array([f'{framename} {s}' for s in coords]) return coords
[docs] def rel2abs(xrel: float, yrel: float, x: np.ndarray, y: np.ndarray) -> np.ndarray: """Transform relative coordinates to absolute ones. Args: xrel (float): 0 <= xrel <= 1. 0 and 1 correspond to x[0] and x[-1], respectively. Arbitrary shape. yrel (float): same as xrel. x (np.ndarray): [x0, x0+dx, x0+2dx, ...] y (np.ndarray): [y0, y0+dy, y0+2dy, ...] Returns: np.ndarray: [xabs, yabs]. Each has the input's shape. """ xabs = (1. - xrel)*x[0] + xrel*x[-1] yabs = (1. - yrel)*y[0] + yrel*y[-1] return np.array([xabs, yabs])
[docs] def abs2rel(xabs: float, yabs: float, x: np.ndarray, y: np.ndarray) -> np.ndarray: """Transform absolute coordinates to relative ones. Args: xabs (float): In the same frame of x. yabs (float): In the same frame of y. x (np.ndarray): [x0, x0+dx, x0+2dx, ...] y (np.ndarray): [y0, y0+dy, y0+2dy, ...] Returns: ndarray: [xrel, yrel]. Each has the input's shape. 0 <= xrel, yrel <= 1. 0 and 1 correspond to x[0] and x[-1], respectively. """ xrel = (xabs - x[0]) / (x[-1] - x[0]) yrel = (yabs - y[0]) / (y[-1] - y[0]) return np.array([xrel, yrel])
[docs] def get_sec(coord: str, mode: str) -> str: """Pick up the second number from a hmsdms string. Args: coord (str): hmsdms string. mode (str): 'ra' or 'dec' Returns: str: The second number as a string without the unit. """ i_axis = 0 if mode == 'ra' else 1 return coord.split(' ')[i_axis].split('m')[1].strip('s')
[docs] def get_min(coord: str, mode: str) -> str: """Pick up the minute number from a hmsdms string. Args: coord (str): hmsdms string. mode (str): 'ra' or 'dec' Returns: str: The minute number as a string without the unit. """ i_axis = 0 if mode == 'ra' else 1 s = 'h' if mode == 'ra' else 'd' return coord.split(' ')[i_axis].split(s)[1].split('m')[0]
[docs] def get_hmdm(coord: str, mode: str) -> str: """Pick up the coordinate string before the second part from a hsmdms string. Args: coord (str): hmsdms string. mode (str): 'ra' or 'dec' Returns: str: The hm or dm string with the units. """ i_axis = 0 if mode == 'ra' else 1 return coord.split(' ')[i_axis].split('m')[0] + 'm'