LSSTApplications  16.0-10-g0ee56ad+5,16.0-11-ga33d1f2+5,16.0-12-g3ef5c14+3,16.0-12-g71e5ef5+18,16.0-12-gbdf3636+3,16.0-13-g118c103+3,16.0-13-g8f68b0a+3,16.0-15-gbf5c1cb+4,16.0-16-gfd17674+3,16.0-17-g7c01f5c+3,16.0-18-g0a50484+1,16.0-20-ga20f992+8,16.0-21-g0e05fd4+6,16.0-21-g15e2d33+4,16.0-22-g62d8060+4,16.0-22-g847a80f+4,16.0-25-gf00d9b8+1,16.0-28-g3990c221+4,16.0-3-gf928089+3,16.0-32-g88a4f23+5,16.0-34-gd7987ad+3,16.0-37-gc7333cb+2,16.0-4-g10fc685+2,16.0-4-g18f3627+26,16.0-4-g5f3a788+26,16.0-5-gaf5c3d7+4,16.0-5-gcc1f4bb+1,16.0-6-g3b92700+4,16.0-6-g4412fcd+3,16.0-6-g7235603+4,16.0-69-g2562ce1b+2,16.0-8-g14ebd58+4,16.0-8-g2df868b+1,16.0-8-g4cec79c+6,16.0-8-gadf6c7a+1,16.0-8-gfc7ad86,16.0-82-g59ec2a54a+1,16.0-9-g5400cdc+2,16.0-9-ge6233d7+5,master-g2880f2d8cf+3,v17.0.rc1
LSSTDataManagementBasePackage
matplotlib.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008, 2009, 2010, 2015 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 
23 #
24 # \file
25 # \brief Definitions to talk to matplotlib from python using the "afwDisplay" interface
26 
27 from __future__ import absolute_import, division, print_function
28 
29 import math
30 import sys
31 import unicodedata
32 import warnings
33 
34 import matplotlib.pyplot as pyplot
35 import matplotlib.cbook
36 import matplotlib.colors as mpColors
37 from matplotlib.blocking_input import BlockingInput
38 
39 import numpy as np
40 import numpy.ma as ma
41 
42 import lsst.afw.display as afwDisplay
43 import lsst.afw.math as afwMath
44 import lsst.afw.display.rgb as afwRgb
45 import lsst.afw.display.interface as interface
46 import lsst.afw.display.virtualDevice as virtualDevice
47 import lsst.afw.display.ds9Regions as ds9Regions
48 import lsst.afw.image as afwImage
49 
50 import lsst.afw.geom as afwGeom
51 
52 # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
53 #
54 # Set the list of backends which support _getEvent and thus interact()
55 #
56 try:
57  interactiveBackends
58 except NameError:
59  # List of backends that support `interact`
60  interactiveBackends = [
61  "Qt4Agg",
62  "Qt5Agg",
63  ]
64 
65 try:
66  matplotlibCtypes
67 except NameError:
68  matplotlibCtypes = {
69  afwDisplay.GREEN : "#00FF00", # noqa: ignore=E203
70  }
71 
72  def mapCtype(ctype):
73  """Map the ctype to a potentially different ctype
74 
75  Specifically, if matplotlibCtypes[ctype] exists, use it instead
76 
77  This is used e.g. to map "green" to a brighter shade
78  """
79  return matplotlibCtypes[ctype] if ctype in matplotlibCtypes else ctype
80 
81 
82 class DisplayImpl(virtualDevice.DisplayImpl):
83  """Provide a matplotlib backend for afwDisplay
84 
85  Recommended backends in notebooks are:
86  %matplotlib notebook
87  or
88  %matplotlib ipympl
89  or
90  %matplotlib qt
91  %gui qt
92  or
93  %matplotlib inline
94  or
95  %matplotlib osx
96 
97  Apparently only qt supports Display.interact(); the list of interactive backends
98  is given by lsst.display.matplotlib.interactiveBackends
99  """
100  def __init__(self, display, verbose=False,
101  interpretMaskBits=True, mtvOrigin=afwImage.PARENT, fastMaskDisplay=True,
102  reopenPlot=False, *args, **kwargs):
103  """
104  Initialise a matplotlib display
105 
106  @param fastMaskDisplay If True, only show the first bitplane that's set in each pixel
107  (e.g. if (SATURATED & DETECTED), ignore DETECTED)
108  Not really what we want, but a bit faster
109  @param interpretMaskBits Interpret the mask value under the cursor
110  @param mtvOrigin Display pixel coordinates with LOCAL origin
111  (bottom left == 0,0 not XY0)
112  @param reopenPlot If true, close the plot before opening it.
113  (useful with e.g. %ipympl)
114  """
115  virtualDevice.DisplayImpl.__init__(self, display, verbose)
116 
117  if reopenPlot:
118  pyplot.close(display.frame)
119  self._figure = pyplot.figure(display.frame)
120  self._display = display
121  self._maskTransparency = {None : 0.7} # noqa: ignore=E203
122  self._interpretMaskBits = interpretMaskBits # interpret mask bits in mtv
123  self._fastMaskDisplay = fastMaskDisplay
124  self._mtvOrigin = mtvOrigin
125  self._mappable = None
126  self._image_colormap = pyplot.cm.gray
127  #
128  self.__alpha = unicodedata.lookup("GREEK SMALL LETTER alpha") # used in cursor display string
129  self.__delta = unicodedata.lookup("GREEK SMALL LETTER delta") # used in cursor display string
130  #
131  # Support self._scale()
132  #
133  self._scaleArgs = dict()
134  self._normalize = None
135  #
136  # Support self._erase(), reporting pixel/mask values, and zscale/minmax; set in mtv
137  #
138  self._i_setImage(None)
139  #
140  # Ignore warnings due to BlockingKeyInput
141  #
142  if not verbose:
143  warnings.filterwarnings("ignore", category=matplotlib.cbook.mplDeprecation)
144 
145  def _close(self):
146  """!Close the display, cleaning up any allocated resources"""
147  self._image = None
148  self._mask = None
149  self._wcs = None
150  self._figure.gca().format_coord = None # keeps a copy of _wcs
151 
152  def _show(self):
153  """Put the plot at the top of the window stacking order"""
154 
155  try:
156  self._figure.canvas._tkcanvas._root().lift() # tk
157  except AttributeError:
158  pass
159 
160  try:
161  self._figure.canvas.manager.window.raise_() # os/x
162  except AttributeError:
163  pass
164 
165  try:
166  self._figure.canvas.raise_() # qt[45]
167  except AttributeError:
168  pass
169 
170  #
171  # Extensions to the API
172  #
173  def savefig(self, *args, **kwargs):
174  """Defer to figure.savefig()"""
175  self._figure.savefig(*args, **kwargs)
176 
177  def show_colorbar(self, show=True):
178  """Show (or hide) the colour bar"""
179  if show:
180  if self._mappable:
181  self._figure.colorbar(self._mappable)
182 
183  def wait(self, prompt="[c(ontinue) p(db)] :", allowPdb=True):
184  """Wait for keyboard input
185 
186  @param prompt `str`
187  The prompt string.
188  @param allowPdb `bool`
189  If true, entering a 'p' or 'pdb' puts you into pdb
190 
191  Returns the string you entered
192 
193  Useful when plotting from a programme that exits such as a processCcd
194  Any key except 'p' continues; 'p' puts you into pdb (unless allowPdb is False)
195  """
196  while True:
197  s = input(prompt)
198  if allowPdb and s in ("p", "pdb"):
199  import pdb
200  pdb.set_trace()
201  continue
202 
203  return s
204  #
205  # Defined API
206  #
207 
208  def _setMaskTransparency(self, transparency, maskplane):
209  """Specify mask transparency (percent)"""
210 
211  self._maskTransparency[maskplane] = 0.01*transparency
212 
213  def _getMaskTransparency(self, maskplane=None):
214  """Return the current mask transparency"""
215  return self._maskTransparency[maskplane if maskplane in self._maskTransparency else None]
216 
217  def _mtv(self, image, mask=None, wcs=None, title=""):
218  """Display an Image and/or Mask on a matplotlib display
219  """
220  title = str(title) if title else ""
221 
222  #
223  # Save a reference to the image as it makes erase() easy and permits printing cursor values
224  # and minmax/zscale stretches. We also save XY0
225  #
226  self._i_setImage(image, mask, wcs)
227 
228  # We need to know the pixel values to support e.g. 'zscale' and 'minmax', so do the scaling now
229  if self._scaleArgs.get('algorithm'): # someone called self.scale()
230  self._i_scale(self._scaleArgs['algorithm'], self._scaleArgs['minval'], self._scaleArgs['maxval'],
231  self._scaleArgs['unit'], *self._scaleArgs['args'], **self._scaleArgs['kwargs'])
232 
233  self._figure.clf() # calling erase() calls _mtv
234 
235  self._i_mtv(image, wcs, title, False)
236  ax = self._figure.gca()
237 
238  if mask:
239  self._i_mtv(mask, wcs, title, True)
240 
241  if title:
242  ax.set_title(title)
243 
244  self._title = title
245 
246  def format_coord(x, y, wcs=self._wcs, x0=self._xy0[0], y0=self._xy0[1],
247  origin=afwImage.PARENT, bbox=self._image.getBBox(afwImage.PARENT)):
248 
249  fmt = '(%1.2f, %1.2f)'
250  if self._mtvOrigin == afwImage.PARENT:
251  msg = fmt % (x, y)
252  else:
253  msg = (fmt + "L") % (x - x0, y - y0)
254 
255  col = int(x + 0.5)
256  row = int(y + 0.5)
257  if bbox.contains(afwGeom.PointI(col, row)):
258  if wcs is not None:
259  ra, dec = wcs.pixelToSky(x, y)
260  msg += r" (%s, %s): (%9.4f, %9.4f)" % (self.__alpha, self.__delta, ra, dec)
261 
262  msg += ' %1.3f' % (self._image[col, row])
263  if self._mask:
264  val = self._mask[col, row]
265  if self._interpretMaskBits:
266  msg += " [%s]" % self._mask.interpret(val)
267  else:
268  msg += " 0x%x" % val
269 
270  return msg
271 
272  ax.format_coord = format_coord
273  # Stop images from reporting their value as we've already printed it nicely
274  from matplotlib.image import AxesImage
275  for a in ax.mouseover_set:
276  if isinstance(a, AxesImage):
277  a.get_cursor_data = lambda ev: None # disabled
278 
279  self._figure.tight_layout()
280  self._figure.canvas.draw_idle()
281 
282  def _i_mtv(self, data, wcs, title, isMask):
283  """Internal routine to display an Image or Mask on a DS9 display"""
284 
285  title = str(title) if title else ""
286  dataArr = data.getArray()
287 
288  if isMask:
289  maskPlanes = data.getMaskPlaneDict()
290  nMaskPlanes = max(maskPlanes.values()) + 1
291 
292  planes = {} # build inverse dictionary
293  for key in maskPlanes:
294  planes[maskPlanes[key]] = key
295 
296  planeList = range(nMaskPlanes)
297 
298  maskArr = np.zeros_like(dataArr, dtype=np.int32)
299 
300  colorNames = ['black']
301  colorGenerator = self.display.maskColorGenerator(omitBW=True)
302  for p in planeList:
303  color = self.display.getMaskPlaneColor(planes[p]) if p in planes else None
304 
305  if not color: # none was specified
306  color = next(colorGenerator)
307  elif color.lower() == afwDisplay.IGNORE:
308  color = 'black' # we'll set alpha = 0 anyway
309 
310  colorNames.append(color)
311  #
312  # Convert those colours to RGBA so we can have per-mask-plane transparency
313  # and build a colour map
314  #
315  # Pixels equal to 0 don't get set (as no bits are set), so leave them transparent
316  # and start our colours at [1] -- hence "i + 1" below
317  #
318  colors = mpColors.to_rgba_array(colorNames)
319  alphaChannel = 3 # the alpha channel; the A in RGBA
320  colors[0][alphaChannel] = 0.0 # it's black anyway
321  for i, p in enumerate(planeList):
322  if colorNames[i + 1] == 'black':
323  alpha = 0.0
324  else:
325  alpha = 1 - self._getMaskTransparency(planes[p] if p in planes else None)
326 
327  colors[i + 1][alphaChannel] = alpha
328 
329  cmap = mpColors.ListedColormap(colors)
330  norm = mpColors.NoNorm()
331  else:
332  cmap = self._image_colormap
333  norm = self._normalize
334 
335  ax = self._figure.gca()
336  bbox = data.getBBox()
337  extent = (bbox.getBeginX() - 0.5, bbox.getEndX() - 0.5,
338  bbox.getBeginY() - 0.5, bbox.getEndY() - 0.5)
339 
340  with pyplot.rc_context(dict(interactive=False)):
341  if isMask:
342  for i, p in reversed(list(enumerate(planeList))):
343  if colors[i + 1][alphaChannel] == 0: # colors[0] is reserved
344  continue
345 
346  bitIsSet = (dataArr & (1 << p)) != 0
347  if bitIsSet.sum() == 0:
348  continue
349 
350  maskArr[bitIsSet] = i + 1 # + 1 as we set colorNames[0] to black
351 
352  if not self._fastMaskDisplay: # we draw each bitplane separately
353  ax.imshow(maskArr, origin='lower', interpolation='nearest',
354  extent=extent, cmap=cmap, norm=norm)
355  maskArr[:] = 0
356 
357  if self._fastMaskDisplay: # we only draw the lowest bitplane
358  ax.imshow(maskArr, origin='lower', interpolation='nearest',
359  extent=extent, cmap=cmap, norm=norm)
360  else:
361  mappable = ax.imshow(dataArr, origin='lower', interpolation='nearest',
362  extent=extent, cmap=cmap, norm=norm)
363  self._mappable = mappable
364 
365  self._figure.canvas.draw_idle()
366 
367  def _i_setImage(self, image, mask=None, wcs=None):
368  """Save the current image, mask, wcs, and XY0"""
369  self._image = image
370  self._mask = mask
371  self._wcs = wcs
372  self._xy0 = self._image.getXY0() if self._image else (0, 0)
373 
374  self._zoomfac = 1.0
375  if self._image is None:
376  self._width, self._height = 0, 0
377  else:
378  self._width, self._height = self._image.getDimensions()
379 
380  self._xcen = 0.5*self._width
381  self._ycen = 0.5*self._height
382 
383  def _setImageColormap(self, cmap):
384  """Set the colormap used for the image
385 
386  cmap should be either the name of an attribute of pyplot.cm or an mpColors.Colormap
387  (e.g. "gray" or pyplot.cm.gray)
388 
389  """
390  if not isinstance(cmap, mpColors.Colormap):
391  cmap = getattr(pyplot.cm, cmap)
392 
393  self._image_colormap = cmap
394 
395  #
396  # Graphics commands
397  #
398 
399  def _buffer(self, enable=True):
400  if enable:
401  pyplot.ioff()
402  else:
403  pyplot.ion()
404  self._figure.show()
405 
406  def _flush(self):
407  pass
408 
409  def _erase(self):
410  """Erase the display"""
411  #
412  # Rather than erase only the glyphs we'll redraw the image.
413  #
414  # This isn't a great solution.
415  #
416  self._figure.clf()
417 
418  if self._image:
419  zoomfac = self._zoomfac
420  xcen = self._xcen
421  ycen = self._ycen
422 
423  self._mtv(self._image, mask=self._mask, wcs=self._wcs, title=self._title)
424 
425  self._xcen = xcen
426  self._ycen = ycen
427  self._zoom(zoomfac)
428 
429  self._figure.canvas.draw_idle()
430 
431  def _dot(self, symb, c, r, size, ctype,
432  fontFamily="helvetica", textAngle=None):
433  """Draw a symbol at (col,row) = (c,r) [0-based coordinates]
434  Possible values are:
435  + Draw a +
436  x Draw an x
437  * Draw a *
438  o Draw a circle
439  @:Mxx,Mxy,Myy Draw an ellipse with moments (Mxx, Mxy, Myy) (argument size is ignored)
440  An afwGeom.ellipses.Axes Draw the ellipse (argument size is ignored)
441  Any other value is interpreted as a string to be drawn. Strings obey the fontFamily (which may be extended
442  with other characteristics, e.g. "times bold italic". Text will be drawn rotated by textAngle
443  (textAngle is ignored otherwise).
444  """
445  if not ctype:
446  ctype = afwDisplay.GREEN
447 
448  axis = self._figure.gca()
449  x0, y0 = self._xy0
450 
451  if isinstance(symb, afwGeom.ellipses.Axes):
452  from matplotlib.patches import Ellipse
453 
454  # Following matplotlib.patches.Ellipse documentation 'width' and 'height' are diameters while
455  # 'angle' is rotation in degrees (anti-clockwise)
456  axis.add_artist(Ellipse((c + x0, r + y0), height=2*symb.getA(), width=2*symb.getB(),
457  angle=90.0 + math.degrees(symb.getTheta()),
458  edgecolor=mapCtype(ctype), facecolor='none'))
459  elif symb == 'o':
460  from matplotlib.patches import CirclePolygon as Circle
461 
462  axis.add_artist(Circle((c + x0, r + y0), radius=size, color=mapCtype(ctype), fill=False))
463  else:
464  from matplotlib.lines import Line2D
465 
466  for ds9Cmd in ds9Regions.dot(symb, c + x0, r + y0, size, fontFamily="helvetica", textAngle=None):
467  tmp = ds9Cmd.split('#')
468  cmd = tmp.pop(0).split()
469  comment = tmp.pop(0) if tmp else "" # noqa: ignore=F581
470 
471  cmd, args = cmd[0], cmd[1:]
472 
473  if cmd == "line":
474  args = np.array(args).astype(float) - 1.0
475 
476  x = np.empty(len(args)//2)
477  y = np.empty_like(x)
478  i = np.arange(len(args), dtype=int)
479  x = args[i%2 == 0]
480  y = args[i%2 == 1]
481 
482  axis.add_line(Line2D(x, y, color=mapCtype(ctype)))
483  elif cmd == "text":
484  x, y = np.array(args[0:2]).astype(float) - 1.0
485  axis.text(x, y, symb, color=mapCtype(ctype),
486  horizontalalignment='center', verticalalignment='center')
487  else:
488  raise RuntimeError(ds9Cmd)
489 
490  def _drawLines(self, points, ctype):
491  """Connect the points, a list of (col,row)
492  Ctype is the name of a colour (e.g. 'red')"""
493 
494  from matplotlib.lines import Line2D
495 
496  if not ctype:
497  ctype = afwDisplay.GREEN
498 
499  points = np.array(points)
500  x = points[:, 0] + self._xy0[0]
501  y = points[:, 1] + self._xy0[1]
502 
503  self._figure.gca().add_line(Line2D(x, y, color=mapCtype(ctype)))
504 
505  def _scale(self, algorithm, minval, maxval, unit, *args, **kwargs):
506  """
507  Set gray scale
508  """
509  self._scaleArgs['algorithm'] = algorithm
510  self._scaleArgs['minval'] = minval
511  self._scaleArgs['maxval'] = maxval
512  self._scaleArgs['unit'] = unit
513  self._scaleArgs['args'] = args
514  self._scaleArgs['kwargs'] = kwargs
515 
516  try:
517  self._i_scale(algorithm, minval, maxval, unit, *args, **kwargs)
518  except (AttributeError, RuntimeError):
519  # Unable to access self._image; we'll try again when we run mtv
520  pass
521 
522  def _i_scale(self, algorithm, minval, maxval, unit, *args, **kwargs):
523  if minval == "minmax":
524  if self._image is None:
525  raise RuntimeError("You may only use minmax if an image is loaded into the display")
526 
527  stats = afwMath.makeStatistics(self._image, afwMath.MIN | afwMath.MAX)
528  minval = stats.getValue(afwMath.MIN)
529  maxval = stats.getValue(afwMath.MAX)
530 
531  if algorithm is None:
532  self._normalize = None
533  elif algorithm == "asinh":
534  if minval == "zscale":
535  if self._image is None:
536  raise RuntimeError("You may only use zscale if an image is loaded into the display")
537 
538  self._normalize = AsinhZScaleNormalize(image=self._image, Q=kwargs.get("Q", 8.0))
539  else:
540  self._normalize = AsinhNormalize(minimum=minval,
541  dataRange=maxval - minval, Q=kwargs.get("Q", 8.0))
542  elif algorithm == "linear":
543  if minval == "zscale":
544  if self._image is None:
545  raise RuntimeError("You may only use zscale if an image is loaded into the display")
546 
547  self._normalize = ZScaleNormalize(image=self._image,
548  nSamples=kwargs.get("nSamples", 1000),
549  contrast=kwargs.get("contrast", 0.25))
550  else:
551  self._normalize = LinearNormalize(minimum=minval, maximum=maxval)
552  else:
553  raise RuntimeError("Unsupported stretch algorithm \"%s\"" % algorithm)
554  #
555  # Zoom and Pan
556  #
557 
558  def _zoom(self, zoomfac):
559  """Zoom by specified amount"""
560 
561  self._zoomfac = zoomfac
562 
563  x0, y0 = self._xy0
564 
565  size = min(self._width, self._height)
566  if size < self._zoomfac: # avoid min == max
567  size = self._zoomfac
568  xmin, xmax = self._xcen + x0 + size/self._zoomfac*np.array([-1, 1])
569  ymin, ymax = self._ycen + y0 + size/self._zoomfac*np.array([-1, 1])
570 
571  ax = self._figure.gca()
572 
573  tb = self._figure.canvas.toolbar
574  if tb is not None: # It's None for e.g. %matplotlib inline in jupyter
575  tb.push_current() # save the current zoom in the view stack
576 
577  ax.set_xlim(xmin, xmax)
578  ax.set_ylim(ymin, ymax)
579  ax.set_aspect('equal', 'datalim')
580 
581  self._figure.canvas.draw_idle()
582 
583  def _pan(self, colc, rowc):
584  """Pan to (colc, rowc)"""
585 
586  self._xcen = colc
587  self._ycen = rowc
588 
589  self._zoom(self._zoomfac)
590 
591  def _getEvent(self, timeout=-1):
592  """Listen for a key press, returning (key, x, y)"""
593 
594  mpBackend = matplotlib.get_backend()
595  if mpBackend not in interactiveBackends:
596  print("The %s matplotlib backend doesn't support display._getEvent()" %
597  (matplotlib.get_backend(),), file=sys.stderr)
598  return interface.Event('q')
599 
600  blocking_input = BlockingKeyInput(self._figure)
601  return blocking_input(timeout=timeout)
602 
603 # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
604 
605 
606 class BlockingKeyInput(BlockingInput):
607  """
608  Callable class to retrieve a single keyboard click
609  """
610  def __init__(self, fig):
611  r"""Create a BlockingKeyInput
612 
613  \param fig The figure to monitor for keyboard events
614  """
615  BlockingInput.__init__(self, fig=fig, eventslist=('key_press_event',))
616 
617  def post_event(self):
618  """
619  Return the event containing the key and (x, y)
620  """
621  try:
622  event = self.events[-1]
623  except IndexError:
624  # details of the event to pass back to the display
625  self.ev = None
626  else:
627  self.ev = interface.Event(event.key, event.xdata, event.ydata)
628 
629  def __call__(self, timeout=-1):
630  """
631  Blocking call to retrieve a single key click
632  Returns key or None if timeout
633  """
634  self.ev = None
635 
636  BlockingInput.__call__(self, n=1, timeout=timeout)
637 
638  return self.ev
639 
640 # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
641 
642 
643 class Normalize(mpColors.Normalize):
644  """Class to support stretches for mtv()"""
645 
646  def __call__(self, value, clip=None):
647  """
648  Return a MaskedArray with value mapped to [0, 255]
649 
650  @param value Input pixel value or array to be mapped
651  """
652  if isinstance(value, np.ndarray):
653  data = value
654  else:
655  data = value.data
656 
657  data = data - self.mapping.minimum[0]
658  return ma.array(data*self.mapping.mapIntensityToUint8(data)/255.0)
659 
660 
662  """Provide an asinh stretch for mtv()"""
663  def __init__(self, minimum=0, dataRange=1, Q=8):
664  """Initialise an object able to carry out an asinh mapping
665 
666  @param minimum Minimum pixel value (default: 0)
667  @param dataRange Range of values for stretch if Q=0; roughly the linear part (default: 1)
668  @param Q Softening parameter (default: 8)
669 
670  See Lupton et al., PASP 116, 133
671  """
672  Normalize.__init__(self)
673 
674  # The object used to perform the desired mapping
675  self.mapping = afwRgb.AsinhMapping(minimum, dataRange, Q)
676 
677 
679  """Provide an asinh stretch using zscale to set limits for mtv()"""
680  def __init__(self, image=None, Q=8):
681  """Initialise an object able to carry out an asinh mapping
682 
683  @param image image to use estimate minimum and dataRange using zscale (see AsinhNormalize)
684  @param Q Softening parameter (default: 8)
685 
686  See Lupton et al., PASP 116, 133
687  """
688  Normalize.__init__(self)
689 
690  # The object used to perform the desired mapping
691  self.mapping = afwRgb.AsinhZScaleMapping(image, Q)
692 
693 
695  """Provide a zscale stretch for mtv()"""
696  def __init__(self, image=None, nSamples=1000, contrast=0.25):
697  """Initialise an object able to carry out a zscale mapping
698 
699  @param image to be used to estimate the stretch
700  @param nSamples Number of data points to use (default: 1000)
701  @param contrast Control the range of pixels to display around the median (default: 0.25)
702  """
703 
704  Normalize.__init__(self)
705 
706  # The object used to perform the desired mapping
707  self.mapping = afwRgb.ZScaleMapping(image, nSamples, contrast)
708 
709 
711  """Provide a linear stretch for mtv()"""
712  def __init__(self, minimum=0, maximum=1):
713  """Initialise an object able to carry out a linear mapping
714 
715  @param minimum Minimum value to display
716  @param maximum Maximum value to display
717  """
718 
719  Normalize.__init__(self)
720 
721  # The object used to perform the desired mapping
722  self.mapping = afwRgb.LinearMapping(minimum, maximum)
def __init__(self, minimum=0, maximum=1)
Definition: matplotlib.py:712
def _i_mtv(self, data, wcs, title, isMask)
Definition: matplotlib.py:282
def __init__(self, display, verbose=False, interpretMaskBits=True, mtvOrigin=afwImage.PARENT, fastMaskDisplay=True, reopenPlot=False, args, kwargs)
Definition: matplotlib.py:102
def _i_scale(self, algorithm, minval, maxval, unit, args, kwargs)
Definition: matplotlib.py:522
int min
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
The makeStatistics() overload to handle lsst::afw::math::MaskedVector<>
Definition: Statistics.h:520
def show(frame=None)
Definition: ds9.py:89
int max
def getMaskPlaneColor(name, frame=None)
Definition: ds9.py:77
def _i_setImage(self, image, mask=None, wcs=None)
Definition: matplotlib.py:367
def wait(self, prompt="[c(ontinue) p(db)] :", allowPdb=True)
Definition: matplotlib.py:183
def __init__(self, image=None, nSamples=1000, contrast=0.25)
Definition: matplotlib.py:696
def _getMaskTransparency(self, maskplane=None)
Definition: matplotlib.py:213
def __init__(self, minimum=0, dataRange=1, Q=8)
Definition: matplotlib.py:663
def __call__(self, value, clip=None)
Definition: matplotlib.py:646
daf::base::PropertyList * list
Definition: fits.cc:833