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

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

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

trunk/thuban/Thuban/Model/classgen.py revision 895 by jonathan, Mon May 12 11:21:02 2003 UTC branches/WIP-pyshapelib-bramz/Thuban/Model/classgen.py revision 2734 by bramz, Thu Mar 1 12:42:59 2007 UTC
# Line 1  Line 1 
1  # Copyright (c) 2003 by Intevation GmbH  # -*- encoding: iso-8859-1 -*-
2    #
3    # Copyright (c) 2003-2004 by Intevation GmbH
4  # Authors:  # Authors:
5  # Jonathan Coles <[email protected]>  # Jan-Oliver Wagner <[email protected]> (2004)
6    # Bernhard Herzog <[email protected]> (2003)
7    # Thomas K�ster <[email protected]> (2003)
8    # Jonathan Coles <[email protected]> (2003)
9  #  #
10  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
11  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
12    
13    """
14    Functions to generate Classifications
15    """
16    
17    __version__ = "$Revision$"
18    # $Source$
19    # $Id$
20    
21  import operator  import operator
22    
23  from color import Color  from color import Color, Transparent
24  from range import Range  from range import Range
25  from classification import Classification, ClassGroupSingleton, \  from classification import Classification, ClassGroupSingleton, \
26      ClassGroupRange, ClassGroupProperties      ClassGroupRange, ClassGroupProperties
27    
28  class ClassGenerator:  def generate_singletons(_list, ramp):
29        """Generate a new classification consisting solely of singletons.
     def GenSingletonsFromList(self, _list, numGroups, ramp):  
         """Generate a new classification consisting solely of singletons.  
30    
31          The resulting classification will consist of at most 'numGroups'      The resulting classification will consist of one group for each
32          groups whose group properties ramp between 'prop1' and 'prop2'. There      item in _list whose properties ramp between 'prop1' and 'prop2'.
         could be fewer groups if '_list' contains fewer that 'numGroups' items.  
33    
34          _list -- any object that implements the iterator interface      _list -- a list of values for each singleton
35    
36          numGroups -- how many groups to generate. This can not be      ramp -- an object which implements the CustomRamp interface
37                       determined while the classification is being      """
                      generated because the stepping values must  
                      be precalculated to ramp between prop1 and prop2.  
38    
39          prop1 -- initial group property values      clazz = Classification()
40    
41          prop2 -- final group property values      i = 0
42          """      maxValue = float(len(_list) - 1)
43        if maxValue < 1: maxValue = 1
44    
45          clazz = Classification()      for value in _list:
46          if numGroups == 0: return clazz          prop = ramp.GetProperties(i / maxValue)
47            clazz.AppendGroup(ClassGroupSingleton(value, prop))
48            i += 1
49    
50          ramp.SetNumGroups(numGroups)      return clazz
51    
52          for value, prop in zip(_list, ramp):  def generate_uniform_distribution(min, max, numGroups, ramp, intStep = False):
53              clazz.AppendGroup(ClassGroupSingleton(value, prop))      """Generate a classification with numGroups range groups
54        each with the same interval.
55    
56          return clazz      intStep -- force the calculated stepping to an integer.
57                   Useful if the values are integers but the
58                   number of groups specified doesn't evenly
59                   divide (max - min).
60        """
61    
62      def GenSingletons(self, min, max, numGroups, ramp):      clazz = Classification()
63    
64          clazz = Classification()      cur_min = min
65    
66          #step = int((max - min) / float(numGroups))      end = "["
67        maxValue = float(numGroups - 1)
68        if maxValue < 1: maxValue = 1
69    
70          if numGroups > 0:      for i in range(1, numGroups + 1):
71    
72              step = int((max - min + 1) / float(numGroups))          prop = ramp.GetProperties(float(i-1) / maxValue)
             cur_value = min  
