/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/classification.py
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/Thuban/Model/classification.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 453 - (hide annotations)
Tue Mar 4 11:31:39 2003 UTC (22 years ago) by bh
Original Path: trunk/thuban/Thuban/Model/classification.py
File MIME type: text/x-python
File size: 12339 byte(s)
Remove unnecessary wxPython import

1 bh 453 # Copyright (c) 2001, 2003 by Intevation GmbH
2 jonathan 371 # Authors:
3     # Jonathan Coles <[email protected]>
4     #
5     # This program is free software under the GPL (>=v2)
6     # Read the file COPYING coming with Thuban for details.
7    
8     __version__ = "$Revision$"
9    
10     """
11     A Classification provides a mapping from an input value
12     to data. This mapping can be specified in two ways.
13     First, specific values can be associated with data.
14     Second, ranges can be associated with data such that if
15     an input value falls with a range that data is returned.
16 jonathan 388 If no mapping can be found then default data will
17 jonathan 371 be returned. Input values must be hashable objects
18    
19 jonathan 449 See the description of GetGroup() for more information
20 jonathan 371 on the mapping algorithm.
21     """
22    
23 jonathan 397 # fix for people using python2.1
24     from __future__ import nested_scopes
25    
26 jonathan 436 from types import *
27    
28 jonathan 388 from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \
29     LAYER_VISIBILITY_CHANGED
30    
31 jan 374 from Thuban import _
32 jonathan 381 from Thuban.Model.color import Color
33 jan 374
34 jonathan 436 import Thuban.Model.layer
35    
36 jonathan 381
37 jonathan 371 # constants
38     RANGE_MIN = 0
39     RANGE_MAX = 1
40     RANGE_DATA = 2
41    
42     class Classification:
43    
44 jonathan 410 def __init__(self, layer = None, field = None):
45 jonathan 371 """Initialize a classification.
46    
47 jonathan 388 layer -- the layer object who owns this classification
48    
49 jonathan 371 field -- the name of the data table field that
50     is to be used to classify layer properties
51     """
52    
53 jonathan 436 self.layer = None # stop message sending
54    
55     self.SetDefaultGroup(ClassGroupDefault())
56     self.SetField(field)
57    
58 jonathan 388 self.layer = layer
59 jonathan 436 self.points = []
60 jonathan 378 self.ranges = []
61 jonathan 410 self.maps = []
62 jonathan 388
63 jonathan 428 def __iter__(self):
64 jonathan 436 return ClassIterator(self.DefaultGroup,
65     self.points,
66 jonathan 428 self.ranges,
67     self.maps)
68    
69     def __SendMessage(self, message):
70 jonathan 410 if self.layer is not None:
71     self.layer.changed(message, self.layer)
72    
73 jonathan 388 def SetField(self, field):
74 jonathan 371 """Set the name of the data table field to use.
75    
76 jonathan 388 field -- if None then all values map to the default data
77 jonathan 371 """
78    
79 jonathan 436 if field == "":
80     field = None
81    
82 jonathan 371 self.field = field
83 jonathan 428 self.__SendMessage(LAYER_LEGEND_CHANGED)
84 jonathan 371
85 jonathan 388 def GetField(self):
86     return self.field
87    
88 jonathan 410 def SetLayer(self, layer):
89 jonathan 436 assert(isinstance(layer, Thuban.Model.layer.Layer))
90 jonathan 410 self.layer = layer
91 jonathan 428 self.__SendMessage(LAYER_LEGEND_CHANGED)
92 jonathan 410
93     def GetLayer(self):
94     return layer.self
95    
96 jonathan 436 def SetDefaultGroup(self, group):
97     """Set the group to be used when a value can't be classified.
98 jonathan 371
99 jonathan 436 group -- group that the value maps to. See class description.
100 jonathan 371 """
101    
102 jonathan 436 assert(isinstance(group, ClassGroupDefault))
103     self.DefaultGroup = group
104 jonathan 371
105 jonathan 436 def GetDefaultGroup(self):
106     return self.DefaultGroup
107 jonathan 385
108 jonathan 428 #
109     # these SetDefault* methods are really only provided for
110     # some backward compatibility. they should be considered
111     # for removal once all the classification code is finished.
112     #
113    
114 jonathan 388 def SetDefaultFill(self, fill):
115 jonathan 436 assert(isinstance(fill, Color))
116     self.DefaultGroup.GetProperties().SetFill(fill)
117 jonathan 428 self.__SendMessage(LAYER_LEGEND_CHANGED)
118 jonathan 388
119     def GetDefaultFill(self):
120 jonathan 436 return self.DefaultGroup.GetProperties().GetFill()
121 jonathan 388
122     def SetDefaultStroke(self, stroke):
123 jonathan 436 assert(isinstance(stroke, Color))
124     self.DefaultGroup.GetProperties().SetStroke(stroke)
125 jonathan 428 self.__SendMessage(LAYER_LEGEND_CHANGED)
126 jonathan 388
127     def GetDefaultStroke(self):
128 jonathan 436 return self.DefaultGroup.GetProperties().GetStroke()
129 jonathan 388
130     def SetDefaultStrokeWidth(self, strokeWidth):
131 jonathan 436 assert(isinstance(strokeWidth, IntType))
132     self.DefaultGroup.GetProperties().SetStrokeWidth(strokeWidth)
133 jonathan 428 self.__SendMessage(LAYER_LEGEND_CHANGED)
134 jonathan 388
135     def GetDefaultStrokeWidth(self):
136 jonathan 436 return self.DefaultGroup.GetProperties().GetStrokeWidth()
137 jonathan 388
138 jonathan 436 def AddGroup(self, item):
139     assert(isinstance(item, ClassGroup))
140 jonathan 371
141 jonathan 436 if isinstance(item, ClassGroupDefault):
142     self.SetDefaultGroup(item)
143     elif isinstance(item, ClassGroupSingleton):
144     self.points.append(item)
145     elif isinstance(item, ClassGroupRange):
146 jonathan 410 self.ranges.append(item)
147 jonathan 436 elif isinstance(item, ClassGroupMap):
148 jonathan 410 self.maps.append(item)
149     else:
150 jonathan 436 raise ValueError(_("Unrecognized ClassGroup"))
151 jonathan 371
152 jonathan 428 self.__SendMessage(LAYER_LEGEND_CHANGED)
153 jonathan 371
154 jonathan 436 def GetGroup(self, value):
155 jonathan 388 """Return the associated data, or the default data.
156 jonathan 371
157     The following search technique is used:
158 jonathan 388 (1) if the field is None, return the default data
159 jonathan 371 (2) check if the value exists as a single value
160     (3) check if the value falls within a range. Ranges
161     are checked in the order they were added to
162     the classification.
163    
164 jonathan 388 value -- the value to classify. If there is no mapping,
165 jonathan 428 or value is None, return the default properties
166 jonathan 371 """
167    
168 jonathan 388 if self.field is not None and value is not None:
169 jonathan 371
170 jonathan 436 for p in self:
171     if p.Matches(value):
172 jonathan 410 return p
173 jonathan 436 # #
174     # # check the discrete values
175     # #
176     # if self.points.has_key(value):
177     # return self.points[value]
178     # #for p in self.points:
179     # #if p.Value
180 jonathan 371
181 jonathan 436 # #
182     # # check the ranges
183     # #
184     # for p in self.ranges:
185     # if p.InRange(value):
186     # return p
187 jonathan 371
188 jonathan 436 # #
189     # # check the maps
190     # #
191     # for p in self.maps:
192     # try:
193     # return p.Map(value)
194     # except: pass
195 jonathan 371
196 jonathan 436 return self.DefaultGroup
197    
198     def GetProperties(self, value):
199     return self.GetGroup(value).GetProperties()
200    
201 jonathan 381 def TreeInfo(self):
202     items = []
203 jonathan 378
204 jonathan 410 def build_color_item(text, color):
205     if color is Color.None:
206     return ("%s: %s" % (text, _("None")), None)
207 jonathan 381
208 jonathan 410 return ("%s: (%.3f, %.3f, %.3f)" %
209     (text, color.red, color.green, color.blue),
210     color)
211 jonathan 381
212 jonathan 436 def build_item(group, string):
213     label = group.GetLabel()
214 jonathan 410 if label == "":
215     label = string
216     else:
217     label += " (%s)" % string
218    
219 jonathan 436 props = group.GetProperties()
220 jonathan 381 i = []
221 jonathan 436 v = props.GetStroke()
222 jonathan 410 i.append(build_color_item(_("Stroke"), v))
223 jonathan 436 v = props.GetStrokeWidth()
224 jonathan 410 i.append(_("Stroke Width: %s") % v)
225 jonathan 436 v = props.GetFill()
226 jonathan 410 i.append(build_color_item(_("Fill"), v))
227     return (label, i)
228 jonathan 388
229 jonathan 428 for p in self:
230 jonathan 436 if isinstance(p, ClassGroupDefault):
231     items.append(build_item(self.DefaultGroup, _("'DEFAULT'")))
232     elif isinstance(p, ClassGroupSingleton):
233 jonathan 428 items.append(build_item(p, str(p.GetValue())))
234 jonathan 436 elif isinstance(p, ClassGroupRange):
235 jonathan 428 items.append(build_item(p, "%s - %s" %
236     (p.GetMin(), p.GetMax())))
237 jonathan 388
238 jonathan 428 # for p in self.points.values():
239     # items.append(build_item(p, str(p.GetValue())))
240 jonathan 381
241 jonathan 428 # for p in self.ranges:
242     # items.append(build_item(p, "%s - %s" % (p.GetMin(), p.GetMax())))
243 jonathan 388
244 jonathan 436 return (_("Classification"), items)
245 jonathan 381
246 jonathan 428 class ClassIterator:
247 jonathan 388
248 jonathan 428 def __init__(self, default, points, ranges, maps):
249     self.data = [default, points, ranges, maps]
250     self.data_iter = iter(self.data)
251     self.iter = None
252    
253     def __iter__(self):
254     return self
255    
256     def next(self):
257     if self.iter is None:
258     try:
259     self.data_item = self.data_iter.next()
260     self.iter = iter(self.data_item)
261     except TypeError:
262     return self.data_item
263    
264     try:
265     return self.iter.next()
266     except StopIteration:
267     self.iter = None
268     return self.next()
269    
270 jonathan 436 class ClassGroupProperties:
271 jonathan 388
272 jonathan 436 def __init__(self, prop = None):
273 jonathan 410
274 jonathan 436 if prop is not None:
275     self.SetStroke(prop.GetStroke())
276     self.SetStrokeWidth(prop.GetStrokeWidth())
277     self.SetFill(prop.GetFill())
278 jonathan 410 else:
279     self.SetStroke(Color.None)
280     self.SetStrokeWidth(1)
281     self.SetFill(Color.None)
282    
283 jonathan 388 def GetStroke(self):
284     return self.stroke
285    
286     def SetStroke(self, stroke):
287 jonathan 410 assert(isinstance(stroke, Color))
288 jonathan 388 self.stroke = stroke
289    
290     def GetStrokeWidth(self):
291     return self.stroke_width
292    
293     def SetStrokeWidth(self, stroke_width):
294 jonathan 436 assert(isinstance(stroke_width, IntType))
295 jonathan 410 if (stroke_width < 1):
296     raise ValueError(_("stroke_width < 1"))
297    
298 jonathan 388 self.stroke_width = stroke_width
299    
300     def GetFill(self):
301     return self.fill
302    
303     def SetFill(self, fill):
304 jonathan 410 assert(isinstance(fill, Color))
305 jonathan 388 self.fill = fill
306    
307 jonathan 436
308     class ClassGroup:
309    
310     def __init__(self, label = ""):
311     self.label = label
312    
313 jonathan 388 def GetLabel(self):
314     return self.label
315    
316     def SetLabel(self, label):
317     self.label = label
318    
319 jonathan 436 def Matches(self, value):
320     """This needs to be implemented by all subclasses."""
321     pass
322    
323     def GetProperties(self, value):
324     """This needs to be implemented by all subclasses."""
325     pass
326    
327 jonathan 410
328 jonathan 436 class ClassGroupSingleton(ClassGroup):
329 jonathan 410
330 jonathan 436 def __init__(self, value = 0, prop = None, label = ""):
331     ClassGroup.__init__(self, label)
332 jonathan 410
333 jonathan 436 self.SetValue(value)
334     self.SetProperties(prop)
335 jonathan 410
336 jonathan 436 def __copy__(self):
337     return ClassGroupSingleton(self.value, self.prop, self.label)
338    
339 jonathan 410 def GetValue(self):
340     return self.value
341    
342     def SetValue(self, value):
343     self.value = value
344    
345 jonathan 436 def Matches(self, value):
346     return self.value == value
347 jonathan 410
348 jonathan 436 def GetProperties(self, value = None):
349     if value is None: return self.prop
350 jonathan 410
351 jonathan 436 if self.Matches(value):
352     return self.prop
353     else:
354     return None
355 jonathan 410
356 jonathan 436 def SetProperties(self, prop):
357     if prop is None: prop = ClassGroupProperties()
358     assert(isinstance(prop, ClassGroupProperties))
359     self.prop = prop
360    
361    
362     class ClassGroupDefault(ClassGroupSingleton):
363     def __init__(self, prop = None, label = ""):
364     ClassGroupSingleton.__init__(self, 0, prop, label)
365    
366     def __copy__(self):
367     return ClassGroupDefault(self.prop, self.label)
368    
369     def GetProperties(self, value = None):
370     return self.prop
371    
372     class ClassGroupRange(ClassGroup):
373    
374     def __init__(self, min = 0, max = 1, prop = None, label = ""):
375     ClassGroup.__init__(self, label)
376    
377 jonathan 410 self.SetRange(min, max)
378 jonathan 436 self.SetProperties(prop)
379 jonathan 410
380 jonathan 436 def __copy__(self):
381     return ClassGroupRange(self.min, self.max, self.prop, self.label)
382    
383 jonathan 410 def GetMin(self):
384     return self.min
385    
386     def SetMin(self, min):
387     self.SetRange(min, self.max)
388    
389     def GetMax(self):
390     return self.max
391    
392     def SetMax(self, max):
393     self.SetRange(self.min, max)
394    
395     def SetRange(self, min, max):
396 jonathan 436 if min >= max:
397     raise ValueError(_("ClassGroupRange: %i(min) >= %i(max)!") %
398     (min, max))
399 jonathan 410 self.min = min
400     self.max = max
401    
402     def GetRange(self):
403     return (self.min, self.max)
404    
405 jonathan 436 def Matches(self, value):
406 jonathan 410 return self.min <= value < self.max
407    
408 jonathan 449 def GetProperties(self, value = None):
409 jonathan 436 if value is None: return self.prop
410 jonathan 410
411 jonathan 436 if self.Matches(value):
412     return self.prop
413     else:
414     return None
415    
416     def SetProperties(self, prop):
417     if prop is None: prop = ClassGroupProperties()
418     assert(isinstance(prop, ClassGroupProperties))
419     self.prop = prop
420    
421     class ClassGroupMap(ClassGroup):
422    
423 jonathan 410 FUNC_ID = "id"
424    
425 jonathan 436 def __init__(self, map_type = FUNC_ID, func = None, prop = None, label=""):
426     ClassGroup.__init__(self, prop)
427 jonathan 410
428     self.map_type = map_type
429     self.func = func
430    
431     if self.func is None:
432     self.func = func_id
433    
434     def Map(self, value):
435     return self.func(value)
436    
437     #
438     # built-in mappings
439     #
440     def func_id(value):
441     return value
442    

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26