~alf-rodrigo/cairoplot/trunk

« back to all changes in this revision

Viewing changes to trunk/cairoplot.py

  • Committer: Rodrigo Moreira Araujo
  • Date: 2009-04-03 00:27:44 UTC
  • Revision ID: rodrigo@scrooge-20090403002744-ulxc7229xfyif0cd
cairoplot.py: Modifying color input system. It's now possible to input colors using the method: color = (r,g,b,a,mode) where the mode stands for 'linear', 'radial' or 'solid'.
For the Scatter family (Scatter, DotLine and Function), only solid colors are used independently of which mode is passed.
For the Bar family, only linear and solid colors are used. If 'radial' is passed, 'linear' will be used.
For the Pie family (Pie and Donut), only radial and solid colors will be used. If 'linear' is passed, 'radial' will be used.

Show diffs side-by-side

added added

removed removed

Lines of Context:
52
52
          "yellow_orange_red" : [(1.0,1.0,0.0,1.0), (1.0,0.7,0.0,1.0), (1.0,0.2,0.0,1.0)],
53
53
          "rainbow"           : [(1.0,0.0,0.0,1.0), (1.0,0.5,0.0,1.0), (1.0,1.0,0.0,1.0), (0.0,1.0,0.0,1.0), (0.0,0.0,1.0,1.0), (0.3, 0.0, 0.5,1.0), (0.5, 0.0, 1.0, 1.0)]}
54
54
 
55
 
def colors_from_theme( theme, series_length ):
 
55
def colors_from_theme( theme, series_length, mode = 'solid' ):
56
56
    colors = []
57
57
    if theme not in THEMES.keys() :
58
58
        raise Exception, "Theme not defined" 
59
59
    color_steps = THEMES[theme]
60
60
    n_colors = len(color_steps)
61
61
    if series_length <= n_colors:
62
 
        colors = [color for color in color_steps[0:n_colors]]
 
62
        colors = [color + tuple([mode]) for color in color_steps[0:n_colors]]
63
63
    else:
64
64
        iterations = [(series_length - n_colors)/(n_colors - 1) for i in color_steps[:-1]]
65
65
        over_iterations = (series_length - n_colors) % (n_colors - 1)
69
69
            iterations[i] += 1
70
70
            over_iterations -= 1
71
71
        for index,color in enumerate(color_steps[:-1]):
72
 
            colors.append(color)
 
72
            colors.append(color + tuple([mode]))
73
73
            if iterations[index] == 0:
74
74
                continue
75
75
            next_color = color_steps[index+1]
81
81
                colors.append((color[0] + color_step[0]*(i+1), 
82
82
                               color[1] + color_step[1]*(i+1), 
83
83
                               color[2] + color_step[2]*(i+1),
84
 
                               color[3] + color_step[3]*(i+1)))
85
 
        colors.append(color_steps[-1])
 
84
                               color[3] + color_step[3]*(i+1),
 
85
                               mode))
 
86
        colors.append(color_steps[-1] + tuple([mode]))
86
87
    return colors
87
88
        
88
89
 
183
184
        self.series_widths = [1.0 for series in self.data]
184
185
        self.process_colors( series_colors )
185
186
        
186
 
    def process_colors( self, series_colors, length = None ):
 
187
    def process_colors( self, series_colors, length = None, mode = 'solid' ):
187
188
        #series_colors might be None, a theme, a string of colors names or a string of color tuples
188
189
        if length is None :
189
190
            length = len( self.data )
190
191
        #no colors passed
191
192
        if not series_colors:
192
193
            #Randomize colors
193
 
            self.series_colors = [ [random.random() for i in range(3)] + [1.0]  for series in range( length ) ]
 
194
            self.series_colors = [ [random.random() for i in range(3)] + [1.0, mode]  for series in range( length ) ]
194
195
        else:
195
 
            #Theme pattern
 
196
            #Just theme pattern
196
197
            if not hasattr( series_colors, "__iter__" ):
197
198
                theme = series_colors
198
199
                self.series_colors = colors_from_theme( theme.lower(), length )
 
200
            #Theme pattern and mode
 
201
            elif not hasattr(series_colors, '__delitem__') and not hasattr( series_colors[0], "__iter__" ):
 
202
                theme = series_colors[0]
 
203
                mode = series_colors[1]
 