73    
74              ramp.SetNumGroups(numGroups)          if intStep:
75                cur_max = min + int(round((i * (max - min + 1)) / float(numGroups)))
76            else:
77                cur_max = min + (i * (max - min)) / float(numGroups)
78    
79              for prop in ramp:          if i == numGroups:
80                  clazz.AppendGroup(ClassGroupSingleton(cur_value), prop)              cur_max = max
81                  cur_value += step              end = "]"
82    
83          return clazz          if cur_min == cur_max:
84                _range = Range(("[", cur_min, cur_max, "]"))
85            else:
86                _range = Range(("[", cur_min, cur_max, end))
87    
88      def GenUnifromDistribution(self, min, max, numGroups,          clazz.AppendGroup(ClassGroupRange(_range, prop))
                                ramp, intStep = False):  
         """Generate a classification with numGroups range groups  
         each with the same interval.  
89    
90          intStep -- force the calculated stepping to an integer.          cur_min = cur_max
                    Useful if the values are integers but the  
                    number of groups specified doesn't evenly  
                    divide (max - min).  
         """  
91    
92          clazz = Classification()      return clazz
         if numGroups == 0: return clazz  
93    
94          ramp.SetNumGroups(numGroups)  def generate_quantiles(_list, percents, ramp, _range):
95        """Generates a Classification which has groups of ranges that
96        represent quantiles of _list at the percentages given in percents.
97        Only the values that fall within _range are considered.
98    
99          step = (max - min) / float(numGroups)      Returns a tuple (adjusted, Classification) where adjusted is
100        True if the Classification does not exactly represent the given
101        range, or if the Classification is empty.
102    
103          if intStep:      _list -- a sort list of values
             step = int(step)  
104    
105          cur_min = min      percents -- a sorted list of floats in the range 0.0-1.0 which
106          cur_max = cur_min + step                  represent the upper bound of each quantile. the
107                    union of all percentiles should be the entire
108                    range from 0.0-1.0
109    
110          i = 0      ramp -- an object which implements the CustomRamp interface
         end = "["  
         for prop in ramp:  
111    
112              if i == (numGroups - 1):      _range -- a Range object
                 cur_max = max  
                 end = "]"  
113    
114        Raises a Value Error if 'percents' has fewer than two items, or
115        does not cover the entire range.
116        """
117    
118              # this check guards against rounding issues      clazz = Classification()
119              if cur_min != cur_max:      quantiles = calculate_quantiles(_list, percents, _range)
120                  range = Range("[" + str(float(cur_min)) + ";" +      adjusted = True
                                     str(float(cur_max)) + end)  
                 clazz.AppendGroup(ClassGroupRange(range, None, prop))  
121    
122              cur_min = cur_max      if quantiles is not None:
             cur_max += step  
             i += 1  
123    
124          return clazz          numGroups = len(quantiles[3])
125    
126            if numGroups != 0:
127    
128      def GenQuantiles(self, _list, percents, ramp, _range):              adjusted = quantiles[0]
         """Generates a Classification which has groups of ranges that  
         represent quantiles of _list at the percentages given in percents.  
         Only the values that fall within _range are considered.  
129    
130          Returns a tuple (adjusted, Classification) where adjusted is              start, min, endMax, right = _range.GetRange()
         True if the Classification does not exactly represent the given  
         range, or if the Classification is empty.  
131    
132          _list -- a sort list of values              oldp = 0
133                i = 1
134                end = "]"
135    
136          percents -- a sorted list of floats in the range 0.0-1.0 which              maxValue = float(numGroups - 1)
137                      represent the upper bound of each quantile              if maxValue < 1: maxValue = 1
138                for (q, p) in quantiles[3]:
139    
140          ramp -- an object which implements the CustomRamp interface                  prop = ramp.GetProperties(float(i-1) / maxValue)
141    
142          _range -- a Range object                  if i == numGroups:
143          """                      max = endMax
144                        end = right
145                    else:
146                        max = _list[q]
147    
148          clazz = Classification()                  group = ClassGroupRange(Range((start, min, max, end)), prop)
         quantiles = self.CalculateQuantiles(_list, percents, _range)  
         adjusted = True  
149    
150          if quantiles is not None:                  group.SetLabel("%s%% - %s%%" % (round(oldp*100, 2),
151                                                    round(p*100, 2)))
152                    oldp = p
153                    start = "]"
154                    min = max
155                    clazz.AppendGroup(group)
156                    i += 1
157    
158              numGroups = len(quantiles[3])      return (adjusted, clazz)
159    
             if numGroups != 0:  
160    
161                  adjusted = quantiles[0]  def calculate_quantiles(_list, percents, _range):
162        """Calculate quantiles for the given _list of percents from the
163        sorted list of values that are in range.
164    
165                  ramp.SetNumGroups(numGroups)      This may not actually generate len(percents) quantiles if
166        many of the values that fall on quantile borders are the same.
167    
168                  min = _list[quantiles[1]]      Returns a tuple of the form:
169                  start = "["          (adjusted, minIndex, maxIndex, [quantile_list])
                 oldp = 0  
                 for (q, p), prop in zip(quantiles[3], ramp):  
                     max = _list[q]  
                     group = ClassGroupRange(Range(start + str(min) + ";" +  
                                                           str(max) + "]"),  
                                             None, prop)  
           
                     group.SetLabel("%s%% - %s%%" % (round(oldp*100, 2),  
                                                     round(p*100, 2)))  
                     oldp = p  
                     start = "]"  
                     min = max  
                     clazz.AppendGroup(group)  
   
         return (adjusted, clazz)  
   
     def CalculateQuantiles(self, _list, percents, _range):  
         """Calculate quantiles for the given _list of percents from the  
         sorted list of values that are in range.  
                                                                                   
         This may not actually generate len(percents) quantiles if  
         many of the values that fall on quantile borders are the same.  
   
         Returns a tuple of the form:  
             (adjusted, minIndex, maxIndex, [quantile_list])  
   
         where adjusted is True if the the quantile percentages differ from  
         those supplied, minIndex is the index into _list where the  
         minimum value used is located, maxIndex is the index into _list  
         where the maximum value used is located, and quantile_list is a  
         list of tuples of the form: (list_index, quantile_percentage)  
   
         Returns None, if no quantiles could be generated based on the  
         given range or input list.  
170    
171          _list -- a sort list of values      where adjusted is True if the the quantile percentages differ from
172        those supplied, minIndex is the index into _list where the
173        minimum value used is located, maxIndex is the index into _list
174        where the maximum value used is located, and quantile_list is a
175        list of tuples of the form: (list_index, quantile_percentage)
176    
177          percents -- a sorted list of floats in the range 0.0-1.0 which      Returns None, if no quantiles could be generated based on the
178                      represent the upper bound of each quantile      given range or input list.
179    
180          _range -- a Range object      _list -- a sort list of values
         """  
       
         quantiles = []  
         adjusted = False  
181    
182          if len(percents) != 0:      percents -- a sorted list of floats in the range 0.0-1.0 which
183                                                                                                  represent the upper bound of each quantile. the
184              #                  union of all percentiles should be the entire
185              # find what part of the _list range covers                  range from 0.0-1.0
             #  
             minIndex = -1  
             maxIndex = -2  
             for i in xrange(0, len(_list), 1):  
                 if operator.contains(_range, _list[i]):  
                     minIndex = i  
                     break  
   
             for i in xrange(len(_list)-1, -1, -1):  
                 if operator.contains(_range, _list[i]):  
                     maxIndex = i  
                     break  
   
             numValues = maxIndex - minIndex + 1  
   
             if numValues > 0:  
   
                 #  
                 # build a list of unique indices into list of where each  
                 # quantile *should* be. set adjusted if the resulting  
                 # indices are different  
                 #  
                 quantiles = {}  
                 for p in percents:  
                     index = min(minIndex + int(p*numValues)-1, maxIndex)  
   
                     adjusted = adjusted \  
                         or quantiles.has_key(index) \  
                         or ((index - minIndex + 1) / float(numValues)) != p  
   
                     quantiles[index] = 0  
   
                 quantiles = quantiles.keys()  
                 quantiles.sort()  
   
                 #  
                 # the current quantile index must be strictly greater than  
                 # the lowerBound  
                 #  
                 lowerBound = minIndex - 1  
       
                 for qindex in xrange(len(quantiles)):  
                     if lowerBound >= maxIndex:  
                         # discard higher quantiles  
                         quantiles = quantiles[:qindex]  
                         break  
       
                     # lowerBound + 1 is always a valid index  
       
                     #  
                     # bump up the current quantile index to be a usable index  
                     # if it currently falls below the lowerBound  
                     #  
                     if quantiles[qindex] <= lowerBound:  
                         quantiles[qindex] = lowerBound + 1  
           
                     listIndex = quantiles[qindex]  
                     value = _list[listIndex]  
       
                     #  
                     # look for similar values around the quantile index  
                     #  
                     lindex = listIndex - 1  
                     while lindex > lowerBound and value == _list[lindex]:  
                         lindex -= 1  
                     lcount = (listIndex - 1) - lindex  
       
                     rindex = listIndex + 1  
                     while rindex < maxIndex + 1 and value == _list[rindex]:  
                         rindex += 1  
                     rcount = (listIndex + 1) - rindex  
       
                     #  
                     # adjust the current quantile index based on how many  
                     # numbers in the _list are the same as the current value  
                     #  
                     newIndex = listIndex  
                     if lcount == rcount:  
                         if lcount != 0:  
                             #  
                             # there are an equal number of numbers to the left  
                             # and right, try going to the left first unless  
                             # doing so creates an empty quantile.  
                             #  
                             if lindex != lowerBound:  
                                 newIndex = lindex  
                             else:  
                                 newIndex = rindex - 1  
       
                     elif lcount < rcount:  
                         # there are fewer items to the left, so  
                         # try going to the left first unless  
                         # doing so creates an empty quantile.  
                         if lindex != lowerBound:  
                             newIndex = lindex  
                         else:  
                             newIndex = rindex - 1  
       
                     elif rcount < lcount:  
                         # there are fewer items to the right, so go to the right  
                         newIndex = rindex - 1  
       
                     adjusted = adjusted or newIndex != listIndex  
186    
187                      quantiles[qindex] = newIndex      _range -- a Range object
                     lowerBound = quantiles[qindex]  
       
         #  
         # since quantiles is only set if the code is at least a little  
         # successful, an empty list will be generated in the case that  
         # we fail to get to the real body of the algorithm  
         #  
         if len(quantiles) == 0:  
             return None  
         else:  
             return (adjusted, minIndex, maxIndex,  
                     [(q, (q - minIndex+1) / float(numValues)) \  
                      for q in quantiles])  
188    
189  CLR  = 0      Raises a Value Error if 'percents' has fewer than two items, or
190  STEP = 1      does not cover the entire range.
191  class CustomRamp:      """
192    
193      def __init__(self, prop1, prop2):      quantiles = []
194          self.prop1 = prop1      adjusted = False
         self.prop2 = prop2  
