117
116
def scale_value(cls, value, range):
118
117
scaled = cls.int_scale_value(value, range)
119
118
clipped = cls.clip_value(scaled)
119
Data.check_clip(scaled, clipped)
123
def check_clip(scaled, clipped):
120
124
if clipped != scaled:
121
125
warnings.warn('One or more of of your data points has been '
122
126
'clipped because it is out of range.')
126
129
class SimpleData(Data):
288
292
LINEAR_STRIPES = 'ls'
290
294
def __init__(self, width, height, title=None, legend=None, colours=None,
291
auto_scale=True, x_range=None, y_range=None):
295
auto_scale=True, x_range=None, y_range=None,
296
colours_within_series=None):
292
297
if type(self) == Chart:
293
298
raise AbstractClassException('This is an abstract class')
294
299
assert(isinstance(width, int))
339
347
# optional arguments
341
349
url_bits.append('chtt=%s' % self.title)
350
if self.title_colour and self.title_font_size:
351
url_bits.append('chts=%s,%s' % (self.title_colour, \
352
self.title_font_size))
343
url_bits.append('chdl=%s' % '|'.join(self.legend))
354
url_bits.append('chdl=%s' % '%7c'.join(self.legend))
355
if self.legend_position:
356
url_bits.append('chdlp=%s' % (self.legend_position))
345
url_bits.append('chco=%s' % ','.join(self.colours))
358
url_bits.append('chco=%s' % ','.join(self.colours))
359
if self.colours_within_series:
360
url_bits.append('chco=%s' % '%7c'.join(self.colours_within_series))
346
361
ret = self.fill_to_url()
348
363
url_bits.append(ret)
349
364
ret = self.axis_to_url()
353
url_bits.append(self.markers_to_url())
368
url_bits.append(self.markers_to_url())
354
369
if self.line_styles:
356
371
for index in xrange(max(self.line_styles) + 1):
407
434
_check_colour(col)
408
435
self.colours = colours
437
def set_colours_within_series(self, colours):
438
# colours needs to be a list, tuple or None
439
assert(isinstance(colours, list) or isinstance(colours, tuple) or
441
# make sure the colours are in the right format
445
self.colours_within_series = colours
410
447
# Background/Chart colours
411
448
# -------------------------------------------------------------------------
473
510
return ExtendedData
512
def _filter_none(self, data):
513
return [r for r in data if r is not None]
475
515
def data_x_range(self):
476
516
"""Return a 2-tuple giving the minimum and maximum x-axis
480
lower = min([min(s) for type, s in self.annotated_data()
520
lower = min([min(self._filter_none(s))
521
for type, s in self.annotated_data()
482
upper = max([max(s) for type, s in self.annotated_data()
523
upper = max([max(self._filter_none(s))
524
for type, s in self.annotated_data()
484
526
return (lower, upper)
485
527
except ValueError:
518
562
if x_range is None:
519
563
x_range = self.data_x_range()
520
564
if x_range and x_range[0] > 0:
521
x_range = (0, x_range[1])
565
x_range = (x_range[0], x_range[1])
522
566
self.scaled_x_range = x_range
524
568
# Determine the y-axis range for scaling.
525
569
if y_range is None:
526
570
y_range = self.data_y_range()
527
571
if y_range and y_range[0] > 0:
528
y_range = (0, y_range[1])
572
y_range = (y_range[0], y_range[1])
529
573
self.scaled_y_range = y_range
615
665
url_bits.append('chxt=%s' % ','.join(available_axis))
617
url_bits.append('chxl=%s' % '|'.join(label_axis))
667
url_bits.append('chxl=%s' % '%7c'.join(label_axis))
619
url_bits.append('chxr=%s' % '|'.join(range_axis))
669
url_bits.append('chxr=%s' % '%7c'.join(range_axis))
621
url_bits.append('chxp=%s' % '|'.join(positions))
671
url_bits.append('chxp=%s' % '%7c'.join(positions))
623
url_bits.append('chxs=%s' % '|'.join(styles))
673
url_bits.append('chxs=%s' % '%7c'.join(styles))
624
674
return '&'.join(url_bits)
626
676
# Markers, Ranges and Fill area (chm)
627
677
# -------------------------------------------------------------------------
629
def markers_to_url(self):
630
return 'chm=%s' % '|'.join([','.join(a) for a in self.markers])
679
def markers_to_url(self):
680
return 'chm=%s' % '%7c'.join([','.join(a) for a in self.markers])
632
682
def add_marker(self, index, point, marker_type, colour, size, priority=0):
633
683
self.markers.append((marker_type, colour, str(index), str(point), \
634
684
str(size), str(priority)))
636
686
def add_horizontal_range(self, colour, start, stop):
637
self.markers.append(('r', colour, '1', str(start), str(stop)))
687
self.markers.append(('r', colour, '0', str(start), str(stop)))
689
def add_data_line(self, colour, data_set, size, priority=0):
690
self.markers.append(('D', colour, str(data_set), '0', str(size), \
693
def add_marker_text(self, string, colour, data_set, data_point, size, \
695
self.markers.append((str(string), colour, str(data_set), \
696
str(data_point), str(size), str(priority)))
639
698
def add_vertical_range(self, colour, start, stop):
640
self.markers.append(('R', colour, '1', str(start), str(stop)))
699
self.markers.append(('R', colour, '0', str(start), str(stop)))
642
701
def add_fill_range(self, colour, index_start, index_end):
643
702
self.markers.append(('b', colour, str(index_start), str(index_end), \
985
class QRChart(Chart):
987
def __init__(self, *args, **kwargs):
988
Chart.__init__(self, *args, **kwargs)
993
def type_to_url(self):
996
def data_to_url(self, data_class=None):
998
raise NoDataGivenException()
999
return 'chl=%s' % urllib.quote(self.data[0])
1001
def get_url_bits(self, data_class=None):
1002
url_bits = Chart.get_url_bits(self, data_class=data_class)
1004
url_bits.append('choe=%s' % self.encoding)
1006
url_bits.append('chld=%s%%7c%s' % (self.ec_level, self.margin))
1009
def set_encoding(self, encoding):
1010
self.encoding = encoding
1012
def set_ec(self, level, margin):
1013
self.ec_level = level
1014
self.margin = margin
921
1017
class ChartGrammar(object):
923
1019
def __init__(self):