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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 388 by jonathan, Mon Feb 10 15:25:05 2003 UTC revision 428 by jonathan, Mon Feb 24 18:46:35 2003 UTC
# Line 16  an input value falls with a range that d Line 16  an input value falls with a range that d
16  If no mapping can be found then default data will  If no mapping can be found then default data will
17  be returned. Input values must be hashable objects  be returned. Input values must be hashable objects
18    
19  See the description of getProperties() for more information  See the description of GetClassData() for more information
20  on the mapping algorithm.  on the mapping algorithm.
21  """  """
22        
23    # fix for people using python2.1
24    from __future__ import nested_scopes
25    
26  from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \  from messages import LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \
27       LAYER_VISIBILITY_CHANGED       LAYER_VISIBILITY_CHANGED
28    
# Line 35  RANGE_DATA = 2 Line 38  RANGE_DATA = 2
38    
39  class Classification:  class Classification:
40    
41      def __init__(self, layer, field = None):      def __init__(self, layer = None, field = None):
42          """Initialize a classification.          """Initialize a classification.
43    
44             layer -- the layer object who owns this classification             layer -- the layer object who owns this classification
# Line 47  class Classification: Line 50  class Classification:
50          self.layer = layer          self.layer = layer
51          self.points = {}          self.points = {}
52          self.ranges = []          self.ranges = []
53          self.DefaultData = ClassData()          self.maps   = []
54            self.DefaultData = ClassDataDefault()
55          self.field = field          self.field = field
56          #self.SetField(field)          #self.SetField(field)
57    
58        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            if self.layer is not None:
66                self.layer.changed(message, self.layer)
67        
68      def SetField(self, field):      def SetField(self, field):
69          """Set the name of the data table field to use.          """Set the name of the data table field to use.
70                    
# Line 58  class Classification: Line 72  class Classification:
72          """          """
73    
74          self.field = field          self.field = field
75          self.layer.changed(LAYER_LEGEND_CHANGED, self.layer)          self.__SendMessage(LAYER_LEGEND_CHANGED)
76    
77      def GetField(self):      def GetField(self):
78          return self.field          return self.field
79    
80        def SetLayer(self, layer):
81            self.layer = layer
82            self.__SendMessage(LAYER_LEGEND_CHANGED)
83    
84        def GetLayer(self):
85            return layer.self
86    
87      def SetDefaultData(self, data):      def SetDefaultData(self, data):
88          """Set the data to be used when a value can't be classified.          """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.             data -- data that the value maps to. See class description.
91          """          """
92    
93            assert(data.GetType() == ClassData.DEFAULT)
94          self.DefaultData = data          self.DefaultData = data
95    
96      def GetDefaultData(self):      def GetDefaultData(self):
97          return self.DefaultData          return self.DefaultData
98    
99        #
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      def SetDefaultFill(self, fill):      def SetDefaultFill(self, fill):
106          self.DefaultData.SetFill(fill)          self.DefaultData.SetFill(fill)
107          self.layer.changed(LAYER_LEGEND_CHANGED, self.layer)          self.__SendMessage(LAYER_LEGEND_CHANGED)
108                    
109      def GetDefaultFill(self):      def GetDefaultFill(self):
110          return self.DefaultData.GetFill()          return self.DefaultData.GetFill()
111                    
112      def SetDefaultStroke(self, stroke):      def SetDefaultStroke(self, stroke):
113          self.DefaultData.SetStroke(stroke)          self.DefaultData.SetStroke(stroke)
114          self.layer.changed(LAYER_LEGEND_CHANGED, self.layer)          self.__SendMessage(LAYER_LEGEND_CHANGED)
115                    
116      def GetDefaultStroke(self):      def GetDefaultStroke(self):
117          return self.DefaultData.GetStroke()          return self.DefaultData.GetStroke()
118                    
119      def SetDefaultStrokeWidth(self, strokeWidth):      def SetDefaultStrokeWidth(self, strokeWidth):
120          self.DefaultData.SetStrokeWidth(strokeWidth)          self.DefaultData.SetStrokeWidth(strokeWidth)
121          self.layer.changed(LAYER_LEGEND_CHANGED, self.layer)          self.__SendMessage(LAYER_LEGEND_CHANGED)
122                    
123      def GetDefaultStrokeWidth(self):      def GetDefaultStrokeWidth(self):
124          return self.DefaultData.GetStrokeWidth()          return self.DefaultData.GetStrokeWidth()
125                    
126      def AddRange(self, min, max, data):      def AddClassData(self, item):
127          """Add a new range to the classification.          type = item.GetType()
   
            A range allows a value to be classified if it falls between  
            min and max. Specifically, min <= value < max  
           
            min -- the lower bound.  
   
            max -- the upper bound.  
   
            data -- data that the value maps to. See class description.  
         """  
   
         if min >= max:  
             raise ValueError(_("Range minimum >= maximum!"))  
         self.ranges.append([min, max, data])  
         self.layer.changed(LAYER_LEGEND_CHANGED, self.layer)  
   
     def AddPoint(self, value, data):  
         """Associate a single value with data.  
128    
129             When this value is to be classified data will be returned.          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    
140             value -- classification value.          self.__SendMessage(LAYER_LEGEND_CHANGED)
   
            data  -- data that the value maps to. See class description.  
         """  
141    
142          self.points[value] = data      def GetClassData(self, value):
         self.layer.changed(LAYER_LEGEND_CHANGED, self.layer)  
   
     def GetProperties(self, value):  