195    
196          self.count = 0      if len(percents) <= 1:
197            raise ValueError("percents parameter must have more than one item")
198    
199      def __iter__(self):      if percents[-1] != 1.0:
200          return self          raise ValueError("percents does not cover the entire range")
201    
202      def GetRamp(self):      #
203          return self      # find what part of the _list range covers
204        #
205        minIndex = -1
206        maxIndex = -2
207        for i in xrange(0, len(_list), 1):
208            if operator.contains(_range, _list[i]):
209                minIndex = i
210                break
211    
212      def SetNumGroups(self, num):      for i in xrange(len(_list)-1, -1, -1):
213            if operator.contains(_range, _list[i]):
214                maxIndex = i
215                break
216    
217          if num <= 0:      numValues = maxIndex - minIndex + 1
             return False  
218    
219          self.count = int(num)      if numValues > 0:
         num = float(num)  
220    
221          prop1 = self.prop1          #
222          prop2 = self.prop2          # build a list of unique indices into list of where each
223            # quantile *should* be. set adjusted if the resulting
224            # indices are different
225            #
226            quantiles = {}
227            for p in percents:
228                index = min(minIndex + int(p*numValues)-1, maxIndex)
229    
230                adjusted = adjusted \
231                    or quantiles.has_key(index) \
232                    or ((index - minIndex + 1) / float(numValues)) != p
233    
234          clr = prop1.GetLineColor()              quantiles[index] = 0
         lineColor2 = prop2.GetLineColor()  
           
         self.noLine = clr is not Color.Transparent \  
                         and lineColor2 is not Color.Transparent  
235    
236            quantiles = quantiles.keys()
237            quantiles.sort()
238    
239          self.lineInfo = self.__GetColorInfo(prop1.GetLineColor(),          #
240                                              prop2.GetLineColor(),          # the current quantile index must be strictly greater than
241                                              num)          # the lowerBound
242            #
243            lowerBound = minIndex - 1
244    
245          self.fillInfo = self.__GetColorInfo(prop1.GetFill(),          for qindex in xrange(len(quantiles)):
246                                              prop2.GetFill(),              if lowerBound >= maxIndex:
247                                              num)                  # discard higher quantiles
248                    quantiles = quantiles[:qindex]
249                    break
250    
251          self.lineWidth = prop1.GetLineWidth()              # lowerBound + 1 is always a valid index
         self.lineWidthStep = (prop2.GetLineWidth() - self.lineWidth) / num  