204
                self.series_colors = colors_from_theme( theme.lower(), length, mode )
199
205
            #List
200
206
            else:
201
207
                self.series_colors = series_colors
202
208
                for index, color in enumerate( self.series_colors ):
203
 
                    #list of color names
 
209
                    #element is a color name
204
210
                    if not hasattr(color, "__iter__"):
205
 
                        self.series_colors[index] = COLORS[color.lower()]
206
 
                    #list of rgb colors instead of rgba
 
211
                        self.series_colors[index] = COLORS[color.lower()] + tuple([mode])
 
212
                    #element is rgb tuple instead of rgba
207
213
                    elif len( color ) == 3 :
208
 
                        self.series_colors[index] += tuple( [1.0] )
 
214
                        self.series_colors[index] += (1.0,mode)
 
215
                    #element has 4 elements, might be rgba tuple or rgb tuple with mode
 
216
                    elif len( color ) == 4 :
 
217
                        #last element is mode
 
218
                        if not hasattr(color[3], "__iter__"):
 
219
                            self.series_colors[index] += tuple([color[3]])
 
220
                            self.series_colors[index][3] = 1.0
 
221
                        #last element is alpha
 
222
                        else:
 
223
                            self.series_colors[index] += tuple([mode])
209
224
 
210
225
    def get_width(self):
211
226
        return self.surface.get_width()
553
568
 
554
569
        for idx,key in enumerate(self.series_labels):
555
570
            #Draw color box
556
 
            cr.set_source_rgba(*self.series_colors[idx])
 
571
            cr.set_source_rgba(*self.series_colors[idx][:4])
557
572
            cr.rectangle(self.dimensions[HORZ] - self.borders[HORZ] - max_width - color_box_width - 10, 
558
573
                                self.borders[VERT] + color_box_height + (idx*max_height) ,
559
574
                                color_box_width, color_box_height)
578
593
        x0 = self.borders[HORZ] - self.bounds[HORZ][0]*self.horizontal_step
579
594
        y0 = self.borders[VERT] - self.bounds[VERT][0]*self.vertical_step
580
595
        for index, serie in enumerate(self.data):
581
 
            cr.set_source_rgba(*self.series_colors[index])
 
596
            cr.set_source_rgba(*self.series_colors[index][:4])
582
597
            for number, tuple in enumerate(serie):
583
598
                x = x0 + self.horizontal_step * tuple[0]
584
599
                y = self.dimensions[VERT] - y0 - self.vertical_step * tuple[1]
621
636
            y0 = self.borders[VERT] - self.bounds[VERT][0]*self.vertical_step
622
637
            radius = self.dots
623
638
            for number, serie in  enumerate (self.data):
624
 
                cr.set_source_rgba(*self.series_colors[number])
 
639
                cr.set_source_rgba(*self.series_colors[number][:4])
625
640
                for tuple in serie :
626
641
                    if self.variable_radius:
627
642
                        radius = tuple[2]*self.z_step
639
654
            radius = self.dots
640
655
            for number, serie in  enumerate (self.data):
641
656
                last_tuple = None
642
 
                cr.set_source_rgba(*self.series_colors[number])
 
657
                cr.set_source_rgba(*self.series_colors[number][:4])
643
658
                for tuple in serie :
644
659
                    x = x0 + self.horizontal_step*tuple[0]
645
660
                    y = y0 + self.vertical_step*tuple[1]
791
806
            last = None
792
807
            cr = self.context
793
808
            for number, series in  enumerate (self.data):
794
 
                cr.set_source_rgba(*self.series_colors[number])
 
809
                cr.set_source_rgba(*self.series_colors[number][:4])
795
810
                x0 = self.borders[HORZ] - self.bounds[HORZ][0]*self.horizontal_step
796
811
                y0 = self.borders[VERT] - self.bounds[VERT][0]*self.vertical_step
797
812
                for tuple in series:
857
872
        else:
858
873
            length = len( self.data )
859
874
            
860
 
        Plot.process_colors( self, series_colors, length )
 
875
        Plot.process_colors( self, series_colors, length, 'linear')
861
876
    
862
877
    def calc_boundaries(self):
863
878
        if not self.bounds[self.main_dir]:
1007
1022
 
1008
1023
        for idx,key in enumerate(self.series_labels):
1009
1024
            #Draw color box
1010
 
            cr.set_source_rgba(*self.series_colors[idx])
 