143          """Return the associated data, or the default data.          """Return the associated data, or the default data.
144    
145             The following search technique is used:             The following search technique is used:
# Line 137  class Classification: Line 150  class Classification:
150                     the classification.                     the classification.
151    
152             value -- the value to classify. If there is no mapping,             value -- the value to classify. If there is no mapping,
153                      or value is None, return the default data                      or value is None, return the default properties
                     (which may be None)  
154          """          """
155    
156          if self.field is not None and value is not None:          if self.field is not None and value is not None:
157              #              #
158              # first check the discrete values              # check the discrete values
159              #              #
160              if self.points.has_key(value):              if self.points.has_key(value):
161                  return self.points[value]                  return self.points[value]
162    
163              #              #
164              # now check the ranges              # check the ranges
165              #              #
166              for p in self.ranges:              for p in self.ranges:
167                  if (p[RANGE_MIN] <= value) and (value < p[RANGE_MAX]):                  if p.InRange(value):
168                      return p[RANGE_DATA]                      return p
169    
170                #
171                # check the maps
172                #
173                for p in self.maps:
174                    try:
175                        return p.Map(value)
176                    except: pass
177    
178          return self.DefaultData          return self.DefaultData
179    
180      def TreeInfo(self):      def TreeInfo(self):
181          items = []          items = []
182    
183          #          def build_color_item(text, color):
184          # XXX: shouldn't print anything if there are no classifications              if color is Color.None:
185          #                  return ("%s: %s" % (text, _("None")), None)
186    
187                return ("%s: (%.3f, %.3f, %.3f)" %
188                        (text, color.red, color.green, color.blue),
189                        color)
190    
191            def build_item(data, string):
192                label = data.GetLabel()
193                if label == "":
194                    label = string
195                else:
196                    label += " (%s)" % string
197    
           
         def color_string(color):  
             if color is None:  
                 return "None"  
             return "(%.3f, %.3f, %.3f)" % (color.red, color.green, color.blue)  
   
         def build_item(data):  
198              i = []              i = []
   
199              v = data.GetStroke()              v = data.GetStroke()
200              i.append((_("Stroke: %s") % color_string(v), v))              i.append(build_color_item(_("Stroke"), v))
201              v = data.GetStrokeWidth()              v = data.GetStrokeWidth()
202              i.append((_("Stroke Width: %s") % v))              i.append(_("Stroke Width: %s") % v)
203              v = data.GetFill()              v = data.GetFill()
204              i.append((_("Fill: %s") % color_string(v), v))              i.append(build_color_item(_("Fill"), v))
205              return i              return (label, i)
206    
207          items.append((_("'DEFAULT'"), build_item(self.DefaultData)))          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    
217          for name, data in self.points.items():  #       for p in self.points.values():
218              items.append((_("%s") % name, build_item(data)))  #           items.append(build_item(p, str(p.GetValue())))
219    
220          for p in self.ranges:  #       for p in self.ranges:
221              data = p[RANGE_DATA]  #           items.append(build_item(p, "%s - %s" % (p.GetMin(), p.GetMax())))
             items.append((_("%s-%s") % (p[RANGE_MIN], p[RANGE_MAX])),  
                          build_item(data))  
222    
223          return (_("Classifications"), items)          return (_("Classifications"), items)
224    
225    class ClassIterator:
226    
227        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  class ClassData:  class ClassData:
250    
251      def __init__(self):      INVALID = -1
252          self.stroke = None      DEFAULT = 0
253          self.stroke_width = 0      POINT = 1
254          self.fill = None      RANGE = 2
255        MAP   = 3
256    
257        def __init__(self, classData = None, type = INVALID):
258    
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          self.label = ""          self.label = ""
270            
271        def GetType(self):
272            return self.type
273    
274      def GetStroke(self):      def GetStroke(self):
275          return self.stroke          return self.stroke
276    
277      def SetStroke(self, stroke):      def SetStroke(self, stroke):
278            assert(isinstance(stroke, Color))
279          self.stroke = stroke          self.stroke = stroke
280    
281      def GetStrokeWidth(self):      def GetStrokeWidth(self):
282          return self.stroke_width          return self.stroke_width
283    
284      def SetStrokeWidth(self, stroke_width):      def SetStrokeWidth(self, stroke_width):
285            if (stroke_width < 1):
286                raise ValueError(_("stroke_width < 1"))
287    
288          self.stroke_width = stroke_width          self.stroke_width = stroke_width
289    
290      def GetFill(self):      def GetFill(self):
291          return self.fill          return self.fill
292    
293      def SetFill(self, fill):      def SetFill(self, fill):
294            assert(isinstance(fill, Color))
295          self.fill = fill          self.fill = fill
296    
297      def GetLabel(self):      def GetLabel(self):
# Line 227  class ClassData: Line 300  class ClassData:
300      def SetLabel(self, label):      def SetLabel(self, label):
301          self.label = label          self.label = label
302    
303    class ClassDataDefault(ClassData):
304        def __init__(self, classData = None):
305            ClassData.__init__(self, classData, ClassData.DEFAULT)
306        
307    class ClassDataPoint(ClassData):
308    
309        def __init__(self, value = 0, classData = None):
310            ClassData.__init__(self, classData, ClassData.POINT)
311    
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            ClassData.__init__(self, classData, ClassData.RANGE)
324    
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            ClassData.__init__(self, classData, ClassData.MAP)
362    
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    

Legend:
Removed from v.388  
changed lines
  Added in v.428

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26