23 "WHITE",
"BLACK",
"RED",
"GREEN",
"BLUE",
"CYAN",
"MAGENTA",
"YELLOW",
"ORANGE",
"IGNORE",
24 "Display",
"Event",
"noop_callback",
"h_callback",
25 "setDefaultBackend",
"getDefaultBackend",
26 "setDefaultFrame",
"getDefaultFrame",
"incrDefaultFrame",
27 "setDefaultMaskTransparency",
"setDefaultMaskPlaneColor",
28 "getDisplay",
"delAllDisplays",
36import lsst.afw.image
as afwImage
38logger = logging.getLogger(__name__)
54 """Return the ``DisplayImpl`` for the named backend
59 Name of device. Should be importable, either absolutely or relative to lsst.display
63 Arguments passed to DisplayImpl.__init__
65 Keywords arguments passed to DisplayImpl.__init__
73 import lsst.afw.display as afwDisplay
74 display = afwDisplay.Display(backend="ds9")
80 _makeDisplayImpl(..., "ds9", 1)
82 and import the ds9 implementation of ``DisplayImpl`` from `lsst.display.ds9`
86 candidateBackends = (f
"lsst.display.{backend}", backend, f
".{backend}", f
"lsst.afw.display.{backend}")
87 for dt
in candidateBackends:
91 if dt.startswith(
"."):
92 impargs[
"package"] =
"lsst.display"
94 _disp = importlib.import_module(dt, **impargs)
97 if hasattr(_disp,
"DisplayImpl"):
101 except (ImportError, SystemError)
as e:
107 if not _disp
or not hasattr(_disp.DisplayImpl,
"_show"):
109 e = ImportError(f
"Could not load the requested backend: {backend} "
110 f
"(tried {', '.join(candidateBackends)}, but none worked).")
117 _impl = _disp.DisplayImpl(display, *args, **kwargs)
118 if not hasattr(_impl,
"frame"):
119 _impl.frame = display.frame
127 """Create an object able to display images and overplot glyphs.
132 An identifier for the display.
134 The backend to use (defaults to value set by setDefaultBackend()).
136 Arguments to pass to the backend.
139 _defaultBackend =
None
141 _defaultMaskPlaneColor = dict(
148 DETECTED_NEGATIVE=CYAN,
155 _defaultMaskTransparency = {}
156 _defaultImageColormap =
"gray"
158 def __init__(self, frame=None, backend=None, **kwargs):
163 if Display._defaultBackend
is None:
169 backend = Display._defaultBackend
183 for ik
in range(ord(
'a'), ord(
'z') + 1):
188 for k
in (
'Return',
'Shift_L',
'Shift_R'):
191 for k
in (
'q',
'Escape'):
194 def _h_callback(k, x, y):
199 print(
" %-6s %s" % (k, doc.split(
"\n")[0]
if doc
else "???"))
203 Display._displays[frame] = self
158 def __init__(self, frame=None, backend=None, **kwargs):
…
206 """Support for python's with statement.
211 """Support for python's with statement.
219 """Return the attribute of ``self._impl``, or ``._impl`` if it is
225 name of the attribute requested.
230 the attribute of self._impl for the requested name.
234 return object.__getattr__(self, name)
236 if not (hasattr(self,
"_impl")
and self.
_impl):
237 raise AttributeError(
"Device has no _impl attached")
240 return getattr(self.
_impl, name)
241 except AttributeError:
242 raise AttributeError(
243 f
"Device {self.name} has no attribute \"{name}\"")
246 if getattr(self,
"_impl",
None)
is not None:
251 if self.
frame in Display._displays:
252 del Display._displays[self.
frame]
256 """The backend's verbosity.
258 return self.
_impl.verbose
263 self.
_impl.verbose = value
266 return f
"Display[{self.frame}]"
274 except Exception
as e:
276 f
"Unable to set backend to {backend}: \"{e}\"")
278 Display._defaultBackend = backend
282 return Display._defaultBackend
286 """Set the default frame for display.
288 Display._defaultFrame = frame
292 """Get the default frame for display.
294 return Display._defaultFrame
298 """Increment the default frame for display.
300 Display._defaultFrame += 1
301 return Display._defaultFrame
305 if hasattr(maskPlaneTransparency,
"copy"):
306 maskPlaneTransparency = maskPlaneTransparency.copy()
308 Display._defaultMaskTransparency = maskPlaneTransparency
312 """Set the default mapping from mask plane names to colors.
316 name : `str` or `dict`
317 Name of mask plane, or a dict mapping names to colors
318 If name is `None`, use the hard-coded default dictionary.
320 Desired color, or `None` if name is a dict.
324 name = Display._defaultMaskPlaneColor
326 if isinstance(name, dict):
328 for k, v
in name.items():
332 Display._defaultMaskPlaneColor[name] = color
336 """Set the default colormap for images.
341 Name of colormap, as interpreted by the backend.
345 The only colormaps that all backends are required to honor
346 (if they pay any attention to setImageColormap) are "gray" and "grey".
349 Display._defaultImageColormap = cmap
352 """Set the colormap to use for images.
357 Name of colormap, as interpreted by the backend.
361 The only colormaps that all backends are required to honor
362 (if they pay any attention to setImageColormap) are "gray" and "grey".
365 self.
_impl._setImageColormap(cmap)
368 def getDisplay(frame=None, backend=None, create=True, verbose=False, **kwargs):
369 """Return a specific `Display`, creating it if need be.
374 The desired frame (`None` => use defaultFrame
375 (see `~Display.setDefaultFrame`)).
377 create the specified frame using this backend (or the default if
378 `None`) if it doesn't already exist. If ``backend == ""``, it's an
379 error to specify a non-existent ``frame``.
381 create the display if it doesn't already exist.
383 Allow backend to be chatty.
385 keyword arguments passed to `Display` constructor.
389 frame = Display._defaultFrame
391 if frame
not in Display._displays:
393 raise RuntimeError(f
"Frame {frame} does not exist")
395 Display._displays[frame] =
Display(
396 frame, backend, verbose=verbose, **kwargs)
398 Display._displays[frame].verbose = verbose
399 return Display._displays[frame]
368 def getDisplay(frame=None, backend=None, create=True, verbose=False, **kwargs):
…
403 """Delete and close all known displays.
405 for disp
in list(Display._displays.values()):
407 Display._displays = {}
410 """A generator for "standard" colors.
415 Don't include `BLACK` and `WHITE`.
422 colorGenerator = interface.maskColorGenerator(omitBW=True)
424 print(p, next(colorGenerator))
426 _maskColors = [WHITE, BLACK, RED, GREEN,
427 BLUE, CYAN, MAGENTA, YELLOW, ORANGE]
432 color = _maskColors[i%len(_maskColors)]
433 if omitBW
and color
in (BLACK, WHITE):
439 """Request that mask plane name be displayed as color.
443 name : `str` or `dict`
444 Name of mask plane or a dictionary of name -> colorName.
446 The name of the color to use (must be `None` if ``name`` is a
449 Colors may be specified as any X11-compliant string (e.g.
450 `"orchid"`), or by one of the following constants in
451 `lsst.afw.display` : `BLACK`, `WHITE`, `RED`, `BLUE`,
452 `GREEN`, `CYAN`, `MAGENTA`, `YELLOW`.
454 If the color is "ignore" (or `IGNORE`) then that mask plane is not
457 The advantage of using the symbolic names is that the python
458 interpreter can detect typos.
460 if isinstance(name, dict):
462 for k, v
in name.items():
469 """Return the color associated with the specified mask plane name.
474 Desired mask plane; if `None`, return entire dict.
487 """Specify display's mask transparency (percent); or `None` to not set
488 it when loading masks.
490 if isinstance(transparency, dict):
492 for k, v
in transparency.items():
496 if transparency
is not None and (transparency < 0
or transparency > 100):
498 "Mask transparency should be in the range [0, 100]; clipping", file=sys.stderr)
504 if transparency
is not None:
505 self.
_impl._setMaskTransparency(transparency, name)
508 """Return the current display's mask transparency.
510 return self.
_impl._getMaskTransparency(name)
513 """Uniconify and Raise display.
517 Throws an exception if frame doesn't exit.
519 return self.
_impl._show()
521 def __addMissingMaskPlanes(self, mask):
522 """Assign colours to any missing mask planes found in mask.
524 maskPlanes = mask.getMaskPlaneDict()
525 nMaskPlanes = max(maskPlanes.values()) + 1
529 for key
in maskPlanes:
530 planes[maskPlanes[key]] = key
533 for p
in range(nMaskPlanes):
538 def image(self, data, title="", wcs=None, metadata=None):
539 """Display an image on a display, with semi-transparent masks
540 overlaid, if available.
544 data : `lsst.afw.image.Exposure` or `lsst.afw.image.MaskedImage` or `lsst.afw.image.Image`
545 Image to display; Exposure and MaskedImage will show transparent
547 title : `str`, optional
548 Title for the display window.
549 wcs : `lsst.afw.geom.SkyWcs`, optional
550 World Coordinate System to align an `~lsst.afw.image.MaskedImage`
551 or `~lsst.afw.image.Image` to; raise an exception if ``data``
552 is an `~lsst.afw.image.Exposure`.
553 metadata : `lsst.daf.base.PropertySet`, optional
554 Additional FITS metadata to be sent to display.
559 Raised if an Exposure is passed with a non-None wcs when the
560 ``wcs`` kwarg is also non-None.
562 Raised if data is an incompatible type.
564 if hasattr(data,
"getXY0"):
565 self.
_xy0 = data.getXY0()
572 raise RuntimeError(
"You may not specify a wcs with an Exposure")
573 data, wcs, metadata = data.getMaskedImage(), data.wcs, data.metadata
582 self.
_xy0 = data.getXY0()
585 self.
_impl._mtv(data,
None, wcs, title, metadata)
591 self.
_impl._mtv(afwImage.ImageI(data.array), data, wcs, title, metadata)
595 self.
_impl._mtv(data.image, data.mask, wcs, title, metadata)
597 raise TypeError(f
"Unsupported type {data!r}")
538 def image(self, data, title="", wcs=None, metadata=None):
…
599 def mtv(self, data, title="", wcs=None, metadata=None):
600 """Display an image on a display, with semi-transparent masks
601 overlaid, if available.
605 Historical note: the name "mtv" comes from Jim Gunn's forth imageprocessing
606 system, Mirella (named after Mirella Freni); The "m" stands for Mirella.
608 self.
image(data, title, wcs, metadata)
599 def mtv(self, data, title="", wcs=None, metadata=None):
…
611 """Context manager for buffering repeated display commands.
617 self.
_impl._buffer(
True)
620 self.
_impl._buffer(
False)
624 """Return a context manager that will buffer repeated display
625 commands, to e.g. speed up displaying points.
631 with display.Buffering():
632 display.dot("+", xc, yc)
637 """Flush any buffering that may be provided by the backend.
642 """Erase the specified display frame.
647 """Draw the sources from a catalog at their pixel centroid positions
648 as given by `~lsst.afw.table.Catalog.getX()` and
649 `~lsst.afw.table.Catalog.getY()`.
651 See `dot` for an explanation of ``symbol`` and available args/kwargs,
652 which are passed to `dot`.
656 catalog : `lsst.afw.table.Catalog`
657 Catalog to display centroids for. Must have valid `slot_Centroid`.
659 if not catalog.getCentroidSlot().isValid():
660 raise RuntimeError(
"Catalog must have a valid `slot_Centroid` defined to get X/Y positions.")
664 self.
dot(symbol, pt.getX(), pt.getY(), **kwargs)
666 def dot(self, symb, c, r, size=2, ctype=None, origin=afwImage.PARENT, **kwargs):
667 """Draw a symbol onto the specified display frame.
683 Draw an ellipse with moments (Mxx, Mxy, Myy) (argument size is ignored)
684 `lsst.afw.geom.ellipses.BaseCore`
685 Draw the ellipse (argument size is ignored). N.b. objects
686 derived from `~lsst.afw.geom.ellipses.BaseCore` include
687 `~lsst.afw.geom.ellipses.Axes` and `~lsst.afw.geom.ellipses.Quadrupole`.
689 Interpreted as a string to be drawn.
691 The column and row where the symbol is drawn [0-based coordinates].
693 Size of symbol, in pixels.
695 The desired color, either e.g. `lsst.afw.display.RED` or a color name known to X11
696 origin : `lsst.afw.image.ImageOrigin`
697 Coordinate system for the given positions.
699 Extra keyword arguments to backend.
701 if isinstance(symb, int):
704 if origin == afwImage.PARENT
and self.
_xy0 is not None:
711 mat = re.search(
r"^@:([^,]+),([^,]+),([^,]+)", symb)
716 mxx, mxy, myy = [float(_)
for _
in mat.groups()]
721 self.
_impl._dot(symb, c, r, size, ctype, **kwargs)
666 def dot(self, symb, c, r, size=2, ctype=None, origin=afwImage.PARENT, **kwargs):
…
723 def line(self, points, origin=afwImage.PARENT, symbs=False, ctype=None, size=0.5):
724 """Draw a set of symbols or connect points
730 origin : `lsst.afw.image.ImageOrigin`
731 Coordinate system for the given positions.
732 symbs : `bool` or sequence
733 If ``symbs`` is `True`, draw points at the specified points using
734 the desired symbol, otherwise connect the dots.
736 If ``symbs`` supports indexing (which includes a string -- caveat
737 emptor) the elements are used to label the points.
739 ``ctype`` is the name of a color (e.g. 'red').
741 Size of points to create if `symbs` is passed.
747 symbs = len(points)*list(symbs)
749 for i, xy
in enumerate(points):
750 self.
dot(symbs[i], *xy, size=size, ctype=ctype)
753 if origin == afwImage.PARENT
and self.
_xy0 is not None:
755 _points = list(points)
756 for i, p
in enumerate(points):
757 _points[i] = (p[0] - x0, p[1] - y0)
760 self.
_impl._drawLines(points, ctype)
723 def line(self, points, origin=afwImage.PARENT, symbs=False, ctype=None, size=0.5):
…
762 def scale(self, algorithm, min, max=None, unit=None, **kwargs):
763 """Set the range of the scaling from DN in the image to the image
769 Desired scaling (e.g. "linear" or "asinh").
771 Minimum value, or "minmax" or "zscale".
773 Maximum value (must be `None` for minmax|zscale).
775 Units for min and max (e.g. Percent, Absolute, Sigma; `None` if
778 Optional keyword arguments to the backend.
780 if min
in (
"minmax",
"zscale"):
781 assert max
is None, f
"You may not specify \"{min}\" and max"
782 assert unit
is None, f
"You may not specify \"{min}\" and unit"
784 raise RuntimeError(
"Please specify max")
786 self.
_impl._scale(algorithm, min, max, unit, **kwargs)
762 def scale(self, algorithm, min, max=None, unit=None, **kwargs):
…
788 def zoom(self, zoomfac=None, colc=None, rowc=None, origin=afwImage.PARENT):
789 """Zoom frame by specified amount, optionally panning also
791 if (rowc
and colc
is None)
or (colc
and rowc
is None):
793 "Please specify row and column center to pan about")
796 if origin == afwImage.PARENT
and self.
_xy0 is not None:
801 self.
_impl._pan(colc, rowc)
803 if zoomfac
is None and rowc
is None:
806 if zoomfac
is not None:
807 self.
_impl._zoom(zoomfac)
788 def zoom(self, zoomfac=None, colc=None, rowc=None, origin=afwImage.PARENT):
…
809 def pan(self, colc=None, rowc=None, origin=afwImage.PARENT):
810 """Pan to a location.
815 Coordinates to pan to.
816 origin : `lsst.afw.image.ImageOrigin`
817 Coordinate system for the given positions.
823 self.
zoom(
None, colc, rowc, origin)
809 def pan(self, colc=None, rowc=None, origin=afwImage.PARENT):
…
826 """Enter an interactive loop, listening for key presses or equivalent
827 UI actions in the display and firing callbacks.
829 Exit with ``q``, ``CR``, ``ESC``, or any equivalent UI action provided
830 in the display. The loop may also be exited by returning `True` from a
831 user-provided callback function.
833 interactFinished =
False
835 while not interactFinished:
836 ev = self.
_impl._getEvent()
839 k, x, y = ev.k, ev.x, ev.y
842 logger.warning(
"No callback registered for %s", k)
845 interactFinished = self.
_callbacks[k](k, x, y)
848 "Display._callbacks['%s'](%s,%s,%s) failed.", k, x, y)
851 """Set the callback for a key.
853 Backend displays may provide an equivalent graphical UI action, but
854 must make the associated key letter visible in the UI in some way.
859 The key to assign the callback to.
861 The callback assigned to ``k``.
863 Do not raise if ``k`` is already in use.
868 The callback previously assigned to ``k``.
875 f
"Key '{k}' is already in use by display, so I can't add a callback for it")
878 self.
_callbacks[k] = func
if func
else noop_callback
885 """Return all callback keys
890 If `True` only return keys that do something
892 return sorted([k
for k, func
in self.
_callbacks.items()
if
893 not (onlyActive
and func == noop_callback)])
900 """A class to handle events such as key presses in image display windows.
903 def __init__(self, k, x=float(
'nan'), y=float(
'nan')):
903 def __init__(self, k, x=float(
'nan'), y=float(
'nan')):
…
909 return f
"{self.k} ({self.x:.2f}, {self.y:.2f}"
928 print(
"Enter q or <ESC> to leave interactive mode, h for this help, or a letter to fire a callback")
936 Display.setDefaultBackend(backend)
940 return Display.getDefaultBackend()
944 return Display.setDefaultFrame(frame)
948 """Get the default frame for display.
950 return Display.getDefaultFrame()
954 """Increment the default frame for display.
956 return Display.incrDefaultFrame()
960 return Display.setDefaultMaskTransparency(maskPlaneTransparency)
964 """Set the default mapping from mask plane names to colors.
968 name : `str` or `dict`
969 Name of mask plane, or a dict mapping names to colors.
970 If ``name`` is `None`, use the hard-coded default dictionary.
972 Desired color, or `None` if ``name`` is a dict.
975 return Display.setDefaultMaskPlaneColor(name, color)
978def getDisplay(frame=None, backend=None, create=True, verbose=False, **kwargs):
979 """Return a specific `Display`, creating it if need be.
984 Desired frame (`None` => use defaultFrame (see `setDefaultFrame`)).
986 Create the specified frame using this backend (or the default if
987 `None`) if it doesn't already exist. If ``backend == ""``, it's an
988 error to specify a non-existent ``frame``.
990 Create the display if it doesn't already exist.
992 Allow backend to be chatty.
994 Keyword arguments passed to `Display` constructor.
1001 return Display.getDisplay(frame, backend, create, verbose, **kwargs)
978def getDisplay(frame=None, backend=None, create=True, verbose=False, **kwargs):
…
1005 """Delete and close all known displays.
1007 return Display.delAllDisplays()
image(self, data, title="", wcs=None, metadata=None)
setMaskTransparency(self, transparency=None, name=None)
getDisplay(frame=None, backend=None, create=True, verbose=False, **kwargs)
getActiveCallbackKeys(self, onlyActive=True)
setDefaultBackend(backend)
dot(self, symb, c, r, size=2, ctype=None, origin=afwImage.PARENT, **kwargs)
getMaskPlaneColor(self, name=None)
setDefaultImageColormap(cmap)
line(self, points, origin=afwImage.PARENT, symbs=False, ctype=None, size=0.5)
scale(self, algorithm, min, max=None, unit=None, **kwargs)
__init__(self, frame=None, backend=None, **kwargs)
setDefaultMaskTransparency(maskPlaneTransparency={})
pan(self, colc=None, rowc=None, origin=afwImage.PARENT)
centroids(self, catalog, *, symbol="o", **kwargs)
getMaskTransparency(self, name=None)
setCallback(self, k, func=None, noRaise=False)
setMaskPlaneColor(self, name, color=None)
setDefaultMaskPlaneColor(name=None, color=None)
__addMissingMaskPlanes(self, mask)
maskColorGenerator(self, omitBW=True)
mtv(self, data, title="", wcs=None, metadata=None)
zoom(self, zoomfac=None, colc=None, rowc=None, origin=afwImage.PARENT)
setImageColormap(self, cmap)
__init__(self, k, x=float('nan'), y=float('nan'))
An ellipse core for the semimajor/semiminor axis and position angle parametrization (a,...
A base class for parametrizations of the "core" of an ellipse - the ellipticity and size.
An ellipse core with quadrupole moments as parameters.
A container for an Image and its associated metadata.
A class to contain the data, WCS, and other information needed to describe an image of the sky.
A class to represent a 2-dimensional array of pixels.
Represent a 2-dimensional array of bitmask pixels.
A class to manipulate images, masks, and variance as a single object.
setDefaultMaskTransparency(maskPlaneTransparency={})
getDisplay(frame=None, backend=None, create=True, verbose=False, **kwargs)
setDefaultMaskPlaneColor(name=None, color=None)
_makeDisplayImpl(display, backend, *args, **kwargs)
setDefaultBackend(backend)
std::shared_ptr< SkyWcs > makeSkyWcs(daf::base::PropertySet &metadata, bool strip=false)
Construct a SkyWcs from FITS keywords.