Commit 87d8daa3 authored by Daniel Scheffler's avatar Daniel Scheffler
Browse files

added holoviews visualization for exploring bands-axis in GeoArray

io.raster.GeoArray.GeoArray:
- __init__(): GeoArray can now be instanced from another GeoArray without exception
- show(): added interactive mode (new keyword) that visualizes an interactive holoviews graphic for quickly exploring all bands of the current GeoArray

- updated __version__
parent a1d96f17
......@@ -15,7 +15,7 @@ __all__=[#'compatibility',
'similarity',
'GeoArray']
__version__ = '20161115_01'
__version__ = '20161117_01'
__author__='Daniel Scheffler'
# Validate GDAL version
......
......@@ -69,56 +69,59 @@ class GeoArray(object):
raise ValueError("%s parameter 'arg' takes only string "
"or np.ndarray types. Got %s." %(self.__class__.__name__,type(path_or_array)))
self._initParams = dict([x for x in locals().items() if x[0] != "self"])
self.arg = path_or_array
self.arr = self.arg if isinstance(self.arg, np.ndarray) else None
self.filePath = self.arg if isinstance(self.arg, str) and self.arg else None
self.basename = os.path.splitext(os.path.basename(self.filePath))[0] if not self.is_inmem else 'IN_MEM'
self.progress = progress
self.q = q
self._arr_cache = None
self._geotransform = None
self._projection = None
self._shape = None
self._dtype = None
self._nodata = nodata
self._mask_nodata = None
self._footprint_poly = None
self._gdalDataset_meta_already_set = False
if isinstance(self.arg, str):
assert ' ' not in self.arg, "The given path contains whitespaces. This is not supported by GDAL."
if not os.path.exists(self.filePath):
raise FileNotFoundError(self.filePath) if PY3 else FileNotFoundError_comp(self.filePath)
ds = gdal.Open(self.filePath)
if not ds:
raise Exception('Error reading file: ' + gdal.GetLastErrorMsg())
bands = ds.RasterCount
ds = None
if type(path_or_array)==type(self):
self.__dict__= path_or_array.__dict__
else:
self._shape = self.arr.shape
self._dtype = self.arr.dtype
bands = self.arr.shape[2] if len(self.arr.shape) == 3 else 1
self._initParams = dict([x for x in locals().items() if x[0] != "self"])
self.arg = path_or_array
self.arr = self.arg if isinstance(self.arg, np.ndarray) else None
self.filePath = self.arg if isinstance(self.arg, str) and self.arg else None
self.basename = os.path.splitext(os.path.basename(self.filePath))[0] if not self.is_inmem else 'IN_MEM'
self.progress = progress
self.q = q
self._arr_cache = None
self._geotransform = None
self._projection = None
self._shape = None
self._dtype = None
self._nodata = nodata
self._mask_nodata = None
self._footprint_poly = None
self._gdalDataset_meta_already_set = False
if isinstance(self.arg, str):
assert ' ' not in self.arg, "The given path contains whitespaces. This is not supported by GDAL."
if not os.path.exists(self.filePath):
raise FileNotFoundError(self.filePath) if PY3 else FileNotFoundError_comp(self.filePath)
ds = gdal.Open(self.filePath)
if not ds:
raise Exception('Error reading file: ' + gdal.GetLastErrorMsg())
bands = ds.RasterCount
ds = None
else:
self._shape = self.arr.shape
self._dtype = self.arr.dtype
bands = self.arr.shape[2] if len(self.arr.shape) == 3 else 1
if self.filePath:
self.set_gdalDataset_meta()
if self.filePath:
self.set_gdalDataset_meta()
if bandnames:
assert len(bandnames) == bands, \
'Number of given bandnames does not match number of bands in array.'
assert len(list(set([type(b) for b in bandnames]))) == 1 and type(bandnames[0] == 'str'), \
"'bandnames must be a set of strings. Got other datetypes in there.'"
self.bandnames = {band: i for i, band in enumerate(bandnames)} # syntax supported since Python 2.7
assert len(self.bandnames) == bands, 'Bands must not have the same name.'
else:
self.bandnames = {'B%s' % band: i for i, band in enumerate(range(1, bands + 1))}
if bandnames:
assert len(bandnames) == bands, \
'Number of given bandnames does not match number of bands in array.'
assert len(list(set([type(b) for b in bandnames]))) == 1 and type(bandnames[0] == 'str'), \
"'bandnames must be a set of strings. Got other datetypes in there.'"
self.bandnames = {band: i for i, band in enumerate(bandnames)} # syntax supported since Python 2.7
assert len(self.bandnames) == bands, 'Bands must not have the same name.'
else:
self.bandnames = {'B%s' % band: i for i, band in enumerate(range(1, bands + 1))}
if geotransform:
self.geotransform = geotransform # use property in order to validate given value
if projection:
self.projection = projection # use property in order to validate given value
if geotransform:
self.geotransform = geotransform # use property in order to validate given value
if projection:
self.projection = projection # use property in order to validate given value
@property
......@@ -628,7 +631,7 @@ class GeoArray(object):
dill.dump(self,outF)
def _get_plottable_image(self, xlim=None, ylim=None, band=0, boundsMap=None, boundsMapPrj=None, res_factor=None,
def _get_plottable_image(self, xlim=None, ylim=None, band=None, boundsMap=None, boundsMapPrj=None, res_factor=None,
nodataVal=None, out_prj=None):
# handle limits
if boundsMap:
......@@ -669,13 +672,14 @@ class GeoArray(object):
return image2plot, gt, prj
def show(self, xlim=None, ylim=None, band=0, boundsMap=None, boundsMapPrj=None, figsize=None, interpolation='none',
cmap=None, nodataVal=None, res_factor=None):
def show(self, xlim=None, ylim=None, band=None, boundsMap=None, boundsMapPrj=None, figsize=None,
interpolation='none', cmap=None, nodataVal=None, res_factor=None, interactive=False):
"""Plots the desired array position into a figure.
:param xlim: [start_column, end_column]
:param ylim: [start_row, end_row]
:param band:
:param band: the band index of the band to be plotted (if None and interactive==True all bands are
shown, otherwise the first band is chosen)
:param boundsMap: xmin, ymin, xmax, ymax
:param boundsMapPrj:
:param figsize:
......@@ -683,9 +687,13 @@ class GeoArray(object):
:param cmap:
:param nodataVal:
:param res_factor:
:param interactive: <bool> activates interactive plotting based on 'holoviews' library.
NOTE: this deactivates the magic '% matplotlib inline' in Jupyter Notebook
:return:
"""
band = (band if band is not None else 0) if not interactive else band
# get image to plot
nodataVal = nodataVal if nodataVal is not None else self.nodata
image2plot, gt, prj = self._get_plottable_image(xlim, ylim, band, boundsMap=boundsMap,
......@@ -703,12 +711,30 @@ class GeoArray(object):
palette.set_over ('1')
palette.set_under('0')
# show image
plt.figure(figsize=figsize)
rows, cols = image2plot.shape[:2]
plt.imshow(image2plot, palette, interpolation=interpolation, extent=(0, cols, rows, 0),
vmin=vmin, vmax=vmax, ) # compressed excludes nodata values
plt.show()
if interactive and image2plot.ndim==3:
import holoviews as hv
from skimage.exposure import rescale_intensity
hv.notebook_extension('matplotlib')
cS, cE = xlim if isinstance(xlim, (tuple, list)) else (0, self.columns - 1)
rS, rE = ylim if isinstance(ylim, (tuple, list)) else (0, self.rows - 1)
image2plot = np.array(rescale_intensity(image2plot, in_range=(vmin, vmax)))
get_hv_image = lambda b: hv.Image(image2plot[:,:,b], bounds=(cS, rS, cE, rE))(style={'cmap': 'gray'}, # FIXME ylabels have the wrong order
plot={'fig_inches':4 if figsize is None else figsize, 'show_grid':True})
#hvIm = hv.Image(image2plot)(style={'cmap': 'gray'}, figure_inches=figsize)
hmap = hv.HoloMap([(band, get_hv_image(band)) for band in range(image2plot.shape[2])], kdims=['band'])
return hmap
else:
# show image
plt.figure(figsize=figsize)
rows, cols = image2plot.shape[:2]
plt.imshow(image2plot, palette, interpolation=interpolation, extent=(0, cols, rows, 0),
vmin=vmin, vmax=vmax, ) # compressed excludes nodata values
plt.show()
def show_map(self, xlim=None, ylim=None, band=0, boundsMap=None, boundsMapPrj=None, figsize=None,
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment