/[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

revision 1157 by jonathan, Thu Jun 12 12:39:54 2003 UTC revision 1759 by bh, Fri Sep 26 18:36:01 2003 UTC
# Line 15  __version__ = "$Revision$" Line 15  __version__ = "$Revision$"
15    
16  import operator  import operator
17    
18  from color import Color  from color import Color, Transparent
19  from range import Range  from range import Range
20  from classification import Classification, ClassGroupSingleton, \  from classification import Classification, ClassGroupSingleton, \
21      ClassGroupRange, ClassGroupProperties      ClassGroupRange, ClassGroupProperties
22    
23  def generate_singletons(_list, numGroups, ramp):  def generate_singletons(_list, ramp):
24      """Generate a new classification consisting solely of singletons.      """Generate a new classification consisting solely of singletons.
25    
26      The resulting classification will consist of at most 'numGroups'      The resulting classification will consist of one group for each
27      groups whose group properties ramp between 'prop1' and 'prop2'. There      item in _list whose properties ramp between 'prop1' and 'prop2'.
28      could be fewer groups if '_list' contains fewer that 'numGroups' items.  
29        _list -- a list of values for each singleton
     _list -- any object that implements the iterator interface  
   
     numGroups -- how many groups to generate. This can not be  
                  determined while the classification is being  
                  generated because the stepping values must  
                  be precalculated to ramp between prop1 and prop2.  
30    
31      ramp -- an object which implements the CustomRamp interface      ramp -- an object which implements the CustomRamp interface
32      """      """
33    
34      clazz = Classification()      clazz = Classification()
     if numGroups == 0: return clazz  
35    
36      ramp.SetNumGroups(numGroups)      i = 0
37        maxValue = float(len(_list) - 1)
38        if maxValue < 1: maxValue = 1
39    
40      for value, prop in zip(_list, ramp):      for value in _list:
41            prop = ramp.GetProperties(i / maxValue)
42          clazz.AppendGroup(ClassGroupSingleton(value, prop))          clazz.AppendGroup(ClassGroupSingleton(value, prop))
43            i += 1
44    
45      return clazz      return clazz
46    
# Line 58  def generate_uniform_distribution(min, m Line 55  def generate_uniform_distribution(min, m
55      """      """
56    
57      clazz = Classification()      clazz = Classification()
     if numGroups == 0: return clazz  
   
     ramp.SetNumGroups(numGroups)  
58    
59      cur_min = min      cur_min = min
60    
     i = 1  
61      end = "["      end = "["
62      for prop in ramp:      maxValue = float(numGroups - 1)
63        if maxValue < 1: maxValue = 1
64    
65        for i in range(1, numGroups + 1):
66    
67            prop = ramp.GetProperties(float(i-1) / maxValue)
68    
69          if intStep:          if intStep:
70              cur_max = min + int(round((i * (max - min + 1)) / float(numGroups)))              cur_max = min + int(round((i * (max - min + 1)) / float(numGroups)))
# Line 78  def generate_uniform_distribution(min, m Line 76  def generate_uniform_distribution(min, m
76              end = "]"              end = "]"
77    
78          if cur_min == cur_max:          if cur_min == cur_max:
79              range = Range(("[", cur_min, cur_max, "]"))              _range = Range(("[", cur_min, cur_max, "]"))
80          else:          else:
81              range = Range(("[", cur_min, cur_max, end))              _range = Range(("[", cur_min, cur_max, end))
82    
83          clazz.AppendGroup(ClassGroupRange(range, None, prop))          clazz.AppendGroup(ClassGroupRange(_range, prop))
84    
85          cur_min = cur_max          cur_min = cur_max
         i += 1  
86    
87      return clazz      return clazz
88    
   
89  def generate_quantiles(_list, percents, ramp, _range):  def generate_quantiles(_list, percents, ramp, _range):
90      """Generates a Classification which has groups of ranges that      """Generates a Classification which has groups of ranges that
91      represent quantiles of _list at the percentages given in percents.      represent quantiles of _list at the percentages given in percents.
# Line 126  def generate_quantiles(_list, percents, Line 122  def generate_quantiles(_list, percents,
122    
123              adjusted = quantiles[0]              adjusted = quantiles[0]
124    
             ramp.SetNumGroups(numGroups)  
   
125              start, min, endMax, right = _range.GetRange()              start, min, endMax, right = _range.GetRange()
126    
127              oldp = 0              oldp = 0
128              i = 1              i = 1
129              end = "]"              end = "]"
130    
131              for (q, p), prop in zip(quantiles[3], ramp):              maxValue = float(numGroups - 1)
132                  if i == numGroups:              if maxValue < 1: maxValue = 1
133                      max = endMax              for (q, p) in quantiles[3]:
                     end = right  
                 else:  
                     max = _list[q]  
   
                 group = ClassGroupRange(Range((start, min, max, end)),  
                                         None, prop)  
       
                 group.SetLabel("%s%% - %s%%" % (round(oldp*100, 2),  
                                                 round(p*100, 2)))  
                 oldp = p  
                 start = "]"  
                 min = max  
                 clazz.AppendGroup(group)  
                 i += 1  
   
     return (adjusted, clazz)  
   
 def GenQuantiles0(_list, percents, ramp, _range):  
     """Same as GenQuantiles, but the first class won't be added to  
     the classification.  
134    
135      Returns a tuple (adjusted, Classification, upper_class0) where                  prop = ramp.GetProperties(float(i-1) / maxValue)
     upper_class0 is the highest value inside the first class.  
136    
     _list -- a sort list of values  
   
     percents -- a sorted list of floats in the range 0.0-1.0 which  
                 represent the upper bound of each quantile. the  
                 union of all percentiles should be the entire  
                 range from 0.0-1.0  
   
     ramp -- an object which implements the CustomRamp interface  
   
     _range -- a Range object  
   
     Raises a Value Error if 'percents' has fewer than two items, or  
     does not cover the entire range.  
     """  
   
     clazz = Classification()  
     quantiles = calculate_quantiles(_list, percents, _range)  
     adjusted = True  
   
     if quantiles is not None:  
   
         numGroups = len(quantiles[3]) - 1  
   
         if numGroups > 0:  
             adjusted = quantiles[0]  
   
             ramp.SetNumGroups(numGroups)  
   
             start, min, endMax, right = _range.GetRange()  
   
             class0 = quantiles[3][0]  
             min = _list[class0[0]]  
             oldp = class0[1]  
             i = 1  
             end = "]"  
   
             for (q, p), prop in zip(quantiles[3][1:], ramp):  
137                  if i == numGroups:                  if i == numGroups:
138                      max = endMax                      max = endMax
139                      end = right                      end = right
140                  else:                  else:
141                      max = _list[q]                      max = _list[q]
142    
143                  group = ClassGroupRange(Range((start, min, max, end)),                  group = ClassGroupRange(Range((start, min, max, end)), prop)
                                         None, prop)  
144            
145                  group.SetLabel("%s%% - %s%%" % (round(oldp*100, 2),                  group.SetLabel("%s%% - %s%%" % (round(oldp*100, 2),
146                                                  round(p*100, 2)))                                                  round(p*100, 2)))
# Line 215  def GenQuantiles0(_list, percents, ramp, Line 150  def GenQuantiles0(_list, percents, ramp,
150                  clazz.AppendGroup(group)                  clazz.AppendGroup(group)
151                  i += 1                  i += 1
152    
153      return (adjusted, clazz, _list[class0[0]])      return (adjusted, clazz)
154    
155    
156  def calculate_quantiles(_list, percents, _range):  def calculate_quantiles(_list, percents, _range):
# Line 256  def calculate_quantiles(_list, percents, Line 191  def calculate_quantiles(_list, percents,
191      if len(percents) <= 1:      if len(percents) <= 1:
192          raise ValueError("percents parameter must have more than one item")          raise ValueError("percents parameter must have more than one item")
193    
194      if percents[len(percents) - 1] != 1.0:      if percents[-1] != 1.0:
195          raise ValueError("percents does not cover the entire range")          raise ValueError("percents does not cover the entire range")
196    
197      #      #
# Line 375  def calculate_quantiles(_list, percents, Line 310  def calculate_quantiles(_list, percents,
310                  [(q, (q - minIndex+1) / float(numValues)) \                  [(q, (q - minIndex+1) / float(numValues)) \
311                   for q in quantiles])                   for q in quantiles])
312    
 CLR  = 0  
 STEP = 1  
