/[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 410 - (hide annotations)
Wed Feb 19 16:51:12 2003 UTC (22 years ago) by jonathan
Original Path: trunk/thuban/Thuban/Model/classification.py
File MIME type: text/x-python
File size: 8995 byte(s)
(Classification):
        Uses the new ClassData* classes. Modification messages are
        passed up to the parent layer (if it exists).
(ClassData): New class to encapsulate the common data in each
        classification property.
(ClassDataDefault): Represents the Default class. data.
(ClassDataPoint): Represents a single class. data point
(ClassDataRange): Represents a class. range
(ClassDataMap): Represents a class. map (unused).

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     See the description of getProperties() for more information
20     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 410 def SendMessage(self, message):
59     if self.layer is not None:
60     self.layer.changed(message, self.layer)
61    
62 jonathan 388 def SetField(self, field):
63 jonathan 371 """Set the name of the data table field to use.
64    
65 jonathan 388 field -- if None then all values map to the default data
66 jonathan 371 """
67    
68     self.field = field
69 jonathan 410 self.SendMessage(LAYER_LEGEND_CHANGED)
70 jonathan 371
71 jonathan 388 def GetField(self):
72     return self.field
73    
74 jonathan 410 def SetLayer(self, layer):
75     self.layer = layer
76     self.SendMessage(LAYER_LEGEND_CHANGED)
77    
78     def GetLayer(self):
79     return layer.self
80    
81 jonathan 388 def SetDefaultData(self, data):
82 jonathan 371 """Set the data to be used when a value can't be classified.
83    
84     data -- data that the value maps to. See class description.
85     """
86    
87 jonathan 388 self.DefaultData = data
88 jonathan 371
89 jonathan 388 def GetDefaultData(self):
90     return self.DefaultData
91 jonathan 385
92 jonathan 388 def SetDefaultFill(self, fill):
93     self.DefaultData.SetFill(fill)
94 jonathan 410 self.SendMessage(LAYER_LEGEND_CHANGED)
95 jonathan 388
96     def GetDefaultFill(self):
97     return self.DefaultData.GetFill()
98    
99     def SetDefaultStroke(self, stroke):
100     self.DefaultData.SetStroke(stroke)
101 jonathan 410 self.SendMessage(LAYER_LEGEND_CHANGED)
102 jonathan 388
103     def GetDefaultStroke(self):
104     return self.DefaultData.GetStroke()
105    
106     def SetDefaultStrokeWidth(self, strokeWidth):
107     self.DefaultData.SetStrokeWidth(strokeWidth)
108 jonathan 410 self.SendMessage(LAYER_LEGEND_CHANGED)
109 jonathan 388
110     def GetDefaultStrokeWidth(self):
111     return self.DefaultData.GetStrokeWidth()
112    
113 jonathan 410 def AddClassData(self, item):
114     type = item.GetType()
115 jonathan 371
116 jonathan 410 if type == ClassData.POINT:
117     self.points[item.GetValue()] = item
118     elif type == ClassData.RANGE:
119     self.ranges.append(item)
120     elif type == ClassData.MAP:
121     self.maps.append(item)
122     elif type == ClassData.DEFAULT:
123     self.DefaultData = item
124     else:
125     raise ValueError(_("Unrecognized ClassData type %s") % type)
126 jonathan 371
127 jonathan 410 self.SendMessage(LAYER_LEGEND_CHANGED)
128 jonathan 371
129 jonathan 388 def GetProperties(self, value):
130     """Return the associated data, or the default data.
131 jonathan 371
132     The following search technique is used:
133 jonathan 388 (1) if the field is None, return the default data
134 jonathan 371 (2) check if the value exists as a single value
135     (3) check if the value falls within a range. Ranges
136     are checked in the order they were added to
137     the classification.
138    
139 jonathan 388 value -- the value to classify. If there is no mapping,
140     or value is None, return the default data
141     (which may be None)
142 jonathan 371 """
143    
144 jonathan 388 if self.field is not None and value is not None:
145 jonathan 371 #
146 jonathan 410 # check the discrete values
147 jonathan 371 #
148 jonathan 378 if self.points.has_key(value):
149     return self.points[value]
150 jonathan 371
151     #
152 jonathan 410 # check the ranges
153 jonathan 371 #
154 jonathan 378 for p in self.ranges:
155 jonathan 410 if p.InRange(value):
156     return p
157 jonathan 371
158 jonathan 410 #
159     # check the maps
160     #
161     for p in self.maps:
162     try:
163     return p.Map(value)
164     except: pass
165 jonathan 371
166 jonathan 388 return self.DefaultData
167 jonathan 371
168 jonathan 381 def TreeInfo(self):
169     items = []
170 jonathan 378
171 jonathan 410 def build_color_item(text, color):
172     if color is Color.None:
173     return ("%s: %s" % (text, _("None")), None)
174 jonathan 381
175 jonathan 410 return ("%s: (%.3f, %.3f, %.3f)" %
176     (text, color.red, color.green, color.blue),
177     color)
178 jonathan 381
179 jonathan 410 def build_item(data, string):
180     label = data.GetLabel()
181     if label == "":
182     label = string
183     else:
184     label += " (%s)" % string
185    
186 jonathan 381 i = []
187 jonathan 388 v = data.GetStroke()
188 jonathan 410 i.append(build_color_item(_("Stroke"), v))
189 jonathan 388 v = data.GetStrokeWidth()
190 jonathan 410 i.append(_("Stroke Width: %s") % v)
191 jonathan 388 v = data.GetFill()
192 jonathan 410 i.append(build_color_item(_("Fill"), v))
193     return (label, i)
194 jonathan 388
195 jonathan 410 items.append(build_item(self.DefaultData, _("'DEFAULT'")))
196 jonathan 388
197 jonathan 410 for p in self.points.values():
198     items.append(build_item(p, str(p.GetValue())))
199 jonathan 381
200     for p in self.ranges:
201 jonathan 410 items.append(build_item(p, "%s - %s" % (p.GetMin(), p.GetMax())))
202 jonathan 388
203 jonathan 381 return (_("Classifications"), items)
204    
205 jonathan 388
206     class ClassData:
207    
208 jonathan 410 INVALID = -1
209     DEFAULT = 0
210     POINT = 1
211     RANGE = 2
212     MAP = 3
213    
214     def __init__(self, type = INVALID, classData = None):
215    
216     if classData is not None:
217     self.SetStroke(classData.GetStroke())
218     self.SetStrokeWidth(classData.GetStrokeWidth())
219     self.SetFill(classData.GetFill())
220     else:
221     self.SetStroke(Color.None)
222     self.SetStrokeWidth(1)
223     self.SetFill(Color.None)
224    
225     self.type = type
226 jonathan 388 self.label = ""
227    
228 jonathan 410 def GetType(self):
229     return self.type
230    
231 jonathan 388 def GetStroke(self):
232     return self.stroke
233    
234     def SetStroke(self, stroke):
235 jonathan 410 assert(isinstance(stroke, Color))
236 jonathan 388 self.stroke = stroke
237    
238     def GetStrokeWidth(self):
239     return self.stroke_width
240    
241     def SetStrokeWidth(self, stroke_width):
242 jonathan 410 if (stroke_width < 1):
243     raise ValueError(_("stroke_width < 1"))
244    
245 jonathan 388 self.stroke_width = stroke_width
246    
247     def GetFill(self):
248     return self.fill
249    
250     def SetFill(self, fill):
251 jonathan 410 assert(isinstance(fill, Color))
252 jonathan 388 self.fill = fill
253    
254     def GetLabel(self):
255     return self.label
256    
257     def SetLabel(self, label):
258     self.label = label
259    
260 jonathan 410 class ClassDataDefault(ClassData):
261     def __init__(self, classData = None):
262     ClassData.__init__(self, ClassData.DEFAULT, classData)
263    
264     class ClassDataPoint(ClassData):
265    
266     def __init__(self, value = 0, classData = None):
267     ClassData.__init__(self, ClassData.POINT, classData)
268    
269     self.value = value
270    
271     def GetValue(self):
272     return self.value
273    
274     def SetValue(self, value):
275     self.value = value
276    
277     class ClassDataRange(ClassData):
278    
279     def __init__(self, min = 0, max = 1, classData = None):
280     ClassData.__init__(self, ClassData.RANGE, classData)
281    
282     if min >= max:
283     raise ValueError(_("ClassDataRange: %i(min) >= %i(max)!") %
284     (min, max))
285    
286     self.SetRange(min, max)
287    
288     def GetMin(self):
289     return self.min
290    
291     def SetMin(self, min):
292     self.SetRange(min, self.max)
293    
294     def GetMax(self):
295     return self.max
296    
297     def SetMax(self, max):
298     self.SetRange(self.min, max)
299    
300     def SetRange(self, min, max):
301     self.min = min
302     self.max = max
303     if min >= max:
304     raise ValueError(_("ClassDataRange: %i(min) >= %i(max)!") %
305     (min, max))
306    
307     def GetRange(self):
308     return (self.min, self.max)
309    
310     def InRange(self, value):
311     return self.min <= value < self.max
312    
313     class ClassDataMap(ClassData):
314    
315     FUNC_ID = "id"
316    
317     def __init__(self, map_type = FUNC_ID, func = None, classData = None):
318     ClassData.__init__(self, ClassData.MAP, classData)
319    
320     self.map_type = map_type
321     self.func = func
322    
323     if self.func is None:
324     self.func = func_id
325    
326     def Map(self, value):
327     return self.func(value)
328    
329     #
330     # built-in mappings
331     #
332     def func_id(value):
333     return value
334    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26