[docs]classGridInterface(DictInterface):""" Interface for simple dictionary-based dataset format using a compressed representation that uses the cartesian product between key dimensions. As with DictInterface, the dictionary keys correspond to the column (i.e. dimension) names and the values are NumPy arrays representing the values in that column. To use this compressed format, the key dimensions must be orthogonal to one another with each key dimension specifying an axis of the multidimensional space occupied by the value dimension data. For instance, given an temperature recordings sampled regularly across the earth surface, a list of N unique latitudes and M unique longitudes can specify the position of NxM temperature samples. """types=(dict,)datatype='grid'gridded=True@classmethoddefinit(cls,eltype,data,kdims,vdims):ifkdimsisNone:kdims=eltype.kdimsifvdimsisNone:vdims=eltype.vdimsifnotvdims:raiseValueError('GridInterface interface requires at least ''one value dimension.')ndims=len(kdims)dimensions=[dimension_name(d)fordinkdims+vdims]vdim_tuple=tuple(dimension_name(vd)forvdinvdims)ifisinstance(data,tuple):if(len(data)!=len(dimensions)andlen(data)==(ndims+1)andlen(data[-1].shape)==(ndims+1)):value_array=data[-1]data={d:vford,vinzip(dimensions,data[:-1])}data[vdim_tuple]=value_arrayelse:data={d:vford,vinzip(dimensions,data)}elif(isinstance(data,list)anddata==[]):iflen(kdims)==1:data=dict([(d,[])fordindimensions])else:data=dict([(d.name,np.array([]))fordinkdims])iflen(vdims)==1:data[vdims[0].name]=np.zeros((0,0))else:data[vdim_tuple]=np.zeros((0,0,len(vdims)))elifnotany(isinstance(data,tuple(tfortininterface.typesiftisnotNone))forinterfaceincls.interfaces.values()):data={k:vfork,vinzip(dimensions,zip(*data))}elifisinstance(data,np.ndarray):ifdata.shape==(0,0)andlen(vdims)==1:array=datadata=dict([(d.name,np.array([]))fordinkdims])data[vdims[0].name]=arrayelifdata.shape==(0,0,len(vdims)):array=datadata=dict([(d.name,np.array([]))fordinkdims])data[vdim_tuple]=arrayelse:ifdata.ndim==1:ifeltype._auto_indexable_1dandlen(kdims)+len(vdims)>1:data=np.column_stack([np.arange(len(data)),data])else:data=np.atleast_2d(data).Tdata={k:data[:,i]fori,kinenumerate(dimensions)}elifisinstance(data,list)anddata==[]:data={d:np.array([])fordindimensions[:ndims]}data.update({d:np.empty((0,)*ndims)fordindimensions[ndims:]})elifnotisinstance(data,dict):raiseTypeError('GridInterface must be instantiated as a ''dictionary or tuple')validate_dims=list(kdims)ifvdim_tupleindata:ifnotisinstance(data[vdim_tuple],get_array_types()):data[vdim_tuple]=np.array(data[vdim_tuple])else:validate_dims+=vdimsfordiminvalidate_dims:name=dimension_name(dim)ifnamenotindata:raiseValueError(f"Values for dimension {dim} not found")ifnotisinstance(data[name],get_array_types()):data[name]=np.array(data[name])kdim_names=[dimension_name(d)fordinkdims]ifvdim_tupleindata:vdim_names=[vdim_tuple]else:vdim_names=[dimension_name(d)fordinvdims]expected=tuple([len(data[kd])forkdinkdim_names])irregular_shape=data[kdim_names[0]].shapeifkdim_nameselse()valid_shape=irregular_shapeiflen(irregular_shape)>1elseexpected[::-1]shapes=tuple([data[kd].shapeforkdinkdim_names])forvdiminvdim_names:shape=data[vdim].shapeerror=DataErroriflen(shape)>1elseValueErrorifvdim_tupleindata:ifshape[-1]!=len(vdims):raiseerror('The shape of the value array does not match the number of value dimensions.')shape=shape[:-1]if(notexpectedandshape==(1,))or(len(set((shape,)+shapes))==1andlen(shape)>1):# If empty or an irregular meshpasseliflen(shape)!=len(expected):raiseerror('The shape of the %s value array does not ''match the expected dimensionality indicated ''by the key dimensions. Expected %d-D array, ''found %d-D array.'%(vdim,len(expected),len(shape)))elifany((enotin(s,s+1))fors,einzip(shape,valid_shape)):raiseerror(f'Key dimension values and value array {vdim} 'f'shapes do not match. Expected shape {valid_shape}, 'f'actual shape: {shape}',cls)returndata,{'kdims':kdims,'vdims':vdims},{}@classmethoddefconcat(cls,datasets,dimensions,vdims):from.importDatasetwithsorted_context(False):datasets=NdMapping(datasets,kdims=dimensions)datasets=datasets.clone([(k,v.dataifisinstance(v,Dataset)elsev)fork,vindatasets.data.items()])iflen(datasets.kdims)>1:items=datasets.groupby(datasets.kdims[:-1]).data.items()returncls.concat([(k,cls.concat(v,v.kdims,vdims=vdims))fork,vinitems],datasets.kdims[:-1],vdims)returncls.concat_dim(datasets,datasets.kdims[0],vdims)@classmethoddefconcat_dim(cls,datasets,dim,vdims):values,grids=zip(*datasets.items())new_data={k:vfork,vingrids[0].items()ifknotinvdims}new_data[dim.name]=np.array(values)forvdiminvdims:arrays=[grid[vdim.name]forgridingrids]shapes={arr.shapeforarrinarrays}iflen(shapes)>1:raiseDataError('When concatenating gridded data the shape 'f'of arrays must match. {cls.__name__} found that arrays 'f'along the {vdim.name} dimension do not match.')stack=dask_array_module().stackifany(is_dask(arr)forarrinarrays)elsenp.stacknew_data[vdim.name]=stack(arrays,-1)returnnew_data@classmethoddefirregular(cls,dataset,dim):returndataset.data[dimension_name(dim)].ndim>1@classmethoddefisscalar(cls,dataset,dim):values=cls.values(dataset,dim,expanded=False)returnvalues.shapein((),(1,))orlen(np.unique(values))==1@classmethoddefvalidate(cls,dataset,vdims=True):dims='all'ifvdimselse'key'not_found=[dfordindataset.dimensions(dims,label='name')ifdnotindataset.data]ifnot_foundandtuple(not_found)notindataset.data:raiseDataError("Supplied data does not contain specified ""dimensions, the following dimensions were ""not found: %s"%repr(not_found),cls)@classmethoddefdimension_type(cls,dataset,dim):ifdimindataset.dimensions():arr=cls.values(dataset,dim,False,False)else:returnNonereturnarr.dtype.type@classmethoddefpacked(cls,dataset):vdim_tuple=tuple(vd.nameforvdindataset.vdims)returnvdim_tupleifvdim_tupleindataset.dataelseFalse@classmethoddefdtype(cls,dataset,dimension):name=dataset.get_dimension(dimension,strict=True).namevdim_tuple=cls.packed(dataset)ifvdim_tupleandnameinvdim_tuple:data=dataset.data[vdim_tuple][...,vdim_tuple.index(name)]else:data=dataset.data[name]ifutil.isscalar(data):returnnp.array([data]).dtypeelse:returndata.dtype@classmethoddefshape(cls,dataset,gridded=False):vdim_tuple=cls.packed(dataset)ifvdim_tuple:shape=dataset.data[vdim_tuple].shape[:-1]else:shape=dataset.data[dataset.vdims[0].name].shapeifgridded:returnshapeelse:return(np.prod(shape,dtype=np.intp),len(dataset.dimensions()))@classmethoddeflength(cls,dataset):returncls.shape(dataset)[0]@classmethoddef_infer_interval_breaks(cls,coord,axis=0):""" >>> GridInterface._infer_interval_breaks(np.arange(5)) array([-0.5, 0.5, 1.5, 2.5, 3.5, 4.5]) >>> GridInterface._infer_interval_breaks([[0, 1], [3, 4]], axis=1) array([[-0.5, 0.5, 1.5], [ 2.5, 3.5, 4.5]]) """coord=np.asarray(coord)ifcoord.shape[axis]==0:returnnp.array([],dtype=coord.dtype)ifcoord.shape[axis]>1:deltas=0.5*np.diff(coord,axis=axis)else:deltas=np.array([0.5])first=np.take(coord,[0],axis=axis)-np.take(deltas,[0],axis=axis)last=np.take(coord,[-1],axis=axis)+np.take(deltas,[-1],axis=axis)trim_last=tuple(slice(None,-1)ifn==axiselseslice(None)forninrange(coord.ndim))returnnp.concatenate([first,coord[trim_last]+deltas,last],axis=axis)
[docs]@classmethoddefcoords(cls,dataset,dim,ordered=False,expanded=False,edges=False):""" Returns the coordinates along a dimension. Ordered ensures coordinates are in ascending order and expanded creates ND-array matching the dimensionality of the dataset. """dim=dataset.get_dimension(dim,strict=True)irregular=cls.irregular(dataset,dim)ifirregularorexpanded:ifirregular:data=dataset.data[dim.name]else:data=util.expand_grid_coords(dataset,dim)ifedgesanddata.shape==dataset.data[dataset.vdims[0].name].shape:data=cls._infer_interval_breaks(data,axis=1)data=cls._infer_interval_breaks(data,axis=0)returndatadata=dataset.data[dim.name]iforderedandnp.all(data[1:]<data[:-1]):data=data[::-1]shape=cls.shape(dataset,True)ifdimindataset.kdims:idx=dataset.get_dimension_index(dim)isedges=(dimindataset.kdimsandlen(shape)==dataset.ndimsandlen(data)==(shape[dataset.ndims-idx-1]+1))else:isedges=Falseifedgesandnotisedges:data=cls._infer_interval_breaks(data)elifnotedgesandisedges:data=data[:-1]+np.diff(data)/2.returndata
[docs]@classmethoddefcanonicalize(cls,dataset,data,data_coords=None,virtual_coords=None):""" Canonicalize takes an array of values as input and reorients and transposes it to match the canonical format expected by plotting functions. In certain cases the dimensions defined via the kdims of an Element may not match the dimensions of the underlying data. A set of data_coords may be passed in to define the dimensionality of the data, which can then be used to np.squeeze the data to remove any constant dimensions. If the data is also irregular, i.e. contains multi-dimensional coordinates, a set of virtual_coords can be supplied, required by some interfaces (e.g. xarray) to index irregular datasets with a virtual integer index. This ensures these coordinates are not simply dropped. """ifvirtual_coordsisNone:virtual_coords=[]ifdata_coordsisNone:data_coords=dataset.dimensions('key',label='name')[::-1]# Transpose datadims=[namefornameindata_coordsifisinstance(cls.coords(dataset,name),get_array_types())]dropped=[dims.index(d)fordindimsifdnotindataset.kdims+virtual_coords]ifdropped:iflen(dropped)==data.ndim:data=data.flatten()else:data=np.squeeze(data,axis=tuple(dropped))ifnotany(cls.irregular(dataset,d)fordindataset.kdims):inds=[dims.index(kd.name)forkdindataset.kdims]inds=[i-sum([1fordindroppedifi>=d])foriininds]ifinds:data=data.transpose(inds[::-1])# Reorient datainvert=Falseslices=[]fordindataset.kdims[::-1]:coords=cls.coords(dataset,d)ifnp.all(coords[1:]<coords[:-1])andnotcoords.ndim>1:slices.append(slice(None,None,-1))invert=Trueelse:slices.append(slice(None))data=data[tuple(slices)]ifinvertelsedata# Allow lower dimensional views into dataiflen(dataset.kdims)<2:data=data.flatten()returndata
@classmethoddefvalues(cls,dataset,dim,expanded=True,flat=True,compute=True,keep_index=False,canonicalize=True):dim=dataset.get_dimension(dim,strict=True)ifdimindataset.vdimsordataset.data[dim.name].ndim>1:vdim_tuple=cls.packed(dataset)ifvdim_tuple:data=dataset.data[vdim_tuple][...,dataset.vdims.index(dim)]else:data=dataset.data[dim.name]ifcanonicalize:data=cls.canonicalize(dataset,data)da=dask_array_module()ifcomputeanddaandisinstance(data,da.Array):data=data.compute()returndata.T.flatten()ifflatelsedataelifexpanded:data=cls.coords(dataset,dim.name,expanded=True,ordered=canonicalize)returndata.T.flatten()ifflatelsedataelse:returncls.coords(dataset,dim.name,ordered=canonicalize)@classmethoddefgroupby(cls,dataset,dim_names,container_type,group_type,**kwargs):# Get dimensions informationdimensions=[dataset.get_dimension(d,strict=True)fordindim_names]if'kdims'inkwargs:kdims=kwargs['kdims']else:kdims=[kdimforkdimindataset.kdimsifkdimnotindimensions]kwargs['kdims']=kdimsinvalid=[dfordindimensionsifdataset.data[d.name].ndim>1]ifinvalid:iflen(invalid)==1:invalid=f"'{invalid[0]}'"raiseValueError("Cannot groupby irregularly sampled dimension(s) %s."%invalid)# 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))else:kwargs.pop('kdims')group_kwargs.update(kwargs)drop_dim=any(dnotingroup_kwargs['kdims']fordinkdims)# Find all the keys along supplied dimensionskeys=[cls.coords(dataset,d.name)fordindimensions]transpose=[dataset.ndims-dataset.kdims.index(kd)-1forkdinkdims]transpose+=[iforiinrange(dataset.ndims)ifinotintranspose]# Iterate over the unique entries applying selection masksgrouped_data=[]forunique_keyinzip(*util.cartesian_product(keys)):select=dict(zip(dim_names,unique_key))ifdrop_dim:group_data=dataset.select(**select)group_data=group_dataifnp.isscalar(group_data)elsegroup_data.columns()else:group_data=cls.select(dataset,**select)ifnp.isscalar(group_data)or(isinstance(group_data,get_array_types())andgroup_data.shape==()):group_data={dataset.vdims[0].name:np.atleast_1d(group_data)}fordim,vinzip(dim_names,unique_key):group_data[dim]=np.atleast_1d(v)elifnotdrop_dim:ifisinstance(group_data,get_array_types()):group_data={dataset.vdims[0].name:group_data}forvdimindataset.vdims:data=group_data[vdim.name]data=data.transpose(transpose[::-1])group_data[vdim.name]=np.squeeze(data)group_data=group_type(group_data,**group_kwargs)grouped_data.append((tuple(unique_key),group_data))ifissubclass(container_type,NdMapping):withitem_check(False):returncontainer_type(grouped_data,kdims=dimensions)else:returncontainer_type(grouped_data)@classmethoddefkey_select_mask(cls,dataset,values,ind):ifvalues.dtype.kind=='M':ind=util.parse_datetime_selection(ind)ifisinstance(ind,tuple):ind=slice(*ind)ifisinstance(ind,get_array_types()):mask=indelifisinstance(ind,slice):mask=Trueifind.startisnotNone:mask&=ind.start<=valuesifind.stopisnotNone:mask&=values<ind.stop# Expand empty maskifmaskisTrue:mask=np.ones(values.shape,dtype=np.bool_)elifisinstance(ind,(set,list)):iter_slcs=[]forikinind:iter_slcs.append(values==ik)mask=np.logical_or.reduce(iter_slcs)elifcallable(ind):mask=ind(values)elifindisNone:mask=Noneelse:index_mask=values==indif(dataset.ndims==1ordataset._binned)andnp.sum(index_mask)==0:data_index=np.argmin(np.abs(values-ind))mask=np.zeros(len(values),dtype=np.bool_)mask[data_index]=Trueelse:mask=index_maskifmaskisNone:mask=np.ones(values.shape,dtype=bool)returnmask@classmethoddefselect(cls,dataset,selection_mask=None,**selection):ifselection_maskisnotNone:raiseValueError(f"Masked selections currently not supported for {cls.__name__}.")dimensions=dataset.kdimsval_dims=[vdimforvdimindataset.vdimsifvdiminselection]ifval_dims:raiseIndexError('Cannot slice value dimensions in compressed format, ''convert to expanded format before slicing.')indexed=cls.indexed(dataset,selection)full_selection=[(d,selection.get(d.name,selection.get(d.label)))fordindimensions]data={}value_select=[]fori,(dim,ind)inenumerate(full_selection):irregular=cls.irregular(dataset,dim)values=cls.coords(dataset,dim,irregular)mask=cls.key_select_mask(dataset,values,ind)ifirregular:ifnp.isscalar(ind)orisinstance(ind,(set,list)):raiseIndexError("Indexing not supported for irregularly "f"sampled data. {ind} value along {dim} dimension.""must be a slice or 2D boolean mask.")mask=mask.max(axis=i)elifdataset._binned:edges=cls.coords(dataset,dim,False,edges=True)inds=np.argwhere(mask)ifnp.isscalar(ind):emin,emax=edges.min(),edges.max()ifind<emin:raiseIndexError(f"Index {ind} less than lower bound "f"of {emin} for {dim} dimension.")elifind>=emax:raiseIndexError(f"Index {ind} more than or equal to upper bound "f"of {emax} for {dim} dimension.")idx=max([np.digitize([ind],edges)[0]-1,0])mask=np.zeros(len(values),dtype=np.bool_)mask[idx]=Truevalues=edges[idx:idx+2]eliflen(inds):values=edges[inds.min():inds.max()+2]else:values=edges[0:0]else:values=values[mask]values,mask=np.asarray(values),np.asarray(mask)value_select.append(mask)data[dim.name]=np.array([values])ifnp.isscalar(values)elsevaluesint_inds=[np.argwhere(v)forvinvalue_select][::-1]index=np.ix_(*[np.atleast_1d(np.squeeze(ind))ifind.ndim>1elsenp.atleast_1d(ind)forindinint_inds])forkdimindataset.kdims:ifcls.irregular(dataset,dim):da=dask_array_module()ifdaandisinstance(dataset.data[kdim.name],da.Array):data[kdim.name]=dataset.data[kdim.name].vindex[index]else:data[kdim.name]=np.asarray(data[kdim.name])[index]forvdimindataset.vdims:da=dask_array_module()ifdaandisinstance(dataset.data[vdim.name],da.Array):data[vdim.name]=dataset.data[vdim.name].vindex[index]else:data[vdim.name]=np.asarray(dataset.data[vdim.name])[index]ifindexed:iflen(dataset.vdims)==1:da=dask_array_module()arr=np.squeeze(data[dataset.vdims[0].name])ifdaandisinstance(arr,da.Array):arr=arr.compute()returnarrifnp.isscalar(arr)elsearr[()]else:returnnp.array([np.squeeze(data[vd.name])forvdindataset.vdims])returndata@classmethoddefmask(cls,dataset,mask,mask_val=np.nan):mask=cls.canonicalize(dataset,mask)packed=cls.packed(dataset)masked=dict(dataset.data)ifpacked:masked=dataset.data[packed].copy()try:masked[mask]=mask_valexceptValueError:masked=masked.astype('float')masked[mask]=mask_valelse:forvdindataset.vdims:masked[vd.name]=marr=masked[vd.name].copy()try:marr[mask]=mask_valexceptValueError:masked[vd.name]=marr=marr.astype('float')marr[mask]=mask_valreturnmasked
[docs]@classmethoddefsample(cls,dataset,samples=None):""" Samples the gridded data into dataset of samples. """ifsamplesisNone:samples=[]ndims=dataset.ndimsdimensions=dataset.dimensions(label='name')arrays=[dataset.data[vdim.name]forvdimindataset.vdims]data=defaultdict(list)forsampleinsamples:ifnp.isscalar(sample):sample=[sample]iflen(sample)!=ndims:sample=[sample[i]ifi<len(sample)elseNoneforiinrange(ndims)]sampled,int_inds=[],[]ford,indinzip(dimensions,sample):cdata=dataset.data[d]mask=cls.key_select_mask(dataset,cdata,ind)inds=np.arange(len(cdata))ifmaskisNoneelsenp.argwhere(mask)int_inds.append(inds)sampled.append(cdata[mask])ford,arrinzip(dimensions,np.meshgrid(*sampled)):data[d].append(arr)forvdim,arrayinzip(dataset.vdims,arrays):da=dask_array_module()flat_index=np.ravel_multi_index(tuple(int_inds)[::-1],array.shape)ifdaandisinstance(array,da.Array):data[vdim.name].append(array.flatten().vindex[tuple(flat_index)])else:data[vdim.name].append(array.flat[flat_index])concatenated={d:np.concatenate(arrays).flatten()ford,arraysindata.items()}returnconcatenated
@classmethoddefaggregate(cls,dataset,kdims,function,**kwargs):kdims=[dimension_name(kd)forkdinkdims]data={kdim:dataset.data[kdim]forkdiminkdims}axes=tuple(dataset.ndims-dataset.get_dimension_index(kdim)-1forkdimindataset.kdimsifkdimnotinkdims)da=dask_array_module()dropped=[]vdim_tuple=cls.packed(dataset)ifvdim_tuple:values=dataset.data[vdim_tuple]ifaxes:data[vdim_tuple]=function(values,axis=axes,**kwargs)else:data[vdim_tuple]=valueselse:forvdimindataset.vdims:values=dataset.data[vdim.name]atleast_1d=da.atleast_1difis_dask(values)elsenp.atleast_1dtry:data[vdim.name]=atleast_1d(function(values,axis=axes,**kwargs))exceptTypeError:dropped.append(vdim)returndata,dropped@classmethoddefreindex(cls,dataset,kdims,vdims):dropped_kdims=[kdforkdindataset.kdimsifkdnotinkdims]dropped_vdims=([vdimforvdimindataset.vdimsifvdimnotinvdims]ifvdimselse[])constant={}forkdindropped_kdims:vals=cls.values(dataset,kd.name,expanded=False)iflen(vals)==1:constant[kd.name]=vals[0]data={k:valuesfork,valuesindataset.data.items()ifknotindropped_kdims+dropped_vdims}iflen(constant)==len(dropped_kdims):joined_dims=kdims+dropped_kdimsaxes=tuple(dataset.ndims-dataset.kdims.index(d)-1fordinjoined_dims)dropped_axes=tuple(dataset.ndims-joined_dims.index(d)-1fordindropped_kdims)forvdiminvdims:vdata=data[vdim.name]iflen(axes)>1:vdata=vdata.transpose(axes[::-1])ifdropped_axes:vdata=np.squeeze(vdata,axis=dropped_axes)data[vdim.name]=vdatareturndataelifdropped_kdims:returntuple(dataset.columns(kdims+vdims).values())returndata@classmethoddefadd_dimension(cls,dataset,dimension,dim_pos,values,vdim):ifnotvdim:raiseException("Cannot add key dimension to a dense representation.")dim=dimension_name(dimension)returndict(dataset.data,**{dim:values})@classmethoddefsort(cls,dataset,by=None,reverse=False):ifbyisNone:by=[]ifnotbyorbyin[dataset.kdims,dataset.dimensions()]:returndataset.dataelse:raiseException('Compressed format cannot be sorted, either instantiate ''in the desired order or use the expanded format.')@classmethoddefiloc(cls,dataset,index):rows,cols=indexscalar=Falseifnp.isscalar(cols):scalar=np.isscalar(rows)cols=[dataset.get_dimension(cols,strict=True)]elifisinstance(cols,slice):cols=dataset.dimensions()[cols]else:cols=[dataset.get_dimension(d,strict=True)fordincols]ifnp.isscalar(rows):rows=[rows]new_data=[]fordincols:new_data.append(cls.values(dataset,d,compute=False)[rows])ifscalar:da=dask_array_module()ifnew_dataand(daandisinstance(new_data[0],da.Array)):returnnew_data[0].compute()[0]returnnew_data[0][0]returntuple(new_data)@classmethoddefrange(cls,dataset,dimension):dimension=dataset.get_dimension(dimension,strict=True)ifdataset._binnedanddimensionindataset.kdims:expanded=cls.irregular(dataset,dimension)array=cls.coords(dataset,dimension,expanded=expanded,edges=True)else:array=cls.values(dataset,dimension,expanded=False,flat=False)ifdimension.nodataisnotNone:array=cls.replace_value(array,dimension.nodata)da=dask_array_module()iflen(array)==0:returnnp.nan,np.nanifarray.dtype.kind=='M':dmin,dmax=array.min(),array.max()else:try:dmin,dmax=(np.nanmin(array),np.nanmax(array))exceptTypeError:returnnp.nan,np.nanifdaandisinstance(array,da.Array):returnfinite_range(array,*da.compute(dmin,dmax))returnfinite_range(array,dmin,dmax)@classmethoddefassign(cls,dataset,new_data):data=dict(dataset.data)fork,vinnew_data.items():ifkindataset.kdims:coords=cls.coords(dataset,k)ifnotcoords.ndim>1andnp.all(coords[1:]<coords[:-1]):v=v[::-1]data[k]=velse:data[k]=cls.canonicalize(dataset,v)returndata