/[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 428 - (hide annotations)
Mon Feb 24 18:46:35 2003 UTC (22 years ago) by jonathan
Original Path: trunk/thuban/Thuban/Model/classification.py
File MIME type: text/x-python
File size: 10436 byte(s)
(Classification): Renamed
        GetProperties() to GetClassData(). Used the new iterator
        in TreeInfo().
(ClassIterator): Iterator implementation to iterate over the
        ClassData objects in a classification object.

1 jonathan 371 # Copyright (c) 2001 by Intevation GmbH
2     # 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 428 See the description of GetClassData() 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 388 from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \
27     LAYER_VISIBILITY_CHANGED
28    
29 jan 374 from Thuban import _
30 jonathan 381 from Thuban.Model.color import Color
31 jan 374
32 jonathan 381 from wxPython.wx import *
33    
34 jonathan 371 # constants
35     RANGE_MIN = 0
36     RANGE_MAX = 1
37     RANGE_DATA = 2
38    
39     class Classification:
40    
41 jonathan 410 def __init__(self, layer = None, field = None):
42 jonathan 371 """Initialize a classification.
43    
44 jonathan 388 layer -- the layer object who owns this classification
45    
46 jonathan 371 field -- the name of the data table field that
47     is to be used to classify layer properties
48     """
49    
50 jonathan 388 self.layer = layer
51 jonathan 378 self.points = {}
52     self.ranges = []
53 jonathan 410 self.maps = []
54     self.DefaultData = ClassDataDefault()
55 jonathan 388 self.field = field
56     #self.SetField(field)
57    
58 jonathan 428 def __iter__(self):
59     return ClassIterator(self.DefaultData,
60     self.points.values(),
61     self.ranges,
62     self.maps)
63    
64     def __SendMessage(self, message):
65 jonathan 410 if self.layer is not None:
66     self.layer.changed(message, self.layer)
67    
68 jonathan 388 def SetField(self, field):
69 jonathan 371 """Set the name of the data table field to use.
70    
71 jonathan 388 field -- if None then all values map to the default data
72 jonathan 371 """
73    
74     self.field = field
75 jonathan 428 self.__SendMessage(LAYER_LEGEND_CHANGED)
76 jonathan 371
77 jonathan 388 def GetField(self):
78     return self.field
79    
80 jonathan 410 def SetLayer(self, layer):
81     self.layer = layer
82 jonathan 428 self.__SendMessage(LAYER_LEGEND_CHANGED)
83 jonathan 410
84     def GetLayer(self):
85     return layer.self
86    
87 jonathan 388 def SetDefaultData(self, data):
88 jonathan 371 """Set the data to be used when a value can't be classified.
89    
90     data -- data that the value maps to. See class description.
91     """
92    
93 jonathan 428 assert(data.GetType() == ClassData.DEFAULT)
94 jonathan 388 self.DefaultData = data
95 jonathan 371
96 jonathan 388 def GetDefaultData(self):
97     return self.DefaultData
98 jonathan 385
99 jonathan 428 #
100     # these SetDefault* methods are really only provided for
101     # some backward compatibility. they should be considered
102     # for removal once all the classification code is finished.
103     #
104    
105 jonathan 388 def SetDefaultFill(self, fill):
106     self.DefaultData.SetFill(fill)
107 jonathan 428 self.__SendMessage(LAYER_LEGEND_CHANGED)
108 jonathan 388
109     def GetDefaultFill(self):
110     return self.DefaultData.GetFill()
111    
112     def SetDefaultStroke(self, stroke):
113     self.DefaultData.SetStroke(stroke)
114 jonathan 428 self.__SendMessage(LAYER_LEGEND_CHANGED)
115 jonathan 388
116     def GetDefaultStroke(self):
117     return self.DefaultData.GetStroke()
118    
119     def SetDefaultStrokeWidth(self, strokeWidth):
120     self.DefaultData.SetStrokeWidth(strokeWidth)
121 jonathan 428 self.__SendMessage(LAYER_LEGEND_CHANGED)
122 jonathan 388
123     def GetDefaultStrokeWidth(self):
124     return self.DefaultData.GetStrokeWidth()
125    
126 jonathan 410 def AddClassData(self, item):
127     type = item.GetType()
128 jonathan 371
129 jonathan 410 if type == ClassData.POINT:
130     self.points[item.GetValue()] = item
131     elif type == ClassData.RANGE:
132     self.ranges.append(item)
133     elif type == ClassData.MAP:
134     self.maps.append(item)
135     elif type == ClassData.DEFAULT:
136     self.DefaultData = item
137     else:
138     raise ValueError(_("Unrecognized ClassData type %s") % type)
139 jonathan 371
140 jonathan 428 self.__SendMessage(LAYER_LEGEND_CHANGED)
141 jonathan 371
142 jonathan 428 def GetClassData(self, value):
143 jonathan 388 """Return the associated data, or the default data.
144 jonathan 371
145     The following search technique is used:
146 jonathan 388 (1) if the field is None, return the default data
147 jonathan 371 (2) check if the value exists as a single value
148     (3) check if the value falls within a range. Ranges
149     are checked in the order they were added to
150     the classification.
151    
152 jonathan 388 value -- the value to classify. If there is no mapping,
153 jonathan 428 or value is None, return the default properties
154 jonathan 371 """
155    
156 jonathan 388 if self.field is not None and value is not None:
157 jonathan 371 #
158 jonathan 410 # check the discrete values
159 jonathan 371 #
160 jonathan 378 if self.points.has_key(value):
161     return self.points[value]
162 jonathan 371
163     #
164 jonathan 410 # check the ranges
165 jonathan 371 #
166 jonathan 378 for p in self.ranges:
167 jonathan 410 if p.InRange(value):
168     return p
169 jonathan 371
170 jonathan 410 #
171     # check the maps
172     #
173     for p in self.maps:
174     try:
175     return p.Map(value)
176     except: pass
177 jonathan 371
178 jonathan 388 return self.DefaultData
179 jonathan 371
180 jonathan 381 def TreeInfo(self):
181     items = []
182 jonathan 378
183 jonathan 410 def build_color_item(text, color):
184     if color is Color.None:
185     return ("%s: %s" % (text, _("None")), None)
186 jonathan 381
187 jonathan 410 return ("%s: (%.3f, %.3f, %.3f)" %
188     (text, color.red, color.green, color.blue),
189     color)
190 jonathan 381
191 jonathan 410 def build_item(data, string):
192     label = data.GetLabel()
193     if label == "":
194     label = string
195     else:
196     label += " (%s)" % string
197    
198 jonathan 381 i = []
199 jonathan 388 v = data.GetStroke()
200 jonathan 410 i.append(build_color_item(_("Stroke"), v))
201 jonathan 388 v = data.GetStrokeWidth()
202 jonathan 410 i.append(_("Stroke Width: %s") % v)
203 jonathan 388 v = data.GetFill()
204 jonathan 410 i.append(build_color_item(_("Fill"), v))
205     return (label, i)
206 jonathan 388
207 jonathan 428 for p in self:
208     type = p.GetType()
209     if type == ClassData.DEFAULT:
210     items.append(build_item(self.DefaultData, _("'DEFAULT'")))
211     elif type == ClassData.POINT:
212     items.append(build_item(p, str(p.GetValue())))
213     elif type == ClassData.RANGE:
214     items.append(build_item(p, "%s - %s" %
215     (p.GetMin(), p.GetMax())))
216 jonathan 388
217 jonathan 428 # for p in self.points.values():
218     # items.append(build_item(p, str(p.GetValue())))
219 jonathan 381
220 jonathan 428 # for p in self.ranges:
221     # items.append(build_item(p, "%s - %s" % (p.GetMin(), p.GetMax())))
222 jonathan 388
223 jonathan 381 return (_("Classifications"), items)
224    
225 jonathan 428 class ClassIterator:
226 jonathan 388
227 jonathan 428 def __init__(self, default, points, ranges, maps):
228     self.data = [default, points, ranges, maps]
229     self.data_iter = iter(self.data)
230     self.iter = None
231    
232     def __iter__(self):
233     return self
234    
235     def next(self):
236     if self.iter is None:
237     try:
238     self.data_item = self.data_iter.next()
239     self.iter = iter(self.data_item)
240     except TypeError:
241     return self.data_item
242    
243     try:
244     return self.iter.next()
245     except StopIteration:
246     self.iter = None
247     return self.next()
248    
249 jonathan 388 class ClassData:
250    
251 jonathan 410 INVALID = -1
252     DEFAULT = 0
253     POINT = 1
254     RANGE = 2
255     MAP = 3
256    
257 jonathan 428 def __init__(self, classData = None, type = INVALID):
258 jonathan 410
259     if classData is not None:
260     self.SetStroke(classData.GetStroke())
261     self.SetStrokeWidth(classData.GetStrokeWidth())
262     self.SetFill(classData.GetFill())
263     else:
264     self.SetStroke(Color.None)
265     self.SetStrokeWidth(1)
266     self.SetFill(Color.None)
267    
268     self.type = type
269 jonathan 388 self.label = ""
270    
271 jonathan 410 def GetType(self):
272     return self.type
273    
274 jonathan 388 def GetStroke(self):
275     return self.stroke
276    
277     def SetStroke(self, stroke):
278 jonathan 410 assert(isinstance(stroke, Color))
279 jonathan 388 self.stroke = stroke
280    
281     def GetStrokeWidth(self):
282     return self.stroke_width
283    
284     def SetStrokeWidth(self, stroke_width):
285 jonathan 410 if (stroke_width < 1):
286     raise ValueError(_("stroke_width < 1"))
287    
288 jonathan 388 self.stroke_width = stroke_width
289    
290     def GetFill(self):
291     return self.fill
292    
293     def SetFill(self, fill):
294 jonathan 410 assert(isinstance(fill, Color))
295 jonathan 388 self.fill = fill
296    
297     def GetLabel(self):
298     return self.label
299    
300     def SetLabel(self, label):
301     self.label = label
302    
303 jonathan 410 class ClassDataDefault(ClassData):
304     def __init__(self, classData = None):
305 jonathan 428 ClassData.__init__(self, classData, ClassData.DEFAULT)
306 jonathan 410
307     class ClassDataPoint(ClassData):
308    
309     def __init__(self, value = 0, classData = None):
310 jonathan 428 ClassData.__init__(self, classData, ClassData.POINT)
311 jonathan 410
312     self.value = value
313    
314     def GetValue(self):
315     return self.value
316    
317     def SetValue(self, value):
318     self.value = value
319    
320     class ClassDataRange(ClassData):
321    
322     def __init__(self, min = 0, max = 1, classData = None):
323 jonathan 428 ClassData.__init__(self, classData, ClassData.RANGE)
324 jonathan 410
325     if min >= max:
326     raise ValueError(_("ClassDataRange: %i(min) >= %i(max)!") %
327     (min, max))
328    
329     self.SetRange(min, max)
330    
331     def GetMin(self):
332     return self.min
333    
334     def SetMin(self, min):
335     self.SetRange(min, self.max)
336    
337     def GetMax(self):
338     return self.max
339    
340     def SetMax(self, max):
341     self.SetRange(self.min, max)
342    
343     def SetRange(self, min, max):
344     self.min = min
345     self.max = max
346     if min >= max:
347     raise ValueError(_("ClassDataRange: %i(min) >= %i(max)!") %
348     (min, max))
349    
350     def GetRange(self):
351     return (self.min, self.max)
352    
353     def InRange(self, value):
354     return self.min <= value < self.max
355    
356     class ClassDataMap(ClassData):
357    
358     FUNC_ID = "id"
359    
360     def __init__(self, map_type = FUNC_ID, func = None, classData = None):
361 jonathan 428 ClassData.__init__(self, classData, ClassData.MAP)
362 jonathan 410
363     self.map_type = map_type
364     self.func = func
365    
366     if self.func is None:
367     self.func = func_id
368    
369     def Map(self, value):
370     return self.func(value)
371    
372     #
373     # built-in mappings
374     #
375     def func_id(value):
376     return value
377    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26