313  class CustomRamp:  class CustomRamp:
314    
315      def __init__(self, prop1, prop2):      def __init__(self, prop1, prop2):
316            """Create a ramp between prop1 and prop2."""
317          self.prop1 = prop1          self.prop1 = prop1
318          self.prop2 = prop2          self.prop2 = prop2
319    
         self.count = 0  
   
     def __iter__(self):  
         return self  
   
320      def GetRamp(self):      def GetRamp(self):
321            """Return this ramp."""
322          return self          return self
323    
324      def SetNumGroups(self, num):      def GetProperties(self, index):
325            """Return a ClassGroupProperties object whose properties
326          if num <= 0:          represent a point at 'index' between prop1 and prop2 in
327              return False          the constructor.
328    
329          self.count = int(num)          index -- a value such that 0 <= index <= 1
330          num = float(num)          """
331    
332          prop1 = self.prop1          if not (0 <= index <= 1):
333          prop2 = self.prop2              raise ValueError(_("invalid index"))
334    
335          clr = prop1.GetLineColor()          newProps = ClassGroupProperties()
336          lineColor2 = prop2.GetLineColor()  
337                    self.__SetProperty(self.prop1.GetLineColor(),
338          self.noLine = clr is not Color.Transparent \                             self.prop2.GetLineColor(),
339                          and lineColor2 is not Color.Transparent                             index, newProps.SetLineColor)
340            self.__SetProperty(self.prop1.GetFill(), self.prop2.GetFill(),
341                               index, newProps.SetFill)
342          self.lineInfo = self.__GetColorInfo(prop1.GetLineColor(),  
343                                              prop2.GetLineColor(),          w = (self.prop2.GetLineWidth() - self.prop1.GetLineWidth()) \
344                                              num)              * index \
345                + self.prop1.GetLineWidth()
346          self.fillInfo = self.__GetColorInfo(prop1.GetFill(),          newProps.SetLineWidth(int(round(w)))
347                                              prop2.GetFill(),  
348                                              num)          return newProps
349    
350          self.lineWidth = prop1.GetLineWidth()      def __SetProperty(self, color1, color2, index, setf):
351          self.lineWidthStep = (prop2.GetLineWidth() - self.lineWidth) / num          """Use setf to set the appropriate property for the point
352            index percent between color1 and color2. setf is a function
353          return True          to call that accepts a Color object or Transparent.
354            """
355      def next(self):  
356          if self.count == 0:          if color1 is Transparent and color2 is Transparent:
357              raise StopIteration              setf(Transparent)
358            elif color1 is Transparent:
359          prop = ClassGroupProperties()              setf(Color(
360                     color2.red   * index,
361          if self.lineInfo is None:                   color2.green * index,
362              prop.SetLineColor(Color.Transparent)                   color2.blue  * index))
363          else:          elif color2 is Transparent:
364              prop.SetLineColor(Color(self.lineInfo[CLR][0] / 255,              setf(Color(
365                                      self.lineInfo[CLR][1] / 255,                   color1.red   * index,
366                                      self.lineInfo[CLR][2] / 255))                   color1.green * index,
367                     color1.blue  * index))
             self.lineInfo[CLR][0] += self.lineInfo[STEP][0]  
             self.lineInfo[CLR][1] += self.lineInfo[STEP][1]  
             self.lineInfo[CLR][2] += self.lineInfo[STEP][2]  
   
         if self.fillInfo is None:  
             prop.SetFill(Color.Transparent)  