252    
253          return True              #
254                # bump up the current quantile index to be a usable index
255                # if it currently falls below the lowerBound
256                #
257                if quantiles[qindex] <= lowerBound:
258                    quantiles[qindex] = lowerBound + 1
259    
260      def next(self):              listIndex = quantiles[qindex]
261          if self.count == 0:              value = _list[listIndex]
             raise StopIteration  
262    
263          prop = ClassGroupProperties()              #
264                # look for similar values around the quantile index
265                #
266                lindex = listIndex - 1
267                while lindex > lowerBound and value == _list[lindex]:
268                    lindex -= 1
269                lcount = (listIndex - 1) - lindex
270    
271                rindex = listIndex + 1
272                while rindex < maxIndex + 1 and value == _list[rindex]:
273                    rindex += 1
274                rcount = (listIndex + 1) - rindex
275    
276          if self.lineInfo is None:              #
277              prop.SetLineColor(Color.Transparent)              # adjust the current quantile index based on how many
278          else:              # numbers in the _list are the same as the current value
279              prop.SetLineColor(Color(self.lineInfo[CLR][0] / 255,              #
280                                      self.lineInfo[CLR][1] / 255,              newIndex = listIndex
281                                      self.lineInfo[CLR][2] / 255))              if lcount == rcount:
282                    if lcount != 0:
283              self.lineInfo[CLR][0] += self.lineInfo[STEP][0]                      #
284              self.lineInfo[CLR][1] += self.lineInfo[STEP][1]                      # there are an equal number of numbers to the left
285              self.lineInfo[CLR][2] += self.lineInfo[STEP][2]                      # and right, try going to the left first unless
286                        # doing so creates an empty quantile.
287                        #
288                        if lindex != lowerBound:
289                            newIndex = lindex
290                        else:
291                            newIndex = rindex - 1
292    
293          if self.fillInfo is None:              elif lcount < rcount:
294              prop.SetFill(Color.Transparent)                  # there are fewer items to the left, so
295          else:                  # try going to the left first unless
296              prop.SetFill(Color(self.fillInfo[CLR][0] / 255,                  # doing so creates an empty quantile.
297                              self.fillInfo[CLR][1] / 255,                  if lindex != lowerBound:
298                              self.fillInfo[CLR][2] / 255))                      newIndex = lindex
299                    else:
300                        newIndex = rindex - 1
301    
302                elif rcount < lcount:
303                    # there are fewer items to the right, so go to the right
304                    newIndex = rindex - 1
305    
306                adjusted = adjusted or newIndex != listIndex
307    
308                quantiles[qindex] = newIndex
309                lowerBound = quantiles[qindex]
310    
311        if len(quantiles) == 0:
312            return None
313        else:
314            return (adjusted, minIndex, maxIndex,
315                    [(q, (q - minIndex+1) / float(numValues)) \
316                     for q in quantiles])
317    
318              self.fillInfo[CLR][0] += self.fillInfo[STEP][0]  class CustomRamp:
             self.fillInfo[CLR][1] += self.fillInfo[STEP][1]  
             self.fillInfo[CLR][2] += self.fillInfo[STEP][2]  
