ejeschke/ginga — pull request #53 by ChrisBeaumont (2014-10-30 17:07:50+00:00)
Title: Further isolation of _get_data

This further consolidates the use of `_get_data` inside BaseImage. The upshot is I can now create a basic model wrapper for Glue subsets by overriding just a few methods:

```python

class SubsetImage(BaseImage):

def __init__(self, subset, **kwargs):
super(SubsetImage, self).__init__(**kwargs)
self._subset = subset

def forbidden(self):
raise ValueError("Forbidden")

get_data = forbidden
_get_data = forbidden
copy_data = forbidden
set_data = forbidden
get_array = forbidden
transfer = forbidden

@property
def shape(self):
return self._subset.data.shape

def _get_fast_data(self):
view = (slice(None, None, 10), slice(None, None, 10))
return self._view(view)

def _slice(self, view):
return self._subset.to_mask(view)

def _set_minmax(self):
self.minval = 0
self.maxval = 1
self.minval_noinf = self.minval
self.maxval_noinf = self.maxval
```

I've added a `shape` property that can be used to implement all other shape-related methods and properties, as well as a `_slice` method that many methods can use as a proxy for `x = self._get_data(), x[blah]`.

Slightly more controversially, I've added a `_get_fast_data` method, that is meant to be used for things like min/max and histogram estimation. The idea is that subclasses, if they want to, could override this method to return an efficiently downsampled version of the array, that would have minimal impact on the result of things like min/max computation. However, I don't know if there are places in ginga that require min/max values to be exact.

There are now seven methods in BaseImage that pose a problem for lazy images:

`set_data`, `cut_levels`, `transform`, and `rotate` all try to modify the underlying array. In general this is ill-defined (subset masks in Glue are meant to be immutable, for example).

`copy_data`, `get_array`, `transfer` all access the full array. This is always possible, but expensive in general.

I was kind of surprised that rotations work in my demo, despite the fact that the rotate method calls _get_data. I gather that ginga must somewhere be extracting a view out of my class, packing it into a new normal class, and then rotating *that*.

Anyways, I wonder what you think of removing these 7 methods from BaseImage, and dropping them down into a subclass or mixin class? It isn't strictly necessary, but it would make it easier to ensure that the rest of the ginga code base is using the most generic interface, which doesn't rely on direct access to a potentially large array.