41
42
"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),
42
43
"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)}
44
THEMES = {"black_red" : [ (0.0,0.0,0.0,1.0), (1.0,0.0,0.0,1.0) ],
45
"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) ],
46
"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) ],
47
"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) ],
48
"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) ] }
45
THEMES = {"black_red" : [(0.0,0.0,0.0,1.0), (1.0,0.0,0.0,1.0)],
46
"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)],
47
"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)],
48
"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)],
49
"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)]}
50
51
def colors_from_theme( theme, series_length ):
52
53
if theme not in THEMES.keys() :
53
54
raise Exception, "Theme not defined"
54
color_steps = THEMES[ theme ]
55
steps_length = len(color_steps)
56
if series_length <= steps_length:
57
colors = [color for color in color_steps[0:steps_length] ]
55
color_steps = THEMES[theme]
56
n_colors = len(color_steps)
57
if series_length <= n_colors:
58
colors = [color for color in color_steps[0:n_colors]]
59
iterations = [ (series_length - steps_length)/(steps_length - 1) for i in color_steps[:-1] ]
60
over_iterations = (series_length - steps_length) % (steps_length - 1)
61
for i in range( steps_length - 1 ):
60
iterations = [(series_length - n_colors)/(n_colors - 1) for i in color_steps[:-1]]
61
over_iterations = (series_length - n_colors) % (n_colors - 1)
62
for i in range(n_colors - 1):
62
63
if over_iterations <= 0:
65
66
over_iterations -= 1
66
for index,color in enumerate( color_steps[:-1] ):
67
for index,color in enumerate(color_steps[:-1]):
67
68
colors.append(color)
68
69
if iterations[index] == 0:
70
71
next_color = color_steps[index+1]
71
color_step = ( (next_color[0] - color[0])/(iterations[index] + 1),
72
(next_color[1] - color[1])/(iterations[index] + 1),
73
(next_color[2] - color[2])/(iterations[index] + 1),
74
(next_color[3] - color[3])/(iterations[index] + 1) )
72
color_step = ((next_color[0] - color[0])/(iterations[index] + 1),
73
(next_color[1] - color[1])/(iterations[index] + 1),
74
(next_color[2] - color[2])/(iterations[index] + 1),
75
(next_color[3] - color[3])/(iterations[index] + 1))
75
76
for i in range( iterations[index] ):
76
colors.append( (color[0] + color_step[0]*(i+1),
77
color[1] + color_step[1]*(i+1),
78
color[2] + color_step[2]*(i+1),
79
color[3] + color_step[3]*(i+1)) )
77
colors.append((color[0] + color_step[0]*(i+1),
78
color[1] + color_step[1]*(i+1),
79
color[2] + color_step[2]*(i+1),
80
color[3] + color_step[3]*(i+1)))
80
81
colors.append(color_steps[-1])
860
818
self.bounds[HORZ] = x_bounds
861
819
self.bounds[VERT] = y_bounds
863
Plot.__init__(self, surface, data, width, height, background, border, x_labels, y_labels, series_colors)
865
821
self.rounded_corners = rounded_corners
866
822
self.three_dimension = three_dimension
823
self.x_label_angle = math.pi / 2.5
868
824
self.max_value = {}
826
Plot.__init__(self, surface, data, width, height, background, border, x_labels, y_labels, series_colors)
870
828
def load_series(self, data, x_labels = None, y_labels = None, series_colors = None):
871
829
Plot.load_series(self, data, x_labels, y_labels, series_colors)
872
830
self.calc_boundaries()
874
832
def process_colors(self, series_colors):
875
833
#Data for a BarPlot might be a List or a List of Lists.
876
#On the first case, colors must generated for all bars,
834
#On the first case, colors must be generated for all bars,
877
835
#On the second, colors must be generated for each of the inner lists.
878
836
if hasattr(self.data[0], '__getitem__'):
879
837
length = max(len(series) for series in self.data)
948
884
self.context.line_to(x0-shift, y0+shift)
949
885
self.context.close_path()
887
def render_ground(self):
888
self.draw_3d_rectangle_front(self.borders[HORZ], self.height - self.borders[VERT],
889
self.width - self.borders[HORZ], self.height - self.borders[VERT] + 5, 10)
892
self.draw_3d_rectangle_side (self.borders[HORZ], self.height - self.borders[VERT],
893
self.width - self.borders[HORZ], self.height - self.borders[VERT] + 5, 10)
896
self.draw_3d_rectangle_top (self.borders[HORZ], self.height - self.borders[VERT],
897
self.width - self.borders[HORZ], self.height - self.borders[VERT] + 5, 10)
900
def render_labels(self):
901
self.context.set_font_size(self.font_size * 0.8)
903
if self.labels[HORZ]:
904
self.render_horz_labels()
905
if self.labels[VERT]:
906
self.render_vert_labels()
908
def draw_rectangle(self, x0, y0, x1, y1):
909
self.context.arc(x0+5, y0+5, 5, -math.pi, -math.pi/2)
910
self.context.line_to(x1-5, y0)
911
self.context.arc(x1-5, y0+5, 5, -math.pi/2, 0)
912
self.context.line_to(x1, y1-5)
913
self.context.arc(x1-5, y1-5, 5, 0, math.pi/2)
914
self.context.line_to(x0+5, y1)
915
self.context.arc(x0+5, y1-5, 5, math.pi/2, math.pi)
916
self.context.line_to(x0, y0+5)
917
self.context.close_path()
919
class HorizontalBarPlot(BarPlot):
928
rounded_corners = False,
929
three_dimension = False,
934
series_colors = None):
937
self.bounds[HORZ] = x_bounds
938
self.bounds[VERT] = y_bounds
940
self.rounded_corners = rounded_corners
941
self.three_dimension = three_dimension
942
self.x_label_angle = math.pi / 2.5
945
Plot.__init__(self, surface, data, width, height, background, border, x_labels, y_labels, series_colors)
947
def calc_boundaries(self):
948
if not self.bounds[HORZ]:
949
max_data_value = max(max(serie) for serie in self.data)
950
self.bounds[HORZ] = (0, max_data_value)
951
if not self.bounds[VERT]:
952
self.bounds[VERT] = (0, len(self.data))
954
def calc_horz_extents(self):
955
self.calc_extents(HORZ)
957
def calc_vert_extents(self):
958
self.calc_extents(VERT)
959
if self.labels[HORZ] and not self.labels[VERT]:
960
self.borders[HORZ] += 10
962
def render_grid(self):
963
self.context.set_source_rgba(0.8, 0.8, 0.8)
964
if self.labels[HORZ]:
965
self.context.set_font_size(self.font_size * 0.8)
966
step = (self.width - 2*self.borders[HORZ])/(len(self.labels[HORZ])-1)
967
x = self.borders[HORZ]
969
for item in self.labels[HORZ]:
970
width = self.context.text_extents(item)[2]
971
if x - width/2 > next_x and x - width/2 > self.border:
972
self.context.move_to(x, self.border)
973
self.context.line_to(x, self.height - self.borders[VERT])
974
self.context.stroke()
979
horizontal_step = float(self.width - 2*self.borders[HORZ])/(lines-1)
980
x = self.borders[HORZ]
981
for y in xrange(0, lines):
982
self.context.move_to(x, self.border)
983
self.context.line_to(x, self.height - self.borders[VERT])
984
self.context.stroke()
987
def render_horz_labels(self):
988
step = (self.width - 2*self.borders[HORZ])/(len(self.labels[HORZ])-1)
989
x = self.borders[HORZ]
992
for item in self.labels[HORZ]:
993
self.context.set_source_rgba(*self.label_color)
994
width = self.context.text_extents(item)[2]
995
if x - width/2 > next_x and x - width/2 > self.border:
996
self.context.move_to(x - width/2, self.height - self.borders[VERT] + self.max_value[HORZ] + 3)
997
self.context.show_text(item)
1001
def render_vert_labels(self):
1002
step = (self.height - self.borders[VERT] - self.border)/(len(self.labels[VERT]))
1003
y = self.border + step/2
1005
for item in self.labels[VERT]:
1006
self.context.set_source_rgba(*self.label_color)
1007
width, height = self.context.text_extents(item)[2:4]
1008
self.context.move_to(self.borders[HORZ] - width - 5, y + height/2)
1009
self.context.show_text(item)
1011
self.labels[VERT].reverse()
1013
def draw_rectangle(self, x0, y0, x1, y1):
1014
self.context.arc(x0+5, y0+5, 5, -math.pi, -math.pi/2)
1015
self.context.line_to(x1-5, y0)
1016
self.context.arc(x1-5, y0+5, 5, -math.pi/2, 0)
1017
self.context.line_to(x1, y1-5)
1018
self.context.arc(x1-5, y1-5, 5, 0, math.pi/2)
1019
self.context.line_to(x0+5, y1)
1020
self.context.arc(x0+5, y1-5, 5, math.pi/2, math.pi)
1021
self.context.line_to(x0, y0+5)
1022
self.context.close_path()
1024
def render_plot(self):
1025
plot_width = self.width - 2*self.borders[HORZ]
1026
plot_height = self.height - self.borders[VERT] - self.border
1027
plot_top = self.height - self.borders[VERT]
1029
series_amplitude = self.bounds[HORZ][1] - self.bounds[HORZ][0]
1031
x0 = self.borders[HORZ]
1033
vertical_step = float(plot_height)/len(self.data)
1034
if series_amplitude:
1035
horizontal_step = float(plot_width)/series_amplitude
1037
horizontal_step = 0.00
1039
for i,series in enumerate(self.data):
1040
inner_step = vertical_step/(len(series) + 0.4)
1041
y0 = self.border + i*vertical_step + 0.2*inner_step
1042
for number,key in enumerate(series):
1043
linear = cairo.LinearGradient( key*horizontal_step/2, y0, key*horizontal_step/2, y0 + inner_step, )
1044
#FIXME: test if set_source_rgba accepts 3 parameters
1045
color = self.series_colors[number]
1046
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)
1047
linear.add_color_stop_rgba(1.0, *color)
1048
self.context.set_source(linear)
1050
if self.rounded_corners and key != 0:
1051
self.draw_rectangle(x0, y0, x0 + key*horizontal_step, y0 + inner_step)
1054
self.context.rectangle(x0, y0, key*horizontal_step, inner_step)
1059
class VerticalBarPlot(BarPlot):
1068
rounded_corners = False,
1069
three_dimension = False,
1074
series_colors = None):
1076
BarPlot.__init__(self, surface, data, width, height, background, border, grid, rounded_corners, three_dimension,
1077
x_labels, y_labels, x_bounds, y_bounds, series_colors)
1079
def calc_boundaries(self):
1080
if not self.bounds[HORZ]:
1081
self.bounds[HORZ] = (0, len(self.data))
1082
if not self.bounds[VERT]:
1083
max_data_value = max(max(serie) for serie in self.data)
1084
self.bounds[VERT] = (0, max_data_value)
1086
def calc_horz_extents(self):
1087
self.calc_extents(HORZ)
1089
def calc_vert_extents(self):
1090
self.calc_extents(VERT)
1091
if self.labels[VERT] and not self.labels[HORZ]:
1092
self.borders[VERT] += 10
951
1094
def render_grid(self):
952
1095
self.context.set_source_rgba(0.8, 0.8, 0.8)
953
1096
if self.labels[VERT]:
1639
rounded_corners = False,
1640
three_dimension = False,
1648
- Function to generate Bar Plot Charts.
1763
def vertical_bar_plot(name,
1770
rounded_corners = False,
1771
three_dimension = False,
1777
#TODO: Fix docstring for vertical_bar_plot
1779
- Function to generate vertical Bar Plot Charts.
1781
bar_plot(name, data, width, height, background, border, grid, rounded_corners, three_dimension,
1782
x_labels, y_labels, x_bounds, y_bounds, colors):
1786
name - Name of the desired output file, no need to input the .svg as it will be added at runtime;
1787
data - The list, list of lists or dictionary holding the data to be plotted;
1788
width, height - Dimensions of the output image;
1789
background - A 3 element tuple representing the rgb color expected for the background or a new cairo linear gradient.
1790
If left None, a gray to white gradient will be generated;
1791
border - Distance in pixels of a square border into which the graphics will be drawn;
1792
grid - Whether or not the gris is to be drawn;
1793
rounded_corners - Whether or not the bars should have rounded corners;
1794
three_dimension - Whether or not the bars should be drawn in pseudo 3D;
1795
x_labels, y_labels - lists of strings containing the horizontal and vertical labels for the axis;
1796
x_bounds, y_bounds - tuples containing the lower and upper value bounds for the data to be plotted;
1797
colors - List containing the colors expected for each of the bars.
1801
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
1802
CairoPlot.vertical_bar_plot ('bar2', data, 400, 300, border = 20, grid = True, rounded_corners = False)
1805
plot = VerticalBarPlot(name, data, width, height, background, border,
1806
grid, rounded_corners, three_dimension, x_labels, y_labels, x_bounds, y_bounds, colors)
1810
def horizontal_bar_plot(name,
1817
rounded_corners = False,
1818
three_dimension = False,
1825
#TODO: Fix docstring for horizontal_bar_plot
1827
- Function to generate Horizontal Bar Plot Charts.
1650
1829
bar_plot(name, data, width, height, background, border, grid, rounded_corners, three_dimension,
1651
1830
x_labels, y_labels, x_bounds, y_bounds, colors):