a27113f0a8e746cf6d8b59b6e7d82283bd0d73f7
2 # -*- coding: utf-8 -*-
6 # Copyright (c) 2008 Rodrigo Moreira Araújo
8 # Author: Rodrigo Moreiro Araujo <alf.rodrigo@gmail.com>
10 # This program is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU Lesser General Public License
12 # as published by the Free Software Foundation; either version 2 of
13 # the License, or (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU Lesser General Public
21 # License along with this program; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 #Contributor: João S. O. Bueno
27 #TODO: review BarPlot Code
28 #TODO: x_label colision problem on Horizontal Bar Plot
29 #TODO: y_label's eat too much space on HBP
37 from series
import Series
, Group
, Data
43 COLORS
= {"red" : (1.0,0.0,0.0,1.0), "lime" : (0.0,1.0,0.0,1.0), "blue" : (0.0,0.0,1.0,1.0),
44 "maroon" : (0.5,0.0,0.0,1.0), "green" : (0.0,0.5,0.0,1.0), "navy" : (0.0,0.0,0.5,1.0),
45 "yellow" : (1.0,1.0,0.0,1.0), "magenta" : (1.0,0.0,1.0,1.0), "cyan" : (0.0,1.0,1.0,1.0),
46 "orange" : (1.0,0.5,0.0,1.0), "white" : (1.0,1.0,1.0,1.0), "black" : (0.0,0.0,0.0,1.0),
47 "gray" : (0.5,0.5,0.5,1.0), "light_gray" : (0.9,0.9,0.9,1.0),
48 "transparent" : (0.0,0.0,0.0,0.0)}
50 THEMES
= {"black_red" : [(0.0,0.0,0.0,1.0), (1.0,0.0,0.0,1.0)],
51 "red_green_blue" : [(1.0,0.0,0.0,1.0), (0.0,1.0,0.0,1.0), (0.0,0.0,1.0,1.0)],
52 "red_orange_yellow" : [(1.0,0.2,0.0,1.0), (1.0,0.7,0.0,1.0), (1.0,1.0,0.0,1.0)],
53 "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)],
54 "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)]}
56 def colors_from_theme( theme
, series_length
, mode
= 'solid' ):
58 if theme
not in THEMES
.keys() :
59 raise Exception, "Theme not defined"
60 color_steps
= THEMES
[theme
]
61 n_colors
= len(color_steps
)
62 if series_length
<= n_colors
:
63 colors
= [color
+ tuple([mode
]) for color
in color_steps
[0:n_colors
]]
65 iterations
= [(series_length
- n_colors
)/(n_colors
- 1) for i
in color_steps
[:-1]]
66 over_iterations
= (series_length
- n_colors
) % (n_colors
- 1)
67 for i
in range(n_colors
- 1):
68 if over_iterations
<= 0:
72 for index
,color
in enumerate(color_steps
[:-1]):
73 colors
.append(color
+ tuple([mode
]))
74 if iterations
[index
] == 0:
76 next_color
= color_steps
[index
+1]
77 color_step
= ((next_color
[0] - color
[0])/(iterations
[index
] + 1),
78 (next_color
[1] - color
[1])/(iterations
[index
] + 1),
79 (next_color
[2] - color
[2])/(iterations
[index
] + 1),
80 (next_color
[3] - color
[3])/(iterations
[index
] + 1))
81 for i
in range( iterations
[index
] ):
82 colors
.append((color
[0] + color_step
[0]*(i
+1),
83 color
[1] + color_step
[1]*(i
+1),
84 color
[2] + color_step
[2]*(i
+1),
85 color
[3] + color_step
[3]*(i
+1),
87 colors
.append(color_steps
[-1] + tuple([mode
]))
91 def other_direction(direction
):
92 "explicit is better than implicit"
110 series_colors
= None):
112 self
.create_surface(surface
, width
, height
)
114 self
.dimensions
[HORZ
] = width
115 self
.dimensions
[VERT
] = height
116 self
.context
= cairo
.Context(self
.surface
)
118 self
.labels
[HORZ
] = x_labels
119 self
.labels
[VERT
] = y_labels
120 self
.load_series(data
, x_labels
, y_labels
, series_colors
)
122 self
.set_background (background
)
125 self
.line_color
= (0.5, 0.5, 0.5)
126 self
.line_width
= 0.5
127 self
.label_color
= (0.0, 0.0, 0.0)
128 self
.grid_color
= (0.8, 0.8, 0.8)
130 def create_surface(self
, surface
, width
=None, height
=None):
132 if isinstance(surface
, cairo
.Surface
):
133 self
.surface
= surface
135 if not type(surface
) in (str, unicode):
136 raise TypeError("Surface should be either a Cairo surface or a filename, not %s" % surface
)
137 sufix
= surface
.rsplit(".")[-1].lower()
138 self
.filename
= surface
140 self
.surface
= cairo
.ImageSurface(cairo
.FORMAT_ARGB32
, width
, height
)
142 self
.surface
= cairo
.PSSurface(surface
, width
, height
)
144 self
.surface
= cairo
.PSSurface(surface
, width
, height
)
147 self
.filename
+= ".svg"
148 self
.surface
= cairo
.SVGSurface(self
.filename
, width
, height
)
152 self
.context
.show_page()
153 if self
.filename
and self
.filename
.endswith(".png"):
154 self
.surface
.write_to_png(self
.filename
)
156 self
.surface
.finish()
160 def load_series (self
, data
, x_labels
=None, y_labels
=None, series_colors
=None):
161 self
.series_labels
= []
165 #if not isinstance(data, Series):
166 # # Not an instance of Series
167 # self.series = Series(data)
171 #self.series_labels = self.series.get_names()
173 #TODO: Remove on next version
174 # The ugly way, keeping retrocompatibility...
175 if callable(data
) or type(data
) is list and callable(data
[0]): # Lambda or List of lambdas
177 self
.series_labels
= None
178 elif isinstance(data
, Series
): # Instance of Series
180 self
.series_labels
= data
.get_names()
181 else: # Anything else
182 self
.series
= Series(data
)
183 self
.series_labels
= self
.series
.get_names()
185 #TODO: allow user passed series_widths
186 self
.series_widths
= [1.0 for group
in self
.series
]
188 #TODO: Remove on next version
189 self
.process_colors( series_colors
)
191 def process_colors( self
, series_colors
, length
= None, mode
= 'solid' ):
192 #series_colors might be None, a theme, a string of colors names or a list of color tuples
194 length
= len( self
.series
.to_list() )
197 if not series_colors
:
199 self
.series_colors
= [ [random
.random() for i
in range(3)] + [1.0, mode
] for series
in range( length
) ]
202 if not hasattr( series_colors
, "__iter__" ):
203 theme
= series_colors
204 self
.series_colors
= colors_from_theme( theme
.lower(), length
)
206 #Theme pattern and mode
207 elif not hasattr(series_colors
, '__delitem__') and not hasattr( series_colors
[0], "__iter__" ):
208 theme
= series_colors
[0]
209 mode
= series_colors
[1]
210 self
.series_colors
= colors_from_theme( theme
.lower(), length
, mode
)
214 self
.series_colors
= series_colors
215 for index
, color
in enumerate( self
.series_colors
):
216 #element is a color name
217 if not hasattr(color
, "__iter__"):
218 self
.series_colors
[index
] = COLORS
[color
.lower()] + tuple([mode
])
219 #element is rgb tuple instead of rgba
220 elif len( color
) == 3 :
221 self
.series_colors
[index
] += (1.0,mode
)
222 #element has 4 elements, might be rgba tuple or rgb tuple with mode
223 elif len( color
) == 4 :
224 #last element is mode
225 if not hasattr(color
[3], "__iter__"):
226 self
.series_colors
[index
] += tuple([color
[3]])
227 self
.series_colors
[index
][3] = 1.0
228 #last element is alpha
230 self
.series_colors
[index
] += tuple([mode
])
233 return self
.surface
.get_width()
235 def get_height(self
):
236 return self
.surface
.get_height()
238 def set_background(self
, background
):
239 if background
is None:
240 self
.background
= (0.0,0.0,0.0,0.0)
241 elif type(background
) in (cairo
.LinearGradient
, tuple):
242 self
.background
= background
243 elif not hasattr(background
,"__iter__"):
244 colors
= background
.split(" ")
245 if len(colors
) == 1 and colors
[0] in COLORS
:
246 self
.background
= COLORS
[background
]
247 elif len(colors
) > 1:
248 self
.background
= cairo
.LinearGradient(self
.dimensions
[HORZ
] / 2, 0, self
.dimensions
[HORZ
] / 2, self
.dimensions
[VERT
])
249 for index
,color
in enumerate(colors
):
250 self
.background
.add_color_stop_rgba(float(index
)/(len(colors
)-1),*COLORS
[color
])
252 raise TypeError ("Background should be either cairo.LinearGradient or a 3/4-tuple, not %s" % type(background
))
254 def render_background(self
):
255 if isinstance(self
.background
, cairo
.LinearGradient
):
256 self
.context
.set_source(self
.background
)
258 self
.context
.set_source_rgba(*self
.background
)
259 self
.context
.rectangle(0,0, self
.dimensions
[HORZ
], self
.dimensions
[VERT
])
262 def render_bounding_box(self
):
263 self
.context
.set_source_rgba(*self
.line_color
)
264 self
.context
.set_line_width(self
.line_width
)
265 self
.context
.rectangle(self
.border
, self
.border
,
266 self
.dimensions
[HORZ
] - 2 * self
.border
,
267 self
.dimensions
[VERT
] - 2 * self
.border
)
268 self
.context
.stroke()
273 class ScatterPlot( Plot
):
288 series_legend
= False,
296 series_colors
= None,
297 circle_colors
= None ):
300 self
.bounds
[HORZ
] = x_bounds
301 self
.bounds
[VERT
] = y_bounds
302 self
.bounds
[NORM
] = z_bounds
304 self
.titles
[HORZ
] = x_title
305 self
.titles
[VERT
] = y_title
308 self
.discrete
= discrete
311 self
.series_legend
= series_legend
312 self
.variable_radius
= False
313 self
.x_label_angle
= math
.pi
/ 2.5
314 self
.circle_colors
= circle_colors
316 Plot
.__init
__(self
, surface
, data
, width
, height
, background
, border
, x_labels
, y_labels
, series_colors
)
320 if hasattr(dash
, "keys"):
321 self
.dash
= [dash
[key
] for key
in self
.series_labels
]
322 elif max([hasattr(item
,'__delitem__') for item
in data
]) :
327 self
.load_errors(errorx
, errory
)
329 def convert_list_to_tuple(self
, data
):
330 #Data must be converted from lists of coordinates to a single
332 out_data
= zip(*data
)
334 self
.variable_radius
= True
337 def load_series(self
, data
, x_labels
= None, y_labels
= None, series_colors
=None):
338 #TODO: In cairoplot 2.0 keep only the Series instances
340 # Convert Data and Group to Series
341 if isinstance(data
, Data
) or isinstance(data
, Group
):
345 if isinstance(data
, Series
):
349 self
.variable_radius
= True
351 #Dictionary with lists
352 if hasattr(data
, "keys") :
353 if hasattr( data
.values()[0][0], "__delitem__" ) :
354 for key
in data
.keys() :
355 data
[key
] = self
.convert_list_to_tuple(data
[key
])
356 elif len(data
.values()[0][0]) == 3:
357 self
.variable_radius
= True
359 elif hasattr(data
[0], "__delitem__") :
361 if hasattr(data
[0][0], "__delitem__") :
362 for index
,value
in enumerate(data
) :
363 data
[index
] = self
.convert_list_to_tuple(value
)
365 elif type(data
[0][0]) != type((0,0)):
366 data
= self
.convert_list_to_tuple(data
)
367 #Three dimensional data
368 elif len(data
[0][0]) == 3:
369 self
.variable_radius
= True
371 #List with three dimensional tuples
372 elif len(data
[0]) == 3:
373 self
.variable_radius
= True
374 Plot
.load_series(self
, data
, x_labels
, y_labels
, series_colors
)
375 self
.calc_boundaries()
378 def load_errors(self
, errorx
, errory
):
380 if errorx
== None and errory
== None:
383 self
.errors
[HORZ
] = None
384 self
.errors
[VERT
] = None
386 if errorx
and hasattr(errorx
[0], "__delitem__"):
387 self
.errors
[HORZ
] = errorx
390 self
.errors
[HORZ
] = [errorx
]
392 if errory
and hasattr(errory
[0], "__delitem__"):
393 self
.errors
[VERT
] = errory
396 self
.errors
[VERT
] = [errory
]
398 def calc_labels(self
):
399 if not self
.labels
[HORZ
]:
400 amplitude
= self
.bounds
[HORZ
][1] - self
.bounds
[HORZ
][0]
401 if amplitude
% 10: #if horizontal labels need floating points
402 self
.labels
[HORZ
] = ["%.2lf" % (float(self
.bounds
[HORZ
][0] + (amplitude
* i
/ 10.0))) for i
in range(11) ]
404 self
.labels
[HORZ
] = ["%d" % (int(self
.bounds
[HORZ
][0] + (amplitude
* i
/ 10.0))) for i
in range(11) ]
405 if not self
.labels
[VERT
]:
406 amplitude
= self
.bounds
[VERT
][1] - self
.bounds
[VERT
][0]
407 if amplitude
% 10: #if vertical labels need floating points
408 self
.labels
[VERT
] = ["%.2lf" % (float(self
.bounds
[VERT
][0] + (amplitude
* i
/ 10.0))) for i
in range(11) ]
410 self
.labels
[VERT
] = ["%d" % (int(self
.bounds
[VERT
][0] + (amplitude
* i
/ 10.0))) for i
in range(11) ]
412 def calc_extents(self
, direction
):
413 self
.context
.set_font_size(self
.font_size
* 0.8)
414 self
.max_value
[direction
] = max(self
.context
.text_extents(item
)[2] for item
in self
.labels
[direction
])
415 self
.borders
[other_direction(direction
)] = self
.max_value
[direction
] + self
.border
+ 20
417 def calc_boundaries(self
):
418 #HORZ = 0, VERT = 1, NORM = 2
419 min_data_value
= [0,0,0]
420 max_data_value
= [0,0,0]
422 for group
in self
.series
:
423 if type(group
[0].content
) in (int, float, long):
424 group
= [Data((index
, item
.content
)) for index
,item
in enumerate(group
)]
427 for index
, item
in enumerate(point
.content
):
428 if item
> max_data_value
[index
]:
429 max_data_value
[index
] = item
430 elif item
< min_data_value
[index
]:
431 min_data_value
[index
] = item
433 if not self
.bounds
[HORZ
]:
434 self
.bounds
[HORZ
] = (min_data_value
[HORZ
], max_data_value
[HORZ
])
435 if not self
.bounds
[VERT
]:
436 self
.bounds
[VERT
] = (min_data_value
[VERT
], max_data_value
[VERT
])
437 if not self
.bounds
[NORM
]:
438 self
.bounds
[NORM
] = (min_data_value
[NORM
], max_data_value
[NORM
])
440 def calc_all_extents(self
):
441 self
.calc_extents(HORZ
)
442 self
.calc_extents(VERT
)
444 self
.plot_height
= self
.dimensions
[VERT
] - 2 * self
.borders
[VERT
]
445 self
.plot_width
= self
.dimensions
[HORZ
] - 2* self
.borders
[HORZ
]
447 self
.plot_top
= self
.dimensions
[VERT
] - self
.borders
[VERT
]
449 def calc_steps(self
):
450 #Calculates all the x, y, z and color steps
451 series_amplitude
= [self
.bounds
[index
][1] - self
.bounds
[index
][0] for index
in range(3)]
453 if series_amplitude
[HORZ
]:
454 self
.horizontal_step
= float (self
.plot_width
) / series_amplitude
[HORZ
]
456 self
.horizontal_step
= 0.00
458 if series_amplitude
[VERT
]:
459 self
.vertical_step
= float (self
.plot_height
) / series_amplitude
[VERT
]
461 self
.vertical_step
= 0.00
463 if series_amplitude
[NORM
]:
464 if self
.variable_radius
:
465 self
.z_step
= float (self
.bounds
[NORM
][1]) / series_amplitude
[NORM
]
466 if self
.circle_colors
:
467 self
.circle_color_step
= tuple([float(self
.circle_colors
[1][i
]-self
.circle_colors
[0][i
])/series_amplitude
[NORM
] for i
in range(4)])
470 self
.circle_color_step
= ( 0.0, 0.0, 0.0, 0.0 )
472 def get_circle_color(self
, value
):
473 return tuple( [self
.circle_colors
[0][i
] + value
*self
.circle_color_step
[i
] for i
in range(4)] )
476 self
.calc_all_extents()
478 self
.render_background()
479 self
.render_bounding_box()
488 if self
.series_legend
and self
.series_labels
:
491 def render_axis(self
):
492 #Draws both the axis lines and their titles
494 cr
.set_source_rgba(*self
.line_color
)
495 cr
.move_to(self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
])
496 cr
.line_to(self
.borders
[HORZ
], self
.borders
[VERT
])
499 cr
.move_to(self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
])
500 cr
.line_to(self
.dimensions
[HORZ
] - self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
])
503 cr
.set_source_rgba(*self
.label_color
)
504 self
.context
.set_font_size( 1.2 * self
.font_size
)
505 if self
.titles
[HORZ
]:
506 title_width
,title_height
= cr
.text_extents(self
.titles
[HORZ
])[2:4]
507 cr
.move_to( self
.dimensions
[HORZ
]/2 - title_width
/2, self
.borders
[VERT
] - title_height
/2 )
508 cr
.show_text( self
.titles
[HORZ
] )
510 if self
.titles
[VERT
]:
511 title_width
,title_height
= cr
.text_extents(self
.titles
[VERT
])[2:4]
512 cr
.move_to( self
.dimensions
[HORZ
] - self
.borders
[HORZ
] + title_height
/2, self
.dimensions
[VERT
]/2 - title_width
/2)
514 cr
.rotate( math
.pi
/2 )
515 cr
.show_text( self
.titles
[VERT
] )
518 def render_grid(self
):
520 horizontal_step
= float( self
.plot_height
) / ( len( self
.labels
[VERT
] ) - 1 )
521 vertical_step
= float( self
.plot_width
) / ( len( self
.labels
[HORZ
] ) - 1 )
523 x
= self
.borders
[HORZ
] + vertical_step
524 y
= self
.plot_top
- horizontal_step
526 for label
in self
.labels
[HORZ
][:-1]:
527 cr
.set_source_rgba(*self
.grid_color
)
528 cr
.move_to(x
, self
.dimensions
[VERT
] - self
.borders
[VERT
])
529 cr
.line_to(x
, self
.borders
[VERT
])
532 for label
in self
.labels
[VERT
][:-1]:
533 cr
.set_source_rgba(*self
.grid_color
)
534 cr
.move_to(self
.borders
[HORZ
], y
)
535 cr
.line_to(self
.dimensions
[HORZ
] - self
.borders
[HORZ
], y
)
539 def render_labels(self
):
540 self
.context
.set_font_size(self
.font_size
* 0.8)
541 self
.render_horz_labels()
542 self
.render_vert_labels()
544 def render_horz_labels(self
):
546 step
= float( self
.plot_width
) / ( len( self
.labels
[HORZ
] ) - 1 )
547 x
= self
.borders
[HORZ
]
548 y
= self
.dimensions
[VERT
] - self
.borders
[VERT
] + 5
550 # store rotation matrix from the initial state
551 rotation_matrix
= cr
.get_matrix()
552 rotation_matrix
.rotate(self
.x_label_angle
)
554 cr
.set_source_rgba(*self
.label_color
)
556 for item
in self
.labels
[HORZ
]:
557 width
= cr
.text_extents(item
)[2]
560 cr
.set_matrix(rotation_matrix
)
565 def render_vert_labels(self
):
567 step
= ( self
.plot_height
) / ( len( self
.labels
[VERT
] ) - 1 )
569 cr
.set_source_rgba(*self
.label_color
)
570 for item
in self
.labels
[VERT
]:
571 width
= cr
.text_extents(item
)[2]
572 cr
.move_to(self
.borders
[HORZ
] - width
- 5,y
)
576 def render_legend(self
):
578 cr
.set_font_size(self
.font_size
)
579 cr
.set_line_width(self
.line_width
)
581 widest_word
= max(self
.series_labels
, key
= lambda item
: self
.context
.text_extents(item
)[2])
582 tallest_word
= max(self
.series_labels
, key
= lambda item
: self
.context
.text_extents(item
)[3])
583 max_width
= self
.context
.text_extents(widest_word
)[2]
584 max_height
= self
.context
.text_extents(tallest_word
)[3] * 1.1
586 color_box_height
= max_height
/ 2
587 color_box_width
= color_box_height
* 2
590 bounding_box_width
= max_width
+ color_box_width
+ 15
591 bounding_box_height
= (len(self
.series_labels
)+0.5) * max_height
592 cr
.set_source_rgba(1,1,1)
593 cr
.rectangle(self
.dimensions
[HORZ
] - self
.borders
[HORZ
] - bounding_box_width
, self
.borders
[VERT
],
594 bounding_box_width
, bounding_box_height
)
597 cr
.set_source_rgba(*self
.line_color
)
598 cr
.set_line_width(self
.line_width
)
599 cr
.rectangle(self
.dimensions
[HORZ
] - self
.borders
[HORZ
] - bounding_box_width
, self
.borders
[VERT
],
600 bounding_box_width
, bounding_box_height
)
603 for idx
,key
in enumerate(self
.series_labels
):
605 cr
.set_source_rgba(*self
.series_colors
[idx
][:4])
606 cr
.rectangle(self
.dimensions
[HORZ
] - self
.borders
[HORZ
] - max_width
- color_box_width
- 10,
607 self
.borders
[VERT
] + color_box_height
+ (idx
*max_height
) ,
608 color_box_width
, color_box_height
)
611 cr
.set_source_rgba(0, 0, 0)
612 cr
.rectangle(self
.dimensions
[HORZ
] - self
.borders
[HORZ
] - max_width
- color_box_width
- 10,
613 self
.borders
[VERT
] + color_box_height
+ (idx
*max_height
),
614 color_box_width
, color_box_height
)
618 cr
.set_source_rgba(0, 0, 0)
619 cr
.move_to(self
.dimensions
[HORZ
] - self
.borders
[HORZ
] - max_width
- 5, self
.borders
[VERT
] + ((idx
+1)*max_height
))
622 def render_errors(self
):
624 cr
.rectangle(self
.borders
[HORZ
], self
.borders
[VERT
], self
.plot_width
, self
.plot_height
)
627 x0
= self
.borders
[HORZ
] - self
.bounds
[HORZ
][0]*self
.horizontal_step
628 y0
= self
.borders
[VERT
] - self
.bounds
[VERT
][0]*self
.vertical_step
629 for index
, group
in enumerate(self
.series
):
630 cr
.set_source_rgba(*self
.series_colors
[index
][:4])
631 for number
, data
in enumerate(group
):
632 x
= x0
+ self
.horizontal_step
* data
.content
[0]
633 y
= self
.dimensions
[VERT
] - y0
- self
.vertical_step
* data
.content
[1]
634 if self
.errors
[HORZ
]:
636 x1
= x
- self
.horizontal_step
* self
.errors
[HORZ
][0][number
]
638 cr
.line_to(x1
, y
- radius
)
639 cr
.line_to(x1
, y
+ radius
)
641 if self
.errors
[HORZ
] and len(self
.errors
[HORZ
]) == 2:
643 x1
= x
+ self
.horizontal_step
* self
.errors
[HORZ
][1][number
]
645 cr
.line_to(x1
, y
- radius
)
646 cr
.line_to(x1
, y
+ radius
)
648 if self
.errors
[VERT
]:
650 y1
= y
+ self
.vertical_step
* self
.errors
[VERT
][0][number
]
652 cr
.line_to(x
- radius
, y1
)
653 cr
.line_to(x
+ radius
, y1
)
655 if self
.errors
[VERT
] and len(self
.errors
[VERT
]) == 2:
657 y1
= y
- self
.vertical_step
* self
.errors
[VERT
][1][number
]
659 cr
.line_to(x
- radius
, y1
)
660 cr
.line_to(x
+ radius
, y1
)
664 def render_plot(self
):
667 cr
.rectangle(self
.borders
[HORZ
], self
.borders
[VERT
], self
.plot_width
, self
.plot_height
)
669 x0
= self
.borders
[HORZ
] - self
.bounds
[HORZ
][0]*self
.horizontal_step
670 y0
= self
.borders
[VERT
] - self
.bounds
[VERT
][0]*self
.vertical_step
672 for number
, group
in enumerate (self
.series
):
673 cr
.set_source_rgba(*self
.series_colors
[number
][:4])
675 if self
.variable_radius
:
676 radius
= data
.content
[2]*self
.z_step
677 if self
.circle_colors
:
678 cr
.set_source_rgba( *self
.get_circle_color( data
.content
[2]) )
679 x
= x0
+ self
.horizontal_step
*data
.content
[0]
680 y
= y0
+ self
.vertical_step
*data
.content
[1]
681 cr
.arc(x
, self
.dimensions
[VERT
] - y
, radius
, 0, 2*math
.pi
)
684 cr
.rectangle(self
.borders
[HORZ
], self
.borders
[VERT
], self
.plot_width
, self
.plot_height
)
686 x0
= self
.borders
[HORZ
] - self
.bounds
[HORZ
][0]*self
.horizontal_step
687 y0
= self
.borders
[VERT
] - self
.bounds
[VERT
][0]*self
.vertical_step
689 for number
, group
in enumerate (self
.series
):
691 cr
.set_source_rgba(*self
.series_colors
[number
][:4])
693 x
= x0
+ self
.horizontal_step
*data
.content
[0]
694 y
= y0
+ self
.vertical_step
*data
.content
[1]
696 if self
.variable_radius
:
697 radius
= data
.content
[2]*self
.z_step
698 cr
.arc(x
, self
.dimensions
[VERT
] - y
, radius
, 0, 2*math
.pi
)
701 old_x
= x0
+ self
.horizontal_step
*last_data
.content
[0]
702 old_y
= y0
+ self
.vertical_step
*last_data
.content
[1]
703 cr
.move_to( old_x
, self
.dimensions
[VERT
] - old_y
)
704 cr
.line_to( x
, self
.dimensions
[VERT
] - y
)
705 cr
.set_line_width(self
.series_widths
[number
])
707 # Display line as dash line
708 if self
.dash
and self
.dash
[number
]:
709 s
= self
.series_widths
[number
]
710 cr
.set_dash([s
*3, s
*3], 0)
716 class DotLinePlot(ScatterPlot
):
728 series_legend
= False,
735 series_colors
= None):
737 ScatterPlot
.__init
__(self
, surface
, data
, None, None, width
, height
, background
, border
,
738 axis
, dash
, False, dots
, grid
, series_legend
, x_labels
, y_labels
,
739 x_bounds
, y_bounds
, None, x_title
, y_title
, series_colors
, None )
742 def load_series(self
, data
, x_labels
= None, y_labels
= None, series_colors
=None):
743 Plot
.load_series(self
, data
, x_labels
, y_labels
, series_colors
)
744 for group
in self
.series
:
745 for index
,data
in enumerate(group
):
746 group
[index
].content
= (index
, data
.content
)
748 self
.calc_boundaries()
751 class FunctionPlot(ScatterPlot
):
763 series_legend
= False,
770 series_colors
= None,
775 self
.discrete
= discrete
777 data
, x_bounds
= self
.load_series_from_function( self
.function
, x_bounds
)
779 ScatterPlot
.__init
__(self
, surface
, data
, None, None, width
, height
, background
, border
,
780 axis
, False, discrete
, dots
, grid
, series_legend
, x_labels
, y_labels
,
781 x_bounds
, y_bounds
, None, x_title
, y_title
, series_colors
, None )
783 def load_series(self
, data
, x_labels
= None, y_labels
= None, series_colors
=None):
784 Plot
.load_series(self
, data
, x_labels
, y_labels
, series_colors
)
786 if len(self
.series
[0][0]) is 1:
787 for group_id
, group
in enumerate(self
.series
) :
788 for index
,data
in enumerate(group
):
789 group
[index
].content
= (self
.bounds
[HORZ
][0] + self
.step
*index
, data
.content
)
791 self
.calc_boundaries()
794 def load_series_from_function( self
, function
, x_bounds
):
795 #TODO: Add the possibility for the user to define multiple functions with different discretization parameters
797 #This function converts a function, a list of functions or a dictionary
798 #of functions into its corresponding array of data
801 if isinstance(function
, Group
) or isinstance(function
, Data
):
802 function
= Series(function
)
804 # If is instance of Series
805 if isinstance(function
, Series
):
806 # Overwrite any bounds passed by the function
807 x_bounds
= (function
.range[0],function
.range[-1])
809 #if no bounds are provided
814 #TODO: Finish the dict translation
815 if hasattr(function
, "keys"): #dictionary:
816 for key
in function
.keys():
817 group
= Group(name
=key
)
820 while i
<= x_bounds
[1] :
821 group
.add_data(function
[ key
](i
))
822 #data[ key ].append( function[ key ](i) )
824 series
.add_group(group
)
826 elif hasattr(function
, "__delitem__"): #list of functions
827 for index
,f
in enumerate( function
) :
831 while i
<= x_bounds
[1] :
833 #data[ index ].append( f(i) )
835 series
.add_group(group
)
837 elif isinstance(function
, Series
): # instance of Series
843 while i
<= x_bounds
[1] :
844 group
.add_data(function(i
))
846 series
.add_group(group
)
849 return series
, x_bounds
851 def calc_labels(self
):
852 if not self
.labels
[HORZ
]:
853 self
.labels
[HORZ
] = []
854 i
= self
.bounds
[HORZ
][0]
855 while i
<=self
.bounds
[HORZ
][1]:
856 self
.labels
[HORZ
].append(str(i
))
857 i
+= float(self
.bounds
[HORZ
][1] - self
.bounds
[HORZ
][0])/10
858 ScatterPlot
.calc_labels(self
)
860 def render_plot(self
):
861 if not self
.discrete
:
862 ScatterPlot
.render_plot(self
)
866 for number
, group
in enumerate (self
.series
):
867 cr
.set_source_rgba(*self
.series_colors
[number
][:4])
868 x0
= self
.borders
[HORZ
] - self
.bounds
[HORZ
][0]*self
.horizontal_step
869 y0
= self
.borders
[VERT
] - self
.bounds
[VERT
][0]*self
.vertical_step
871 x
= x0
+ self
.horizontal_step
* data
.content
[0]
872 y
= y0
+ self
.vertical_step
* data
.content
[1]
873 cr
.move_to(x
, self
.dimensions
[VERT
] - y
)
874 cr
.line_to(x
, self
.plot_top
)
875 cr
.set_line_width(self
.series_widths
[number
])
879 cr
.arc(x
, self
.dimensions
[VERT
] - y
, 3, 0, 2.1 * math
.pi
)
889 background
= "white light_gray",
891 display_values
= False,
893 rounded_corners
= False,
895 three_dimension
= False,
900 series_colors
= None,
904 self
.bounds
[HORZ
] = x_bounds
905 self
.bounds
[VERT
] = y_bounds
906 self
.display_values
= display_values
908 self
.rounded_corners
= rounded_corners
910 self
.three_dimension
= three_dimension
911 self
.x_label_angle
= math
.pi
/ 2.5
912 self
.main_dir
= main_dir
914 self
.plot_dimensions
= {}
916 self
.value_label_color
= (0.5,0.5,0.5,1.0)
918 Plot
.__init
__(self
, surface
, data
, width
, height
, background
, border
, x_labels
, y_labels
, series_colors
)
920 def load_series(self
, data
, x_labels
= None, y_labels
= None, series_colors
= None):
921 Plot
.load_series(self
, data
, x_labels
, y_labels
, series_colors
)
922 self
.calc_boundaries()
924 def process_colors(self
, series_colors
):
925 #Data for a BarPlot might be a List or a List of Lists.
926 #On the first case, colors must be generated for all bars,
927 #On the second, colors must be generated for each of the inner lists.
929 #TODO: Didn't get it...
930 #if hasattr(self.data[0], '__getitem__'):
931 # length = max(len(series) for series in self.data)
933 # length = len( self.data )
935 length
= max(len(group
) for group
in self
.series
)
937 Plot
.process_colors( self
, series_colors
, length
, 'linear')
939 def calc_boundaries(self
):
940 if not self
.bounds
[self
.main_dir
]:
942 max_data_value
= max(sum(group
.to_list()) for group
in self
.series
)
944 max_data_value
= max(max(group
.to_list()) for group
in self
.series
)
945 self
.bounds
[self
.main_dir
] = (0, max_data_value
)
946 if not self
.bounds
[other_direction(self
.main_dir
)]:
947 self
.bounds
[other_direction(self
.main_dir
)] = (0, len(self
.series
))
949 def calc_extents(self
, direction
):
950 self
.max_value
[direction
] = 0
951 if self
.labels
[direction
]:
952 widest_word
= max(self
.labels
[direction
], key
= lambda item
: self
.context
.text_extents(item
)[2])
953 self
.max_value
[direction
] = self
.context
.text_extents(widest_word
)[3 - direction
]
954 self
.borders
[other_direction(direction
)] = (2-direction
)*self
.max_value
[direction
] + self
.border
+ direction
*(5)
956 self
.borders
[other_direction(direction
)] = self
.border
958 def calc_horz_extents(self
):
959 self
.calc_extents(HORZ
)
961 def calc_vert_extents(self
):
962 self
.calc_extents(VERT
)
964 def calc_all_extents(self
):
965 self
.calc_horz_extents()
966 self
.calc_vert_extents()
967 other_dir
= other_direction(self
.main_dir
)
969 if self
.display_values
:
971 self
.value_label
= self
.context
.text_extents(str(max(sum(group
.to_list()) for group
in self
.series
)))[2 + self
.main_dir
]
973 self
.value_label
= self
.context
.text_extents(str(max(max(group
.to_list()) for group
in self
.series
)))[2 + self
.main_dir
]
974 if self
.labels
[self
.main_dir
]:
975 self
.plot_dimensions
[self
.main_dir
] = self
.dimensions
[self
.main_dir
] - 2*self
.borders
[self
.main_dir
] - self
.value_label
977 self
.plot_dimensions
[self
.main_dir
] = self
.dimensions
[self
.main_dir
] - self
.borders
[self
.main_dir
] - 1.2*self
.border
- self
.value_label
978 self
.plot_dimensions
[other_dir
] = self
.dimensions
[other_dir
] - self
.borders
[other_dir
] - self
.border
979 self
.plot_top
= self
.dimensions
[VERT
] - self
.borders
[VERT
]
981 def calc_steps(self
):
982 other_dir
= other_direction(self
.main_dir
)
983 self
.series_amplitude
= self
.bounds
[self
.main_dir
][1] - self
.bounds
[self
.main_dir
][0]
984 if self
.series_amplitude
:
985 self
.steps
[self
.main_dir
] = float(self
.plot_dimensions
[self
.main_dir
])/self
.series_amplitude
987 self
.steps
[self
.main_dir
] = 0.00
988 series_length
= len(self
.series
)
989 self
.steps
[other_dir
] = float(self
.plot_dimensions
[other_dir
])/(series_length
+ 0.1*(series_length
+ 1))
990 self
.space
= 0.1*self
.steps
[other_dir
]
993 self
.calc_all_extents()
995 self
.render_background()
996 self
.render_bounding_box()
999 if self
.three_dimension
:
1000 self
.render_ground()
1001 if self
.display_values
:
1002 self
.render_values()
1003 self
.render_labels()
1005 if self
.series_labels
:
1006 self
.render_legend()
1008 def draw_3d_rectangle_front(self
, x0
, y0
, x1
, y1
, shift
):
1009 self
.context
.rectangle(x0
-shift
, y0
+shift
, x1
-x0
, y1
-y0
)
1011 def draw_3d_rectangle_side(self
, x0
, y0
, x1
, y1
, shift
):
1012 self
.context
.move_to(x1
-shift
,y0
+shift
)
1013 self
.context
.line_to(x1
, y0
)
1014 self
.context
.line_to(x1
, y1
)
1015 self
.context
.line_to(x1
-shift
, y1
+shift
)
1016 self
.context
.line_to(x1
-shift
, y0
+shift
)
1017 self
.context
.close_path()
1019 def draw_3d_rectangle_top(self
, x0
, y0
, x1
, y1
, shift
):
1020 self
.context
.move_to(x0
-shift
,y0
+shift
)
1021 self
.context
.line_to(x0
, y0
)
1022 self
.context
.line_to(x1
, y0
)
1023 self
.context
.line_to(x1
-shift
, y0
+shift
)
1024 self
.context
.line_to(x0
-shift
, y0
+shift
)
1025 self
.context
.close_path()
1027 def draw_round_rectangle(self
, x0
, y0
, x1
, y1
):
1028 self
.context
.arc(x0
+5, y0
+5, 5, -math
.pi
, -math
.pi
/2)
1029 self
.context
.line_to(x1
-5, y0
)
1030 self
.context
.arc(x1
-5, y0
+5, 5, -math
.pi
/2, 0)
1031 self
.context
.line_to(x1
, y1
-5)
1032 self
.context
.arc(x1
-5, y1
-5, 5, 0, math
.pi
/2)
1033 self
.context
.line_to(x0
+5, y1
)
1034 self
.context
.arc(x0
+5, y1
-5, 5, math
.pi
/2, math
.pi
)
1035 self
.context
.line_to(x0
, y0
+5)
1036 self
.context
.close_path()
1038 def render_ground(self
):
1039 self
.draw_3d_rectangle_front(self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
],
1040 self
.dimensions
[HORZ
] - self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
] + 5, 10)
1043 self
.draw_3d_rectangle_side (self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
],
1044 self
.dimensions
[HORZ
] - self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
] + 5, 10)
1047 self
.draw_3d_rectangle_top (self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
],
1048 self
.dimensions
[HORZ
] - self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
] + 5, 10)
1051 def render_labels(self
):
1052 self
.context
.set_font_size(self
.font_size
* 0.8)
1053 if self
.labels
[HORZ
]:
1054 self
.render_horz_labels()
1055 if self
.labels
[VERT
]:
1056 self
.render_vert_labels()
1058 def render_legend(self
):
1060 cr
.set_font_size(self
.font_size
)
1061 cr
.set_line_width(self
.line_width
)
1063 widest_word
= max(self
.series_labels
, key
= lambda item
: self
.context
.text_extents(item
)[2])
1064 tallest_word
= max(self
.series_labels
, key
= lambda item
: self
.context
.text_extents(item
)[3])
1065 max_width
= self
.context
.text_extents(widest_word
)[2]
1066 max_height
= self
.context
.text_extents(tallest_word
)[3] * 1.1 + 5
1068 color_box_height
= max_height
/ 2
1069 color_box_width
= color_box_height
* 2
1071 #Draw a bounding box
1072 bounding_box_width
= max_width
+ color_box_width
+ 15
1073 bounding_box_height
= (len(self
.series_labels
)+0.5) * max_height
1074 cr
.set_source_rgba(1,1,1)
1075 cr
.rectangle(self
.dimensions
[HORZ
] - self
.border
- bounding_box_width
, self
.border
,
1076 bounding_box_width
, bounding_box_height
)
1079 cr
.set_source_rgba(*self
.line_color
)
1080 cr
.set_line_width(self
.line_width
)
1081 cr
.rectangle(self
.dimensions
[HORZ
] - self
.border
- bounding_box_width
, self
.border
,
1082 bounding_box_width
, bounding_box_height
)
1085 for idx
,key
in enumerate(self
.series_labels
):
1087 cr
.set_source_rgba(*self
.series_colors
[idx
][:4])
1088 cr
.rectangle(self
.dimensions
[HORZ
] - self
.border
- max_width
- color_box_width
- 10,
1089 self
.border
+ color_box_height
+ (idx
*max_height
) ,
1090 color_box_width
, color_box_height
)
1093 cr
.set_source_rgba(0, 0, 0)
1094 cr
.rectangle(self
.dimensions
[HORZ
] - self
.border
- max_width
- color_box_width
- 10,
1095 self
.border
+ color_box_height
+ (idx
*max_height
),
1096 color_box_width
, color_box_height
)
1100 cr
.set_source_rgba(0, 0, 0)
1101 cr
.move_to(self
.dimensions
[HORZ
] - self
.border
- max_width
- 5, self
.border
+ ((idx
+1)*max_height
))
1105 class HorizontalBarPlot(BarPlot
):
1111 background
= "white light_gray",
1113 display_values
= False,
1115 rounded_corners
= False,
1117 three_dimension
= False,
1118 series_labels
= None,
1123 series_colors
= None):
1125 BarPlot
.__init
__(self
, surface
, data
, width
, height
, background
, border
,
1126 display_values
, grid
, rounded_corners
, stack
, three_dimension
,
1127 x_labels
, y_labels
, x_bounds
, y_bounds
, series_colors
, HORZ
)
1128 self
.series_labels
= series_labels
1130 def calc_vert_extents(self
):
1131 self
.calc_extents(VERT
)
1132 if self
.labels
[HORZ
] and not self
.labels
[VERT
]:
1133 self
.borders
[HORZ
] += 10
1135 def draw_rectangle_bottom(self
, x0
, y0
, x1
, y1
):
1136 self
.context
.arc(x0
+5, y1
-5, 5, math
.pi
/2, math
.pi
)
1137 self
.context
.line_to(x0
, y0
+5)
1138 self
.context
.arc(x0
+5, y0
+5, 5, -math
.pi
, -math
.pi
/2)
1139 self
.context
.line_to(x1
, y0
)
1140 self
.context
.line_to(x1
, y1
)
1141 self
.context
.line_to(x0
+5, y1
)
1142 self
.context
.close_path()
1144 def draw_rectangle_top(self
, x0
, y0
, x1
, y1
):
1145 self
.context
.arc(x1
-5, y0
+5, 5, -math
.pi
/2, 0)
1146 self
.context
.line_to(x1
, y1
-5)
1147 self
.context
.arc(x1
-5, y1
-5, 5, 0, math
.pi
/2)
1148 self
.context
.line_to(x0
, y1
)
1149 self
.context
.line_to(x0
, y0
)
1150 self
.context
.line_to(x1
, y0
)
1151 self
.context
.close_path()
1153 def draw_rectangle(self
, index
, length
, x0
, y0
, x1
, y1
):
1155 BarPlot
.draw_rectangle(self
, x0
, y0
, x1
, y1
)
1157 self
.draw_rectangle_bottom(x0
, y0
, x1
, y1
)
1158 elif index
== length
-1:
1159 self
.draw_rectangle_top(x0
, y0
, x1
, y1
)
1161 self
.context
.rectangle(x0
, y0
, x1
-x0
, y1
-y0
)
1163 #TODO: Review BarPlot.render_grid code
1164 def render_grid(self
):
1165 self
.context
.set_source_rgba(0.8, 0.8, 0.8)
1166 if self
.labels
[HORZ
]:
1167 self
.context
.set_font_size(self
.font_size
* 0.8)
1168 step
= (self
.dimensions
[HORZ
] - 2*self
.borders
[HORZ
] - self
.value_label
)/(len(self
.labels
[HORZ
])-1)
1169 x
= self
.borders
[HORZ
]
1171 for item
in self
.labels
[HORZ
]:
1172 width
= self
.context
.text_extents(item
)[2]
1173 if x
- width
/2 > next_x
and x
- width
/2 > self
.border
:
1174 self
.context
.move_to(x
, self
.border
)
1175 self
.context
.line_to(x
, self
.dimensions
[VERT
] - self
.borders
[VERT
])
1176 self
.context
.stroke()
1177 next_x
= x
+ width
/2
1181 horizontal_step
= float(self
.plot_dimensions
[HORZ
])/(lines
-1)
1182 x
= self
.borders
[HORZ
]
1183 for y
in xrange(0, lines
):
1184 self
.context
.move_to(x
, self
.border
)
1185 self
.context
.line_to(x
, self
.dimensions
[VERT
] - self
.borders
[VERT
])
1186 self
.context
.stroke()
1187 x
+= horizontal_step
1189 def render_horz_labels(self
):
1190 step
= (self
.dimensions
[HORZ
] - 2*self
.borders
[HORZ
])/(len(self
.labels
[HORZ
])-1)
1191 x
= self
.borders
[HORZ
]
1194 for item
in self
.labels
[HORZ
]:
1195 self
.context
.set_source_rgba(*self
.label_color
)
1196 width
= self
.context
.text_extents(item
)[2]
1197 if x
- width
/2 > next_x
and x
- width
/2 > self
.border
:
1198 self
.context
.move_to(x
- width
/2, self
.dimensions
[VERT
] - self
.borders
[VERT
] + self
.max_value
[HORZ
] + 3)
1199 self
.context
.show_text(item
)
1200 next_x
= x
+ width
/2
1203 def render_vert_labels(self
):
1204 series_length
= len(self
.labels
[VERT
])
1205 step
= (self
.plot_dimensions
[VERT
] - (series_length
+ 1)*self
.space
)/(len(self
.labels
[VERT
]))
1206 y
= self
.border
+ step
/2 + self
.space
1208 for item
in self
.labels
[VERT
]:
1209 self
.context
.set_source_rgba(*self
.label_color
)
1210 width
, height
= self
.context
.text_extents(item
)[2:4]
1211 self
.context
.move_to(self
.borders
[HORZ
] - width
- 5, y
+ height
/2)
1212 self
.context
.show_text(item
)
1213 y
+= step
+ self
.space
1214 self
.labels
[VERT
].reverse()
1216 def render_values(self
):
1217 self
.context
.set_source_rgba(*self
.value_label_color
)
1218 self
.context
.set_font_size(self
.font_size
* 0.8)
1220 for i
,group
in enumerate(self
.series
):
1221 value
= sum(group
.to_list())
1222 height
= self
.context
.text_extents(str(value
))[3]
1223 x
= self
.borders
[HORZ
] + value
*self
.steps
[HORZ
] + 2
1224 y
= self
.borders
[VERT
] + (i
+0.5)*self
.steps
[VERT
] + (i
+1)*self
.space
+ height
/2
1225 self
.context
.move_to(x
, y
)
1226 self
.context
.show_text(str(value
))
1228 for i
,group
in enumerate(self
.series
):
1229 inner_step
= self
.steps
[VERT
]/len(group
)
1230 y0
= self
.border
+ i
*self
.steps
[VERT
] + (i
+1)*self
.space
1231 for number
,data
in enumerate(group
):
1232 height
= self
.context
.text_extents(str(data
.content
))[3]
1233 self
.context
.move_to(self
.borders
[HORZ
] + data
.content
*self
.steps
[HORZ
] + 2, y0
+ 0.5*inner_step
+ height
/2, )
1234 self
.context
.show_text(str(data
.content
))
1237 def render_plot(self
):
1239 for i
,group
in enumerate(self
.series
):
1240 x0
= self
.borders
[HORZ
]
1241 y0
= self
.borders
[VERT
] + i
*self
.steps
[VERT
] + (i
+1)*self
.space
1242 for number
,data
in enumerate(group
):
1243 if self
.series_colors
[number
][4] in ('radial','linear') :
1244 linear
= cairo
.LinearGradient( data
.content
*self
.steps
[HORZ
]/2, y0
, data
.content
*self
.steps
[HORZ
]/2, y0
+ self
.steps
[VERT
] )
1245 color
= self
.series_colors
[number
]
1246 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)
1247 linear
.add_color_stop_rgba(1.0, *color
[:4])
1248 self
.context
.set_source(linear
)
1249 elif self
.series_colors
[number
][4] == 'solid':
1250 self
.context
.set_source_rgba(*self
.series_colors
[number
][:4])
1251 if self
.rounded_corners
:
1252 self
.draw_rectangle(number
, len(group
), x0
, y0
, x0
+data
.content
*self
.steps
[HORZ
], y0
+self
.steps
[VERT
])
1255 self
.context
.rectangle(x0
, y0
, data
.content
*self
.steps
[HORZ
], self
.steps
[VERT
])
1257 x0
+= data
.content
*self
.steps
[HORZ
]
1259 for i
,group
in enumerate(self
.series
):
1260 inner_step
= self
.steps
[VERT
]/len(group
)
1261 x0
= self
.borders
[HORZ
]
1262 y0
= self
.border
+ i
*self
.steps
[VERT
] + (i
+1)*self
.space
1263 for number
,data
in enumerate(group
):
1264 linear
= cairo
.LinearGradient(data
.content
*self
.steps
[HORZ
]/2, y0
, data
.content
*self
.steps
[HORZ
]/2, y0
+ inner_step
)
1265 color
= self
.series_colors
[number
]
1266 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)
1267 linear
.add_color_stop_rgba(1.0, *color
[:4])
1268 self
.context
.set_source(linear
)
1269 if self
.rounded_corners
and data
.content
!= 0:
1270 BarPlot
.draw_round_rectangle(self
,x0
, y0
, x0
+ data
.content
*self
.steps
[HORZ
], y0
+ inner_step
)
1273 self
.context
.rectangle(x0
, y0
, data
.content
*self
.steps
[HORZ
], inner_step
)
1277 class VerticalBarPlot(BarPlot
):
1283 background
= "white light_gray",
1285 display_values
= False,
1287 rounded_corners
= False,
1289 three_dimension
= False,
1290 series_labels
= None,
1295 series_colors
= None):
1297 BarPlot
.__init
__(self
, surface
, data
, width
, height
, background
, border
,
1298 display_values
, grid
, rounded_corners
, stack
, three_dimension
,
1299 x_labels
, y_labels
, x_bounds
, y_bounds
, series_colors
, VERT
)
1300 self
.series_labels
= series_labels
1302 def calc_vert_extents(self
):
1303 self
.calc_extents(VERT
)
1304 if self
.labels
[VERT
] and not self
.labels
[HORZ
]:
1305 self
.borders
[VERT
] += 10
1307 def draw_rectangle_bottom(self
, x0
, y0
, x1
, y1
):
1308 self
.context
.move_to(x1
,y1
)
1309 self
.context
.arc(x1
-5, y1
-5, 5, 0, math
.pi
/2)
1310 self
.context
.line_to(x0
+5, y1
)
1311 self
.context
.arc(x0
+5, y1
-5, 5, math
.pi
/2, math
.pi
)
1312 self
.context
.line_to(x0
, y0
)
1313 self
.context
.line_to(x1
, y0
)
1314 self
.context
.line_to(x1
, y1
)
1315 self
.context
.close_path()
1317 def draw_rectangle_top(self
, x0
, y0
, x1
, y1
):
1318 self
.context
.arc(x0
+5, y0
+5, 5, -math
.pi
, -math
.pi
/2)
1319 self
.context
.line_to(x1
-5, y0
)
1320 self
.context
.arc(x1
-5, y0
+5, 5, -math
.pi
/2, 0)
1321 self
.context
.line_to(x1
, y1
)
1322 self
.context
.line_to(x0
, y1
)
1323 self
.context
.line_to(x0
, y0
)
1324 self
.context
.close_path()
1326 def draw_rectangle(self
, index
, length
, x0
, y0
, x1
, y1
):
1328 BarPlot
.draw_rectangle(self
, x0
, y0
, x1
, y1
)
1330 self
.draw_rectangle_bottom(x0
, y0
, x1
, y1
)
1331 elif index
== length
-1:
1332 self
.draw_rectangle_top(x0
, y0
, x1
, y1
)
1334 self
.context
.rectangle(x0
, y0
, x1
-x0
, y1
-y0
)
1336 def render_grid(self
):
1337 self
.context
.set_source_rgba(0.8, 0.8, 0.8)
1338 if self
.labels
[VERT
]:
1339 lines
= len(self
.labels
[VERT
])
1340 vertical_step
= float(self
.plot_dimensions
[self
.main_dir
])/(lines
-1)
1341 y
= self
.borders
[VERT
] + self
.value_label
1344 vertical_step
= float(self
.plot_dimensions
[self
.main_dir
])/(lines
-1)
1345 y
= 1.2*self
.border
+ self
.value_label
1346 for x
in xrange(0, lines
):
1347 self
.context
.move_to(self
.borders
[HORZ
], y
)
1348 self
.context
.line_to(self
.dimensions
[HORZ
] - self
.border
, y
)
1349 self
.context
.stroke()
1352 def render_ground(self
):
1353 self
.draw_3d_rectangle_front(self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
],
1354 self
.dimensions
[HORZ
] - self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
] + 5, 10)
1357 self
.draw_3d_rectangle_side (self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
],
1358 self
.dimensions
[HORZ
] - self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
] + 5, 10)
1361 self
.draw_3d_rectangle_top (self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
],
1362 self
.dimensions
[HORZ
] - self
.borders
[HORZ
], self
.dimensions
[VERT
] - self
.borders
[VERT
] + 5, 10)
1365 def render_horz_labels(self
):
1366 series_length
= len(self
.labels
[HORZ
])
1367 step
= float (self
.plot_dimensions
[HORZ
] - (series_length
+ 1)*self
.space
)/len(self
.labels
[HORZ
])
1368 x
= self
.borders
[HORZ
] + step
/2 + self
.space
1371 for item
in self
.labels
[HORZ
]:
1372 self
.context
.set_source_rgba(*self
.label_color
)
1373 width
= self
.context
.text_extents(item
)[2]
1374 if x
- width
/2 > next_x
and x
- width
/2 > self
.borders
[HORZ
]:
1375 self
.context
.move_to(x
- width
/2, self
.dimensions
[VERT
] - self
.borders
[VERT
] + self
.max_value
[HORZ
] + 3)
1376 self
.context
.show_text(item
)
1377 next_x
= x
+ width
/2
1378 x
+= step
+ self
.space
1380 def render_vert_labels(self
):
1381 self
.context
.set_source_rgba(*self
.label_color
)
1382 y
= self
.borders
[VERT
] + self
.value_label
1383 step
= (self
.dimensions
[VERT
] - 2*self
.borders
[VERT
] - self
.value_label
)/(len(self
.labels
[VERT
]) - 1)
1384 self
.labels
[VERT
].reverse()
1385 for item
in self
.labels
[VERT
]:
1386 width
, height
= self
.context
.text_extents(item
)[2:4]
1387 self
.context
.move_to(self
.borders
[HORZ
] - width
- 5, y
+ height
/2)
1388 self
.context
.show_text(item
)
1390 self
.labels
[VERT
].reverse()
1392 def render_values(self
):
1393 self
.context
.set_source_rgba(*self
.value_label_color
)
1394 self
.context
.set_font_size(self
.font_size
* 0.8)
1396 for i
,group
in enumerate(self
.series
):
1397 value
= sum(group
.to_list())
1398 width
= self
.context
.text_extents(str(value
))[2]
1399 x
= self
.borders
[HORZ
] + (i
+0.5)*self
.steps
[HORZ
] + (i
+1)*self
.space
- width
/2
1400 y
= value
*self
.steps
[VERT
] + 2
1401 self
.context
.move_to(x
, self
.plot_top
-y
)
1402 self
.context
.show_text(str(value
))
1404 for i
,group
in enumerate(self
.series
):
1405 inner_step
= self
.steps
[HORZ
]/len(group
)
1406 x0
= self
.borders
[HORZ
] + i
*self
.steps
[HORZ
] + (i
+1)*self
.space
1407 for number
,data
in enumerate(group
):
1408 width
= self
.context
.text_extents(str(data
.content
))[2]
1409 self
.context
.move_to(x0
+ 0.5*inner_step
- width
/2, self
.plot_top
- data
.content
*self
.steps
[VERT
] - 2)
1410 self
.context
.show_text(str(data
.content
))
1413 def render_plot(self
):
1415 for i
,group
in enumerate(self
.series
):
1416 x0
= self
.borders
[HORZ
] + i
*self
.steps
[HORZ
] + (i
+1)*self
.space
1418 for number
,data
in enumerate(group
):
1419 if self
.series_colors
[number
][4] in ('linear','radial'):
1420 linear
= cairo
.LinearGradient( x0
, data
.content
*self
.steps
[VERT
]/2, x0
+ self
.steps
[HORZ
], data
.content
*self
.steps
[VERT
]/2 )
1421 color
= self
.series_colors
[number
]
1422 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)
1423 linear
.add_color_stop_rgba(1.0, *color
[:4])
1424 self
.context
.set_source(linear
)
1425 elif self
.series_colors
[number
][4] == 'solid':
1426 self
.context
.set_source_rgba(*self
.series_colors
[number
][:4])
1427 if self
.rounded_corners
:
1428 self
.draw_rectangle(number
, len(group
), x0
, self
.plot_top
- y0
- data
.content
*self
.steps
[VERT
], x0
+ self
.steps
[HORZ
], self
.plot_top
- y0
)
1431 self
.context
.rectangle(x0
, self
.plot_top
- y0
- data
.content
*self
.steps
[VERT
], self
.steps
[HORZ
], data
.content
*self
.steps
[VERT
])
1433 y0
+= data
.content
*self
.steps
[VERT
]
1435 for i
,group
in enumerate(self
.series
):
1436 inner_step
= self
.steps
[HORZ
]/len(group
)
1437 y0
= self
.borders
[VERT
]
1438 x0
= self
.borders
[HORZ
] + i
*self
.steps
[HORZ
] + (i
+1)*self
.space
1439 for number
,data
in enumerate(group
):
1440 if self
.series_colors
[number
][4] == 'linear':
1441 linear
= cairo
.LinearGradient( x0
, data
.content
*self
.steps
[VERT
]/2, x0
+ inner_step
, data
.content
*self
.steps
[VERT
]/2 )
1442 color
= self
.series_colors
[number
]
1443 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)
1444 linear
.add_color_stop_rgba(1.0, *color
[:4])
1445 self
.context
.set_source(linear
)
1446 elif self
.series_colors
[number
][4] == 'solid':
1447 self
.context
.set_source_rgba(*self
.series_colors
[number
][:4])
1448 if self
.rounded_corners
and data
.content
!= 0:
1449 BarPlot
.draw_round_rectangle(self
, x0
, self
.plot_top
- data
.content
*self
.steps
[VERT
], x0
+inner_step
, self
.plot_top
)
1451 elif self
.three_dimension
:
1452 self
.draw_3d_rectangle_front(x0
, self
.plot_top
- data
.content
*self
.steps
[VERT
], x0
+inner_step
, self
.plot_top
, 5)
1454 self
.draw_3d_rectangle_side(x0
, self
.plot_top
- data
.content
*self
.steps
[VERT
], x0
+inner_step
, self
.plot_top
, 5)
1456 self
.draw_3d_rectangle_top(x0
, self
.plot_top
- data
.content
*self
.steps
[VERT
], x0
+inner_step
, self
.plot_top
, 5)
1459 self
.context
.rectangle(x0
, self
.plot_top
- data
.content
*self
.steps
[VERT
], inner_step
, data
.content
*self
.steps
[VERT
])
1464 class StreamChart(VerticalBarPlot
):
1470 background
= "white light_gray",
1473 series_legend
= None,
1477 series_colors
= None):
1479 VerticalBarPlot
.__init
__(self
, surface
, data
, width
, height
, background
, border
,
1480 False, grid
, False, True, False,
1481 None, x_labels
, None, x_bounds
, y_bounds
, series_colors
)
1483 def calc_steps(self
):
1484 other_dir
= other_direction(self
.main_dir
)
1485 self
.series_amplitude
= self
.bounds
[self
.main_dir
][1] - self
.bounds
[self
.main_dir
][0]
1486 if self
.series_amplitude
:
1487 self
.steps
[self
.main_dir
] = float(self
.plot_dimensions
[self
.main_dir
])/self
.series_amplitude
1489 self
.steps
[self
.main_dir
] = 0.00
1490 series_length
= len(self
.data
)
1491 self
.steps
[other_dir
] = float(self
.plot_dimensions
[other_dir
])/series_length
1493 def render_legend(self
):
1496 def ground(self
, index
):
1497 sum_values
= sum(self
.data
[index
])
1498 return -0.5*sum_values
1500 def calc_angles(self
):
1501 middle
= self
.plot_top
- self
.plot_dimensions
[VERT
]/2.0
1502 self
.angles
= [tuple([0.0 for x
in range(len(self
.data
)+1)])]
1503 for x_index
in range(1, len(self
.data
)-1):
1505 x0
= self
.borders
[HORZ
] + (0.5 + x_index
- 1)*self
.steps
[HORZ
]
1506 x2
= self
.borders
[HORZ
] + (0.5 + x_index
+ 1)*self
.steps
[HORZ
]
1507 y0
= middle
- self
.ground(x_index
-1)*self
.steps
[VERT
]
1508 y2
= middle
- self
.ground(x_index
+1)*self
.steps
[VERT
]
1509 t
.append(math
.atan(float(y0
-y2
)/(x0
-x2
)))
1510 for data_index
in range(len(self
.data
[x_index
])):
1511 x0
= self
.borders
[HORZ
] + (0.5 + x_index
- 1)*self
.steps
[HORZ
]
1512 x2
= self
.borders
[HORZ
] + (0.5 + x_index
+ 1)*self
.steps
[HORZ
]
1513 y0
= middle
- self
.ground(x_index
-1)*self
.steps
[VERT
] - self
.data
[x_index
-1][data_index
]*self
.steps
[VERT
]
1514 y2
= middle
- self
.ground(x_index
+1)*self
.steps
[VERT
] - self
.data
[x_index
+1][data_index
]*self
.steps
[VERT
]
1516 for i
in range(0,data_index
):
1517 y0
-= self
.data
[x_index
-1][i
]*self
.steps
[VERT
]
1518 y2
-= self
.data
[x_index
+1][i
]*self
.steps
[VERT
]
1520 if data_index
== len(self
.data
[0])-1 and False:
1521 self
.context
.set_source_rgba(0.0,0.0,0.0,0.3)
1522 self
.context
.move_to(x0
,y0
)
1523 self
.context
.line_to(x2
,y2
)
1524 self
.context
.stroke()
1525 self
.context
.arc(x0
,y0
,2,0,2*math
.pi
)
1527 t
.append(math
.atan(float(y0
-y2
)/(x0
-x2
)))
1528 self
.angles
.append(tuple(t
))
1529 self
.angles
.append(tuple([0.0 for x
in range(len(self
.data
)+1)]))
1531 def render_plot(self
):
1533 middle
= self
.plot_top
- self
.plot_dimensions
[VERT
]/2.0
1534 p
= 0.4*self
.steps
[HORZ
]
1535 for data_index
in range(len(self
.data
[0])-1,-1,-1):
1536 self
.context
.set_source_rgba(*self
.series_colors
[data_index
][:4])
1538 #draw the upper line
1539 for x_index
in range(len(self
.data
)-1) :
1540 x1
= self
.borders
[HORZ
] + (0.5 + x_index
)*self
.steps
[HORZ
]
1541 y1
= middle
- self
.ground(x_index
)*self
.steps
[VERT
] - self
.data
[x_index
][data_index
]*self
.steps
[VERT
]
1542 x2
= self
.borders
[HORZ
] + (0.5 + x_index
+ 1)*self
.steps
[HORZ
]
1543 y2
= middle
- self
.ground(x_index
+ 1)*self
.steps
[VERT
] - self
.data
[x_index
+ 1][data_index
]*self
.steps
[VERT
]
1545 for i
in range(0,data_index
):
1546 y1
-= self
.data
[x_index
][i
]*self
.steps
[VERT
]
1547 y2
-= self
.data
[x_index
+1][i
]*self
.steps
[VERT
]
1550 self
.context
.move_to(x1
,y1
)
1552 ang1
= self
.angles
[x_index
][data_index
+1]
1553 ang2
= self
.angles
[x_index
+1][data_index
+1] + math
.pi
1554 self
.context
.curve_to(x1
+p
*math
.cos(ang1
),y1
+p
*math
.sin(ang1
),
1555 x2
+p
*math
.cos(ang2
),y2
+p
*math
.sin(ang2
),
1558 for x_index
in range(len(self
.data
)-1,0,-1) :
1559 x1
= self
.borders
[HORZ
] + (0.5 + x_index
)*self
.steps
[HORZ
]
1560 y1
= middle
- self
.ground(x_index
)*self
.steps
[VERT
]
1561 x2
= self
.borders
[HORZ
] + (0.5 + x_index
- 1)*self
.steps
[HORZ
]
1562 y2
= middle
- self
.ground(x_index
- 1)*self
.steps
[VERT
]
1564 for i
in range(0,data_index
):
1565 y1
-= self
.data
[x_index
][i
]*self
.steps
[VERT
]
1566 y2
-= self
.data
[x_index
-1][i
]*self
.steps
[VERT
]
1568 if x_index
== len(self
.data
)-1:
1569 self
.context
.line_to(x1
,y1
+2)
1571 #revert angles by pi degrees to take the turn back
1572 ang1
= self
.angles
[x_index
][data_index
] + math
.pi
1573 ang2
= self
.angles
[x_index
-1][data_index
]
1574 self
.context
.curve_to(x1
+p
*math
.cos(ang1
),y1
+p
*math
.sin(ang1
),
1575 x2
+p
*math
.cos(ang2
),y2
+p
*math
.sin(ang2
),
1578 self
.context
.close_path()
1582 self
.context
.move_to(self
.borders
[HORZ
] + 0.5*self
.steps
[HORZ
], middle
)
1583 for x_index
in range(len(self
.data
)-1) :
1584 x1
= self
.borders
[HORZ
] + (0.5 + x_index
)*self
.steps
[HORZ
]
1585 y1
= middle
- self
.ground(x_index
)*self
.steps
[VERT
] - self
.data
[x_index
][data_index
]*self
.steps
[VERT
]
1586 x2
= self
.borders
[HORZ
] + (0.5 + x_index
+ 1)*self
.steps
[HORZ
]
1587 y2
= middle
- self
.ground(x_index
+ 1)*self
.steps
[VERT
] - self
.data
[x_index
+ 1][data_index
]*self
.steps
[VERT
]
1589 for i
in range(0,data_index
):
1590 y1
-= self
.data
[x_index
][i
]*self
.steps
[VERT
]
1591 y2
-= self
.data
[x_index
+1][i
]*self
.steps
[VERT
]
1593 ang1
= self
.angles
[x_index
][data_index
+1]
1594 ang2
= self
.angles
[x_index
+1][data_index
+1] + math
.pi
1595 self
.context
.set_source_rgba(1.0,0.0,0.0)
1596 self
.context
.arc(x1
+p
*math
.cos(ang1
),y1
+p
*math
.sin(ang1
),2,0,2*math
.pi
)
1598 self
.context
.set_source_rgba(0.0,0.0,0.0)
1599 self
.context
.arc(x2
+p
*math
.cos(ang2
),y2
+p
*math
.sin(ang2
),2,0,2*math
.pi
)
1601 '''self.context.set_source_rgba(0.0,0.0,0.0,0.3)
1602 self.context.arc(x2,y2,2,0,2*math.pi)
1603 self.context.fill()'''
1604 self
.context
.move_to(x1
,y1
)
1605 self
.context
.line_to(x1
+p
*math
.cos(ang1
),y1
+p
*math
.sin(ang1
))
1606 self
.context
.stroke()
1607 self
.context
.move_to(x2
,y2
)
1608 self
.context
.line_to(x2
+p
*math
.cos(ang2
),y2
+p
*math
.sin(ang2
))
1609 self
.context
.stroke()
1611 for x_index
in range(len(self
.data
)-1,0,-1) :
1612 x1
= self
.borders
[HORZ
] + (0.5 + x_index
)*self
.steps
[HORZ
]
1613 y1
= middle
- self
.ground(x_index
)*self
.steps
[VERT
]
1614 x2
= self
.borders
[HORZ
] + (0.5 + x_index
- 1)*self
.steps
[HORZ
]
1615 y2
= middle
- self
.ground(x_index
- 1)*self
.steps
[VERT
]
1617 for i
in range(0,data_index
):
1618 y1
-= self
.data
[x_index
][i
]*self
.steps
[VERT
]
1619 y2
-= self
.data
[x_index
-1][i
]*self
.steps
[VERT
]
1621 #revert angles by pi degrees to take the turn back
1622 ang1
= self
.angles
[x_index
][data_index
] + math
.pi
1623 ang2
= self
.angles
[x_index
-1][data_index
]
1624 self
.context
.set_source_rgba(0.0,1.0,0.0)
1625 self
.context
.arc(x1
+p
*math
.cos(ang1
),y1
+p
*math
.sin(ang1
),2,0,2*math
.pi
)
1627 self
.context
.set_source_rgba(0.0,0.0,1.0)
1628 self
.context
.arc(x2
+p
*math
.cos(ang2
),y2
+p
*math
.sin(ang2
),2,0,2*math
.pi
)
1630 '''self.context.set_source_rgba(0.0,0.0,0.0,0.3)
1631 self.context.arc(x2,y2,2,0,2*math.pi)
1632 self.context.fill()'''
1633 self
.context
.move_to(x1
,y1
)
1634 self
.context
.line_to(x1
+p
*math
.cos(ang1
),y1
+p
*math
.sin(ang1
))
1635 self
.context
.stroke()
1636 self
.context
.move_to(x2
,y2
)
1637 self
.context
.line_to(x2
+p
*math
.cos(ang2
),y2
+p
*math
.sin(ang2
))
1638 self
.context
.stroke()
1641 #self.context.arc(self.dimensions[HORZ]/2, self.dimensions[VERT]/2,50,0,3*math.pi/2)
1642 #self.context.fill()
1645 class PiePlot(Plot
):
1646 #TODO: Check the old cairoplot, graphs aren't matching
1652 background
= "white light_gray",
1657 Plot
.__init
__( self
, surface
, data
, width
, height
, background
, series_colors
= colors
)
1658 self
.center
= (self
.dimensions
[HORZ
]/2, self
.dimensions
[VERT
]/2)
1659 self
.total
= sum( self
.series
.to_list() )
1660 self
.radius
= min(self
.dimensions
[HORZ
]/3,self
.dimensions
[VERT
]/3)
1661 self
.gradient
= gradient
1662 self
.shadow
= shadow
1664 def sort_function(x
,y
):
1665 return x
.content
- y
.content
1667 def load_series(self
, data
, x_labels
=None, y_labels
=None, series_colors
=None):
1668 Plot
.load_series(self
, data
, x_labels
, y_labels
, series_colors
)
1669 # Already done inside series
1670 #self.data = sorted(self.data)
1672 def draw_piece(self
, angle
, next_angle
):
1673 self
.context
.move_to(self
.center
[0],self
.center
[1])
1674 self
.context
.line_to(self
.center
[0] + self
.radius
*math
.cos(angle
), self
.center
[1] + self
.radius
*math
.sin(angle
))
1675 self
.context
.arc(self
.center
[0], self
.center
[1], self
.radius
, angle
, next_angle
)
1676 self
.context
.line_to(self
.center
[0], self
.center
[1])
1677 self
.context
.close_path()
1680 self
.render_background()
1681 self
.render_bounding_box()
1683 self
.render_shadow()
1685 self
.render_series_labels()
1687 def render_shadow(self
):
1688 horizontal_shift
= 3
1690 self
.context
.set_source_rgba(0, 0, 0, 0.5)
1691 self
.context
.arc(self
.center
[0] + horizontal_shift
, self
.center
[1] + vertical_shift
, self
.radius
, 0, 2*math
.pi
)
1694 def render_series_labels(self
):
1699 for number
,key
in enumerate(self
.series_labels
):
1700 # self.data[number] should be just a number
1701 data
= sum(self
.series
[number
].to_list())
1703 next_angle
= angle
+ 2.0*math
.pi
*data
/self
.total
1704 cr
.set_source_rgba(*self
.series_colors
[number
][:4])
1705 w
= cr
.text_extents(key
)[2]
1706 if (angle
+ next_angle
)/2 < math
.pi
/2 or (angle
+ next_angle
)/2 > 3*math
.pi
/2:
1707 cr
.move_to(x0
+ (self
.radius
+10)*math
.cos((angle
+next_angle
)/2), y0
+ (self
.radius
+10)*math
.sin((angle
+next_angle
)/2) )
1709 cr
.move_to(x0
+ (self
.radius
+10)*math
.cos((angle
+next_angle
)/2) - w
, y0
+ (self
.radius
+10)*math
.sin((angle
+next_angle
)/2) )
1713 def render_plot(self
):
1718 for number
,group
in enumerate(self
.series
):
1719 # Group should be just a number
1720 data
= sum(group
.to_list())
1721 next_angle
= angle
+ 2.0*math
.pi
*data
/self
.total
1722 if self
.gradient
or self
.series_colors
[number
][4] in ('linear','radial'):
1723 gradient_color
= cairo
.RadialGradient(self
.center
[0], self
.center
[1], 0, self
.center
[0], self
.center
[1], self
.radius
)
1724 gradient_color
.add_color_stop_rgba(0.3, *self
.series_colors
[number
][:4])
1725 gradient_color
.add_color_stop_rgba(1, self
.series_colors
[number
][0]*0.7,
1726 self
.series_colors
[number
][1]*0.7,
1727 self
.series_colors
[number
][2]*0.7,
1728 self
.series_colors
[number
][3])
1729 cr
.set_source(gradient_color
)
1731 cr
.set_source_rgba(*self
.series_colors
[number
][:4])
1733 self
.draw_piece(angle
, next_angle
)
1736 cr
.set_source_rgba(1.0, 1.0, 1.0)
1737 self
.draw_piece(angle
, next_angle
)
1742 class DonutPlot(PiePlot
):
1748 background
= "white light_gray",
1754 Plot
.__init
__( self
, surface
, data
, width
, height
, background
, series_colors
= colors
)
1756 self
.center
= ( self
.dimensions
[HORZ
]/2, self
.dimensions
[VERT
]/2 )
1757 self
.total
= sum( self
.series
.to_list() )
1758 self
.radius
= min( self
.dimensions
[HORZ
]/3,self
.dimensions
[VERT
]/3 )
1759 self
.inner_radius
= inner_radius
*self
.radius
1761 if inner_radius
== -1:
1762 self
.inner_radius
= self
.radius
/3
1764 self
.gradient
= gradient
1765 self
.shadow
= shadow
1767 def draw_piece(self
, angle
, next_angle
):
1768 self
.context
.move_to(self
.center
[0] + (self
.inner_radius
)*math
.cos(angle
), self
.center
[1] + (self
.inner_radius
)*math
.sin(angle
))
1769 self
.context
.line_to(self
.center
[0] + self
.radius
*math
.cos(angle
), self
.center
[1] + self
.radius
*math
.sin(angle
))
1770 self
.context
.arc(self
.center
[0], self
.center
[1], self
.radius
, angle
, next_angle
)
1771 self
.context
.line_to(self
.center
[0] + (self
.inner_radius
)*math
.cos(next_angle
), self
.center
[1] + (self
.inner_radius
)*math
.sin(next_angle
))
1772 self
.context
.arc_negative(self
.center
[0], self
.center
[1], self
.inner_radius
, next_angle
, angle
)
1773 self
.context
.close_path()
1775 def render_shadow(self
):
1776 horizontal_shift
= 3
1778 self
.context
.set_source_rgba(0, 0, 0, 0.5)
1779 self
.context
.arc(self
.center
[0] + horizontal_shift
, self
.center
[1] + vertical_shift
, self
.inner_radius
, 0, 2*math
.pi
)
1780 self
.context
.arc_negative(self
.center
[0] + horizontal_shift
, self
.center
[1] + vertical_shift
, self
.radius
, 0, -2*math
.pi
)
1783 class GanttChart (Plot
) :
1794 Plot
.__init
__(self
, surface
, data
, width
, height
, x_labels
= x_labels
, y_labels
= y_labels
, series_colors
= colors
)
1796 def load_series(self
, data
, x_labels
=None, y_labels
=None, series_colors
=None):
1797 Plot
.load_series(self
, data
, x_labels
, y_labels
, series_colors
)
1798 self
.calc_boundaries()
1800 def calc_boundaries(self
):
1801 self
.bounds
[HORZ
] = (0,len(self
.series
))
1802 end_pos
= max(self
.series
.to_list())
1804 #for group in self.series:
1805 # if hasattr(item, "__delitem__"):
1806 # for sub_item in item:
1807 # end_pos = max(sub_item)
1809 # end_pos = max(item)
1810 self
.bounds
[VERT
] = (0,end_pos
)
1812 def calc_extents(self
, direction
):
1813 self
.max_value
[direction
] = 0
1814 if self
.labels
[direction
]:
1815 self
.max_value
[direction
] = max(self
.context
.text_extents(item
)[2] for item
in self
.labels
[direction
])
1817 self
.max_value
[direction
] = self
.context
.text_extents( str(self
.bounds
[direction
][1] + 1) )[2]
1819 def calc_horz_extents(self
):
1820 self
.calc_extents(HORZ
)
1821 self
.borders
[HORZ
] = 100 + self
.max_value
[HORZ
]
1823 def calc_vert_extents(self
):
1824 self
.calc_extents(VERT
)
1825 self
.borders
[VERT
] = self
.dimensions
[VERT
]/(self
.bounds
[HORZ
][1] + 1)
1827 def calc_steps(self
):
1828 self
.horizontal_step
= (self
.dimensions
[HORZ
] - self
.borders
[HORZ
])/(len(self
.labels
[VERT
]))
1829 self
.vertical_step
= self
.borders
[VERT
]
1832 self
.calc_horz_extents()
1833 self
.calc_vert_extents()
1835 self
.render_background()
1837 self
.render_labels()
1841 def render_background(self
):
1843 cr
.set_source_rgba(255,255,255)
1844 cr
.rectangle(0,0,self
.dimensions
[HORZ
], self
.dimensions
[VERT
])
1846 for number
,group
in enumerate(self
.series
):
1847 linear
= cairo
.LinearGradient(self
.dimensions
[HORZ
]/2, self
.borders
[VERT
] + number
*self
.vertical_step
,
1848 self
.dimensions
[HORZ
]/2, self
.borders
[VERT
] + (number
+1)*self
.vertical_step
)
1849 linear
.add_color_stop_rgba(0,1.0,1.0,1.0,1.0)
1850 linear
.add_color_stop_rgba(1.0,0.9,0.9,0.9,1.0)
1851 cr
.set_source(linear
)
1852 cr
.rectangle(0,self
.borders
[VERT
] + number
*self
.vertical_step
,self
.dimensions
[HORZ
],self
.vertical_step
)
1855 def render_grid(self
):
1857 cr
.set_source_rgba(0.7, 0.7, 0.7)
1858 cr
.set_dash((1,0,0,0,0,0,1))
1859 cr
.set_line_width(0.5)
1860 for number
,label
in enumerate(self
.labels
[VERT
]):
1861 h
= cr
.text_extents(label
)[3]
1862 cr
.move_to(self
.borders
[HORZ
] + number
*self
.horizontal_step
, self
.vertical_step
/2 + h
)
1863 cr
.line_to(self
.borders
[HORZ
] + number
*self
.horizontal_step
, self
.dimensions
[VERT
])
1866 def render_labels(self
):
1867 self
.context
.set_font_size(0.02 * self
.dimensions
[HORZ
])
1869 self
.render_horz_labels()
1870 self
.render_vert_labels()
1872 def render_horz_labels(self
):
1874 labels
= self
.labels
[HORZ
]
1876 labels
= [str(i
) for i
in range(1, self
.bounds
[HORZ
][1] + 1) ]
1877 for number
,label
in enumerate(labels
):
1879 cr
.set_source_rgba(0.5, 0.5, 0.5)
1880 w
,h
= cr
.text_extents(label
)[2], cr
.text_extents(label
)[3]
1881 cr
.move_to(40,self
.borders
[VERT
] + number
*self
.vertical_step
+ self
.vertical_step
/2 + h
/2)
1884 def render_vert_labels(self
):
1886 labels
= self
.labels
[VERT
]
1888 labels
= [str(i
) for i
in range(1, self
.bounds
[VERT
][1] + 1) ]
1889 for number
,label
in enumerate(labels
):
1890 w
,h
= cr
.text_extents(label
)[2], cr
.text_extents(label
)[3]
1891 cr
.move_to(self
.borders
[HORZ
] + number
*self
.horizontal_step
- w
/2, self
.vertical_step
/2)
1894 def render_rectangle(self
, x0
, y0
, x1
, y1
, color
):
1895 self
.draw_shadow(x0
, y0
, x1
, y1
)
1896 self
.draw_rectangle(x0
, y0
, x1
, y1
, color
)
1898 def draw_rectangular_shadow(self
, gradient
, x0
, y0
, w
, h
):
1899 self
.context
.set_source(gradient
)
1900 self
.context
.rectangle(x0
,y0
,w
,h
)
1903 def draw_circular_shadow(self
, x
, y
, radius
, ang_start
, ang_end
, mult
, shadow
):
1904 gradient
= cairo
.RadialGradient(x
, y
, 0, x
, y
, 2*radius
)
1905 gradient
.add_color_stop_rgba(0, 0, 0, 0, shadow
)
1906 gradient
.add_color_stop_rgba(1, 0, 0, 0, 0)
1907 self
.context
.set_source(gradient
)
1908 self
.context
.move_to(x
,y
)
1909 self
.context
.line_to(x
+ mult
[0]*radius
,y
+ mult
[1]*radius
)
1910 self
.context
.arc(x
, y
, 8, ang_start
, ang_end
)
1911 self
.context
.line_to(x
,y
)
1912 self
.context
.close_path()
1915 def draw_rectangle(self
, x0
, y0
, x1
, y1
, color
):
1918 linear
= cairo
.LinearGradient(middle
,y0
,middle
,y1
)
1919 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)
1920 linear
.add_color_stop_rgba(1,*color
[:4])
1921 cr
.set_source(linear
)
1923 cr
.arc(x0
+5, y0
+5, 5, 0, 2*math
.pi
)
1924 cr
.arc(x1
-5, y0
+5, 5, 0, 2*math
.pi
)
1925 cr
.arc(x0
+5, y1
-5, 5, 0, 2*math
.pi
)
1926 cr
.arc(x1
-5, y1
-5, 5, 0, 2*math
.pi
)
1927 cr
.rectangle(x0
+5,y0
,x1
-x0
-10,y1
-y0
)
1928 cr
.rectangle(x0
,y0
+5,x1
-x0
,y1
-y0
-10)
1931 def draw_shadow(self
, x0
, y0
, x1
, y1
):
1935 h_linear_1
= cairo
.LinearGradient(h_mid
,y0
-4,h_mid
,y0
+4)
1936 h_linear_2
= cairo
.LinearGradient(h_mid
,y1
-4,h_mid
,y1
+4)
1937 v_linear_1
= cairo
.LinearGradient(x0
-4,v_mid
,x0
+4,v_mid
)
1938 v_linear_2
= cairo
.LinearGradient(x1
-4,v_mid
,x1
+4,v_mid
)
1940 h_linear_1
.add_color_stop_rgba( 0, 0, 0, 0, 0)
1941 h_linear_1
.add_color_stop_rgba( 1, 0, 0, 0, shadow
)
1942 h_linear_2
.add_color_stop_rgba( 0, 0, 0, 0, shadow
)
1943 h_linear_2
.add_color_stop_rgba( 1, 0, 0, 0, 0)
1944 v_linear_1
.add_color_stop_rgba( 0, 0, 0, 0, 0)
1945 v_linear_1
.add_color_stop_rgba( 1, 0, 0, 0, shadow
)
1946 v_linear_2
.add_color_stop_rgba( 0, 0, 0, 0, shadow
)
1947 v_linear_2
.add_color_stop_rgba( 1, 0, 0, 0, 0)
1949 self
.draw_rectangular_shadow(h_linear_1
,x0
+4,y0
-4,x1
-x0
-8,8)
1950 self
.draw_rectangular_shadow(h_linear_2
,x0
+4,y1
-4,x1
-x0
-8,8)
1951 self
.draw_rectangular_shadow(v_linear_1
,x0
-4,y0
+4,8,y1
-y0
-8)
1952 self
.draw_rectangular_shadow(v_linear_2
,x1
-4,y0
+4,8,y1
-y0
-8)
1954 self
.draw_circular_shadow(x0
+4, y0
+4, 4, math
.pi
, 3*math
.pi
/2, (-1,0), shadow
)
1955 self
.draw_circular_shadow(x1
-4, y0
+4, 4, 3*math
.pi
/2, 2*math
.pi
, (0,-1), shadow
)
1956 self
.draw_circular_shadow(x0
+4, y1
-4, 4, math
.pi
/2, math
.pi
, (0,1), shadow
)
1957 self
.draw_circular_shadow(x1
-4, y1
-4, 4, 0, math
.pi
/2, (1,0), shadow
)
1959 def render_plot(self
):
1960 for index
,group
in enumerate(self
.series
):
1962 self
.render_rectangle(self
.borders
[HORZ
] + data
.content
[0]*self
.horizontal_step
,
1963 self
.borders
[VERT
] + index
*self
.vertical_step
+ self
.vertical_step
/4.0,
1964 self
.borders
[HORZ
] + data
.content
[1]*self
.horizontal_step
,
1965 self
.borders
[VERT
] + index
*self
.vertical_step
+ 3.0*self
.vertical_step
/4.0,
1966 self
.series_colors
[index
])
1968 # Function definition
1970 def scatter_plot(name
,
1976 background
= "white light_gray",
1983 series_legend
= False,
1991 series_colors
= None,
1992 circle_colors
= None):
1995 - Function to plot scatter data.
1999 data - The values to be ploted might be passed in a two basic:
2000 list of points: [(0,0), (0,1), (0,2)] or [(0,0,1), (0,1,4), (0,2,1)]
2001 lists of coordinates: [ [0,0,0] , [0,1,2] ] or [ [0,0,0] , [0,1,2] , [1,4,1] ]
2002 Notice that these kinds of that can be grouped in order to form more complex data
2003 using lists of lists or dictionaries;
2004 series_colors - Define color values for each of the series
2005 circle_colors - Define a lower and an upper bound for the circle colors for variable radius
2006 (3 dimensions) series
2009 plot
= ScatterPlot( name
, data
, errorx
, errory
, width
, height
, background
, border
,
2010 axis
, dash
, discrete
, dots
, grid
, series_legend
, x_labels
, y_labels
,
2011 x_bounds
, y_bounds
, z_bounds
, x_title
, y_title
, series_colors
, circle_colors
)
2015 def dot_line_plot(name
,
2019 background
= "white light_gray",
2025 series_legend
= False,
2032 series_colors
= None):
2034 - Function to plot graphics using dots and lines.
2036 dot_line_plot (name, data, width, height, background = "white light_gray", border = 0, axis = False, grid = False, x_labels = None, y_labels = None, x_bounds = None, y_bounds = None)
2040 name - Name of the desired output file, no need to input the .svg as it will be added at runtim;
2041 data - The list, list of lists or dictionary holding the data to be plotted;
2042 width, height - Dimensions of the output image;
2043 background - A 3 element tuple representing the rgb color expected for the background or a new cairo linear gradient.
2044 If left None, a gray to white gradient will be generated;
2045 border - Distance in pixels of a square border into which the graphics will be drawn;
2046 axis - Whether or not the axis are to be drawn;
2047 dash - Boolean or a list or a dictionary of booleans indicating whether or not the associated series should be drawn in dashed mode;
2048 dots - Whether or not dots should be drawn on each point;
2049 grid - Whether or not the gris is to be drawn;
2050 series_legend - Whether or not the legend is to be drawn;
2051 x_labels, y_labels - lists of strings containing the horizontal and vertical labels for the axis;
2052 x_bounds, y_bounds - tuples containing the lower and upper value bounds for the data to be plotted;
2053 x_title - Whether or not to plot a title over the x axis.
2054 y_title - Whether or not to plot a title over the y axis.
2058 data = [0, 1, 3, 8, 9, 0, 10, 10, 2, 1]
2059 CairoPlot.dot_line_plot('teste', data, 400, 300)
2061 data = { "john" : [10, 10, 10, 10, 30], "mary" : [0, 0, 3, 5, 15], "philip" : [13, 32, 11, 25, 2] }
2062 x_labels = ["jan/2008", "feb/2008", "mar/2008", "apr/2008", "may/2008" ]
2063 CairoPlot.dot_line_plot( 'test', data, 400, 300, axis = True, grid = True,
2064 series_legend = True, x_labels = x_labels )
2066 plot
= DotLinePlot( name
, data
, width
, height
, background
, border
,
2067 axis
, dash
, dots
, grid
, series_legend
, x_labels
, y_labels
,
2068 x_bounds
, y_bounds
, x_title
, y_title
, series_colors
)
2072 def function_plot(name
,
2076 background
= "white light_gray",
2082 series_legend
= False,
2089 series_colors
= None,
2093 - Function to plot functions.
2095 function_plot(name, data, width, height, background = "white light_gray", border = 0, axis = True, grid = False, dots = False, x_labels = None, y_labels = None, x_bounds = None, y_bounds = None, step = 1, discrete = False)
2099 name - Name of the desired output file, no need to input the .svg as it will be added at runtim;
2100 data - The list, list of lists or dictionary holding the data to be plotted;
2101 width, height - Dimensions of the output image;
2102 background - A 3 element tuple representing the rgb color expected for the background or a new cairo linear gradient.
2103 If left None, a gray to white gradient will be generated;
2104 border - Distance in pixels of a square border into which the graphics will be drawn;
2105 axis - Whether or not the axis are to be drawn;
2106 grid - Whether or not the gris is to be drawn;
2107 dots - Whether or not dots should be shown at each point;
2108 x_labels, y_labels - lists of strings containing the horizontal and vertical labels for the axis;
2109 x_bounds, y_bounds - tuples containing the lower and upper value bounds for the data to be plotted;
2110 step - the horizontal distance from one point to the other. The smaller, the smoother the curve will be;
2111 discrete - whether or not the function should be plotted in discrete format.
2115 data = lambda x : x**2
2116 CairoPlot.function_plot('function4', data, 400, 300, grid = True, x_bounds=(-10,10), step = 0.1)
2119 plot
= FunctionPlot( name
, data
, width
, height
, background
, border
,
2120 axis
, discrete
, dots
, grid
, series_legend
, x_labels
, y_labels
,
2121 x_bounds
, y_bounds
, x_title
, y_title
, series_colors
, step
)
2125 def pie_plot( name
, data
, width
, height
, background
= "white light_gray", gradient
= False, shadow
= False, colors
= None ):
2128 - Function to plot pie graphics.
2130 pie_plot(name, data, width, height, background = "white light_gray", gradient = False, colors = None)
2134 name - Name of the desired output file, no need to input the .svg as it will be added at runtim;
2135 data - The list, list of lists or dictionary holding the data to be plotted;
2136 width, height - Dimensions of the output image;
2137 background - A 3 element tuple representing the rgb color expected for the background or a new cairo linear gradient.
2138 If left None, a gray to white gradient will be generated;
2139 gradient - Whether or not the pie color will be painted with a gradient;
2140 shadow - Whether or not there will be a shadow behind the pie;
2141 colors - List of slices colors.
2145 teste_data = {"john" : 123, "mary" : 489, "philip" : 890 , "suzy" : 235}
2146 CairoPlot.pie_plot("pie_teste", teste_data, 500, 500)
2149 plot
= PiePlot( name
, data
, width
, height
, background
, gradient
, shadow
, colors
)
2153 def donut_plot(name
, data
, width
, height
, background
= "white light_gray", gradient
= False, shadow
= False, colors
= None, inner_radius
= -1):
2156 - Function to plot donut graphics.
2158 donut_plot(name, data, width, height, background = "white light_gray", gradient = False, inner_radius = -1)
2162 name - Name of the desired output file, no need to input the .svg as it will be added at runtim;
2163 data - The list, list of lists or dictionary holding the data to be plotted;
2164 width, height - Dimensions of the output image;
2165 background - A 3 element tuple representing the rgb color expected for the background or a new cairo linear gradient.
2166 If left None, a gray to white gradient will be generated;
2167 shadow - Whether or not there will be a shadow behind the donut;
2168 gradient - Whether or not the donut color will be painted with a gradient;
2169 colors - List of slices colors;
2170 inner_radius - The radius of the donut's inner circle.
2174 teste_data = {"john" : 123, "mary" : 489, "philip" : 890 , "suzy" : 235}
2175 CairoPlot.donut_plot("donut_teste", teste_data, 500, 500)
2178 plot
= DonutPlot(name
, data
, width
, height
, background
, gradient
, shadow
, colors
, inner_radius
)
2182 def gantt_chart(name
, pieces
, width
, height
, x_labels
, y_labels
, colors
):
2185 - Function to generate Gantt Charts.
2187 gantt_chart(name, pieces, width, height, x_labels, y_labels, colors):
2191 name - Name of the desired output file, no need to input the .svg as it will be added at runtim;
2192 pieces - A list defining the spaces to be drawn. The user must pass, for each line, the index of its start and the index of its end. If a line must have two or more spaces, they must be passed inside a list;
2193 width, height - Dimensions of the output image;
2194 x_labels - A list of names for each of the vertical lines;
2195 y_labels - A list of names for each of the horizontal spaces;
2196 colors - List containing the colors expected for each of the horizontal spaces
2200 pieces = [ (0.5,5.5) , [(0,4),(6,8)] , (5.5,7) , (7,8)]
2201 x_labels = [ 'teste01', 'teste02', 'teste03', 'teste04']
2202 y_labels = [ '0001', '0002', '0003', '0004', '0005', '0006', '0007', '0008', '0009', '0010' ]
2203 colors = [ (1.0, 0.0, 0.0), (1.0, 0.7, 0.0), (1.0, 1.0, 0.0), (0.0, 1.0, 0.0) ]
2204 CairoPlot.gantt_chart('gantt_teste', pieces, 600, 300, x_labels, y_labels, colors)
2207 plot
= GanttChart(name
, pieces
, width
, height
, x_labels
, y_labels
, colors
)
2211 def vertical_bar_plot(name
,
2215 background
= "white light_gray",
2217 display_values
= False,
2219 rounded_corners
= False,
2221 three_dimension
= False,
2222 series_labels
= None,
2228 #TODO: Fix docstring for vertical_bar_plot
2230 - Function to generate vertical Bar Plot Charts.
2232 bar_plot(name, data, width, height, background, border, grid, rounded_corners, three_dimension,
2233 x_labels, y_labels, x_bounds, y_bounds, colors):
2237 name - Name of the desired output file, no need to input the .svg as it will be added at runtime;
2238 data - The list, list of lists or dictionary holding the data to be plotted;
2239 width, height - Dimensions of the output image;
2240 background - A 3 element tuple representing the rgb color expected for the background or a new cairo linear gradient.
2241 If left None, a gray to white gradient will be generated;
2242 border - Distance in pixels of a square border into which the graphics will be drawn;
2243 grid - Whether or not the gris is to be drawn;
2244 rounded_corners - Whether or not the bars should have rounded corners;
2245 three_dimension - Whether or not the bars should be drawn in pseudo 3D;
2246 x_labels, y_labels - lists of strings containing the horizontal and vertical labels for the axis;
2247 x_bounds, y_bounds - tuples containing the lower and upper value bounds for the data to be plotted;
2248 colors - List containing the colors expected for each of the bars.
2252 data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2253 CairoPlot.vertical_bar_plot ('bar2', data, 400, 300, border = 20, grid = True, rounded_corners = False)
2256 plot
= VerticalBarPlot(name
, data
, width
, height
, background
, border
,
2257 display_values
, grid
, rounded_corners
, stack
, three_dimension
,
2258 series_labels
, x_labels
, y_labels
, x_bounds
, y_bounds
, colors
)
2262 def horizontal_bar_plot(name
,
2266 background
= "white light_gray",
2268 display_values
= False,
2270 rounded_corners
= False,
2272 three_dimension
= False,
2273 series_labels
= None,
2280 #TODO: Fix docstring for horizontal_bar_plot
2282 - Function to generate Horizontal Bar Plot Charts.
2284 bar_plot(name, data, width, height, background, border, grid, rounded_corners, three_dimension,
2285 x_labels, y_labels, x_bounds, y_bounds, colors):
2289 name - Name of the desired output file, no need to input the .svg as it will be added at runtime;
2290 data - The list, list of lists or dictionary holding the data to be plotted;
2291 width, height - Dimensions of the output image;
2292 background - A 3 element tuple representing the rgb color expected for the background or a new cairo linear gradient.
2293 If left None, a gray to white gradient will be generated;
2294 border - Distance in pixels of a square border into which the graphics will be drawn;
2295 grid - Whether or not the gris is to be drawn;
2296 rounded_corners - Whether or not the bars should have rounded corners;
2297 three_dimension - Whether or not the bars should be drawn in pseudo 3D;
2298 x_labels, y_labels - lists of strings containing the horizontal and vertical labels for the axis;
2299 x_bounds, y_bounds - tuples containing the lower and upper value bounds for the data to be plotted;
2300 colors - List containing the colors expected for each of the bars.
2304 data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2305 CairoPlot.bar_plot ('bar2', data, 400, 300, border = 20, grid = True, rounded_corners = False)
2308 plot
= HorizontalBarPlot(name
, data
, width
, height
, background
, border
,
2309 display_values
, grid
, rounded_corners
, stack
, three_dimension
,
2310 series_labels
, x_labels
, y_labels
, x_bounds
, y_bounds
, colors
)
2314 def stream_chart(name
,
2318 background
= "white light_gray",
2321 series_legend
= None,
2327 #TODO: Fix docstring for horizontal_bar_plot
2328 plot
= StreamChart(name
, data
, width
, height
, background
, border
,
2329 grid
, series_legend
, x_labels
, x_bounds
, y_bounds
, colors
)
2334 if __name__
== "__main__":
This page took 0.101784 seconds and 3 git commands to generate.