[docs]classImageInterface(GridInterface):""" Interface for 2 or 3D arrays representing images of raw luminance values, RGB values or HSV values. """types=(np.ndarray,)datatype='image'named=False@classmethoddefinit(cls,eltype,data,kdims,vdims):ifkdimsisNone:kdims=eltype.kdimsifvdimsisNone:vdims=eltype.vdimskwargs={}dimensions=[dimension_name(d)fordinkdims+vdims]ifisinstance(data,tuple):data=dict(zip(dimensions,data))ifisinstance(data,dict):xs,ys=np.asarray(data[kdims[0].name]),np.asarray(data[kdims[1].name])xvalid=util.validate_regular_sampling(xs,eltype.rtolorutil.config.image_rtol)yvalid=util.validate_regular_sampling(ys,eltype.rtolorutil.config.image_rtol)ifnotxvalidornotyvalid:raiseValueError('ImageInterface only supports regularly sampled coordinates')l,r,xdensity,invertx=util.bound_range(xs,None,eltype._time_unit)b,t,ydensity,inverty=util.bound_range(ys,None,eltype._time_unit)kwargs['bounds']=BoundingBox(points=((l,b),(r,t)))iflen(vdims)==1:data=np.flipud(np.asarray(data[vdims[0].name]))else:data=np.dstack([np.flipud(data[vd.name])forvdinvdims])ifinvertx:data=data[:,::-1]ifinverty:data=data[::-1,:]expected=(len(ys),len(xs))shape=data.shape[:2]error=DataErroriflen(shape)>1andnoteltype._binnedelseValueErrorifshape!=expectedandnot(notexpectedandshape==(1,)):raiseerror(f'Key dimension values and value array {vdims[0]} 'f'shapes do not match. Expected shape {expected}, 'f'actual shape: {shape}',cls)ifnotisinstance(data,np.ndarray)ordata.ndimnotin[2,3]:raiseValueError('ImageInterface expects a 2D array.')elifnotissubclass(eltype,SheetCoordinateSystem):raiseValueError('ImageInterface may only be used on elements ''that subclass SheetCoordinateSystem.')returndata,{'kdims':kdims,'vdims':vdims},kwargs
[docs]@classmethoddefirregular(cls,dataset,dim):"ImageInterface does not support irregular data"returnFalse
[docs]@classmethoddefvalues(cls,dataset,dim,expanded=True,flat=True,compute=True,keep_index=False):""" The set of samples available along a particular dimension. """dim_idx=dataset.get_dimension_index(dim)ifdim_idxin[0,1]:l,b,r,t=dataset.bounds.lbrt()dim2,dim1=dataset.data.shape[:2]xdate,ydate=isinstance(l,util.datetime_types),isinstance(b,util.datetime_types)ifl==rordim1==0:xlin=np.full((dim1,),l,dtype=('datetime64[us]'ifxdateelse'float'))elifxdate:xlin=util.date_range(l,r,dim1,dataset._time_unit)else:xstep=float(r-l)/dim1xlin=np.linspace(l+(xstep/2.),r-(xstep/2.),dim1)ifb==tordim2==0:ylin=np.full((dim2,),b,dtype=('datetime64[us]'ifydateelse'float'))elifydate:ylin=util.date_range(b,t,dim2,dataset._time_unit)else:ystep=float(t-b)/dim2ylin=np.linspace(b+(ystep/2.),t-(ystep/2.),dim2)ifexpanded:values=np.meshgrid(ylin,xlin)[abs(dim_idx-1)]returnvalues.flatten()ifflatelsevalues.Telse:returnylinifdim_idxelsexlinelifdataset.ndims<=dim_idx<len(dataset.dimensions()):# Raster arrays are stored with different orientation# than expanded column format, reorient before expandingifdataset.data.ndim>2:data=dataset.data[:,:,dim_idx-dataset.ndims]else:data=dataset.datadata=np.flipud(data)returndata.T.flatten()ifflatelsedataelse:returnNone
[docs]@classmethoddefselect(cls,dataset,selection_mask=None,**selection):""" Slice the underlying numpy array in sheet coordinates. """selection={k:slice(*sel)ifisinstance(sel,tuple)elseselfork,selinselection.items()}coords=tuple(selection[kd.name]ifkd.nameinselectionelseslice(None)forkdindataset.kdims)ifnotany([isinstance(el,slice)forelincoords]):returndataset.data[dataset.sheet2matrixidx(*coords)]# Apply slicesxidx,yidx=coordsl,b,r,t=dataset.bounds.lbrt()ifisinstance(xidx,slice):l=lifxidx.startisNoneelsemax(l,xidx.start)r=rifxidx.stopisNoneelsemin(r,xidx.stop)ifisinstance(yidx,slice):b=bifyidx.startisNoneelsemax(b,yidx.start)t=tifyidx.stopisNoneelsemin(t,yidx.stop)bounds=BoundingBox(points=((l,b),(r,t)))slc=Slice(bounds,dataset)returnslc.submatrix(dataset.data)
[docs]@classmethoddefsample(cls,dataset,samples=None):""" Sample the Raster along one or both of its dimensions, returning a reduced dimensionality type, which is either a ItemTable, Curve or Scatter. If two dimension samples and a new_xaxis is provided the sample will be the value of the sampled unit indexed by the value in the new_xaxis tuple. """ifsamplesisNone:samples=[]iflen(samples[0])==1:select={dataset.kdims[0].name:[s[0]forsinsamples]}returntuple(dataset.select(**select).columns().values())return[c+(dataset.data[dataset._coord2matrix(c)],)forcinsamples]
@classmethoddefgroupby(cls,dataset,dim_names,container_type,group_type,**kwargs):# Get dimensions informationdimensions=[dataset.get_dimension(d)fordindim_names]kdims=[kdimforkdimindataset.kdimsifkdimnotindimensions]# Update the kwargs appropriately for Element group typesgroup_kwargs={}group_type=dictifgroup_type=='raw'elsegroup_typeifissubclass(group_type,Element):group_kwargs.update(util.get_param_values(dataset))group_kwargs['kdims']=kdimsgroup_kwargs.update(kwargs)iflen(dimensions)==1:didx=dataset.get_dimension_index(dimensions[0])coords=dataset.dimension_values(dimensions[0],expanded=False)xvals=dataset.dimension_values(abs(didx-1),expanded=False)samples=[(i,slice(None))ifdidxelse(slice(None),i)foriinrange(dataset.data.shape[abs(didx-1)])]data=np.flipud(dataset.data)groups=[(c,group_type((xvals,data[s]),**group_kwargs))fors,cinzip(samples,coords)]else:data=zip(*[dataset.dimension_values(i)foriinrange(len(dataset.dimensions()))])groups=[(g[:dataset.ndims],group_type([g[dataset.ndims:]],**group_kwargs))forgindata]ifissubclass(container_type,NdMapping):withitem_check(False):returncontainer_type(groups,kdims=dimensions)else:returncontainer_type(groups)
[docs]@classmethoddefunpack_scalar(cls,dataset,data):""" Given a dataset object and data in the appropriate format for the interface, return a simple scalar. """ifnp.isscalar(data)orlen(data)!=1:returndatakey=next(iter(data.keys()))iflen(data[key])==1andkeyindataset.vdims:returndata[key][0]