1025
            cr.set_source_rgba(*self.series_colors[idx][:4])
1011
1026
            cr.rectangle(self.dimensions[HORZ] - self.border - max_width - color_box_width - 10, 
1012
1027
                                self.border + color_box_height + (idx*max_height) ,
1013
1028
                                color_box_width, color_box_height)
1166
1181
                    linear = cairo.LinearGradient( key*self.steps[HORZ]/2, y0, key*self.steps[HORZ]/2, y0 + self.steps[VERT] )
1167
1182
                    color = self.series_colors[number]
1168
1183
                    linear.add_color_stop_rgba(0.0, 3.5*color[0]/5.0, 3.5*color[1]/5.0, 3.5*color[2]/5.0,1.0)
1169
 
                    linear.add_color_stop_rgba(1.0, *color)
 
1184
                    linear.add_color_stop_rgba(1.0, *color[:4])
1170
1185
                    self.context.set_source(linear)
1171
1186
                    if self.rounded_corners:
1172
1187
                        self.draw_rectangle(number, len(series), x0, y0, x0+key*self.steps[HORZ], y0+self.steps[VERT])
1184
1199
                    linear = cairo.LinearGradient(key*self.steps[HORZ]/2, y0, key*self.steps[HORZ]/2, y0 + inner_step)
1185
1200
                    color = self.series_colors[number]
1186
1201
                    linear.add_color_stop_rgba(0.0, 3.5*color[0]/5.0, 3.5*color[1]/5.0, 3.5*color[2]/5.0,1.0)
1187
 
                    linear.add_color_stop_rgba(1.0, *color)
 
1202
                    linear.add_color_stop_rgba(1.0, *color[:4])
1188
1203
                    self.context.set_source(linear)
1189
1204
                    if self.rounded_corners and key != 0:
1190
1205
                        BarPlot.draw_round_rectangle(self,x0, y0, x0 + key*self.steps[HORZ], y0 + inner_step)
1336
1351
                x0 = self.borders[HORZ] + i*self.steps[HORZ] + (i+1)*self.space
1337
1352
                y0 = 0
1338
1353
                for number,key in enumerate(series):
1339
 
                    linear = cairo.LinearGradient( x0, key*self.steps[VERT]/2, x0 + self.steps[HORZ], key*self.steps[VERT]/2 )
1340
 
                    color = self.series_colors[number]
1341
 
                    linear.add_color_stop_rgba(0.0, 3.5*color[0]/5.0, 3.5*color[1]/5.0, 3.5*color[2]/5.0,1.0)
1342
 
                    linear.add_color_stop_rgba(1.0, *color)
1343
 
                    self.context.set_source(linear)
 
1354
                    if self.series_colors[number][4] == 'linear':
 
1355
                        linear = cairo.LinearGradient( x0, key*self.steps[VERT]/2, x0 + self.steps[HORZ], key*self.steps[VERT]/2 )
 
1356
                        color = self.series_colors[number]
 
1357
                        linear.add_color_stop_rgba(0.0, 3.5*color[0]/5.0, 3.5*color[1]/5.0, 3.5*color[2]/5.0,1.0)
 
1358
                        linear.add_color_stop_rgba(1.0, *color[:4])
 
1359
                        self.context.set_source(linear)
 
1360
                    elif self.series_colors[number][4] == 'solid':
 
1361
                        self.context.set_source_rgba(*self.series_colors[number][:4])
1344
1362
                    if self.rounded_corners:
1345
1363
                        self.draw_rectangle(number, len(series), x0, self.plot_top - y0 - key*self.steps[VERT], x0 + self.steps[HORZ], self.plot_top - y0)
1346
1364
                        self.context.fill()
1354
1372
                y0 = self.borders[VERT]
1355
1373
                x0 = self.borders[HORZ] + i*self.steps[HORZ] + (i+1)*self.space
1356
1374
                for number,key in enumerate(series):
1357
 
                    linear = cairo.LinearGradient( x0, key*self.steps[VERT]/2, x0 + inner_step, key*self.steps[VERT]/2 )
1358
 
                    color = self.series_colors[number]
1359
 
                    linear.add_color_stop_rgba(0.0, 3.5*color[0]/5.0, 3.5*color[1]/5.0, 3.5*color[2]/5.0,1.0)
