238
247
if min(series) < min_data_value:
239
248
min_data_value = min(series)
240
249
self.bounds[VERT] = (min_data_value, max_data_value)
251
def calc_labels(self):
252
if not self.labels[HORZ]:
253
self.labels[HORZ] = [str(i) for i in range(self.bounds[HORZ][0], self.bounds[HORZ][1])]
254
if not self.labels[VERT]:
255
amplitude = self.bounds[VERT][1] - self.bounds[VERT][0]
256
if amplitude % 10: #if vertical labels need floating points
257
self.labels[VERT] = ["%.2lf" % (float(self.bounds[VERT][0] + (amplitude * i / 10.0))) for i in range(11) ]
259
self.labels[VERT] = [str(int(self.bounds[VERT][0] + (amplitude * i / 10.0))) for i in range(11) ]
242
261
def calc_extents(self, direction):
243
262
self.context.set_font_size(self.font_size * 0.8)
244
self.max_value[direction] = 0
245
if self.labels[direction]:
246
self.max_value[direction] = max(self.context.text_extents(item)[2] for item in self.labels[direction])
247
self.borders[other_direction(direction)] = self.max_value[direction] + self.border + 20
249
self.max_value[direction] = self.context.text_extents(str(self.bounds[direction][1]))[2]
250
self.borders[other_direction(direction)] = self.max_value[direction] + self.border + 20
263
self.max_value[direction] = max(self.context.text_extents(item)[2] for item in self.labels[direction])
264
self.borders[other_direction(direction)] = self.max_value[direction] + self.border + 20
265
#if self.titles[direction] :
266
# self.borders[other_direction(direction)] += self.context.text_extents(self.titles[direction])[3] #subtract axis title height
252
268
def calc_all_extents(self):
253
269
self.calc_extents(HORZ)
256
272
self.plot_height = self.height - 2 * self.borders[VERT]
257
273
self.plot_top = self.height - self.borders[VERT]
258
274
series_amplitude = self.bounds[VERT][1] - self.bounds[VERT][0]
259
self.vertical_step = float (self.plot_height) / series_amplitude
276
self.vertical_step = float (self.plot_height) / series_amplitude
278
self.vertical_step = 0.00
261
280
self.plot_width = self.width - 2* self.borders[HORZ]
262
281
largest_series_length = max(len(x) for x in self.data)
263
self.horizontal_step = float (self.plot_width) / largest_series_length
265
def render_axis(self):
267
h_border = self.borders[HORZ]
268
v_border = self.borders[VERT]
269
cr.set_source_rgb(*self.line_color)
271
cr.move_to(h_border, self.height - v_border)
272
cr.line_to(h_border, v_border)
275
cr.move_to(h_border, self.height - v_border)
276
cr.line_to(self.width - h_border, self.height - v_border)
279
def render_labels(self):
280
self.context.set_font_size(self.font_size * 0.8)
282
self.render_horz_labels()
283
self.render_vert_labels()
285
def render_horz_labels(self):
287
labels = self.labels[HORZ]
289
labels = [str(i) for i in range(self.bounds[HORZ][0], self.bounds[HORZ][1])]
290
border = self.borders[HORZ]
292
step = float(self.width - 2 * border) / len(labels)
295
cr.set_source_rgb(*self.label_color)
296
width = cr.text_extents(item)[2]
297
cr.move_to(x, self.height - self.borders[VERT] + 5)
298
cr.rotate(self.h_label_angle)
300
cr.rotate(-self.h_label_angle)
301
#FIXME: render grid in a separate method
302
if self.grid and x != border:
303
cr.set_source_rgb(*self.grid_color)
304
cr.move_to(x, self.height - self.borders[VERT])
305
cr.line_to(x, self.borders[VERT])
309
def render_vert_labels(self):
311
labels = self.labels[VERT]
313
amplitude = self.bounds[VERT][1] - self.bounds[VERT][0]
314
#if vertical labels need floating points
316
labels = ["%.2lf" % (float(self.bounds[VERT][0] + (amplitude * i / 10.0))) for i in range(11) ]
318
labels = [str(int(self.bounds[VERT][0] + (amplitude * i / 10.0))) for i in range(11) ]
319
border = self.borders[VERT]
321
step = (self.height - 2 * border)/( len(labels) - 1 )
322
y = self.height - border
324
cr.set_source_rgb(*self.label_color)
325
width = cr.text_extents(item)[2]
326
cr.move_to(self.borders[HORZ] - width - 5,y)
328
#FIXME: render grid in a separate method
329
if self.grid and y != self.height - border:
330
cr.set_source_rgb(*self.grid_color)
331
cr.move_to(self.borders[HORZ], y)
332
cr.line_to(self.width - self.borders[HORZ], y)
336
#TODO move titles to a new function
338
cr.set_source_rgb(*self.label_color)
339
cr.set_font_size(self.font_size)
340
cr.move_to(5,y + step - self.font_size)
341
cr.show_text(self.v_title)
282
self.horizontal_step = float (self.plot_width) / ( largest_series_length - 1 )
343
284
def render(self):
344
285
self.calc_all_extents()
356
300
if self.series_legend and self.series_labels:
357
301
self.render_legend()
303
def render_axis(self):
305
cr.set_source_rgb(*self.line_color)
306
cr.move_to(self.borders[HORZ], self.height - self.borders[VERT])
307
cr.line_to(self.borders[HORZ], self.borders[VERT])
310
cr.move_to(self.borders[HORZ], self.height - self.borders[VERT])
311
cr.line_to(self.width - self.borders[HORZ], self.height - self.borders[VERT])
314
cr.set_source_rgb(*self.label_color)
315
self.context.set_font_size( 1.2 * self.font_size )
316
if self.titles[HORZ]:
317
title_width,title_height = cr.text_extents(self.titles[HORZ])[2:4]
318
cr.move_to( self.width/2 - title_width/2, self.borders[VERT] - title_height/2 )
319
cr.show_text( self.titles[HORZ] )
321
if self.titles[VERT]:
322
title_width,title_height = cr.text_extents(self.titles[VERT])[2:4]
323
cr.move_to( self.width - self.borders[HORZ] + title_height/2, self.height/2 - title_width/2)
324
cr.rotate( math.pi/2 )
325
cr.show_text( self.titles[VERT] )
326
cr.rotate( -math.pi/2 )
328
def render_grid(self):
330
horizontal_step = float( self.plot_height ) / ( len( self.labels[VERT] ) - 1 )
331
vertical_step = float( self.plot_width ) / ( len( self.labels[HORZ] ) - 1 )
333
x = self.borders[HORZ] + vertical_step
334
y = self.plot_top - horizontal_step
336
for label in self.labels[HORZ][:-1]:
337
cr.set_source_rgb(*self.grid_color)
338
cr.move_to(x, self.height - self.borders[VERT])
339
cr.line_to(x, self.borders[VERT])
342
for label in self.labels[VERT][:-1]:
343
cr.set_source_rgb(*self.grid_color)
344
cr.move_to(self.borders[HORZ], y)
345
cr.line_to(self.width - self.borders[HORZ], y)
349
def render_labels(self):
350
self.context.set_font_size(self.font_size * 0.8)
351
self.render_horz_labels()
352
self.render_vert_labels()
354
def render_horz_labels(self):
356
step = float( self.plot_width ) / ( len( self.labels[HORZ] ) - 1 )
357
x = self.borders[HORZ]
358
for item in self.labels[HORZ]:
359
cr.set_source_rgb(*self.label_color)
360
width = cr.text_extents(item)[2]
361
cr.move_to(x, self.height - self.borders[VERT] + 5)
362
cr.rotate(self.h_label_angle)
364
cr.rotate(-self.h_label_angle)
367
def render_vert_labels(self):
369
step = ( self.plot_height ) / ( len( self.labels[VERT] ) - 1 )
371
for item in self.labels[VERT]:
372
cr.set_source_rgb(*self.label_color)
373
width = cr.text_extents(item)[2]
374
cr.move_to(self.borders[HORZ] - width - 5,y)
359
378
def render_legend(self):
360
379
cr = self.context
361
380
cr.set_font_size(self.font_size)
468
486
DotLinePlot.__init__(self, surface, data, width, height, background, border,
469
487
axis, dash, dots, grid, series_legend, h_labels, v_labels,
470
h_bounds, v_bounds, v_title, series_colors)
488
h_bounds, v_bounds, h_title, v_title, series_colors)
472
490
if hasattr(radius, "__delitem__") == 2:
473
491
self.bounds[NORM] = radius
537
555
if not self.bounds[NORM]:
538
556
self.bounds[NORM] = (min_data_value[NORM], max_data_value[NORM])
558
def calc_labels(self):
559
if not self.labels[HORZ]:
560
amplitude = self.bounds[HORZ][1] - self.bounds[HORZ][0]
561
if amplitude % 10: #if vertical labels need floating points
562
self.labels[HORZ] = ["%.2lf" % (float(self.bounds[HORZ][0] + (amplitude * i / 10.0))) for i in range(11) ]
564
self.labels[HORZ] = [str(int(self.bounds[HORZ][0] + (amplitude * i / 10.0))) for i in range(11) ]
565
DotLinePlot.calc_labels(self)
540
567
def calc_all_extents(self):
541
568
self.calc_extents(HORZ)
542
569
self.calc_extents(VERT)
544
571
self.plot_height = self.height - 2 * self.borders[VERT]
545
572
self.plot_width = self.width - 2* self.borders[HORZ]
574
self.plot_top = self.height - self.borders[VERT]
547
576
series_amplitude = [0,0,0]
548
577
series_amplitude[HORZ] = self.bounds[HORZ][1] - self.bounds[HORZ][0]
549
578
series_amplitude[VERT] = self.bounds[VERT][1] - self.bounds[VERT][0]
550
579
if self.variable_radius :
551
580
series_amplitude[NORM] = self.bounds[NORM][1] - self.bounds[NORM][0]
553
self.vertical_step = float (self.plot_height) / series_amplitude[VERT]
554
self.horizontal_step = float (self.plot_width) / series_amplitude[HORZ]
555
if self.variable_radius:
556
self.z_step = float (self.bounds[NORM][1]) / series_amplitude[NORM]
557
if self.circle_colors:
558
r = float( self.circle_colors[1][0] - self.circle_colors[0][0] ) / series_amplitude[NORM]
559
g = float( self.circle_colors[1][1] - self.circle_colors[0][1] ) / series_amplitude[NORM]
560
b = float( self.circle_colors[1][2] - self.circle_colors[0][2] ) / series_amplitude[NORM]
561
a = float( self.circle_colors[1][3] - self.circle_colors[0][3] ) / series_amplitude[NORM]
562
self.circle_color_step = ( r, g, b, a )
582
if series_amplitude[HORZ]:
583
self.horizontal_step = float (self.plot_width) / series_amplitude[HORZ]
585
self.horizontal_step = 0.00
587
if series_amplitude[VERT]:
588
self.vertical_step = float (self.plot_height) / series_amplitude[VERT]
590
self.vertical_step = 0.00
592
if series_amplitude[NORM]:
593
if self.variable_radius:
594
self.z_step = float (self.bounds[NORM][1]) / series_amplitude[NORM]
595
if self.circle_colors:
596
r = float( self.circle_colors[1][0] - self.circle_colors[0][0] ) / series_amplitude[NORM]
597
g = float( self.circle_colors[1][1] - self.circle_colors[0][1] ) / series_amplitude[NORM]
598
b = float( self.circle_colors[1][2] - self.circle_colors[0][2] ) / series_amplitude[NORM]
599
a = float( self.circle_colors[1][3] - self.circle_colors[0][3] ) / series_amplitude[NORM]
600
self.circle_color_step = ( r, g, b, a )
603
self.circle_color_step = ( 0.0, 0.0, 0.0, 0.0 )
564
605
def get_circle_color(self, value):
565
606
r = self.circle_colors[0][0] + value*self.circle_color_step[0]
649
691
DotLinePlot.__init__(self, surface, data, width, height, background, border,
650
692
axis, False, dots, grid, False, h_labels, v_labels,
651
h_bounds, v_bounds, None,series_colors)
693
h_bounds, v_bounds, h_title, v_title, series_colors)
653
695
def load_series_from_function( self, function, h_bounds ):
696
#TODO: Add the possibility for the user to define multiple functions with different discretization parameters
654
698
#This function converts a function, a list of functions or a dictionary
655
699
#of functions into its corresponding array of data
660
703
#if no bounds are provided
692
735
return data, h_bounds
694
def render_horz_labels(self):
696
labels = self.labels[HORZ]
737
def calc_labels(self):
738
if not self.labels[HORZ]:
739
self.labels[HORZ] = []
699
740
i = self.bounds[HORZ][0]
700
while i<self.bounds[HORZ][1]:
701
labels.append(str(i*self.step))
741
while i<=self.bounds[HORZ][1]:
742
self.labels[HORZ].append(str(i))
702
743
i += float(self.bounds[HORZ][1] - self.bounds[HORZ][0])/10
703
border = self.borders[HORZ]
705
step = (self.width - 2 * border) / len(labels)
708
cr.set_source_rgb(*self.label_color)
709
width = cr.text_extents(item)[2]
710
cr.move_to(x, self.height - self.borders[VERT] + 10)
711
cr.rotate(self.h_label_angle)
713
cr.rotate(-self.h_label_angle)
714
#FIXME: render grid in a separate method
715
if self.grid and x != border:
716
cr.set_source_rgb(*self.grid_color)
717
cr.move_to(x, self.height - self.borders[VERT])
718
cr.line_to(x, self.borders[VERT])
744
DotLinePlot.calc_labels(self)
722
746
def render_plot(self):
723
747
if not self.discrete:
724
748
DotLinePlot.render_plot(self)
726
#render_series_labels
727
largest_series_length = max(len(x) for x in self.data)
728
#FIXME: plot_width and plot_height should be object properties and be re-used.
729
plot_width = self.width - 2* self.borders[HORZ]
730
plot_height = self.height - 2 * self.borders[VERT]
731
plot_top = self.height - self.borders[VERT]
733
series_amplitude = self.bounds[VERT][1] - self.bounds[VERT][0]
735
horizontal_step = float (plot_width) / largest_series_length
736
vertical_step = float (plot_height) / series_amplitude
738
751
cr = self.context
739
752
for number, series in enumerate (self.data):
740
753
cr.set_source_rgb(*self.series_colors[number])
741
754
x = self.borders[HORZ]
742
755
for value in series:
743
cr.move_to(x, plot_top - int((value - self.bounds[VERT][0]) * vertical_step))
744
cr.line_to(x, plot_top)
756
cr.move_to(x, self.plot_top - int((value - self.bounds[VERT][0]) * self.vertical_step))
757
cr.line_to(x, self.plot_top)
745
758
cr.set_line_width(self.series_widths[number])
749
cr.arc(x, plot_top - int((value - self.bounds[VERT][0]) * vertical_step), 3, 0, 2.1 * math.pi)
762
cr.arc(x, self.plot_top - int((value - self.bounds[VERT][0]) * self.vertical_step), 3, 0, 2.1 * math.pi)
765
x += self.horizontal_step
757
767
class BarPlot(Plot):
758
768
def __init__(self,
1333
1347
plot = ScatterPlot( name, data, width, height, background, border,
1334
1348
axis, dash, discrete, dots, grid, series_legend, h_labels, v_labels,
1335
h_bounds, v_bounds, v_title, series_colors, circle_colors, radius )
1349
h_bounds, v_bounds, h_title, v_title, series_colors, circle_colors, radius )
1341
1353
def dot_line_plot(name,
1390
1404
plot = DotLinePlot( name, data, width, height, background, border,
1391
1405
axis, dash, dots, grid, series_legend, h_labels, v_labels,
1392
h_bounds, v_bounds, v_title, series_colors )
1406
h_bounds, v_bounds, h_title, v_title, series_colors )
1440
1456
plot = FunctionPlot( name, data, width, height, background, border,
1441
1457
axis, discrete, dots, grid, h_labels, v_labels,
1442
h_bounds, v_bounds, series_colors, step )
1458
h_bounds, v_bounds, h_title, v_title, series_colors, step )
1447
1462
def pie_plot( name, data, width, height, background = None, gradient = False, shadow = False, colors = None ):