Repository URL to install this package:
Version:
4.8.0 ▾
|
chaco
/
cmap_image_plot.py
|
---|
#
# (C) Copyright 2013 Enthought, Inc., Austin, TX
# All right reserved.
#
# This file is open source software distributed according to the terms in
# LICENSE.txt
#
from numpy import zeros
# Enthought library imports.
from traits.api import Any, Bool, Float, Instance, Property, Tuple
# Local relative imports
from .image_plot import ImagePlot
from .abstract_colormap import AbstractColormap
from .speedups import apply_selection_fade
class CMapImagePlot(ImagePlot):
""" Colormapped image plot. Takes a value data object whose elements are
scalars, and renders them as a colormapped image.
"""
# TODO: Modify ImageData to explicitly support scalar value arrays
#------------------------------------------------------------------------
# Data-related traits
#------------------------------------------------------------------------
#: Maps from scalar data values in self.data.value to color tuples
value_mapper = Instance(AbstractColormap)
#: Convenience property for value_mapper as color_mapper
color_mapper = Property
#: Convenience property for accessing the data range of the mapper.
value_range = Property
#: alpha value to use to fade out unselected data points when there is an
#: active selection
fade_alpha = Float(0.3)
#fade_background = Tuple((255,255,255))
#: RGB color to use to fade out unselected points.
fade_background = Tuple((0,0,0))
#: whether to pre-compute the full colormapped RGB(A) image
cache_full_map = Bool(True)
#------------------------------------------------------------------------
# Private Traits
#------------------------------------------------------------------------
# Is the mapped image valid?
_mapped_image_cache_valid = Bool(False)
# Cache of the fully mapped RGB(A) image.
_cached_mapped_image = Any
#------------------------------------------------------------------------
# Public methods
#------------------------------------------------------------------------
def __init__(self, **kwargs):
super(CMapImagePlot, self).__init__(**kwargs)
if self.value_mapper:
self.value_mapper.on_trait_change(self._update_value_mapper,
"updated")
if self.value:
self.value.on_trait_change(self._update_selections,
"metadata_changed")
def set_value_selection(self, val):
""" Sets a range of values in the value data source as selected.
"""
if val is not None:
low, high = val
data = self.value.get_data()
new_mask = (data>=low) & (data<=high)
self.value.metadata["selection_masks"] = [new_mask]
else:
del self.value.metadata["selection_masks"]
self._update_selections()
#------------------------------------------------------------------------
# Base2DPlot interface
#------------------------------------------------------------------------
def _render(self, gc):
""" Ensures that the cached image is valid.
Called before _render() is called. Implements the Base2DPlot interface.
"""
if not self._mapped_image_cache_valid:
if 'selection_masks' in self.value.metadata:
self._compute_cached_image(self.value.metadata['selection_masks'])
else:
self._compute_cached_image()
ImagePlot._render(self, gc)
#------------------------------------------------------------------------
# Private methods
#------------------------------------------------------------------------
def _cmap_values(self, data, selection_masks=None):
""" Maps the data to RGB(A) with optional selection masks overlayed
"""
# get the RGBA values from the color map as uint8
mapped_image = self.value_mapper.map_uint8(data)
if selection_masks is not None:
# construct a composite mask
if len(selection_masks) > 0:
mask = zeros(mapped_image.shape[:2], dtype=bool)
for m in selection_masks:
mask = mask | m
else:
mask = zeros(self._cached_mapped_image.shape[:2], dtype=bool)
# Apply the selection fade, from speedups.py
apply_selection_fade(mapped_image, mask,
self.fade_alpha, self.fade_background)
return mapped_image
def _compute_cached_image(self, selection_masks=None):
""" Updates the cached image.
"""
if self.cache_full_map:
if not self._mapped_image_cache_valid:
self._cached_mapped_image = self._cmap_values(self.value.data,
selection_masks)
self._mapped_image_cache_valid = True
mapped_value = self._cached_mapped_image
ImagePlot._compute_cached_image(self, mapped_value)
else:
self._mapped_image_cache_valid = True
ImagePlot._compute_cached_image(self, self.value.data, mapper=lambda data:
self._cmap_values(data))
def _update_value_mapper(self):
self._mapped_image_cache_valid = False
self._image_cache_valid = False
self.invalidate_and_redraw()
def _update_selections(self):
self._mapped_image_cache_valid = False
self._image_cache_valid = False
self.invalidate_and_redraw()
#------------------------------------------------------------------------
# Properties
#------------------------------------------------------------------------
def _get_value_range(self):
return self.value_mapper.range
def _set_value_range(self, val):
self.value_mapper.range = val
def _get_color_mapper(self):
return self.value_mapper
def _set_color_mapper(self, val):
self.value_mapper = val
#------------------------------------------------------------------------
# Event handlers
#------------------------------------------------------------------------
def _value_mapper_changed(self, old, new):
if old is not None:
old.on_trait_change(self._update_value_mapper,
"updated", remove=True)
if new is not None:
new.on_trait_change(self._update_value_mapper, "updated")
if old and new:
if new.range is None and old.range is not None:
new.range = old.range
self._update_value_mapper()
def _value_data_changed_fired(self):
super(CMapImagePlot, self)._value_data_changed_fired()
self._mapped_image_cache_valid = False
return
def _index_data_changed_fired(self):
super(CMapImagePlot, self)._index_data_changed_fired()
self._mapped_image_cache_valid = False
return
def _cache_full_map_changed(self):
self._mapped_image_cache_valid = False