Source code for mosviz.widgets.plots
import os
from qtpy.QtCore import Signal
from qtpy.QtWidgets import QMainWindow
from matplotlib.patches import Rectangle
from glue.viewers.common.qt.toolbar import BasicToolbar
from glue.viewers.matplotlib.qt.widget import MplWidget
from glue.viewers.common.qt.tool import Tool
from glue.config import viewer_tool
from glue.utils import defer_draw
try:
from glue.viewers.matplotlib.mpl_axes import init_mpl
except ImportError: # glue < 0.14
from glue.viewers.common.viz_client import init_mpl
from glue.viewers.image.qt.standalone_image_viewer import StandaloneImageViewer
__all__ = ['Line1DWidget', 'DrawableImageWidget', 'MOSImageWidget']
ICON_PATH = os.path.abspath(
os.path.join(
os.path.abspath(__file__),
"..",
"..",
"data",
"resources",
"slit_icon.png"
)
)
@viewer_tool
class SlitButton(Tool):
"""
Image viewer tool to launch slit editor.
"""
icon = ICON_PATH
tool_id = 'mosviz:slit'
action_text = ''
tool_tip = 'Slit options'
status_tip = ''
shortcut = None
def __init__(self, viewer):
super(SlitButton, self).__init__(viewer)
self.function = viewer.launch_slit_ui
def activate(self):
self.function()
[docs]class Line1DWidget(QMainWindow):
window_closed = Signal()
_toolbar_cls = BasicToolbar
tools = ['mpl:home', 'mpl:save', 'mpl:pan', 'mpl:zoom']
def __init__(self, parent=None):
super(Line1DWidget, self).__init__(parent)
self.central_widget = MplWidget()
self.setCentralWidget(self.central_widget)
_, self._axes = init_mpl(figure=self.central_widget.canvas.fig)
self.initialize_toolbar()
self._artists = []
[docs] def initialize_toolbar(self):
from glue.config import viewer_tool
self.toolbar = self._toolbar_cls(self)
for tool_id in self.tools:
mode_cls = viewer_tool.members[tool_id]
mode = mode_cls(self)
self.toolbar.add_tool(mode)
self.addToolBar(self.toolbar)
@property
def axes(self):
return self._axes
def _clear_artists(self):
# Note: we can't use self._axes.cla() here since that removes events
# which will cause the locked axes to not work.
for artist in self._artists:
try:
artist.remove()
except ValueError: # some artists may already not be in plot
pass
for t in self.axes.texts:
t.remove()
[docs] def set_data(self, x, y, yerr=None):
self._clear_artists()
self.axes.set_axis_on()
# Plot data
if yerr is None:
self._artists = self._axes.plot(x, y, color='k')
else:
self._artists = [self._axes.errorbar(x, y, yerr=yerr, color='k')]
# Refresh canvas
self._redraw()
[docs] def no_data(self):
self._clear_artists()
self.axes.set_axis_off()
xbounds = self.axes.get_xlim()
if xbounds is None:
return
x = sum(xbounds) / 2.
ybounds = self.axes.get_ylim()
if ybounds is None:
return
y = sum(ybounds) / 2.
fontdict = {"fontsize": 30,
"color": "black",
"ha": "center",
"va": "center"}
self.axes.text(x, y, "No 1D Spectrum", fontdict=fontdict)
# Refresh canvas
self._redraw()
def _redraw(self):
self.central_widget.canvas.draw()
[docs] def set_status(self, message):
pass
[docs]class MOSImageWidget(StandaloneImageViewer):
def __init__(self, *args, **kwargs):
super(MOSImageWidget, self).__init__(*args, **kwargs)
[docs] def set_status(self, status):
pass
class Spectrum2DWidget(MOSImageWidget):
def __init__(self, *args, **kwargs):
super(MOSImageWidget, self).__init__(*args, **kwargs)
def _clear_image(self):
if self._im is not None:
self._im.remove()
self._im = None
@defer_draw
def set_image(self, image=None, wcs=None, **kwargs):
#self.axes.set_axis_on()
for c in self.axes.coords:
c.set_ticks_visible(True)
c.set_ticklabel_visible(True)
for t in self.axes.texts:
t.remove()
super(MOSImageWidget, self).set_image(image, wcs, **kwargs)
def no_data(self):
self._clear_image()
#self.axes.set_axis_off()
for c in self.axes.coords:
c.set_ticks_visible(False)
c.set_ticklabel_visible(False)
xbounds = self.axes.get_xlim()
if xbounds is None:
return
x = sum(xbounds) / 2.
ybounds = self.axes.get_ylim()
if ybounds is None:
return
y = sum(ybounds) / 2.
fontdict = {"fontsize": 30,
"color": "black",
"ha": "center",
"va": "center"}
self.axes.text(x, y, "No 2D Spectrum", fontdict=fontdict)
# Refresh canvas
self._redraw()
[docs]class DrawableImageWidget(MOSImageWidget):
tools = ['mpl:home', 'mpl:save', 'mpl:pan', 'mpl:zoom',
'image:contrast', 'image:colormap', 'mosviz:slit']
slit_controller = None
def __init__(self, *args, slit_controller=None, **kwargs):
super(DrawableImageWidget, self).__init__(*args, **kwargs)
self._slit_patch = None
self.slit_controller = slit_controller
[docs] def draw_rectangle(self, x=None, y=None, width=None, height=None):
if self._slit_patch is not None:
self._slit_patch.remove()
self._slit_patch = Rectangle((x - width / 2, y - height / 2),
width=width, height=height,
edgecolor='red', facecolor='none')
self._axes.add_patch(self._slit_patch)
[docs] def draw_slit(self):
"""
Draw the slit patch stored in the slit controller.
"""
if self.slit_controller.has_slits:
self.slit_controller.draw_slits(self._axes)
[docs] def set_limits(self, x_min=None, x_max=None, y_min=None, y_max=None):
"""Manually set the limits of the axes."""
self._axes.set_xlim(x_min, x_max)
self._axes.set_ylim(y_min, y_max)
[docs] def set_slit_limits(self):
"""Set y limits of plot according to slit length"""
if self.slit_controller.has_slits:
# We want the image dimensions to be dy x dy
limits = self.slit_controller.get_cutout_limit()
if limits is not None:
self.set_limits(*limits)
[docs] def reset_limits(self):
"""Auto set the limits of the axes."""
self._axes.relim()
[docs] def launch_slit_ui(self):
self.slit_controller.launch_slit_ui()