319    
320        def __init__(self, prop1, prop2):
321            """Create a ramp between prop1 and prop2."""
322            self.prop1 = prop1
323            self.prop2 = prop2
324    
325          prop.SetLineWidth(int(self.lineWidth))      def GetRamp(self):
326          self.lineWidth        += self.lineWidthStep          """Return this ramp."""
327            return self
328    
329          self.count -= 1      def GetProperties(self, index):
330            """Return a ClassGroupProperties object whose properties
331            represent a point at 'index' between prop1 and prop2 in
332            the constructor.
333    
334          return prop          index -- a value such that 0 <= index <= 1
335            """
336    
337      def __GetColorInfo(self, color1, color2, numGroups):          if not (0 <= index <= 1):
338                raise ValueError(_("invalid index"))
339    
340          if color1 is Color.Transparent and color2 is Color.Transparent:          newProps = ClassGroupProperties()
             #  
             # returning early  
             #  
             return None  
         elif color1 is not Color.Transparent and color2 is Color.Transparent:  
             color = [color1.red   * 255,  
                      color1.green * 255,  
                      color1.blue  * 255]  
             step = (0, 0, 0)  
         elif color1 is Color.Transparent and color2 is not Color.Transparent:  
             color = [color2.red   * 255,  
                      color2.green * 255,  
                      color2.blue  * 255]  
             step = (0, 0, 0)  
         else:  
             color = [color1.red   * 255,  
                      color1.green * 255,  
                      color1.blue  * 255]  
             step = ((color2.red   * 255 - color1.red   * 255)   / numGroups,  
                     (color2.green * 255 - color1.green * 255) / numGroups,  
                     (color2.blue  * 255 - color1.blue  * 255)  / numGroups)  
341    
342            self.__SetProperty(self.prop1.GetLineColor(),
343                               self.prop2.GetLineColor(),
344                               index, newProps.SetLineColor)
345            self.__SetProperty(self.prop1.GetFill(), self.prop2.GetFill(),
346                               index, newProps.SetFill)
347    
348            w = (self.prop2.GetLineWidth() - self.prop1.GetLineWidth()) \
349                * index \
350                + self.prop1.GetLineWidth()
351            newProps.SetLineWidth(int(round(w)))
352    
353            s = (self.prop2.GetSize() - self.prop1.GetSize()) \
354                * index \
355                + self.prop1.GetSize()
356            newProps.SetSize(int(round(s)))
357    
358            return newProps
359    
360        def __SetProperty(self, color1, color2, index, setf):
361            """Use setf to set the appropriate property for the point
362            index percent between color1 and color2. setf is a function
363            to call that accepts a Color object or Transparent.
364            """
365    
366          return (color, step)          if color1 is Transparent and color2 is Transparent:
367                setf(Transparent)
368            elif color1 is Transparent:
369                setf(Color(
370                     color2.red   * index,
371                     color2.green * index,
372                     color2.blue  * index))
373            elif color2 is Transparent:
374                setf(Color(
375                     color1.red   * index,
376                     color1.green * index,
377                     color1.blue  * index))
378            else:
379                setf(Color(
380                    (color2.red   - color1.red)   * index + color1.red,
381                    (color2.green - color1.green) * index + color1.green,
382                    (color2.blue  - color1.blue)  * index + color1.blue))
383    
384  class MonochromaticRamp(CustomRamp):  class MonochromaticRamp(CustomRamp):
385        """Helper class to make ramps between two colors."""
386    
387      def __init__(self, start, end):      def __init__(self, start, end):
388            """Create a Monochromatic Ramp.
389    
390            start -- starting Color
391    
392            end -- ending Color
393            """
394          sp = ClassGroupProperties()          sp = ClassGroupProperties()
395          sp.SetLineColor(start)          sp.SetLineColor(start)
396          sp.SetFill(start)          sp.SetFill(start)
# Line 435  class MonochromaticRamp(CustomRamp): Line 401  class MonochromaticRamp(CustomRamp):
401    
402          CustomRamp.__init__(self, sp, ep)          CustomRamp.__init__(self, sp, ep)
403    
404  class GreyRamp(MonochromaticRamp):  grey_ramp         = MonochromaticRamp(Color(1, 1, 1),  Color(0, 0, 0))
405      def __init__(self):  red_ramp          = MonochromaticRamp(Color(1, 1, 1),  Color(.8, 0, 0))
406          MonochromaticRamp.__init__(self, Color(1, 1, 1), Color(0, 0, 0))  green_ramp        = MonochromaticRamp(Color(1, 1, 1),  Color(0, .8, 0))
407    blue_ramp         = MonochromaticRamp(Color(1, 1, 1),  Color(0, 0, .8))
408  class RedRamp(MonochromaticRamp):  green_to_red_ramp = MonochromaticRamp(Color(0, .8, 0), Color(1, 0, 0))
     def __init__(self):  
         MonochromaticRamp.__init__(self, Color(1, 1, 1), Color(.8, 0, 0))  
   
 class GreenRamp(MonochromaticRamp):  
     def __init__(self):  
         MonochromaticRamp.__init__(self, Color(1, 1, 1), Color(0, .8, 0))  
   
 class BlueRamp(MonochromaticRamp):  
     def __init__(self):  
         MonochromaticRamp.__init__(self, Color(1, 1, 1), Color(0, 0, .8))  
   
 class GreenToRedRamp(MonochromaticRamp):  
     def __init__(self):  
         MonochromaticRamp.__init__(self, Color(0, .8, 0), Color(1, 0, 0))  