368          else:          else:
369              prop.SetFill(Color(self.fillInfo[CLR][0] / 255,              setf(Color(
370                              self.fillInfo[CLR][1] / 255,                  (color2.red   - color1.red)   * index + color1.red,
371                              self.fillInfo[CLR][2] / 255))                  (color2.green - color1.green) * index + color1.green,
372                    (color2.blue  - color1.blue)  * index + color1.blue))
             self.fillInfo[CLR][0] += self.fillInfo[STEP][0]  
             self.fillInfo[CLR][1] += self.fillInfo[STEP][1]  
             self.fillInfo[CLR][2] += self.fillInfo[STEP][2]  
   
373    
374          prop.SetLineWidth(int(self.lineWidth))  class MonochromaticRamp(CustomRamp):
375          self.lineWidth        += self.lineWidthStep      """Helper class to make ramps between two colors."""
   
         self.count -= 1  
   
         return prop  
   
     def __GetColorInfo(self, color1, color2, numGroups):  
   
         if color1 is Color.Transparent and color2 is Color.Transparent:  
             #  
             # 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)  
376    
377        def __init__(self, start, end):
378            """Create a Monochromatic Ramp.
379    
380          return (color, step)          start -- starting Color
381    
382  class MonochromaticRamp(CustomRamp):          end -- ending Color
383      def __init__(self, start, end):          """
384          sp = ClassGroupProperties()          sp = ClassGroupProperties()
385          sp.SetLineColor(start)          sp.SetLineColor(start)
386          sp.SetFill(start)          sp.SetFill(start)
# Line 498  class MonochromaticRamp(CustomRamp): Line 391  class MonochromaticRamp(CustomRamp):
391    
392          CustomRamp.__init__(self, sp, ep)          CustomRamp.__init__(self, sp, ep)
393    
394  class GreyRamp(MonochromaticRamp):  grey_ramp         = MonochromaticRamp(Color(1, 1, 1),  Color(0, 0, 0))
395      def __init__(self):  red_ramp          = MonochromaticRamp(Color(1, 1, 1),  Color(.8, 0, 0))
396          MonochromaticRamp.__init__(self, Color(1, 1, 1), Color(0, 0, 0))  green_ramp        = MonochromaticRamp(Color(1, 1, 1),  Color(0, .8, 0))
397    blue_ramp         = MonochromaticRamp(Color(1, 1, 1),  Color(0, 0, .8))
398  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))  
399    
400  class HotToColdRamp:  class HotToColdRamp:
401        """A ramp that generates properties with colors ranging from
402        'hot' colors (e.g. red, orange) to 'cold' colors (e.g. green, blue)
403        """
404    
     def __iter__(self):  
         return self  
           
