Source code for glue_jupyter.bqplot.histogram.layer_artist

import numpy as np
import bqplot

from glue.core.exceptions import IncompatibleAttribute
from glue.viewers.histogram.state import HistogramLayerState
from glue_jupyter.compat import LayerArtist
from glue.utils import color2hex

from ...link import link, dlink

__all__ = ['BqplotHistogramLayerArtist']


[docs]class BqplotHistogramLayerArtist(LayerArtist): _layer_state_cls = HistogramLayerState def __init__(self, view, viewer_state, layer_state=None, layer=None): super(BqplotHistogramLayerArtist, self).__init__(viewer_state, layer_state=layer_state, layer=layer) self.view = view self.bars = bqplot.Bars( scales=self.view.scales, x=[0, 1], y=[0, 1]) self.view.figure.marks = list(self.view.figure.marks) + [self.bars] dlink((self.state, 'color'), (self.bars, 'colors'), lambda x: [color2hex(x)]) self._viewer_state.add_global_callback(self._update_histogram) self.state.add_global_callback(self._update_histogram) self.bins = None link((self.state, 'visible'), (self.bars, 'visible')) def _update_xy_att(self, *args): self.update() def _calculate_histogram(self): try: self.bins, self.hist_unscaled = self.state.histogram except IncompatibleAttribute: self.disable('Could not compute histogram') self.bins = self.hist_unscaled = None def _scale_histogram(self): # TODO: comes from glue/viewers/histogram/layer_artist.py if self.bins is None: return # can happen when the subset is empty if self.bins.size == 0 or self.hist_unscaled.sum() == 0: return self.hist = self.hist_unscaled.astype(np.float) dx = self.bins[1] - self.bins[0] if self._viewer_state.cumulative: self.hist = self.hist.cumsum() if self._viewer_state.normalize: self.hist /= self.hist.max() elif self._viewer_state.normalize: self.hist /= (self.hist.sum() * dx) # TODO this won't work for log ... centers = (self.bins[:-1] + self.bins[1:]) / 2 assert len(centers) == len(self.hist) self.bars.x = centers self.bars.y = self.hist # We have to do the following to make sure that we reset the y_max as # needed. We can't simply reset based on the maximum for this layer # because other layers might have other values, and we also can't do: # # self._viewer_state.y_max = max(self._viewer_state.y_max, result[0].max()) # # because this would never allow y_max to get smaller. self.state._y_max = self.hist.max() if self._viewer_state.y_log: self.state._y_max *= 2 else: self.state._y_max *= 1.2 if self._viewer_state.y_log: self.state._y_min = self.hist[self.hist > 0].min() / 10 else: self.state._y_min = 0 largest_y_max = max(getattr(layer, '_y_max', 0) for layer in self._viewer_state.layers) if largest_y_max != self._viewer_state.y_max: self._viewer_state.y_max = largest_y_max smallest_y_min = min(getattr(layer, '_y_min', np.inf) for layer in self._viewer_state.layers) if smallest_y_min != self._viewer_state.y_min: self._viewer_state.y_min = smallest_y_min self.redraw() def _update_visual_attributes(self): if not self.enabled: return # TODO: set visual attrs self.redraw() def _update_histogram(self, force=False, **kwargs): # TODO: comes from glue/viewers/histogram/layer_artist.py if (self._viewer_state.hist_x_min is None or self._viewer_state.hist_x_max is None or self._viewer_state.hist_n_bin is None or self._viewer_state.x_att is None or self.state.layer is None): return changed = set() if force else self.pop_changed_properties() if force or any(prop in changed for prop in ('layer', 'x_att', 'hist_x_min', 'hist_x_max', 'hist_n_bin', 'x_log')): self._calculate_histogram() force = True # make sure scaling and visual attributes are updated if force or any(prop in changed for prop in ('y_log', 'normalize', 'cumulative')): self._scale_histogram() if force or any(prop in changed for prop in ('alpha', 'color', 'zorder', 'visible')): self._update_visual_attributes()
[docs] def update(self): self.state.reset_cache() self._update_histogram(force=True) self.redraw()