97 def __init__(self, display, dims=None, use_opencv=False, verbose=False, *args, **kwargs):
98 virtualDevice.DisplayImpl.__init__(self, display, verbose)
100 width, height = 1024, 768
104 self.
logger = get_logger(
"ginga", log_stderr=
True, level=40)
107 self.
_viewer = astrowidgets.ImageWidget(image_width=width, image_height=height,
108 use_opencv=use_opencv, logger=self.
logger)
118 self.
_canvas.enable_draw(
False)
140 def show_pan_mark(self, show=True, color='red'):
141 """Show (or hide) the pan mark.
145 show : `bool`, optional
146 Should the pan marker be shown?
147 color : `str`, optional
148 What color should the pan mark be?
150 self._gingaViewer.show_pan_mark(show, color)
152 def _setMaskTransparency(self, transparency, maskplane=None):
153 """Specify mask transparency (percent); or None to not set it when loading masks.
157 transparency : `float`
158 Transparency of the masks in percent (0-100).
159 maskplane : `str`, optional
160 Unsupported option to only change the transparency of
163 if maskplane is not None:
164 print("display_astrowidgets is not yet able to set transparency for individual maskplanes" % maskplane, # noqa E501
168 self._maskTransparency = 0.01*transparency
174 def _mtv(self, image, mask=None, wcs=None, title=""):
175 """Display an Image and/or Mask on a ginga display
179 image : `lsst.afw.image.Image` or `lsst.afw.image.Exposure`
181 mask : `lsst.afw.image.Mask`, optional
182 Mask to use, if the input does not contain one.
183 wcs : `ginga.util.wcsmod.wcs_astropy`
184 WCS to use, if the input does not contain one.
185 title : `str`, optional
186 Unsupported display title.
189 self._canvas.delete_all_objects()
192 Aimage = AstroImage(inherit_primary_header=True)
193 Aimage.set_data(image.getArray())
195 self._gingaViewer.set_image(Aimage)
199 _wcs = AstropyWCS(self.logger)
200 Aimage.lsst_wcs = WcsAdaptorForGinga(wcs)
201 _wcs.pixtoradec = Aimage.lsst_wcs.pixtoradec
202 _wcs.pixtosystem = Aimage.lsst_wcs.pixtosystem
203 _wcs.radectopix = Aimage.lsst_wcs.radectopix
206 Aimage.wcs.wcs = Aimage.lsst_wcs
209 maskColorFromName = {'BAD': 'red',
215 'DETECTED_NEGATIVE': 'cyan',
221 for plane, bit in mask.getMaskPlaneDict().items():
222 color = maskColorFromName.get(plane, None)
224 maskDict[1 << bit] = color
225 # This value of 0.9 is pretty thick for the alpha.
226 self.overlay_mask(mask, maskDict,
227 self._maskTransparency)
228 self._buffer(enable=False)
231 def overlay_mask(self, maskImage, maskDict, maskAlpha):
232 """Draw mask onto the image display.
236 maskImage : `lsst.afw.image.Mask`
238 maskDict : `dict` [`str`, `str`]
239 Dictionary of mask plane names to colors.
241 Transparency to display the mask.
244 from ginga.RGBImage import RGBImage
245 from ginga import colors
247 maskArray = maskImage.getArray()
248 height, width = maskArray.shape
249 maskRGBA = np.zeros((height, width, 4), dtype=np.uint8)
250 nSet = np.zeros_like(maskArray, dtype=np.uint8)
252 for maskValue, maskColor in maskDict.items():
253 r, g, b = colors.lookup_color(maskColor)
254 isSet = (maskArray & maskValue) != 0
255 if (isSet == 0).all():
258 maskRGBA[:, :, 0][isSet] = 255 * r
259 maskRGBA[:, :, 1][isSet] = 255 * g
260 maskRGBA[:, :, 2][isSet] = 255 * b
264 maskRGBA[:, :, 3][nSet == 0] = 0
265 maskRGBA[:, :, 3][nSet != 0] = 255 * maskAlpha
269 maskRGBA[:, :, C] //= nSet
271 rgb_img = RGBImage(data_np=maskRGBA)
272 Image = self._viewer.canvas.get_draw_class('image')
273 maskImageRGBA = Image(0, 0, rgb_img)
275 if "mask_overlay" in self._gingaViewer.canvas.get_tags():
276 self._gingaViewer.canvas.delete_object_by_tag("mask_overlay")
277 self._gingaViewer.canvas.add(maskImageRGBA, tag="mask_overlay")
289 def _dot(self, symb, c, r, size, ctype, fontFamily="helvetica", textAngle=None, label='_dot'):
290 """Draw a symbol at (col,row) = (c,r) [0-based coordinates].
295 Symbol to draw. Should be one of '+', 'x', '*', 'o', '.'.
297 Image column for dot center (0-based coordinates).
299 Image row for dot center (0-based coordinate).
302 fontFamily : `str`, optional
303 Font to use for text symbols.
304 textAngle : `float`, optional
306 label : `str`, optional
307 Label to store this dot in the internal list.
309 dataTable = Table([{'x': c, 'y': r}])
311 self._viewer.marker = {'type': self.markerDict[symb], 'color': ctype, 'radius': size}
312 self._viewer.add_markers(dataTable, marker_name=label)
315 Line = self._canvas.get_draw_class('line')
316 Text = self._canvas.get_draw_class('text')
318 for ds9Cmd in ds9Regions.dot(symb, c, r, size, fontFamily="helvetica", textAngle=None):
319 tmp = ds9Cmd.split('#')
320 cmd = tmp.pop(0).split()
321 comment = tmp.pop(0) if tmp else ""
323 cmd, args = cmd[0], cmd[1:]
325 self._gingaViewer.canvas.add(Line(*[float(p) - 1 for p in args], color=ctype),
328 x, y = [float(p) - 1 for p in args[0:2]]
329 self._gingaViewer.canvas.add(Text(x, y, symb, color=ctype), redraw=self._redraw)
331 raise RuntimeError(ds9Cmd)
335 def _drawLines(self, points, ctype):
336 """Connect the points, a list of (col,row).
340 points : `list` [`tuple` [`int`, `int`]]
341 Points to connect with lines.
345 Line = self._gingaViewer.canvas.get_draw_class('line')
348 self._gingaViewer.canvas.add(Line(p0[0], p0[1], p[0], p[1], color=ctype), redraw=self._redraw)
351 def beginMarking(self, symb='+', ctype='cyan', size=10, label='interactive'):
352 """Begin interactive mark adding.
356 symb : `str`, optional
357 Symbol to use. Should be one of '+', 'x', '*', 'o', '.'.
358 ctype : `str`, optional
360 size : `float`, optional
363 Label to store this marker in the internal list.
365 self._viewer.start_marking(marker_name=label,
366 marker={'type': self.markerDict[symb], 'color': ctype, 'radius': size})
372 def getMarkers(self, label='interactive'):
373 """Get list of markers.
377 label : `str`, optional
378 Marker label to return.
382 table : `astropy.table.Table`
383 Table of markers with the given label.
385 return self._viewer.get_markers(marker_name=label)
387 def clearMarkers(self, label=None):
392 label : `str`, optional
393 Marker label to clear. If None, all markers are cleared.
396 self._viewer.remove_markers(label)
398 self._viewer.reset_markers()
400 def linkMarkers(self, ctype='brown', label='interactive'):
401 """Connect markers with lines.
405 ctype : `str`, optional
406 Color to draw the lines.
407 label : `str`, optional
408 Marker label to connect. Lines are drawn in the order
411 Line = self._gingaViewer.canvas.get_draw_class('line')
412 table = self._viewer.get_markers(marker_name=label)
415 for rowCount, (x, y) in enumerate(table.iterrows('x', 'y')):
417 self._gingaViewer.canvas.add(Line(x0, y0, x, y, color=ctype), redraw=self._redraw)
425 def _scale(self, algorithm, min, max, unit, *args, **kwargs):
426 """Set greyscale values.
431 Image scaling algorithm to use.
432 min : `float` or `str`
433 Minimum value to set to black. If a string, should be one of 'zscale' or 'minmax'.
435 Maximum value to set to white.
437 Scaling units. This is ignored.
439 self._gingaViewer.set_color_map('gray')
440 self._gingaViewer.set_color_algorithm(algorithm)
443 self._gingaViewer.set_autocut_params('zscale', contrast=0.25)
444 self._gingaViewer.auto_levels()
445 elif min == "minmax":
446 self._gingaViewer.set_autocut_params('minmax')
447 self._gingaViewer.auto_levels()
450 print("ginga: ignoring scale unit %s" % unit, file=sys.stderr)
452 self._gingaViewer.cut_levels(min, max)
455 """Show the requested display.
457 In this case, embed it in the notebook (equivalent to
458 Display.get_viewer().show(); see also
459 Display.get_viewer().embed() N.b. These command *must* be the
460 last entry in their cell
462 return self._gingaViewer.show()
477 def _pan(self, colc, rowc):
478 """Pan to (colc, rowc)
483 Column to center in viewer (0-based coordinate).
485 Row to center in viewer (0-based coordinate).
487 self._gingaViewer.set_pan(colc, rowc)