405      def GetRamp(self):      def GetRamp(self):
406            """Return this ramp."""
407          return self          return self
408    
409      def SetNumGroups(self, num):      def GetProperties(self, index):
410          if num < 0:          """Return a ClassGroupProperties object whose properties
411              return False          represent a point at 'index' between "hot" and "cold".
412    
413          self.num = float(num)          index -- a value such that 0 <= index <= 1
414          self.index = 0          """
   
         return True  
   
     def next(self):  
         if self.index == self.num:  
             raise StopIteration  
415    
416          clr = [1.0, 1.0, 1.0]          clr = [1.0, 1.0, 1.0]
417    
418          if self.index < (.25 * self.num):          if index < .25:
419              clr[0] = 0              clr[0] = 0
420              clr[1] = 4 * self.index / self.num              clr[1] = 4 * index
421          elif self.index < (.5 * self.num):          elif index < .5:
422              clr[0] = 0              clr[0] = 0
423              clr[2] = 1 + 4 * (.25 * self.num - self.index) / self.num              clr[2] = 1 + 4 * (.25 - index)
424          elif self.index < (.75 * self.num):          elif index < .75:
425              clr[0] = 4 * (self.index - .5 * self.num) / self.num              clr[0] = 4 * (index - .5)
426              clr[2] = 0              clr[2] = 0
427          else:          else:
428              clr[1] = 1 + 4 * (.75 * self.num - self.index) / self.num              clr[1] = 1 + 4 * (.75 - index)
429              clr[2] = 0              clr[2] = 0
430    
         self.index += 1  
   
431          prop = ClassGroupProperties()          prop = ClassGroupProperties()
432          prop.SetLineColor(Color(clr[0], clr[1], clr[2]))          prop.SetLineColor(Color(clr[0], clr[1], clr[2]))
433          prop.SetFill(Color(clr[0], clr[1], clr[2]))          prop.SetFill(Color(clr[0], clr[1], clr[2]))
434    
435          return prop          return prop
436    
437    class FixedRamp:
438        """FixedRamp allows particular properties of a ramp to be
439        held constant over the ramp.
440        """
441    
442        def __init__(self, ramp, fixes):
443            """
444            ramp -- a source ramp to get the default properties
445    
446            fixes -- a tuple (lineColor, lineWidth, fillColor) such that
447                 if any item is not None, the appropriate property will
448                 be fixed to that item value.
449            """
450    
451            self.fixes = fixes
452            self.ramp = ramp
453    
454        def GetRamp(self):
455            """Return this ramp."""
456            return self
457    
458        def GetProperties(self, index):
459            """Return a ClassGroupProperties object whose properties
460            represent a point at 'index' between the properties in
461            the ramp that initialized this FixedRamp.
462    
463            index -- a value such that 0 <= index <= 1
464            """
465    
466            props = self.ramp.GetProperties(index)
467            if self.fixes[0] is not None: props.SetLineColor(self.fixes[0])
468            if self.fixes[1] is not None: props.SetLineWidth(self.fixes[1])
469            if self.fixes[2] is not None: props.SetFill(self.fixes[2])
470    
471            return props

Legend:
Removed from v.1157  
changed lines
  Added in v.1759

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26