1 from __future__
import print_function
2 from builtins
import range
3 from builtins
import object
40 "WHITE",
"BLACK",
"RED",
"GREEN",
"BLUE",
"CYAN",
"MAGENTA",
"YELLOW",
"ORANGE",
41 "Display",
"Event",
"noop_callback",
"h_callback",
42 "setDefaultBackend",
"getDefaultBackend",
43 "setDefaultFrame",
"getDefaultFrame",
"incrDefaultFrame",
44 "setDefaultMaskTransparency",
"setDefaultMaskPlaneColor",
45 "getDisplay",
"delAllDisplays",
64 """!Return the DisplayImpl for the named backend
66 \param display Name of device. Should be importable, either absolutely or relative to lsst.display
67 \param backend The desired backend
68 \param args Arguments passed to DisplayImpl.__init__
69 \param kwargs Keywords arguments passed to DisplayImpl.__init__
72 import lsst.afw.display as afwDisplay
73 display = afwDisplay.Display(display=1, backend="ds9")
75 _makeDisplayImpl(..., "ds9", 1)
76 and import the ds9 implementation of DisplayImpl from lsst.display.ds9
80 for dt
in (
"lsst.display.%s" % backend, backend,
".%s" % backend,
"lsst.afw.display.%s" % backend):
84 if dt.startswith(
"."):
85 impargs[
"package"] =
"lsst.display"
87 _disp = importlib.import_module(dt, **impargs)
89 except (ImportError, SystemError)
as e:
95 if not _disp
or not hasattr(_disp.DisplayImpl,
"_show"):
103 _impl = _disp.DisplayImpl(display, *args, **kwargs)
104 if not hasattr(_impl,
"frame"):
105 _impl.frame = display.frame
115 _defaultBackend =
None
117 _defaultMaskPlaneColor = dict(
124 DETECTED_NEGATIVE=CYAN,
131 _defaultMaskTransparency = {}
133 def __init__(self, frame=None, backend=None, *args, **kwargs):
134 """!Create an object able to display images and overplot glyphs
136 \param frame An identifier for the display
137 \param backend The backend to use (defaults to value set by setDefaultBackend())
138 \param args Arguments to pass to the backend
139 \param kwargs Arguments to pass to the backend
145 if Display._defaultBackend
is None:
151 backend = Display._defaultBackend
164 for ik
in range(ord(
'a'), ord(
'z') + 1):
169 for k
in (
'Return',
'Shift_L',
'Shift_R'):
172 for k
in (
'q',
'Escape'):
175 def _h_callback(k, x, y):
178 for k
in sorted(self._callbacks.keys()):
180 print(
" %-6s %s" % (k, doc.split(
"\n")[0]
if doc
else "???"))
184 Display._displays[frame] = self
187 """!Support for python's with statement"""
191 """!Support for python's with statement"""
198 """Try to call self._impl.name(*args, *kwargs)"""
200 if not (hasattr(self,
"_impl")
and self.
_impl):
201 raise AttributeError(
"Device has no _impl attached")
204 return getattr(self.
_impl, name)
205 except AttributeError:
206 raise AttributeError(
"Device %s has no attribute \"%s\"" % (self.
name, name))
209 if hasattr(self,
"_impl")
and self.
_impl:
213 if self.
frame in Display._displays:
214 del Display._displays[self.
frame]
218 """!The backend's verbosity"""
219 return self._impl.verbose
224 self._impl.verbose = value
227 return "Display[%s]" % (self.
frame)
236 except Exception
as e:
237 raise RuntimeError(
"Unable to set backend to %s: \"%s\"" % (backend, e))
239 Display._defaultBackend = backend
243 return Display._defaultBackend
247 """Set the default frame for display"""
248 Display._defaultFrame = frame
252 """Get the default frame for display"""
253 return Display._defaultFrame
257 """Increment the default frame for display"""
258 Display._defaultFrame += 1
259 return Display._defaultFrame
263 if hasattr(maskPlaneTransparency,
"copy"):
264 maskPlaneTransparency = maskPlaneTransparency.copy()
266 Display._defaultMaskTransparency = maskPlaneTransparency
270 """!Set the default mapping from mask plane names to colours
271 \param name name of mask plane, or a dict mapping names to colours
272 \param color Desired color, or None if name is a dict
274 If name is None, use the hard-coded default dictionary
278 name = Display._defaultMaskPlaneColor
280 if isinstance(name, dict):
282 for k, v
in name.items():
288 Display._defaultMaskPlaneColor[name] = color
291 def getDisplay(frame=None, backend=None, create=True, verbose=False, *args, **kwargs):
292 """!Return the Display indexed by frame, creating it if needs be
294 \param frame The desired frame (None => use defaultFrame (see setDefaultFrame))
295 \param backend create the specified frame using this backend (or the default if None) \
296 if it doesn't already exist. If backend == "", it's an error to specify a non-existent frame
297 \param create create the display if it doesn't already exist.
298 \param verbose Allow backend to be chatty
299 \param args arguments passed to Display constructor
300 \param kwargs keyword arguments passed to Display constructor
304 frame = Display._defaultFrame
306 if not frame
in Display._displays:
308 raise RuntimeError(
"Frame %s does not exist" % frame)
310 Display._displays[frame] =
Display(frame, backend, verbose=verbose, *args, **kwargs)
312 Display._displays[frame].verbose = verbose
313 return Display._displays[frame]
317 """!Delete and close all known display
319 for disp
in list(Display._displays.values()):
321 Display._displays = {}
324 """!A generator for "standard" colours
326 \param omitBW Don't include Black and White
329 colorGenerator = interface.maskColorGenerator(omitBW=True)
331 print p, next(colorGenerator)
333 _maskColors = [WHITE, BLACK, RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW, ORANGE]
338 color = _maskColors[i%len(_maskColors)]
339 if omitBW
and color
in (BLACK, WHITE):
345 """!Request that mask plane name be displayed as color
347 \param name Name of mask plane or a dictionary of name -> colourName
348 \param color The name of the colour to use (must be None if name is a dict)
350 Colours may be specified as any X11-compliant string (e.g. <tt>"orchid"</tt>), or by one
351 of the following constants defined in \c afwDisplay: \c BLACK, \c WHITE, \c RED, \c BLUE,
352 \c GREEN, \c CYAN, \c MAGENTA, \c YELLOW.
354 The advantage of using the symbolic names is that the python interpreter can detect typos.
358 if isinstance(name, dict):
360 for k, v
in name.items():
367 """!Return the colour associated with the specified mask plane name"""
369 return self._maskPlaneColors.get(name)
372 """!Specify display's mask transparency (percent); or None to not set it when loading masks"""
374 if isinstance(transparency, dict):
376 for k, v
in transparency.items():
380 if transparency
is not None and (transparency < 0
or transparency > 100):
381 print(
"Mask transparency should be in the range [0, 100]; clipping", file=sys.stderr)
387 if transparency
is not None:
388 self._impl._setMaskTransparency(transparency, name)
391 """!Return the current display's mask transparency"""
393 return self._impl._getMaskTransparency(name)
396 """!Uniconify and Raise display. N.b. throws an exception if frame doesn't exit"""
397 return self._impl._show()
399 def mtv(self, data, title="", wcs=None):
400 """!Display an Image or Mask on a DISPLAY display
402 Historical note: the name "mtv" comes from Jim Gunn's forth imageprocessing
403 system, Mirella (named after Mirella Freni); The "m" stands for Mirella.
405 if hasattr(data,
"getXY0"):
406 self.
_xy0 = data.getXY0()
410 if re.search(
"::Exposure<", repr(data)):
412 raise RuntimeError(
"You may not specify a wcs with an Exposure")
413 data, wcs = data.getMaskedImage(), data.getWcs()
414 elif re.search(
"::DecoratedImage<", repr(data)):
416 self.
_xy0 = data.getXY0()
418 if re.search(
"::Image<", repr(data)):
419 self._impl._mtv(data,
None, wcs, title)
420 elif re.search(
"::Mask<", repr(data)):
425 self._impl._mtv(afwImage.ImageU(data.getArray()), data, wcs, title)
426 elif re.search(
"::MaskedImage<", repr(data)):
427 self._impl._mtv(data.getImage(), data.getMask(
True), wcs, title)
429 raise RuntimeError(
"Unsupported type %s" % repr(data))
434 """A class intended to be used with python's with statement"""
438 self._impl._buffer(
True)
440 self._impl._buffer(
False)
444 """Return a class intended to be used with python's with statement
446 with display.Buffering():
447 display.dot("+", xc, yc)
452 """!Flush the buffers"""
456 """!Erase the specified DISPLAY frame
460 def dot(self, symb, c, r, size=2, ctype=None, origin=afwImage.PARENT, *args, **kwargs):
461 """!Draw a symbol onto the specified DISPLAY frame at (col,row) = (c,r) [0-based coordinates]
468 @:Mxx,Mxy,Myy Draw an ellipse with moments (Mxx, Mxy, Myy) (argument size is ignored)
469 An object derived from afwGeom.ellipses.BaseCore Draw the ellipse (argument size is ignored)
470 Any other value is interpreted as a string to be drawn. Strings obey the fontFamily (which may be extended
471 with other characteristics, e.g. "times bold italic". Text will be drawn rotated by textAngle (textAngle is
474 N.b. objects derived from BaseCore include Axes and Quadrupole.
476 if isinstance(symb, int):
479 if origin == afwImage.PARENT
and self.
_xy0 is not None:
484 if isinstance(symb, afwGeom.ellipses.BaseCore)
or re.search(
r"^@:", symb):
486 mat = re.search(
r"^@:([^,]+),([^,]+),([^,]+)", symb)
491 mxx, mxy, myy = [float(_)
for _
in mat.groups()]
492 symb = afwGeom.ellipses.Quadrupole(mxx, myy, mxy)
494 symb = afwGeom.ellipses.Axes(symb)
496 self._impl._dot(symb, c, r, size, ctype, **kwargs)
498 def line(self, points, origin=afwImage.PARENT, symbs=False, ctype=None, size=0.5):
499 """!Draw a set of symbols or connect the points, a list of (col,row)
500 If symbs is True, draw points at the specified points using the desired symbol,
501 otherwise connect the dots. Ctype is the name of a colour (e.g. 'red')
503 If symbs supports indexing (which includes a string -- caveat emptor) the elements are used to label the points
509 symbs = len(points)*list(symbs)
511 for i, xy
in enumerate(points):
512 self.
dot(symbs[i], *xy, size=size, ctype=ctype)
515 if origin == afwImage.PARENT
and self.
_xy0 is not None:
517 _points = list(points)
518 for i, p
in enumerate(points):
519 _points[i] = (p[0] - x0, p[1] - y0)
522 self._impl._drawLines(points, ctype)
526 def scale(self, algorithm, min, max=None, unit=None, *args, **kwargs):
527 """!Set the range of the scaling from DN in the image to the image display
528 \param algorithm Desired scaling (e.g. "linear" or "asinh")
529 \param min Minimum value, or "minmax" or "zscale"
530 \param max Maximum value (must be None for minmax|zscale)
531 \param unit Units for min and max (e.g. Percent, Absolute, Sigma; None if min==minmax|zscale)
532 \param *args Optional arguments
533 \param **kwargs Optional keyword arguments
535 if min
in (
"minmax",
"zscale"):
536 assert max ==
None,
"You may not specify \"%s\" and max" % min
537 assert unit ==
None,
"You may not specify \"%s\" and unit" % min
539 raise RuntimeError(
"Please specify max")
541 self._impl._scale(algorithm, min, max, unit, *args, **kwargs)
545 def zoom(self, zoomfac=None, colc=None, rowc=None, origin=afwImage.PARENT):
546 """!Zoom frame by specified amount, optionally panning also"""
548 if (rowc
and colc
is None)
or (colc
and rowc
is None):
549 raise RuntimeError(
"Please specify row and column center to pan about")
552 if origin == afwImage.PARENT
and self.
_xy0 is not None:
557 self._impl._pan(colc, rowc)
559 if zoomfac ==
None and rowc ==
None:
562 if zoomfac
is not None:
563 self._impl._zoom(zoomfac)
565 def pan(self, colc=None, rowc=None, origin=afwImage.PARENT):
566 """!Pan to (rowc, colc); see also zoom"""
568 self.
zoom(
None, colc, rowc, origin)
571 """!Enter an interactive loop, listening for key presses in display and firing callbacks.
572 Exit with q, \c CR, \c ESC, or any other callback function that returns a ``True`` value.
574 interactFinished =
False
576 while not interactFinished:
577 ev = self._impl._getEvent()
580 k, x, y = ev.k, ev.x, ev.y
583 logger.warn(
"No callback registered for {0}".
format(k))
586 interactFinished = self.
_callbacks[k](k, x, y)
587 except Exception
as e:
588 logger.error(
"Display._callbacks[{0}]({0},{1},{2}) failed: {3}".
format(k, x, y, e))
591 """!Set the callback for key k to be func, returning the old callback
598 "Key '%s' is already in use by display, so I can't add a callback for it" % k)
600 ofunc = self._callbacks.get(k)
601 self.
_callbacks[k] = func
if func
else noop_callback
603 self._impl._setCallback(k, self.
_callbacks[k])
608 """!Return all callback keys
609 \param onlyActive If true only return keys that do something
612 return sorted([k
for k, func
in self._callbacks.items()
if
613 not (onlyActive
and func == noop_callback)])
620 """!A class to handle events such as key presses in image display windows"""
621 def __init__(self, k, x=float(
'nan'), y=float(
'nan')):
627 return "%s (%.2f, %.2f)" % (self.
k, self.
x, self.
y)
632 """!Callback function: arguments key, x, y"""
636 print(
"Enter q or <ESC> to leave interactive mode, h for this help, or a letter to fire a callback")
646 Display.setDefaultBackend(backend)
649 return Display.getDefaultBackend()
652 return Display.setDefaultFrame(frame)
655 """Get the default frame for display"""
656 return Display.getDefaultFrame()
659 """Increment the default frame for display"""
660 return Display.incrDefaultFrame()
663 return Display.setDefaultMaskTransparency(maskPlaneTransparency)
666 """!Set the default mapping from mask plane names to colours
667 \param name name of mask plane, or a dict mapping names to colours
668 \param color Desired color, or None if name is a dict
670 If name is None, use the hard-coded default dictionary
673 return Display.setDefaultMaskPlaneColor(name, color)
675 def getDisplay(frame=None, backend=None, create=True, verbose=False, *args, **kwargs):
676 """!Return the Display indexed by frame, creating it if needs be
678 See Display.getDisplay
680 \param frame The desired frame (None => use defaultFrame (see setDefaultFrame))
681 \param backend create the specified frame using this backend (or the default if None) \
682 if it doesn't already exist. If backend == "", it's an error to specify a non-existent frame
683 \param create create the display if it doesn't already exist.
684 \param verbose Allow backend to be chatty
685 \param args arguments passed to Display constructor
686 \param kwargs keyword arguments passed to Display constructor
689 return Display.getDisplay(frame, backend, create, verbose, *args, **kwargs)
692 """!Delete and close all known display
694 return Display.delAllDisplays()
def getMaskTransparency
Return the current display's mask transparency.
def getDisplay
Return the Display indexed by frame, creating it if needs be.
def setMaskTransparency
Specify display's mask transparency (percent); or None to not set it when loading masks...
def interact
Enter an interactive loop, listening for key presses in display and firing callbacks.
def setMaskPlaneColor
Request that mask plane name be displayed as color.
def zoom
Zoom frame by specified amount, optionally panning also.
metadata import lsst afw display as afwDisplay except ImportError
def setDefaultMaskTransparency
def delAllDisplays
Delete and close all known display.
def mtv
Display an Image or Mask on a DISPLAY display.
def __enter__
Support for python's with statement.
def pan
Pan to (rowc, colc); see also zoom.
def verbose
The backend's verbosity.
def __init__
Create an object able to display images and overplot glyphs.
def getMaskPlaneColor
Return the colour associated with the specified mask plane name.
A class to handle events such as key presses in image display windows.
def setDefaultMaskTransparency
def dot
Draw a symbol onto the specified DISPLAY frame at (col,row) = (c,r) [0-based coordinates].
def _makeDisplayImpl
Return the DisplayImpl for the named backend.
boost::shared_ptr< Wcs > makeWcs(coord::Coord const &crval, geom::Point2D const &crpix, double CD11, double CD12, double CD21, double CD22)
Create a Wcs object from crval, crpix, CD, using CD elements (useful from python) ...
def scale
Set the range of the scaling from DN in the image to the image display.
def delAllDisplays
Delete and close all known display.
def show
Uniconify and Raise display.
def line
Draw a set of symbols or connect the points, a list of (col,row) If symbs is True, draw points at the specified points using the desired symbol, otherwise connect the dots.
def setCallback
Set the callback for key k to be func, returning the old callback.
def erase
Erase the specified DISPLAY frame.
static Log getLogger(Log const &logger)
def getDisplay
Return the Display indexed by frame, creating it if needs be.
def flush
Flush the buffers.
def __exit__
Support for python's with statement.
def getActiveCallbackKeys
Return all callback keys.
def noop_callback
Callback function: arguments key, x, y.
def maskColorGenerator
A generator for "standard" colours.
def setDefaultMaskPlaneColor
Set the default mapping from mask plane names to colours.
def setDefaultMaskPlaneColor
Set the default mapping from mask plane names to colours.