1 """
2 Plot class.
3
4 $Id: plot.py 11314 2010-07-27 17:18:52Z ceball $
5 """
6 __version__='$Revision: 11314 $'
7
8
9 import copy
10
11 from numpy.oldnumeric import zeros, ones, Float, divide
12
13 import param
14
15 from topo.base.sheetcoords import SheetCoordinateSystem,Slice
16
17 from bitmap import HSVBitmap, RGBBitmap, Bitmap
18
19
20
21
22
23
24
25
26
27
28
29
30 -class Plot(param.Parameterized):
31 """
32 Simple Plot object constructed from a specified PIL image.
33 """
34
35 staleness_warning=param.Number(default=10,bounds=(0,None),doc="""
36 Time length allowed between bitmaps making up a single plot before warning.
37
38 If the difference between the SheetView with the earliest
39 timestamp and the one with the latest timestamp is larger
40 than this parameter's value, produce a warning.
41 """)
42
58
59
61 """
62 Change the size of this image by the specified numerical factor.
63
64 The original image is kept as-is in _orig_bitmap; the scaled
65 image is stored in bitmap. The scale_factor argument is
66 taken as relative to the current scaling of the bitmap. For
67 instance, calling scale(1.5) followed by scale(2.0) will
68 yield a final scale of 3.0, not 2.0.
69 """
70 self.scale_factor *= scale_factor
71
72 if (self._orig_bitmap):
73 self.bitmap = copy.copy(self._orig_bitmap)
74 self.bitmap.image = self._orig_bitmap.zoom(self.scale_factor)
75
76
78 """
79 Specify the numerical value of the scaling factor for this image.
80
81 The original image is kept as-is in _orig_bitmap; the scaled
82 image is stored in bitmap. The scale_factor argument is
83 taken as relative to the original size of the bitmap. For
84 instance, calling scale(1.5) followed by scale(2.0) will
85 yield a final scale of 2.0, not 3.0.
86 """
87 self.scale_factor = scale_factor
88
89 if (self._orig_bitmap):
90 self.bitmap = copy.copy(self._orig_bitmap)
91 self.bitmap.image = self._orig_bitmap.zoom(self.scale_factor)
92
94 """Return a label for this plot."""
95 return self.plot_src_name + '\n' + self.name
96
97
98
100
101
102 s_chan = channels.get('Strength')
103 if s_chan is not None and len(s_chan)>0 and s_chan[0]=='Weights':
104 return channels['Strength'] in sheet_views
105 else:
106 return True
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 -def make_template_plot(channels,sheet_views,density=None,
122 plot_bounding_box=None,normalize='None',
123 name='None',range_=False):
124 """
125 Factory function for constructing a Plot object whose type is not yet known.
126
127 Typically, a TemplatePlot will be constructed through this call, because
128 it selects the appropriate type automatically, rather than calling
129 one of the Plot subclasses automatically. See TemplatePlot.__init__ for
130 a description of the arguments.
131 """
132 if _sane_plot_data(channels,sheet_views):
133 plot_types=[SHCPlot,RGBPlot,PalettePlot]
134 for pt in plot_types:
135 plot = pt(channels,sheet_views,density,plot_bounding_box,normalize,
136 name=name,range_=range_)
137 if plot.bitmap is not None or range_ is None:
138
139 return plot
140
141 param.Parameterized(name="make_template_plot").verbose('No',name,'plot constructed for this Sheet')
142 return None
143
144
145
147 """
148 A bitmap-based plot as specified by a plot template (or plot channels).
149 """
150
151
152 warn_time=param.Number(-2,precedence=-1,doc="Time last warned about stale plots")
153
154
155 - def __init__(self,channels,sheet_views,density,
156 plot_bounding_box,normalize,
157 range_=False,**params):
158 """
159 Build a plot out of a set of SheetViews as determined by a plot_template.
160
161 channels is a plot_template, i.e. a dictionary with keys
162 (i.e. 'Strength','Hue','Confidence' ...). Each key typically
163 has a string value naming specifies a SheetView in
164 sheet_views, though specific channels may contain other
165 types of information as required by specific Plot subclasses.
166 channels that are not used by a particular Plot subclass will
167 silently be ignored.
168
169 sheet_views is a dictionary of SheetViews, generally (but
170 not necessarily) belonging to a Sheet object.
171
172 density is the density of the Sheet whose sheet_views was
173 passed.
174
175 plot_bounding_box is the outer bounding_box of the plot to
176 apply if specified. If not, the bounds of
177 the smallest SheetView are used.
178
179 normalize specifies how the Plot should be normalized: any
180 value of normalize other than 'None' will result in normalization
181 according to the value of the range argument:
182
183 range=(A,B) - scale plot so that A is 0 and B is 1
184
185 range=False - scale plot so that min(plot) is 0 and
186 max(plot) is 1 (i.e. fill the maximim
187 dynamic range)
188
189 range=None - calculate value_range only
190
191
192 name (which is inherited from Parameterized) specifies the name
193 to use for this plot.
194 """
195 super(TemplatePlot,self).__init__(**params)
196
197 self.resize=True
198 self.bitmap = None
199
200
201 self.channels = channels
202 self.view_dict = copy.copy(sheet_views)
203
204 self.plot_bounding_box = plot_bounding_box
205
206
207
208
209
210
211
212
213 self._set_plot_src_name()
214
215
216
217
218
219
220
221
223 """
224 Retrieve the matrix view associated with a given key, if any.
225
226 If the key is found in self.channels and the corresponding
227 sheetview is found in self.view_dict, the view's matrix is
228 returned; otherwise None is returned (with no error).
229 """
230 sheet_view_key = self.channels.get(key,None)
231 sv = self.view_dict.get(sheet_view_key, None)
232 if sv == None:
233 matrix = None
234 else:
235 view = sv.view()
236 matrix = view[0]
237
238
239 timestamp = sv.timestamp
240 if timestamp >=0:
241 if self.timestamp < 0:
242 self.timestamp = timestamp
243 elif abs(timestamp - self.timestamp) > self.staleness_warning:
244 if TemplatePlot.warn_time != min(timestamp, self.timestamp):
245 self.warning("Combining SheetViews from different times (%s,%s) for plot %s; see staleness_warning" %
246 (timestamp, self.timestamp,self.name))
247 TemplatePlot.warn_time = min(timestamp, self.timestamp)
248 return matrix
249
250
252 """ Set the Plot plot_src_name. Called when Plot is created"""
253 for key in self.channels:
254 sheet_view_key = self.channels.get(key,None)
255 sv = self.view_dict.get(sheet_view_key, None)
256 if sv != None:
257 self.plot_src_name = sv.src_name
258 self.precedence = sv.precedence
259 self.row_precedence = sv.row_precedence
260 if hasattr(sv,'proj_src_name'):
261 self.proj_src_name=sv.proj_src_name
262
263
264
266 """
267 Sub-function used by plot: get the matrix shape and the bounding box
268 of the SheetViews that constitue the TemplatePlot.
269 """
270 for name in self.channels.values():
271 sv = self.view_dict.get(name,None)
272 if sv != None:
273 shape = sv.view()[0].shape
274 box = sv.view()[1]
275
276 return shape,box
277
278
279
280
281
282
283
284
285
286
288 """
289 Normalize an array s to be in the range 0 to 1.0.
290 For an array of identical elements, returns an array of ones
291 if the elements are greater than zero, and zeros if the
292 elements are less than or equal to zero.
293 """
294 if range_:
295 range_min = float(range_[0])
296 range_max = float(range_[1])
297
298 if range_min==range_max:
299 if range_min>0:
300 resu = ones(a.shape)
301 else:
302 resu = zeros(a.shape)
303 else:
304 a_offset = a - range_min
305 resu = a_offset/range_max
306
307 return resu
308 else:
309 if range_ is None:
310 if not hasattr(self,'value_range'):
311 self.value_range=(a.min(),a.max())
312 else:
313
314 self.value_range=(min(self.value_range[0],a.min()),
315 max(self.value_range[1],a.max()))
316 return None
317 else:
318 a_offset = a-a.min()
319 max_a_offset = a_offset.max()
320
321 if max_a_offset>0:
322 a = divide(a_offset,float(max_a_offset))
323 else:
324 if min(a.ravel())<=0:
325 a=zeros(a.shape,Float)
326 else:
327 a=ones(a.shape,Float)
328 return a
329
330
331
332 - def _re_bound(self,plot_bounding_box,mat,box,density):
333
334
335
336
337
338
339
340
341
342
343
344
345
346 if plot_bounding_box.containsbb_exclusive(box):
347 ct = SheetCoordinateSystem(plot_bounding_box,density,density)
348 new_mat = zeros(ct.shape,Float)
349 r1,r2,c1,c2 = Slice(box,ct)
350 new_mat[r1:r2,c1:c2] = mat
351 else:
352 scs = SheetCoordinateSystem(box,density,density)
353 s=Slice(plot_bounding_box,scs)
354 s.crop_to_sheet(scs)
355 new_mat = s.submatrix(mat)
356
357 return new_mat
358
359
360
361
362
364 """
365 Bitmap plot based on Strength, Hue, and Confidence matrices.
366
367 Constructs an HSV (hue, saturation, and value) plot by choosing
368 the appropriate matrix for each channel.
369 """
370
371 - def __init__(self,channels,sheet_views,density,
372 plot_bounding_box,normalize,
373 range_=False,**params):
374 super(SHCPlot,self).__init__(channels,sheet_views,density,
375 plot_bounding_box,normalize,**params)
376
377
378 s_mat = self._get_matrix('Strength')
379 h_mat = self._get_matrix('Hue')
380 c_mat = self._get_matrix('Confidence')
381
382
383 if (s_mat==None and c_mat==None and h_mat==None):
384 self.debug('Empty plot.')
385
386
387 else:
388
389 shape,box = self._get_shape_and_box()
390
391 hue,sat,val = self.__make_hsv_matrices((s_mat,h_mat,c_mat),shape,normalize,range_)
392
393 if range_ is None:
394 return
395
396
397 if self.plot_bounding_box == None:
398 self.plot_bounding_box = box
399
400 hue = self._re_bound(self.plot_bounding_box,hue,box,density)
401 sat = self._re_bound(self.plot_bounding_box,sat,box,density)
402 val = self._re_bound(self.plot_bounding_box,val,box,density)
403
404 self.bitmap = HSVBitmap(hue,sat,val)
405
406 self._orig_bitmap=self.bitmap
407
408
410 """
411 Sub-function of plot() that return the h,s,v matrices corresponding
412 to the current matrices in sliced_matrices_dict. The shape of the matrices
413 in the dict is passed, as well as the normalize boolean parameter.
414 The result specified a bitmap in hsv coordinate.
415
416 Applies normalizing and cropping if required.
417 """
418 zero=zeros(shape,Float)
419 one=ones(shape,Float)
420
421 s,h,c = hsc_matrices
422
423 if s is None: s=one
424 if c is None: c=one
425 if h is None:
426 h=zero
427 c=zero
428
429
430
431 if normalize!='None':
432 s=self._normalize(s,range_=range_)
433
434 c=self._normalize(c,range_=False)
435
436
437
438
439 hue,sat,val=h,c,s
440 return (hue,sat,val)
441
442
443
444
445
447 """
448 Bitmap plot based on Red, Green, and Blue matrices.
449
450 Construct an RGB (red, green, and blue) plot from the Red, Green,
451 and Blue channels.
452 """
453 - def __init__(self,channels,sheet_views,density,
454 plot_bounding_box,normalize,
455 range_=False,**params):
456
457 super(RGBPlot,self).__init__(channels,sheet_views,density,
458 plot_bounding_box,normalize,**params)
459
460
461
462 r_mat = self._get_matrix('Red')
463 g_mat = self._get_matrix('Green')
464 b_mat = self._get_matrix('Blue')
465
466
467 if (r_mat==None and g_mat==None and b_mat==None):
468 self.debug('Empty plot.')
469
470 else:
471
472 shape,box = self._get_shape_and_box()
473
474 red,green,blue = self.__make_rgb_matrices((r_mat,g_mat,b_mat),shape,
475 normalize,range_=range_)
476
477 if range_ is None:
478 return
479
480 if self.plot_bounding_box == None:
481 self.plot_bounding_box = box
482
483 red = self._re_bound(self.plot_bounding_box,red,box,density)
484 green = self._re_bound(self.plot_bounding_box,green,box,density)
485 blue = self._re_bound(self.plot_bounding_box,blue,box,density)
486
487 self.bitmap = RGBBitmap(red,green,blue)
488
489 self._orig_bitmap=self.bitmap
490
492 """
493 Sub-function of plot() that return the h,s,v matrices
494 corresponding to the current matrices in
495 sliced_matrices_dict. The shape of the matrices in the dict is
496 passed, as well as the normalize boolean parameter. The
497 result specified a bitmap in hsv coordinate.
498
499 Applies normalizing and cropping if required.
500 """
501 zero=zeros(shape,Float)
502 one=ones(shape,Float)
503
504 r,g,b = rgb_matrices
505
506 if r is None: r=zero
507 if g is None: g=zero
508 if b is None: b=zero
509
510
511 if normalize!='None':
512 r = self._normalize(r,range_=range_)
513 g = self._normalize(g,range_=range_)
514 b = self._normalize(b,range_=range_)
515
516 return (r,g,b)
517
518
519
520
521
523 """
524 Bitmap plot based on a Strength matrix, with optional colorization.
525
526 Not yet implemented.
527
528 When implemented, construct an RGB plot from a Strength channel,
529 optionally colorized using a specified Palette.
530 """
531
532 - def __init__(self,channels,sheet_views,density,
533 plot_bounding_box,normalize,**params):
537
538
539
540