Source code for astropy.visualization.wcsaxes.coordinates_map

# Licensed under a 3-clause BSD style license - see LICENSE.rst

from collections import OrderedDict
from textwrap import indent

from .coordinate_helpers import CoordinateHelper
from .coordinate_range import find_coordinate_range
from .frame import RectangularFrame, RectangularFrame1D


[docs]class CoordinatesMap: """ A container for coordinate helpers that represents a coordinate system. This object can be used to access coordinate helpers by index (like a list) or by name (like a dictionary). Parameters ---------- axes : :class:`~astropy.visualization.wcsaxes.WCSAxes` The axes the coordinate map belongs to. transform : `~matplotlib.transforms.Transform`, optional The transform for the data. coord_meta : dict, optional A dictionary providing additional metadata. This should include the keys ``type``, ``wrap``, and ``unit``. Each of these should be a list with as many items as the dimension of the coordinate system. The ``type`` entries should be one of ``longitude``, ``latitude``, or ``scalar``, the ``wrap`` entries should give, for the longitude, the angle at which the coordinate wraps (and `None` otherwise), and the ``unit`` should give the unit of the coordinates as :class:`~astropy.units.Unit` instances. This can optionally also include a ``format_unit`` entry giving the units to use for the tick labels (if not specified, this defaults to ``unit``). frame_class : type, optional The class for the frame, which should be a subclass of :class:`~astropy.visualization.wcsaxes.frame.BaseFrame`. The default is to use a :class:`~astropy.visualization.wcsaxes.frame.RectangularFrame` previous_frame_path : `~matplotlib.path.Path`, optional When changing the WCS of the axes, the frame instance will change but we might want to keep re-using the same underlying matplotlib `~matplotlib.path.Path` - in that case, this can be passed to this keyword argument. """ def __init__( self, axes, transform=None, coord_meta=None, frame_class=RectangularFrame, previous_frame_path=None, ): self._axes = axes self._transform = transform self.frame = frame_class(axes, self._transform, path=previous_frame_path) # Set up coordinates self._coords = [] self._aliases = {} visible_count = 0 for index in range(len(coord_meta["type"])): # Extract coordinate metadata coord_type = coord_meta["type"][index] coord_wrap = coord_meta["wrap"][index] coord_unit = coord_meta["unit"][index] name = coord_meta["name"][index] visible = True if "visible" in coord_meta: visible = coord_meta["visible"][index] format_unit = None if "format_unit" in coord_meta: format_unit = coord_meta["format_unit"][index] default_label = name[0] if isinstance(name, (tuple, list)) else name if "default_axis_label" in coord_meta: default_label = coord_meta["default_axis_label"][index] coord_index = None if visible: visible_count += 1 coord_index = visible_count - 1 self._coords.append( CoordinateHelper( parent_axes=axes, parent_map=self, transform=self._transform, coord_index=coord_index, coord_type=coord_type, coord_wrap=coord_wrap, coord_unit=coord_unit, format_unit=format_unit, frame=self.frame, default_label=default_label, ) ) # Set up aliases for coordinates if isinstance(name, tuple): for nm in name: nm = nm.lower() # Do not replace an alias already in the map if we have # more than one alias for this axis. if nm not in self._aliases: self._aliases[nm] = index else: self._aliases[name.lower()] = index def __getitem__(self, item): if isinstance(item, str): return self._coords[self._aliases[item.lower()]] else: return self._coords[item] def __contains__(self, item): if isinstance(item, str): return item.lower() in self._aliases else: return 0 <= item < len(self._coords)
[docs] def set_visible(self, visibility): raise NotImplementedError()
def __iter__(self): yield from self._coords
[docs] def grid(self, draw_grid=True, grid_type=None, **kwargs): """ Plot gridlines for both coordinates. Standard matplotlib appearance options (color, alpha, etc.) can be passed as keyword arguments. Parameters ---------- draw_grid : bool Whether to show the gridlines grid_type : { 'lines' | 'contours' } Whether to plot the contours by determining the grid lines in world coordinates and then plotting them in world coordinates (``'lines'``) or by determining the world coordinates at many positions in the image and then drawing contours (``'contours'``). The first is recommended for 2-d images, while for 3-d (or higher dimensional) cubes, the ``'contours'`` option is recommended. By default, 'lines' is used if the transform has an inverse, otherwise 'contours' is used. """ for coord in self: coord.grid(draw_grid=draw_grid, grid_type=grid_type, **kwargs)
[docs] def get_coord_range(self): xmin, xmax = self._axes.get_xlim() if isinstance(self.frame, RectangularFrame1D): extent = [xmin, xmax] else: ymin, ymax = self._axes.get_ylim() extent = [xmin, xmax, ymin, ymax] return find_coordinate_range( self._transform, extent, [coord.coord_type for coord in self if coord.coord_index is not None], [coord.coord_unit for coord in self if coord.coord_index is not None], [coord.coord_wrap for coord in self if coord.coord_index is not None], )
def _as_table(self): # Import Table here to avoid importing the astropy.table package # every time astropy.visualization.wcsaxes is imported. from astropy.table import Table rows = [] for icoord, coord in enumerate(self._coords): aliases = [key for key, value in self._aliases.items() if value == icoord] row = OrderedDict( [ ("index", icoord), ("aliases", " ".join(aliases)), ("type", coord.coord_type), ("unit", coord.coord_unit), ("wrap", coord.coord_wrap), ("format_unit", coord.get_format_unit()), ("visible", "no" if coord.coord_index is None else "yes"), ] ) rows.append(row) return Table(rows=rows) def __repr__(self): s = f"<CoordinatesMap with {len(self._coords)} world coordinates:\n\n" table = indent(str(self._as_table()), " ") return s + table + "\n\n>"