Source code for specviz.core.plots

"""
Spectrum Layer Plotting
"""
from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

from qtpy.QtGui import *

from astropy.units import spectral_density, spectral
import pyqtgraph as pg
import logging
import numpy as np

__all__ = [
    'LinePlot',
]


[docs]class LinePlot(object): """ Plot representation of a layer Parameters ---------- layer: `Spectrum1DRefLayer` The layer to plot plot: LinePlot LinePlot instance to reuse. visible: bool If True, the plot will be visible style: str The plotting style pen: str If defined, the pen style to use. err_pen: str If defined, the pen style to use for the error/uncertainty. """ def __init__(self, layer, plot=None, visible=True, style='line', pen=None, err_pen=None, color=(0, 0, 0)): self._layer = layer self.style = style self._plot = plot self.error = None self._plot_units = (self._layer.dispersion_unit, self._layer.unit, None) self.line_width = 1 self.mode = None self.checked = True r, g, b = color r, g, b = r * 255, g * 255, b * 255 rand_pen = pg.mkPen(QColor(r, g, b, 255), width=self.line_width) _pen = pg.mkPen(pen, width=self.line_width) if pen is not None else rand_pen _inactive_pen = pg.mkPen(QColor(_pen.color().red(), _pen.color().green(), _pen.color().blue(), 255)) _err_pen = err_pen if err_pen is not None else pg.mkPen( color=(100, 100, 100, 50)) self._pen_stash = {'pen_on': pg.mkPen(_pen), 'pen_inactive': pg.mkPen(_inactive_pen), 'pen_off': pg.mkPen(None), 'error_pen_on': _err_pen, 'error_pen_off': pg.mkPen(None)} self.set_plot_visibility(True) self.set_error_visibility(True) if self._plot is not None: self.change_units(self._layer.dispersion_unit, self._layer.unit) @staticmethod
[docs] def from_layer(layer, **kwargs): """Create a LinePlot from a layer Parameters ---------- layer: `Spectrum1DRefLayer` The layer to create from. kwargs: dict Other arguments for `LinePlot` class. Returns ------- plot_container: The new LinePlot """ plot_data_item = pg.PlotDataItem(layer.dispersion, layer.data) plot_container = LinePlot(layer=layer, plot=plot_data_item, **kwargs) if plot_container.layer.raw_uncertainty is not None: # err_top = pg.PlotDataItem( # plot_container.layer.dispersion.value, # plot_container.layer.data.value + # plot_container.layer.uncertainty.array * 0.5) # err_btm = pg.PlotDataItem( # plot_container.layer.dispersion.value, # plot_container.layer.data.value - # plot_container.layer.uncertainty.array * 0.5) # # plot_error_item = pg.FillBetweenItem(err_top, err_btm, 'r') plot_error_item = pg.ErrorBarItem( x=plot_container.layer.dispersion.compressed().value, y=plot_container.layer.data.compressed().value, height=plot_container.layer.raw_uncertainty.compressed().value, ) plot_container.error = plot_error_item return plot_container
[docs] def change_units(self, x, y=None, z=None): """ Change the displayed units Parameters ---------- x: `~astropy.units` The new units for the dispersion y: `~astropy.units` The new units for the flux z: `~astropy.units` The new units for the multi-spectral dimension. """ if x is None or not self._layer.dispersion_unit.is_equivalent( x, equivalencies=spectral()): logging.error("Failed to convert x-axis plot units. {} to {" "}".format(self._layer.dispersion_unit, x)) x = None if y is None or not self._layer.unit.is_equivalent( y, equivalencies=spectral_density(self.layer.dispersion)): logging.error("Failed to convert y-axis plot units.") y = self._layer.unit self._layer.set_units(x, y) self._plot_units = (x, y, z) self.update()
[docs] def set_plot_visibility(self, show=None, inactive=None): """ Set visibility and active state Parameters ---------- show: bool If True, show the plot inactive: bool If True, set plot style to indicate this is not the active plot. """ if show is not None: if show: self._plot.setPen(self._pen_stash['pen_on']) else: self._plot.setPen(self._pen_stash['pen_off']) if inactive is not None: if inactive: self._plot.setPen(self._pen_stash['pen_inactive'])
[docs] def set_error_visibility(self, show=None): """ Show the error/uncertainty Parameters ---------- show: bool If True, show the error/uncertainty info. """ if self.error is not None and show is not None: if show: self.error.setOpts(pen=self._pen_stash['error_pen_on']) else: self.error.setOpts(pen=self._pen_stash['error_pen_off'])
@property def plot(self): return self._plot @plot.setter def plot(self, plot_item): self._plot = plot_item # self._plot.setPen(self.pen) @property def layer(self): return self._layer @property def pen(self): return self._pen_stash['pen_on'] @pen.setter def pen(self, pen): if isinstance(pen, QColor): pen = pg.mkPen(pen) _inactive_pen = pg.mkPen(QColor(pen.color().red(), pen.color().green(), pen.color().blue(), 50)) if self._plot.opts['pen'] == self._pen_stash['pen_on']: self._pen_stash['pen_on'] = pg.mkPen(pen, width=self.line_width) self._plot.setPen(self._pen_stash['pen_on']) elif self._plot.opts['pen'] == self._pen_stash['pen_inactive']: self._pen_stash['pen_inactive'] = _inactive_pen self._plot.setPen(self._pen_stash['pen_inactive']) @property def error_pen(self): return self._pen_stash['error_pen_on'] @error_pen.setter def error_pen(self, pen): self._pen_stash['error_pen_on'] = pg.mkPen(pen) if self.error is not None: self.error.setOpts(pen=pg.mkPen(pen))
[docs] def set_mode(self, mode): """ Set the line plotting mode Parameters ---------- mode: 'line' | 'scatter | 'histogram' The plot mode """ if mode in ['line', 'scatter', 'histogram']: self.mode = mode else: self.mode = None self.update()
[docs] def set_line_width(self, width): """ Set the line plot width Parameters ---------- width: float The width of the line """ self.line_width = width _pen = pg.mkPen(self._plot.opts['pen']) _pen.setWidth(self.line_width) self.pen = _pen
[docs] def update(self, autoscale=False): """ Refresh the plot Parameters ---------- autoscale: bool If True, rescale the plot to match the data. """ if hasattr(self.layer, '_model'): disp = self.layer.unmasked_dispersion.compressed().value data = self.layer.unmasked_data.compressed().value uncert = self.layer.unmasked_raw_uncertainty.compressed().value else: disp = self.layer.dispersion.compressed().value data = self.layer.data.compressed().value uncert = self.layer.raw_uncertainty.compressed().value #-- Changes specific for scatter plot rendering symbol = 'o' if self.mode == 'scatter' else None pen = None if self.mode == 'scatter' else self.pen #-- changes specific for histrogram rendering stepMode = True if self.mode == 'histogram' else False disp = np.append(disp, disp[-1]) if self.mode == 'histogram' else disp self._plot.setData(disp, data, symbol=symbol, stepMode=stepMode, pen=pen) if self.error is not None: self.error.setData(x=disp[:-1] if self.mode == 'histogram' else disp, y=data, height=uncert)