1360
 
                    linear.add_color_stop_rgba(1.0, *color)
1361
 
                    self.context.set_source(linear)
 
1375
                    if self.series_colors[number][4] == 'linear':
 
1376
                        linear = cairo.LinearGradient( x0, key*self.steps[VERT]/2, x0 + inner_step, key*self.steps[VERT]/2 )
 
1377
                        color = self.series_colors[number]
 
1378
                        linear.add_color_stop_rgba(0.0, 3.5*color[0]/5.0, 3.5*color[1]/5.0, 3.5*color[2]/5.0,1.0)
 
1379
                        linear.add_color_stop_rgba(1.0, *color[:4])
 
1380
                        self.context.set_source(linear)
 
1381
                    elif self.series_colors[number][4] == 'solid':
 
1382
                        self.context.set_source_rgba(*self.series_colors[number][:4])
1362
1383
                    if self.rounded_corners and key != 0:
1363
1384
                        BarPlot.draw_round_rectangle(self, x0, self.plot_top - key*self.steps[VERT], x0+inner_step, self.plot_top)
1364
1385
                        self.context.fill()
1447
1468
        middle = self.plot_top - self.plot_dimensions[VERT]/2.0
1448
1469
        p = 0.4*self.steps[HORZ]
1449
1470
        for data_index in range(len(self.data[0])-1,-1,-1):
1450
 
            self.context.set_source_rgba(*self.series_colors[data_index])
 
1471
            self.context.set_source_rgba(*self.series_colors[data_index][:4])
1451
1472
            
1452
1473
            #draw the upper line
1453
1474
            for x_index in range(len(self.data)-1) :
1605
1626
        next_angle = 0
1606
1627
        x0,y0 = self.center
1607
1628
        cr = self.context
1608
 
        cr.set_source_rgba(*self.series_colors[0])
1609
1629
        for number,key in enumerate(self.series_labels):
1610
1630
            next_angle = angle + 2.0*math.pi*self.data[number]/self.total
1611
 
            cr.set_source_rgba(*self.series_colors[number])
 
1631
            cr.set_source_rgba(*self.series_colors[number][:4])
1612
1632
            w = cr.text_extents(key)[2]
1613
1633
            if (angle + next_angle)/2 < math.pi/2 or (angle + next_angle)/2 > 3*math.pi/2:
1614
1634
                cr.move_to(x0 + (self.radius+10)*math.cos((angle+next_angle)/2), y0 + (self.radius+10)*math.sin((angle+next_angle)/2) )
1624
1644
        cr = self.context
1625
1645
        for number,series in enumerate(self.data):
1626
1646
            next_angle = angle + 2.0*math.pi*series/self.total
1627
 
            if self.gradient:        
 
1647
            if self.gradient or self.series_colors[number][4] == 'radial':
1628
1648
                gradient_color = cairo.RadialGradient(self.center[0], self.center[1], 0, self.center[0], self.center[1], self.radius)
1629
 
                gradient_color.add_color_stop_rgba(0.3, *self.series_colors[number])
 
1649
                gradient_color.add_color_stop_rgba(0.3, *self.series_colors[number][:4])
1630
1650
                gradient_color.add_color_stop_rgba(1, self.series_colors[number][0]*0.7,
1631
1651
                                                      self.series_colors[number][1]*0.7,
1632
1652
                                                      self.series_colors[number][2]*0.7,
1633
1653
                                                      self.series_colors[number][3])
1634
1654
                cr.set_source(gradient_color)
1635
1655
            else:
1636
 
                cr.set_source_rgba(*self.series_colors[number])
 
1656
                cr.set_source_rgba(*self.series_colors[number][:4])
1637
1657
 
1638
1658
            self.draw_piece(angle, next_angle)
1639
1659
            cr.fill()
1820
1840
        middle = (x0+x1)/2
1821
1841
        linear = cairo.LinearGradient(middle,y0,middle,y1)
1822
1842
        linear.add_color_stop_rgba(0,3.5*color[0]/5.0, 3.5*color[1]/5.0, 3.5*color[2]/5.0,1.0)
1823
 
        linear.add_color_stop_rgba(1,*color)
 
1843
        linear.add_color_stop_rgba(1,*color[:4])
1824
1844
        cr.set_source(linear)
1825
1845
 
1826
1846
        cr.arc(x0+5, y0+5, 5, 0, 2*math.pi)