class TestBoundingBox(unittest.TestCase): def setUp(self): self.left = -0.1 self.bottom = -0.2 self.right = 0.3 self.top = 0.4 self.lbrt = (self.left,self.bottom,self.right,self.top) self.region = BoundingBox(points = ((self.left,self.bottom),(self.right,self.top))) self.xc,self.yc = self.region.aarect().centroid() def test_way_inside(self): self.assert_(self.region.contains(0,0)) def test_above(self): self.failIf(self.region.contains(0,1)) def test_below(self): self.failIf(self.region.contains(0,-1)) def test_left_of(self): self.failIf(self.region.contains(-1,0)) def test_right_of(self): self.failIf(self.region.contains(1,0)) def test_centroid_x(self): self.assertEqual(self.xc, (self.left+self.right)/2.0) def test_centroid_y(self): self.assertEqual(self.yc, (self.bottom+self.top)/2.0) def test_left_boundary(self): self.assert_(self.region.contains(self.left,self.yc)) def test_right_boundary(self): self.assert_(self.region.contains(self.right,self.yc)) def test_bottom_boundary(self): self.assert_(self.region.contains(self.xc, self.bottom)) def test_top_boundary(self): self.assert_(self.region.contains(self.xc, self.top))
def test_bounds_unequal_lbrt(self): try: self.assertEqual(BoundingBox(points=((-1, -1), (3, 4.5))), BoundingBox(points=((-1, -1), (3, 5.0)))) except AssertionError as e: msg = 'BoundingBox(points=((-1,-1),(3,4.5))) != BoundingBox(points=((-1,-1),(3,5.0)))' self.assertEqual(str(e), msg)
def setUp(self): self.left = -0.1 self.bottom = -0.2 self.right = 0.3 self.top = 0.4 self.lbrt = (self.left, self.bottom, self.right, self.top) self.region = BoundingBox(points=((self.left, self.bottom), (self.right, self.top))) self.xc, self.yc = self.region.aarect().centroid()
def setUp(self): self.arr1 = np.array([[1,2], [3,4]]) self.arr2 = np.array([[10,2], [3,4]]) self.arr3 = np.array([[10,2], [3,40]]) # Varying arrays, default bounds self.mat1 = Image(self.arr1, BoundingBox()) self.mat2 = Image(self.arr2, BoundingBox()) self.mat3 = Image(self.arr3, BoundingBox()) # Varying arrays, different bounds self.mat4 = Image(self.arr1, BoundingBox(radius=0.3)) self.mat5 = Image(self.arr2, BoundingBox(radius=0.3))
class PatternGenerator(param.Parameterized): __abstract = True bounds = BoundingBox(points=((-0.5, -0.5), (0.5, 0.5))) xdensity = 256 ydensity = 256 x = 0.0 y = 0.0 z = None group = 'Pattern' position = param.Composite(attribs=['x', 'y']) orientation = 0.0 size = 1.0 scale = 1.0 offset = 0.0 output_fns = [] def __init__(self, **params): super(PatternGenerator, self).__init__(**params) def __call__(self, **kwargs): pass def channels(self, **params): pass def num_channels(self): return 1 def function(self, p): pass
def setUp(self): self.left = -0.1 self.bottom = -0.2 self.right = 0.3 self.top = 0.4 self.lbrt = (self.left,self.bottom,self.right,self.top) self.region = BoundingBox(points = ((self.left,self.bottom),(self.right,self.top))) self.xc,self.yc = self.region.aarect().centroid()
class TestBoundingBox(unittest.TestCase): def setUp(self): self.left = -0.1 self.bottom = -0.2 self.right = 0.3 self.top = 0.4 self.lbrt = (self.left, self.bottom, self.right, self.top) self.region = BoundingBox(points=((self.left, self.bottom), (self.right, self.top))) self.xc, self.yc = self.region.aarect().centroid() def test_way_inside(self): self.assert_(self.region.contains(0, 0)) def test_above(self): self.failIf(self.region.contains(0, 1)) def test_below(self): self.failIf(self.region.contains(0, -1)) def test_left_of(self): self.failIf(self.region.contains(-1, 0)) def test_right_of(self): self.failIf(self.region.contains(1, 0)) def test_centroid_x(self): self.assertEqual(self.xc, (self.left + self.right) / 2.0) def test_centroid_y(self): self.assertEqual(self.yc, (self.bottom + self.top) / 2.0) def test_left_boundary(self): self.assert_(self.region.contains(self.left, self.yc)) def test_right_boundary(self): self.assert_(self.region.contains(self.right, self.yc)) def test_bottom_boundary(self): self.assert_(self.region.contains(self.xc, self.bottom)) def test_top_boundary(self): self.assert_(self.region.contains(self.xc, self.top))
def _set_image(self, image): # Stores a SheetCoordinateSystem with an activity matrix # representing the image if not isinstance(image, np.ndarray): image = np.array(image, np.float) rows, cols = image.shape self.scs = SheetCoordinateSystem( xdensity=1.0, ydensity=1.0, bounds=BoundingBox(points=((-cols / 2.0, -rows / 2.0), (cols / 2.0, rows / 2.0)))) self.scs.activity = image
def test_bounds_unequal(self): try: self.assertEqual(BoundingBox(radius=0.5), BoundingBox(radius=0.7)) except AssertionError as e: self.assertEqual( str(e), "BoundingBox(radius=0.5) != BoundingBox(radius=0.7)")
def test_bounds_equal(self): self.assertEqual(BoundingBox(radius=0.5), BoundingBox(radius=0.5))
size=p[1], orientation=p[0], phase=p[3], xdensity=x, ydensity=y)() if BlackBackground: assert T[idx_proto][idx_shift].max() <= 1.0 and T[idx_proto][idx_shift].min() >= 0 T[idx_proto][idx_shift] = 1 - T[idx_proto][idx_shift] idx_shift += 1 idx_proto += 1 return T if __name__ == '__main__': # image size x = 800/1.2 y = 800/1.2 Bound = BoundingBox(radius=0.6) BlackBackground = True # convert image to black background phase_shift = False # generate different phases f = 4 SpG = SpiralG(x, y, BlackBackground, phase_shift, Bound, frames=f) sio.savemat('SpG_b.mat', {'imgs': SpG}) # ############ waves # SG = SineG(x, y, BlackBackground, phase_shift, Bound, frames=f) # SpG = SpiralG(x, y, BlackBackground, phase_shift, Bound, frames=f) # T = Targets(x, y, BlackBackground, phase_shift, Bound, frames=f) # HG = HyperG(x, y, BlackBackground, phase_shift, Bound, frames=f) # RG = RadialG(x, y, BlackBackground, phase_shift, Bound, frames=f) # # ############## save images to .mat file
class CFProjection(Projection): """ A projection composed of ConnectionFields from a Sheet into a ProjectionSheet. CFProjection computes its activity using a response_fn of type CFPResponseFn (typically a CF-aware version of mdot) and output_fns (typically none). The initial contents of the ConnectionFields mapping from the input Sheet into the target ProjectionSheet are controlled by the weights_generator, cf_shape, and weights_output_fn parameters, while the location of the ConnectionField is controlled by the coord_mapper parameter. Any subclass has to implement the interface activate(self,input_activity) that computes the response from the input and stores it in the activity array. """ response_fn = param.ClassSelector( CFPResponseFn, default=CFPRF_Plugin(), doc= 'Function for computing the Projection response to an input pattern.') cf_type = param.Parameter( default=ConnectionField, constant=True, doc="Type of ConnectionField to use when creating individual CFs.") # JPHACKALERT: Not all support for null CFs has been implemented. # CF plotting and C-optimized CFPxF_ functions need # to be fixed to support null CFs without crashing. allow_null_cfs = param.Boolean( default=False, doc="Whether or not the projection can have entirely empty CFs") nominal_bounds_template = BoundingRegionParameter( default=BoundingBox(radius=0.1), doc=""" Bounds defining the Sheet area covered by a prototypical ConnectionField. The true bounds will differ depending on the density (see create_slice_template()).""" ) weights_generator = param.ClassSelector( PatternGenerator, default=patterngenerator.Constant(), constant=True, doc="Generate initial weights values.") cf_shape = param.ClassSelector( PatternGenerator, default=patterngenerator.Constant(), constant=True, doc="Mask pattern to define the shape of the connection fields.") same_cf_shape_for_all_cfs = param.Boolean(default=True, doc=""" Whether or not to share a single cf_shape mask for all CFs. If True, the cf_shape is evaluated only once and shared for all CFs, which saves computation time and memory. If False, the cf_shape is evaluated once for each CF, allowing each to have its own shape.""") learning_fn = param.ClassSelector( CFPLearningFn, default=CFPLF_Plugin(), doc= 'Function for computing changes to the weights based on one activation step.' ) # JABALERT: Shouldn't learning_rate be owned by the learning_fn? learning_rate = param.Number(default=0.0, softbounds=(0, 100), doc=""" Amount of learning at each step for this projection, specified in units that are independent of the density of each Sheet.""") weights_output_fns = param.HookList( default=[CFPOF_Plugin()], class_=CFPOutputFn, doc='Functions applied to each CF after learning.') strength = param.Number(default=1.0, doc=""" Global multiplicative scaling applied to the Activity of this Sheet.""" ) coord_mapper = param.ClassSelector( CoordinateMapperFn, default=IdentityMF(), doc='Function to map a projected coordinate into the target sheet.') # CEBALERT: this is temporary (allows c++ matching in certain # cases). We will allow the user to override the mask size, but # by offering a scaling parameter. autosize_mask = param.Boolean(default=True, constant=True, precedence=-1, doc=""" Topographica sets the mask size so that it is the same as the connection field's size, unless this parameter is False - in which case the user-specified size of the cf_shape is used. In normal usage of Topographica, this parameter should remain True.""") mask_threshold = param.Number(default=0.5, constant=True, doc=""" If a unit is above this value in the cf_shape mask, it is included; otherwise it is excluded from the mask.""") apply_output_fns_init = param.Boolean(default=True, doc=""" Whether to apply the output function to connection fields (e.g. for normalization) when the CFs are first created.""") min_matrix_radius = param.Integer(default=1, bounds=(0, None), doc=""" Enforced minimum for radius of weights matrix. The default of 1 gives a minimum matrix of 3x3. 0 would allow a 1x1 matrix.""") hash_format = param.String(default="{name}-{src}-{dest}", doc=""" Format string to determine the hash value used to initialize random weight generation. Format keys available include {name} {src} and {dest}.""") seed = param.Integer(default=None, allow_None=True, doc=""" The random seed used to determine the randomized weight initialization stream. If not None, equivalent to appending the chosen integer to the hash_format.""") precedence = param.Number(default=0.8) def __init__(self, initialize_cfs=True, **params): """ Initialize the Projection with a set of cf_type objects (typically ConnectionFields), each located at the location in the source sheet corresponding to the unit in the target sheet. The cf_type objects are stored in the 'cfs' array. The nominal_bounds_template specified may be altered: the bounds must be fitted to the Sheet's matrix, and the weights matrix must have odd dimensions. These altered bounds are passed to the individual connection fields. A mask for the weights matrix is constructed. The shape is specified by cf_shape; the size defaults to the size of the nominal_bounds_template. """ super(CFProjection, self).__init__(**params) self.weights_generator.set_dynamic_time_fn(None, sublistattr='generators') # get the actual bounds_template by adjusting a copy of the # nominal_bounds_template to ensure an odd slice, and to be # cropped to sheet if necessary self._slice_template = Slice(copy(self.nominal_bounds_template), self.src, force_odd=True, min_matrix_radius=self.min_matrix_radius) self.bounds_template = self._slice_template.compute_bounds(self.src) self.mask_template = _create_mask(self.cf_shape, self.bounds_template, self.src, self.autosize_mask, self.mask_threshold) self.n_units = self._calc_n_units() if initialize_cfs: self._create_cfs() if self.apply_output_fns_init: self.apply_learn_output_fns(active_units_mask=False) ### JCALERT! We might want to change the default value of the ### input value to self.src.activity; but it fails, raising a ### type error. It probably has to be clarified why this is ### happening self.input_buffer = None self.activity = np.array(self.dest.activity) if 'cfs' not in self.dest.views: self.dest.views.CFs = Layout() self.dest.views.CFs[self.name] = self._cf_grid() def _cf_grid(self, shape=None, **kwargs): "Create GridSpace with the correct metadata." grid = GridSpace({}) grid.metadata = AttrDict(timestamp=self.src.simulation.time(), info=self.name, proj_src_name=self.src.name, proj_dest_name=self.dest.name, **kwargs) return grid def _generate_coords(self): X, Y = self.dest.sheetcoords_of_idx_grid() vectorized_coord_mapper = simple_vectorize( self.coord_mapper, num_outputs=2, # CB: could switch to float32? output_type=float) return vectorized_coord_mapper(X, Y) # CB: should be _initialize_cfs() since we already have 'initialize_cfs' flag? def _create_cfs(self): vectorized_create_cf = simple_vectorize(self._create_cf) self.cfs = vectorized_create_cf(*self._generate_coords()) self.flatcfs = list(self.cfs.flat) def _create_cf(self, x, y): """ Create a ConnectionField at x,y in the src sheet. """ # (to restore would need to have an r,c counter) # self.debug("Creating CF(%d,%d) from src (%.3f,%.3f) to dest (%.3f,%.3f)"%(r,c,x_cf,y_cf,x,y)) label = self.hash_format.format(name=self.name, src=self.src.name, dest=self.dest.name) label = label + ('-%d' % self.seed if self.seed is not None else '') name = "%s_CF (%.5f, %.5f)" % ('' if label is None else label, x, y) try: if self.same_cf_shape_for_all_cfs: mask_template = self.mask_template else: mask_template = _create_mask(self.cf_shape, self.bounds_template, self.src, self.autosize_mask, self.mask_threshold, name=name) CF = self.cf_type(self.src, x=x, y=y, template=self._slice_template, weights_generator=self.weights_generator, mask=mask_template, min_matrix_radius=self.min_matrix_radius, label=label) except NullCFError: if self.allow_null_cfs: CF = None else: raise return CF def _calc_n_units(self): """Return the number of unmasked units in a typical ConnectionField.""" return min( len(self.mask_template.ravel().nonzero()[0]), # CEBALERT: if the mask_template is bigger than the # src sheet (e.g. conn radius bigger than src # radius), return the size of the source sheet self.src.shape[0] * self.src.shape[1]) def cf(self, r, c): """Return the specified ConnectionField""" # CB: should we offer convenience cf(x,y) (i.e. sheetcoords) method instead? self.warning( "CFProjection.cf(r,c) is deprecated: use cfs[r,c] instead") return self.cfs[r, c] def cf_bounds(self, r, c): """Return the bounds of the specified ConnectionField.""" return self.cfs[r, c].get_bounds(self.src) def grid(self, rows=11, cols=11, lbrt=None, situated=False, **kwargs): xdensity, ydensity = self.dest.xdensity, self.dest.ydensity l, b, r, t = self.dest.bounds.lbrt() half_x_unit = ((r - l) / xdensity) / 2. half_y_unit = ((t - b) / ydensity) / 2. if lbrt is None: l, b, r, t = (l + half_x_unit, b + half_y_unit, r - half_x_unit, t - half_y_unit) else: l, b = self.dest.closest_cell_center(lbrt[0], lbrt[1]) r, t = self.dest.closest_cell_center(lbrt[2], lbrt[3]) x, y = np.meshgrid(np.linspace(l, r, cols), np.linspace(b, t, rows)) coords = zip(x.flat, y.flat) grid_items = {} for x, y in coords: grid_items[x, y] = self.view(x, y, situated=situated, **kwargs) grid = GridSpace(grid_items, label=' '.join([self.dest.name, self.name]), group='CFs') grid.metadata = AttrDict(info=self.name, proj_src_name=self.src.name, proj_dest_name=self.dest.name, timestamp=self.src.simulation.time(), **kwargs) return grid def view(self, sheet_x, sheet_y, timestamp=None, situated=False, **kwargs): """ Return a single connection field Image, for the unit located nearest to sheet coordinate (sheet_x,sheet_y). """ if timestamp is None: timestamp = self.src.simulation.time() time_dim = Dimension("Time", type=param.Dynamic.time_fn.time_type) (r, c) = self.dest.sheet2matrixidx(sheet_x, sheet_y) cf = self.cfs[r, c] r1, r2, c1, c2 = cf.input_sheet_slice situated_shape = self.src.activity.shape situated_bounds = self.src.bounds roi_bounds = cf.get_bounds(self.src) if situated: matrix_data = np.zeros(situated_shape, dtype=np.float64) matrix_data[r1:r2, c1:c2] = cf.weights.copy() bounds = situated_bounds else: matrix_data = cf.weights.copy() bounds = roi_bounds sv = CFView(matrix_data, bounds, situated_bounds=situated_bounds, input_sheet_slice=(r1, r2, c1, c2), roi_bounds=roi_bounds, label=self.name, group='CF Weight') sv.metadata = AttrDict(timestamp=timestamp) viewmap = HoloMap((timestamp, sv), kdims=[time_dim]) viewmap.metadata = AttrDict(coords=(sheet_x, sheet_y), dest_name=self.dest.name, precedence=self.src.precedence, proj_name=self.name, src_name=self.src.name, row_precedence=self.src.row_precedence, timestamp=timestamp, **kwargs) return viewmap def get_view(self, sheet_x, sheet_y, timestamp=None): self.warning("Deprecated, call 'view' method instead.") return self.view(sheet_x, sheet_y, timestamp) def activate(self, input_activity): """Activate using the specified response_fn and output_fn.""" if self.input_fns: input_activity = input_activity.copy() for iaf in self.input_fns: iaf(input_activity) self.input_buffer = input_activity self.activity *= 0.0 self.response_fn(CFIter(self), input_activity, self.activity, self.strength) for of in self.output_fns: of(self.activity) # CEBALERT: should add active_units_mask to match # apply_learn_output_fns. def learn(self): """ For a CFProjection, learn consists of calling the learning_fn. """ # Learning is performed if the input_buffer has already been set, # i.e. there is an input to the Projection. if self.input_buffer is not None: self.learning_fn(CFIter(self), self.input_buffer, self.dest.activity, self.learning_rate) # CEBALERT: called 'learn' output fns here, but called 'weights' output fns # elsewhere (mostly). Change all to 'learn'? def apply_learn_output_fns(self, active_units_mask=True): """ Apply the weights_output_fns to each unit. If active_units_mask is True, inactive units will be skipped. """ for of in self.weights_output_fns: of(CFIter(self, active_units_mask=active_units_mask)) # CEBALERT: see gc alert in simulation.__new__ def _cleanup(self): for cf in self.cfs.flat: # cf could be None or maybe something else if hasattr(cf, 'input_sheet'): cf.input_sheet = None if hasattr(cf, 'input_sheet_slice'): cf.input_sheet_slice = None if hasattr(cf, 'weights_slice'): cf.weights_slice = None def n_bytes(self): # Could also count the input_sheet_slice rows, cols = self.cfs.shape return super(CFProjection,self).n_bytes() + \ sum([cf.weights.nbytes + cf.mask.nbytes for cf,i in CFIter(self,ignore_sheet_mask=True)()]) def n_conns(self): # Counts non-masked values, if mask is available; otherwise counts # weights as connections if nonzero rows, cols = self.cfs.shape return np.sum([ len((cf.mask if cf.mask is not None else cf.weights).ravel().nonzero()[0]) for cf, i in CFIter(self)() ])
def __init__(self, input_sheet, x=0.0, y=0.0, template=BoundingBox(radius=0.1), weights_generator=patterngenerator.Constant(), mask=patterngenerator.Constant(), output_fns=None, min_matrix_radius=1, label=None): """ Create weights at the specified (x,y) location on the specified input_sheet. The supplied template (if a BoundingRegion) is converted to a Slice, moved to the specified (x,y) location, and then the weights pattern is drawn inside by the weights_generator. Note that if the appropriate template Slice is already known, then it can be passed in instead of a BoundingRegion template. This slice will then be used directly, instead of converting the template into a Slice. The supplied template object itself will not be modified (it is copied before use). The mask allows the weights to be limited to being non-zero in a subset of the rectangular weights area. The actual mask used is a view of the given mask created by cropping to the boundaries of the input_sheet, so that the weights all correspond to actual locations in the input sheet. For instance, if a circular pattern of weights is desired, the mask should have a disk-shaped pattern of elements with value 1, surrounded by elements with the value 0. If the CF extends over the edge of the input sheet then the weights will actually be half-moon (or similar) rather than circular. """ #print "Create CF",input_sheet.name,x,y,"template=",template,"wg=",weights_generator,"m=",mask,"ofs=",output_fns,"min r=",min_matrix_radius template = copy(template) if not isinstance(template, Slice): template = Slice(template, input_sheet, force_odd=True, min_matrix_radius=min_matrix_radius) # Note: if passed in, mask is shared between CFs (but not if created here) if not hasattr(mask, 'view'): mask = _create_mask( mask, template.compute_bounds(input_sheet), # CEBALERT: it's not really worth adding more ALERTs on this # topic, but...there's no way for the CF to control autosize # and threshold. input_sheet, True, 0.5) # CB: has to be set for C code. Can't be initialized at the # class level, or it would become a read-only class attribute # (because it's a slot: # http://docs.python.org/reference/datamodel.html). Can we # somehow avoid having to think about _has_norm_total in the # python code? Could the C code initialize this value? self._has_norm_total = np.array([0], dtype=np.int32) self._norm_total = np.array([0.0], dtype=np.float64) if output_fns is None: output_fns = [] # CEBALERT: now even more confusing; weights_slice is # different from input_sheet_slice. At least need to rename. weights_slice = self._create_input_sheet_slice(input_sheet, x, y, template, min_matrix_radius) # CBNOTE: this would be clearer (but not perfect, and probably slower) # m = mask_template[self.weights_slice()] self.mask = weights_slice.submatrix(mask) # view of original mask self.mask = np.array(self.mask, copy=1) # CEBALERT: why is this necessary? # (without it, optimized learning function creates artifacts in CFs at # left and right edges of sheet, at some densities) # CBENHANCEMENT: might want to do something about a size # that's specified (right now the size is assumed to be that # of the bounds) # shouldn't be extra computation of boundingbox because it's gone from Slice.__init__; could avoid extra lookups by getting straight from slice pattern_params = dict(x=x, y=y, bounds=self.get_bounds(input_sheet), xdensity=input_sheet.xdensity, ydensity=input_sheet.ydensity, mask=self.mask) controlled_weights = (param.Dynamic.time_dependent and isinstance(param.Dynamic.time_fn, param.Time) and self.independent_weight_generation) if controlled_weights: with param.Dynamic.time_fn as t: t(0) # Initialize weights at time zero. # Controls random streams name = "%s_CF (%.5f, %.5f)" % ('' if label is None else label, x, y) w = weights_generator(**dict(pattern_params, name=name)) else: w = weights_generator(**pattern_params) # CEBALERT: unnecessary copy! Pass type to PG & have it draw # in that. (Should be simple, except making it work for all # the PG subclasses that override array creation in various # ways (producing or using inconsistent types) turned out to # be too painful.) self.weights = w.astype(weight_type) # CEBHACKALERT: the system of masking through multiplication # by 0 works for now, while the output_fns are all # multiplicative. But in the long run we need a better way to # apply the mask. The same applies anywhere the mask is used, # including in learningfn/. We should investigate masked # arrays (from numpy). for of in output_fns: of(self.weights)
ydensity=y)() if BlackBackground: assert SpG[idx_proto][idx_shift].max( ) <= 1.0 and SpG[idx_proto][idx_shift].min() >= 0 SpG[idx_proto][idx_shift] = 1 - SpG[idx_proto][idx_shift] idx_shift += 1 idx_proto += 1 return SpG if __name__ == '__main__': # image size x = 192 y = 192 Bound = BoundingBox(radius=1) BlackBackground = True # convert image to black background phase_shift = False # generate different phases f = 4 ############ waves SpG = SpiralG(x, y, BlackBackground, phase_shift, Bound, frames=f) ############## save images to .mat file if phase_shift: if BlackBackground: sio.savemat('SpG_shift_b.mat', {'imgs': SpG}) else: sio.savemat('SpG_shift_w.mat', {'imgs': SpG}) else: if BlackBackground:
class PatternGenerator(param.Parameterized): """ A class hierarchy for callable objects that can generate 2D patterns. Once initialized, PatternGenerators can be called to generate a value or a matrix of values from a 2D function, typically accepting at least x and y. A PatternGenerator's Parameters can make use of Parameter's precedence attribute to specify the order in which they should appear, e.g. in a GUI. The precedence attribute has a nominal range of 0.0 to 1.0, with ordering going from 0.0 (first) to 1.0 (last), but any value is allowed. The orientation and layout of the pattern matrices is defined by the SheetCoordinateSystem class, which see. Note that not every parameter defined for a PatternGenerator will be used by every subclass. For instance, a Constant pattern will ignore the x, y, orientation, and size parameters, because the pattern does not vary with any of those parameters. However, those parameters are still defined for all PatternGenerators, even Constant patterns, to allow PatternGenerators to be scaled, rotated, translated, etc. uniformly. """ __abstract = True bounds = BoundingRegionParameter( default=BoundingBox(points=((-0.5, -0.5), (0.5, 0.5))), precedence=-1, doc="BoundingBox of the area in which the pattern is generated.") xdensity = param.Number(default=256, bounds=(0, None), precedence=-1, doc=""" Density (number of samples per 1.0 length) in the x direction.""") ydensity = param.Number(default=256, bounds=(0, None), precedence=-1, doc=""" Density (number of samples per 1.0 length) in the y direction. Typically the same as the xdensity.""") x = param.Number(default=0.0, softbounds=(-1.0, 1.0), precedence=0.20, doc=""" X-coordinate location of pattern center.""") y = param.Number(default=0.0, softbounds=(-1.0, 1.0), precedence=0.21, doc=""" Y-coordinate location of pattern center.""") z = param.ClassSelector(default=None, precedence=-1, class_=Dimension, doc=""" The Dimension object associated with the z-values generated by the PatternGenerator . If None, uses the default set by HoloViews.Image.""") group = param.String(default='Pattern', precedence=-1, doc=""" The group name assigned to the returned HoloViews object.""") position = param.Composite(attribs=['x', 'y'], precedence=-1, doc=""" Coordinates of location of pattern center. Provides a convenient way to set the x and y parameters together as a tuple (x,y), but shares the same actual storage as x and y (and thus only position OR x and y need to be specified).""") orientation = param.Number(default=0.0, softbounds=(0.0, 2 * pi), precedence=0.40, doc=""" Polar angle of pattern, i.e., the orientation in the Cartesian coordinate system, with zero at 3 o'clock and increasing counterclockwise.""") size = param.Number(default=1.0, bounds=(0.0, None), softbounds=(0.0, 6.0), precedence=0.30, doc="""Determines the overall size of the pattern.""") scale = param.Number(default=1.0, softbounds=(0.0, 2.0), precedence=0.10, doc=""" Multiplicative strength of input pattern, defaulting to 1.0""") offset = param.Number(default=0.0, softbounds=(-1.0, 1.0), precedence=0.11, doc=""" Additive offset to input pattern, defaulting to 0.0""") mask = param.Parameter(default=None, precedence=-1, doc=""" Optional object (expected to be an array) with which to multiply the pattern array after it has been created, before any output_fns are applied. This can be used to shape the pattern.""") # Note that the class type is overridden to PatternGenerator below mask_shape = param.ClassSelector(param.Parameterized, default=None, precedence=0.06, doc=""" Optional PatternGenerator used to construct a mask to be applied to the pattern.""") output_fns = param.HookList(default=[], precedence=0.08, doc=""" Optional function(s) to apply to the pattern array after it has been created. Can be used for normalization, thresholding, etc.""") def __init__(self, **params): super(PatternGenerator, self).__init__(**params) self.set_matrix_dimensions(self.bounds, self.xdensity, self.ydensity) def __call__(self, **params_to_override): """ Call the subclass's 'function' method on a rotated and scaled coordinate system. Creates and fills an array with the requested pattern. If called without any params, uses the values for the Parameters as currently set on the object. Otherwise, any params specified override those currently set on the object. """ if 'output_fns' in params_to_override: self.warning( "Output functions specified through the call method will be ignored." ) p = ParamOverrides(self, params_to_override) # CEBERRORALERT: position parameter is not currently # supported. We should delete the position parameter or fix # this. # # position=params_to_override.get('position',None) if position # is not None: x,y = position self._setup_xy(p.bounds, p.xdensity, p.ydensity, p.x, p.y, p.orientation) fn_result = self.function(p) self._apply_mask(p, fn_result) if p.scale != 1.0: result = p.scale * fn_result else: result = fn_result if p.offset != 0.0: result += p.offset for of in p.output_fns: of(result) return result def __getitem__(self, coords): value_dims = {} if self.num_channels() in [0, 1]: raster, data = Image, self() value_dims = { 'value_dimensions': [self.z] } if self.z else value_dims elif self.num_channels() in [3, 4]: raster = RGB data = np.dstack(self.channels().values()[1:]) image = raster(data, bounds=self.bounds, **dict(group=self.group, label=self.__class__.__name__, **value_dims)) # Works round a bug fixed shortly after HoloViews 1.0.0 release return image if isinstance(coords, slice) else image.__getitem__(coords) def channels(self, use_cached=False, **params_to_override): """ Channels() adds a shared interface for single channel and multichannel structures. It will always return an ordered dict: its first element is the single channel of the pattern (if single-channel) or the channel average (if multichannel); the successive elements are the individual channels' arrays (key: 0,1,..N-1). """ return collections.OrderedDict( {'default': self.__call__(**params_to_override)}) def num_channels(self): """ Query the number of channels implemented by the PatternGenerator. In case of single-channel generators this will return 1; in case of multichannel, it will return the number of channels (eg, in the case of RGB images it would return '3', Red-Green-Blue, even though the OrderedDict returned by channels() will have 4 elements -- the 3 channels + their average). """ return 1 def _setup_xy(self, bounds, xdensity, ydensity, x, y, orientation): """ Produce pattern coordinate matrices from the bounds and density (or rows and cols), and transforms them according to x, y, and orientation. """ self.debug( "bounds=%s, xdensity=%s, ydensity=%s, x=%s, y=%s, orientation=%s", bounds, xdensity, ydensity, x, y, orientation) # Generate vectors representing coordinates at which the pattern # will be sampled. # CB: note to myself - use slice_._scs if supplied? x_points, y_points = SheetCoordinateSystem( bounds, xdensity, ydensity).sheetcoordinates_of_matrixidx() # Generate matrices of x and y sheet coordinates at which to # sample pattern, at the correct orientation self.pattern_x, self.pattern_y = self._create_and_rotate_coordinate_arrays( x_points - x, y_points - y, orientation) def function(self, p): """ Function to draw a pattern that will then be scaled and rotated. Instead of implementing __call__ directly, PatternGenerator subclasses will typically implement this helper function used by __call__, because that way they can let __call__ handle the scaling and rotation for them. Alternatively, __call__ itself can be reimplemented entirely by a subclass (e.g. if it does not need to do any scaling or rotation), in which case this function will be ignored. """ raise NotImplementedError def _create_and_rotate_coordinate_arrays(self, x, y, orientation): """ Create pattern matrices from x and y vectors, and rotate them to the specified orientation. """ # Using this two-liner requires that x increase from left to # right and y decrease from left to right; I don't think it # can be rewritten in so little code otherwise - but please # prove me wrong. pattern_y = np.subtract.outer( np.cos(orientation) * y, np.sin(orientation) * x) pattern_x = np.add.outer( np.sin(orientation) * y, np.cos(orientation) * x) return pattern_x, pattern_y def _apply_mask(self, p, mat): """Create (if necessary) and apply the mask to the given matrix mat.""" mask = p.mask ms = p.mask_shape if ms is not None: mask = ms( x=p.x + p.size * (ms.x * np.cos(p.orientation) - ms.y * np.sin(p.orientation)), y=p.y + p.size * (ms.x * np.sin(p.orientation) + ms.y * np.cos(p.orientation)), orientation=ms.orientation + p.orientation, size=ms.size * p.size, bounds=p.bounds, ydensity=p.ydensity, xdensity=p.xdensity) if mask is not None: mat *= mask def set_matrix_dimensions(self, bounds, xdensity, ydensity): """ Change the dimensions of the matrix into which the pattern will be drawn. Users of this class should call this method rather than changing the bounds, xdensity, and ydensity parameters directly. Subclasses can override this method to update any internal data structures that may depend on the matrix dimensions. """ self.bounds = bounds self.xdensity = xdensity self.ydensity = ydensity scs = SheetCoordinateSystem(bounds, xdensity, ydensity) for of in self.output_fns: if isinstance(of, TransferFn): of.initialize(SCS=scs, shape=scs.shape) def state_push(self): "Save the state of the output functions, to be restored with state_pop." for of in self.output_fns: if hasattr(of, 'state_push'): of.state_push() super(PatternGenerator, self).state_push() def state_pop(self): "Restore the state of the output functions saved by state_push." for of in self.output_fns: if hasattr(of, 'state_pop'): of.state_pop() super(PatternGenerator, self).state_pop() def anim(self, duration, offset=0, timestep=1, label=None, unit=None, time_fn=param.Dynamic.time_fn): """ duration: The temporal duration to animate in the units defined on the global time function. offset: The temporal offset from which the animation is generated given the supplied pattern timestep: The time interval between successive frames. The duration must be an exact multiple of the timestep. label: A label string to override the label of the global time function (if not None). unit: The unit string to override the unit value of the global time function (if not None). time_fn: The global time function object that is shared across the time-varying objects that are being sampled. Note that the offset, timestep and time_fn only affect patterns parameterized by time-dependent number generators. Otherwise, the frames are generated by successive call to the pattern which may or may not be varying (e.g to view the patterns contained within a Selector). """ frames = (duration // timestep) + 1 if duration % timestep != 0: raise ValueError( "The duration value must be an exact multiple of the timestep." ) if label is None: label = time_fn.label if hasattr(time_fn, 'label') else 'Time' unit = time_fn.unit if (not unit and hasattr(time_fn, 'unit')) else unit vmap = HoloMap( key_dimensions=[Dimension(label, unit=unit if unit else '')]) self.state_push() with time_fn as t: t(offset) for i in range(frames): vmap[t()] = self[:] t += timestep self.state_pop() return vmap ## Support for compositional expressions of PatternGenerator objects def _promote(self, other): if not isinstance(other, PatternGenerator): other = Constant(scale=other, offset=0) return [self, other] def _rpromote(self, other): if not isinstance(other, PatternGenerator): other = Constant(scale=other, offset=0) return [other, self] # Could define any of Python's operators here, esp. if they have operator or ufunc equivalents def __add__(self, other): return Composite(generators=self._promote(other), operator=np.add) def __sub__(self, other): return Composite(generators=self._promote(other), operator=np.subtract) def __mul__(self, other): return Composite(generators=self._promote(other), operator=np.multiply) def __mod__(self, other): return Composite(generators=self._promote(other), operator=np.mod) def __pow__(self, other): return Composite(generators=self._promote(other), operator=np.power) def __div__(self, other): return Composite(generators=self._promote(other), operator=np.divide) def __and__(self, other): return Composite(generators=self._promote(other), operator=np.minimum) def __or__(self, other): return Composite(generators=self._promote(other), operator=np.maximum) def __radd__(self, other): return Composite(generators=self._rpromote(other), operator=np.add) def __rsub__(self, other): return Composite(generators=self._rpromote(other), operator=np.subtract) def __rmul__(self, other): return Composite(generators=self._rpromote(other), operator=np.multiply) def __rmod__(self, other): return Composite(generators=self._rpromote(other), operator=np.mod) def __rpow__(self, other): return Composite(generators=self._rpromote(other), operator=np.power) def __rdiv__(self, other): return Composite(generators=self._rpromote(other), operator=np.divide) def __rand__(self, other): return Composite(generators=self._rpromote(other), operator=np.minimum) def __ror__(self, other): return Composite(generators=self._rpromote(other), operator=np.maximum) def __neg__(self): return Composite(generators=[Constant(scale=0), self], operator=np.subtract) class abs_first(object): @staticmethod def reduce(x): return np.abs(x[0]) def __abs__(self): return Composite(generators=[self], operator=self.abs_first) def pil(self, **params_to_override): """Returns a PIL image for this pattern, overriding parameters if provided.""" from PIL.Image import fromarray nchans = self.num_channels() if nchans in [0, 1]: mode, arr = None, self(**params_to_override) arr = (255.0 / arr.max() * (arr - arr.min())).astype(np.uint8) elif nchans in [3, 4]: mode = 'RGB' if nchans == 3 else 'RGBA' arr = np.dstack(self.channels(**params_to_override).values()[1:]) arr = (255.0 * arr).astype(np.uint8) else: raise ValueError("Unsupported number of channels") return fromarray(arr, mode)
class Sheet(EventProcessor, SheetCoordinateSystem): # pylint: disable-msg=W0223 """ The generic base class for neural sheets. See SheetCoordinateSystem for how Sheet represents space, and EventProcessor for how Sheet handles time. output_fns are functions that take an activity matrix and produce an identically shaped output matrix. The default is having no output_fns. """ __abstract = True nominal_bounds = BoundingRegionParameter(BoundingBox(radius=0.5), constant=True, doc=""" User-specified BoundingBox of the Sheet coordinate area covered by this Sheet. The left and right bounds--if specified--will always be observed, but the top and bottom bounds may be adjusted to ensure the density in the y direction is the same as the density in the x direction. In such a case, the top and bottom bounds are adjusted so that the center y point remains the same, and each bound is as close as possible to its specified value. The actual value of this Parameter is not adjusted, but the true bounds may be found from the 'bounds' attribute of this object. """) nominal_density = param.Number(default=10, constant=True, doc=""" User-specified number of processing units per 1.0 distance horizontally or vertically in Sheet coordinates. The actual number may be different because of discretization; the matrix needs to tile the plane exactly, and for that to work the density might need to be adjusted. For instance, an area of 3x2 cannot have a density of 2 in each direction. The true density may be obtained from either the xdensity or ydensity attribute (since these are identical for a Sheet). """) plastic = param.Boolean(True, doc=""" Setting this to False tells the Sheet not to change its permanent state (e.g. any connection weights) based on incoming events. """) precedence = param.Number(default=0.1, softbounds=(0.0, 1.0), doc=""" Allows a sorting order for Sheets, e.g. in the GUI.""") row_precedence = param.Number(default=0.5, softbounds=(0.0, 1.0), doc=""" Allows grouping of Sheets before sorting precedence is applied, e.g. for two-dimensional plots in the GUI.""") layout_location = param.NumericTuple(default=(-1, -1), precedence=-1, doc=""" Location for this Sheet in an arbitrary pixel-based space in which Sheets can be laid out for visualization.""") output_fns = param.HookList( default=[], class_=TransferFn, doc= "Output function(s) to apply (if apply_output_fns is true) to this Sheet's activity." ) apply_output_fns = param.Boolean( default=True, doc="Whether to apply the output_fn after computing an Activity matrix." ) properties = param.Dict(default={}, doc=""" A dictionary of property values associated with the Sheet object. For instance, the dictionary: {'polarity':'ON', 'eye':'Left'} could be used to indicate a left, LGN Sheet with ON-surround receptive fields.""") def _get_density(self): return self.xdensity density = property(_get_density, doc="""The sheet's true density (i.e. the xdensity, which is equal to the ydensity for a Sheet.)""") def __init__(self, **params): """ Initialize this object as an EventProcessor, then also as a SheetCoordinateSystem with equal xdensity and ydensity. views is a Layout, which stores associated measurements, i.e. representations of the sheet for use by analysis or plotting code. """ EventProcessor.__init__(self, **params) # Initialize this object as a SheetCoordinateSystem, with # the same density along y as along x. SheetCoordinateSystem.__init__(self, self.nominal_bounds, self.nominal_density) n_units = round((self.lbrt[2] - self.lbrt[0]) * self.xdensity, 0) if n_units < 1: raise ValueError( "Sheet bounds and density must be specified such that the "+ \ "sheet has at least one unit in each direction; " \ +self.name+ " does not.") # setup the activity matrix self.activity = zeros(self.shape, activity_type) # For non-plastic inputs self.__saved_activity = [] self._plasticity_setting_stack = [] self.views = Layout() self.views.Maps = Layout() self.views.Curves = Layout() ### JABALERT: This should be deleted now that sheet_views is public ### JC: shouldn't we keep that, or at least write a function in ### utils that deletes a value in a dictinnary without returning an ### error if the key is not in the dict? I leave for the moment, ### and have to ask Jim to advise. def release_sheet_view(self, view_name): """ Delete the dictionary entry with key entry 'view_name' to save memory. """ if view_name in self.views.Maps: self.views.Maps[view_name] = None # CB: what to call this? sheetcoords()? sheetcoords_of_grid()? idxsheetcoords()? def sheetcoords_of_idx_grid(self): """ Return an array of x-coordinates and an array of y-coordinates corresponding to the activity matrix of the sheet. """ nrows, ncols = self.activity.shape C, R = meshgrid(arange(ncols), arange(nrows)) X, Y = self.matrixidx2sheet(R, C) return X, Y # CB: check whether we need this function any more. def row_col_sheetcoords(self): """ Return an array of Y-coordinates corresponding to the rows of the activity matrix of the sheet, and an array of X-coordinates corresponding to the columns. """ # The row and column centers are returned in matrix (not # sheet) order (hence the reversals below). nrows, ncols = self.activity.shape return self.matrixidx2sheet(arange(nrows - 1, -1, -1), arange(ncols))[::-1] # CBALERT: to be removed once other code uses # row_col_sheetcoords() or sheetcoords_of_idx_grid(). def sheet_rows(self): return self.row_col_sheetcoords()[0] def sheet_cols(self): return self.row_col_sheetcoords()[1] # CEBALERT: haven't really thought about what to put in this. The # way it is now, subclasses could make a super.activate() call to # avoid repeating some stuff. def activate(self): """ Collect activity from each projection, combine it to calculate the activity for this sheet, and send the result out. Subclasses will need to override this method to whatever it means to calculate activity in that subclass. """ if self.apply_output_fns: for of in self.output_fns: of(self.activity) self.send_output(src_port='Activity', data=self.activity) def state_push(self): """ Save the current state of this sheet to an internal stack. This method is used by operations that need to test the response of the sheet without permanently altering its state, e.g. for measuring maps or probing the current behavior non-invasively. By default, only the activity pattern of this sheet is saved, but subclasses should add saving for any additional state that they maintain, or strange bugs are likely to occur. The state can be restored using state_pop(). Note that Sheets that do learning need not save the values of all connection weights, if any, because plasticity can be turned off explicitly. Thus this method is intended only for shorter-term state. """ self.__saved_activity.append(array(self.activity)) EventProcessor.state_push(self) for of in self.output_fns: if hasattr(of, 'state_push'): of.state_push() def state_pop(self): """ Pop the most recently saved state off the stack. See state_push() for more details. """ self.activity = self.__saved_activity.pop() EventProcessor.state_pop(self) for of in self.output_fns: if hasattr(of, 'state_pop'): of.state_pop() def activity_len(self): """Return the number of items that have been saved by state_push().""" return len(self.__saved_activity) def override_plasticity_state(self, new_plasticity_state): """ Temporarily override plasticity of medium and long term internal state. This function should be implemented by all subclasses so that it preserves the ability of the Sheet to compute activity, i.e. to operate over a short time scale, while preventing any lasting changes to the state (if new_plasticity_state=False). Any operation that does not have any lasting state, such as those affecting only the current activity level, should not be affected by this call. By default, simply saves a copy of the plastic flag to an internal stack (so that it can be restored by restore_plasticity_state()), and then sets plastic to new_plasticity_state. """ self._plasticity_setting_stack.append(self.plastic) self.plastic = new_plasticity_state def restore_plasticity_state(self): """ Restores plasticity of medium and long term internal state after a override_plasticity_state call. This function should be implemented by all subclasses to remove the effect of the most recent override_plasticity_state call, i.e. to restore plasticity of any type that was overridden. """ self.plastic = self._plasticity_setting_stack.pop() def n_bytes(self): """ Return a lower bound for the memory taken by this sheet, in bytes. Typically, this number will include the activity array and any similar arrays, plus any other significant data owned (in some sense) by this Sheet. It will not usually include memory taken by the Python dictionary or various "housekeeping" attributes, which usually contribute only a small amount to the memory requirements. Subclasses should reimplement this method if they store a significant amount of data other than in the activity array. """ return self.activity.nbytes def __getitem__(self, coords): metadata = AttrDict(precedence=self.precedence, row_precedence=self.row_precedence, timestamp=self.simulation.time()) image = Image(self.activity.copy(), self.bounds, label=self.name, group='Activity')[coords] image.metadata = metadata return image
ydensity=y)() if BlackBackground: assert T[idx_proto][idx_shift].max( ) <= 1.0 and T[idx_proto][idx_shift].min() >= 0 T[idx_proto][idx_shift] = 1 - T[idx_proto][idx_shift] idx_shift += 1 idx_proto += 1 return T if __name__ == '__main__': # image size x = 24 y = 24 Bound = BoundingBox(radius=20.4) BlackBackground = True # convert image to black background phase_shift = False # generate different phases ############ waves SG = SineG(x, y, BlackBackground, phase_shift, Bound, frames=24) SpG = SpiralG(x, y, BlackBackground, phase_shift, Bound, frames=24) T = Targets(x, y, BlackBackground, phase_shift, Bound, frames=24) HG = HyperG(x, y, BlackBackground, phase_shift, Bound, frames=24) RG = RadialG(x, y, BlackBackground, phase_shift, Bound, frames=24) # ############## save images to .mat file if phase_shift: if BlackBackground: sio.savemat('SG_shift_b.mat', {'imgs': SG}) sio.savemat('HG_shift_b.mat', {'imgs': HG})
T[idx_proto][idx_shift] = 1 - T[idx_proto][idx_shift] idx_shift += 1 idx_proto += 1 return T if __name__ == '__main__': BlackBackground = True # convert image to black background phase_shift = False # generate different phases f = 4 # for training, to generate images used for slant and tilt Bound = BoundingBox(radius=2.08) # r = 2.08 for slant and tilt cropping #r=1.1 for all 159 set for scale in [1/1.2, 1, 1.2]: x = 192*scale y = 192*scale # ########### only the spirals for training SpG = SpiralG(x, y, BlackBackground, phase_shift, Bound, frames=f) save_name = 'SpG_b_scale{0:.2f}.mat'.format(scale) sio.savemat(save_name, {'imgs': SpG}) # # for 159 complete set # x = 192 # y = 192 # Bound = BoundingBox(radius=1.1) # r = 2.08 for slant and tilt cropping #r=1.1 for all 159 set
def test_bounds_equal_lbrt(self): self.assertEqual(BoundingBox(points=((-1, -1), (3, 4.5))), BoundingBox(points=((-1, -1), (3, 4.5))))
if BlackBackground: assert Ba[idx].max() <= 1.0 and Ba[idx].min >= 0 Ba[idx] = 1 - Ba[idx] idx += 1 return Ba if __name__ == '__main__': # image size # x = 256 # y = 256 # Bound = BoundingBox(radius=1.16) x = 256 y = 256 Bound = BoundingBox(radius=0.58 * 2) BlackBackground = True # convert image to black background jetter = False # add perturbations # ############# waves SG = SineG(x, y, BlackBackground, jetter, Bound) HG = HyperG(x, y, BlackBackground, jetter, Bound) SpG = SpiralG(x, y, BlackBackground, jetter, Bound) RG = RadialG(x, y, BlackBackground, jetter, Bound) T = Targets(x, y, BlackBackground, jetter, Bound) # ############## save images to .mat file if jetter: if BlackBackground: sio.savemat('SG_pert_b.mat', {'imgs': SG}) sio.savemat('HG_pert_b.mat', {'imgs': HG})
ydensity=y)() if BlackBackground: assert T[idx_proto][idx_shift].max( ) <= 1.0 and T[idx_proto][idx_shift].min() >= 0 T[idx_proto][idx_shift] = 1 - T[idx_proto][idx_shift] idx_shift += 1 idx_proto += 1 return T if __name__ == '__main__': # image size x = 192 y = 192 Bound = BoundingBox(radius=1.05) BlackBackground = True # convert image to black background phase_shift = False # generate different phases f = 4 ############ waves SG = SineG(x, y, BlackBackground, phase_shift, Bound, frames=f) T = Targets(x, y, BlackBackground, phase_shift, Bound, frames=f) HG = HyperG(x, y, BlackBackground, phase_shift, Bound, frames=f) RG = RadialG(x, y, BlackBackground, phase_shift, Bound, frames=f) Bound = BoundingBox(radius=1.5) SpG = SpiralG(x, y, BlackBackground, phase_shift, Bound, frames=f) ############## save images to .mat file if phase_shift:
def setUp(self): ### Simple case: we only pass a dictionary to Plot() ### that does not belong to a Sheet: views = {} time = 0 metadata = AttrDict(timestamp=time) ### SheetView1: ### Find a way to assign randomly the matrix. self.matrix1 = np.zeros((10,10),dtype=np.float) + np.random.random((10,10)) self.bounds1 = BoundingBox(points=((-0.5,-0.5),(0.5,0.5))) sv = Matrix(self.matrix1, self.bounds1) sv.metadata=metadata self.sheet_view1 = NdMapping((None, sv)) self.sheet_view1.metadata = AttrDict(src_name='TestInputParam', precedence=0.1, row_precedence=0.1, cyclic_range=None, timestamp=time) self.key1 = 'SV1' views[self.key1] = self.sheet_view1 ### SheetView2: ### Find a way to assign randomly the matrix. self.matrix2 = np.zeros((10,10),dtype=np.float) + 0.3 self.bounds2 = BoundingBox(points=((-0.5,-0.5),(0.5,0.5))) sv = Matrix(self.matrix2, self.bounds2) sv.metadata=metadata self.sheet_view2 = NdMapping((None, sv)) self.sheet_view2.metadata = AttrDict(src_name='TestInputParam', precedence=0.2, row_precedence=0.2, cyclic_range=None, timestamp=time) self.key2 = 'SV2' views[self.key2] = self.sheet_view2 ### SheetView3: ### Find a way to assign randomly the matrix. self.matrix3 = np.zeros((10,10),dtype=np.float) + np.random.random((10,10)) self.bounds3 = BoundingBox(points=((-0.5,-0.5),(0.5,0.5))) sv = Matrix(self.matrix3, self.bounds3) sv.metadata=metadata self.sheet_view3 = NdMapping((None, sv)) self.sheet_view3.metadata = AttrDict(src_name='TestInputParam', precedence=0.3, row_precedence=0.3, cyclic_range=None, timestamp=time) self.key3 = 'SV3' views[self.key3] = self.sheet_view3 ### SheetView4: for testing clipping + different bounding box ### Find a way to assign randomly the matrix. self.matrix4 = np.zeros((10,10),dtype=np.float) + 1.6 self.bounds4 = BoundingBox(points=((-0.7,-0.7),(0.7,0.7))) sv = Matrix(self.matrix4, self.bounds4) sv.metadata=metadata self.sheet_view4 = NdMapping((None, sv)) self.sheet_view4.metadata = AttrDict(src_name='TestInputParam', precedence=0.4, row_precedence=0.4, cyclic_range=None, timestamp=time) self.key4 = 'SV4' views[self.key4] = self.sheet_view4 self.view_dict = {'Strength': views, 'Hue': views, 'Confidence': views} ### JCALERT! for the moment we can only pass a triple when creating plot ### adding more sheetView to test when plot will be fixed for accepting ### as much as you want. # plot0: empty plot + no sheetviewdict passed: error or empty plot? ### JCALERT! It has to be fixed what to do in this case in plot.. ### disabled test for the moment. #self.plot0 = Plot((None,None,None),None,name='plot0') ### CATCH EXCEPTION plot_channels1 = {'Strength':None,'Hue':None,'Confidence':None} # plot1: empty plot self.plot1 = make_template_plot(plot_channels1,self.view_dict,density=10.0,name='plot1') plot_channels2 = {'Strength':self.key1,'Hue':None,'Confidence':None} # plot2: sheetView 1, no normalize, no clipping self.plot2 = make_template_plot(plot_channels2,self.view_dict,density=10.0,name='plot2') plot_channels3 = {'Strength':self.key1,'Hue':self.key2,'Confidence':None} # plot3: sheetView 1+2, no normalize, no clipping self.plot3 = make_template_plot(plot_channels3,self.view_dict,density=10.0,name='plot3') plot_channels4 = {'Strength':self.key1,'Hue':self.key2,'Confidence':self.key3} # plot4: sheetView 1+2+3, no normalize , no clipping self.plot4 = make_template_plot(plot_channels4,self.view_dict,density=10.0,name='plot4') plot_channels5 = {'Strength':self.key1,'Hue':None,'Confidence':self.key3} # plot5: sheetView 1+3, no normalize, no clipping self.plot5 = make_template_plot(plot_channels5,self.view_dict,density=10.0,name='plot5') plot_channels6 = {'Strength':None,'Hue':self.key2,'Confidence':self.key3} # plot6: sheetView 2+3, no normalize , no clipping self.plot6 = make_template_plot(plot_channels6,self.view_dict,density=10.0,name='plot6') plot_channels7 = {'Strength':self.key4,'Hue':self.key2,'Confidence':self.key3} # plot7: sheetView 1+2+3, no normalize , clipping self.plot7 = make_template_plot(plot_channels7,self.view_dict,density=10.0,name='plot7') plot_channels8 = {'Strength':self.key1,'Hue':self.key2,'Confidence':self.key3} # plot8: sheetView 1+2+3, normalize , no clipping self.plot8 = make_template_plot(plot_channels8,self.view_dict,density=10.0,normalize=True,name='plot8') ### JCALERT! FOR THE MOMENT I TAKE THE DEFAULT FOR NORMALIZE. ### WE WILL SEE IF IT REMAINS IN PLOT FIRST. ### also makes a sheet to test realease_sheetviews self.sheet = Sheet() self.sheet.views.Maps[self.key1]=self.sheet_view1 self.sheet.views.Maps[self.key2]=self.sheet_view2 self.sheet.views.Maps[self.key3]=self.sheet_view3 self.sheet.views.Maps[self.key4]=self.sheet_view4 plot_channels9 = {'Strength':self.key1,'Hue':self.key2,'Confidence':self.key3} self.plot9 = make_template_plot(plot_channels9,self.sheet.views.Maps,density=10.0,name='plot9')