409    
410  class HotToColdRamp:  class HotToColdRamp:
411        """A ramp that generates properties with colors ranging from
412        'hot' colors (e.g. red, orange) to 'cold' colors (e.g. green, blue)
413        """
414    
     def __iter__(self):  
         return self  
           
415      def GetRamp(self):      def GetRamp(self):
416            """Return this ramp."""
417          return self          return self
418    
419      def SetNumGroups(self, num):      def GetProperties(self, index):
420          if num < 0:          """Return a ClassGroupProperties object whose properties
421              return False          represent a point at 'index' between "hot" and "cold".
422    
423          self.num = float(num)          index -- a value such that 0 <= index <= 1
424          self.index = 0          """
   
         return True  
   
     def next(self):  
         if self.index == self.num:  
             raise StopIteration  
425    
426          clr = [1.0, 1.0, 1.0]          clr = [1.0, 1.0, 1.0]
427    
428          if self.index < (.25 * self.num):          if index < .25:
429              clr[0] = 0              clr[0] = 0
430              clr[1] = 4 * self.index / self.num              clr[1] = 4 * index
431          elif self.index < (.5 * self.num):          elif index < .5:
432              clr[0] = 0              clr[0] = 0
433              clr[2] = 1 + 4 * (.25 * self.num - self.index) / self.num              clr[2] = 1 + 4 * (.25 - index)
434          elif self.index < (.75 * self.num):          elif index < .75:
435              clr[0] = 4 * (self.index - .5 * self.num) / self.num              clr[0] = 4 * (index - .5)
436              clr[2] = 0              clr[2] = 0
437          else:          else:
438              clr[1] = 1 + 4 * (.75 * self.num - self.index) / self.num              clr[1] = 1 + 4 * (.75 - index)
439              clr[2] = 0              clr[2] = 0
440    
         self.index += 1  
   
441          prop = ClassGroupProperties()          prop = ClassGroupProperties()
442          prop.SetLineColor(Color(clr[0], clr[1], clr[2]))          prop.SetLineColor(Color(clr[0], clr[1], clr[2]))
443          prop.SetFill(Color(clr[0], clr[1], clr[2]))          prop.SetFill(Color(clr[0], clr[1], clr[2]))
444    
445          return prop          return prop
446    
447  #class Colors16Ramp:  class FixedRamp:
448  #      """FixedRamp allows particular properties of a ramp to be
449      #def __iter__(self):      held constant over the ramp.
450          #return self      """
451  #  
452      #def GetRamp(self):      def __init__(self, ramp, fixes):
453          #return self          """
454  #          ramp -- a source ramp to get the default properties
455      #def SetNumGroups(self, num):  
456          #if num < 0:          fixes -- a tuple (lineColor, lineWidth, fillColor) such that
457              #return False               if any item is not None, the appropriate property will
458  #               be fixed to that item value.
459          #self.index = 0          """
460  #  
461          #return True          self.fixes = fixes
462            self.ramp = ramp
463    
464        def GetRamp(self):
465            """Return this ramp."""
466            return self
467    
468        def GetProperties(self, index):
469            """Return a ClassGroupProperties object whose properties
470            represent a point at 'index' between the properties in
471            the ramp that initialized this FixedRamp.
472    
473            index -- a value such that 0 <= index <= 1
474            """
475    
476            props = self.ramp.GetProperties(index)
477            if self.fixes[0] is not None: props.SetLineColor(self.fixes[0])
478            if self.fixes[1] is not None: props.SetLineWidth(self.fixes[1])
479            if self.fixes[2] is not None: props.SetFill(self.fixes[2])
480    
481            return props

Legend:
Removed from v.895  
changed lines
  Added in v.2734

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26