/+junk/pygooglechart-py3k

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/%2Bjunk/pygooglechart-py3k

« back to all changes in this revision

Viewing changes to pygooglechart.py

  • Committer: gak
  • Date: 2008-05-03 07:30:58 UTC
  • Revision ID: git-v1:9342edb8666dde7e843e3eb438f1f6a717aa32fc
- Really added initial unit tests
- Converted setup.py to unix file format
- warnings made when data is being clipped and when data scaling is incorrect
- max_value is now a variable
- pie and google-o-meter chart data is now on the x-axis
- More grammar work

Show diffs side-by-side

added added

removed removed

Lines of Context:
47
47
def _reset_warnings():
48
48
    """Helper function to reset all warnings. Used by the unit tests."""
49
49
    globals()['__warningregistry__'] = None
 
50
#def _warn(message):
 
51
#    warnings.warn_explicit(msg, warnings.UserWarning,
50
52
 
51
53
 
52
54
# Exception Classes
115
117
    def scale_value(cls, value, range):
116
118
        scaled = cls.int_scale_value(value, range)
117
119
        clipped = cls.clip_value(scaled)
118
 
        Data.check_clip(scaled, clipped)
119
 
        return clipped
120
 
 
121
 
    @staticmethod
122
 
    def check_clip(scaled, clipped):
123
120
        if clipped != scaled:
124
121
            warnings.warn('One or more of of your data points has been '
125
122
                'clipped because it is out of range.')
 
123
        return clipped
126
124
 
127
125
 
128
126
class SimpleData(Data):
170
168
        # map index
171
169
        scaled = cls.float_scale_value(value, range)
172
170
        clipped = cls.clip_value(scaled)
173
 
        Data.check_clip(scaled, clipped)
174
171
        return clipped
175
172
 
176
173
 
291
288
    LINEAR_STRIPES = 'ls'
292
289
 
293
290
    def __init__(self, width, height, title=None, legend=None, colours=None,
294
 
            auto_scale=True, x_range=None, y_range=None,
295
 
            colours_within_series=None):
 
291
            auto_scale=True, x_range=None, y_range=None):
296
292
        if type(self) == Chart:
297
293
            raise AbstractClassException('This is an abstract class')
298
294
        assert(isinstance(width, int))
302
298
        self.data = []
303
299
        self.set_title(title)
304
300
        self.set_legend(legend)
305
 
        self.set_legend_position(None)
306
301
        self.set_colours(colours)
307
 
        self.set_colours_within_series(colours_within_series)
308
302
 
309
303
        # Data for scaling.
310
304
        self.auto_scale = auto_scale  # Whether to automatically scale data
347
341
            url_bits.append('chtt=%s' % self.title)
348
342
        if self.legend:
349
343
            url_bits.append('chdl=%s' % '|'.join(self.legend))
350
 
        if self.legend_position:
351
 
            url_bits.append('chdlp=%s' % (self.legend_position))
352
344
        if self.colours:
353
 
            url_bits.append('chco=%s' % ','.join(self.colours))            
354
 
        if self.colours_within_series:
355
 
            url_bits.append('chco=%s' % '|'.join(self.colours_within_series))
 
345
            url_bits.append('chco=%s' % ','.join(self.colours))
356
346
        ret = self.fill_to_url()
357
347
        if ret:
358
348
            url_bits.append(ret)
359
349
        ret = self.axis_to_url()
360
350
        if ret:
361
 
            url_bits.append(ret)                    
 
351
            url_bits.append(ret)
362
352
        if self.markers:
363
 
            url_bits.append(self.markers_to_url())        
 
353
            url_bits.append(self.markers_to_url())
364
354
        if self.line_styles:
365
355
            style = []
366
356
            for index in xrange(max(self.line_styles) + 1):
384
374
            raise BadContentTypeException('Server responded with a ' \
385
375
                'content-type of %s' % opener.headers['content-type'])
386
376
 
387
 
        open(file_name, 'wb').write(opener.read())
 
377
        open(file_name, 'wb').write(urllib.urlopen(self.get_url()).read())
388
378
 
389
379
    # Simple settings
390
380
    # -------------------------------------------------------------------------
404
394
        else:
405
395
            self.legend = None
406
396
 
407
 
    def set_legend_position(self, legend_position):
408
 
        if legend_position:
409
 
            self.legend_position = urllib.quote(legend_position)
410
 
        else:    
411
 
            self.legend_position = None
412
 
 
413
397
    # Chart colours
414
398
    # -------------------------------------------------------------------------
415
399
 
423
407
                _check_colour(col)
424
408
        self.colours = colours
425
409
 
426
 
    def set_colours_within_series(self, colours):
427
 
        # colours needs to be a list, tuple or None
428
 
        assert(isinstance(colours, list) or isinstance(colours, tuple) or
429
 
            colours is None)
430
 
        # make sure the colours are in the right format
431
 
        if colours:
432
 
            for col in colours:
433
 
                _check_colour(col)
434
 
        self.colours_within_series = colours        
435
 
 
436
410
    # Background/Chart colours
437
411
    # -------------------------------------------------------------------------
438
412
 
498
472
        else:
499
473
            return ExtendedData
500
474
 
501
 
    def _filter_none(self, data):
502
 
        return [r for r in data if r is not None]
503
 
 
504
475
    def data_x_range(self):
505
476
        """Return a 2-tuple giving the minimum and maximum x-axis
506
477
        data range.
507
478
        """
508
479
        try:
509
 
            lower = min([min(self._filter_none(s))
510
 
                         for type, s in self.annotated_data()
 
480
            lower = min([min(s) for type, s in self.annotated_data()
511
481
                         if type == 'x'])
512
 
            upper = max([max(self._filter_none(s))
513
 
                         for type, s in self.annotated_data()
 
482
            upper = max([max(s) for type, s in self.annotated_data()
514
483
                         if type == 'x'])
515
484
            return (lower, upper)
516
485
        except ValueError:
521
490
        data range.
522
491
        """
523
492
        try:
524
 
            lower = min([min(self._filter_none(s))
525
 
                         for type, s in self.annotated_data()
 
493
            lower = min([min(s) for type, s in self.annotated_data()
526
494
                         if type == 'y'])
527
 
            upper = max([max(self._filter_none(s)) + 1
528
 
                         for type, s in self.annotated_data()
 
495
            upper = max([max(s) + 1 for type, s in self.annotated_data()
529
496
                         if type == 'y'])
530
497
            return (lower, upper)
531
498
        except ValueError:
551
518
        if x_range is None:
552
519
            x_range = self.data_x_range()
553
520
            if x_range and x_range[0] > 0:
554
 
                x_range = (x_range[0], x_range[1])
 
521
                x_range = (0, x_range[1])
555
522
        self.scaled_x_range = x_range
556
523
 
557
524
        # Determine the y-axis range for scaling.
558
525
        if y_range is None:
559
526
            y_range = self.data_y_range()
560
527
            if y_range and y_range[0] > 0:
561
 
                y_range = (y_range[0], y_range[1])
 
528
                y_range = (0, y_range[1])
562
529
        self.scaled_y_range = y_range
563
530
 
564
531
        scaled_data = []
569
536
                scale_range = y_range
570
537
            elif type == 'marker-size':
571
538
                scale_range = (0, max(dataset))
572
 
            scaled_dataset = []
573
 
            for v in dataset:
574
 
                if v is None:
575
 
                    scaled_dataset.append(None)
576
 
                else:
577
 
                    scaled_dataset.append(
578
 
                        data_class.scale_value(v, scale_range))
579
 
            scaled_data.append(scaled_dataset)
 
539
            scaled_data.append([data_class.scale_value(v, scale_range)
 
540
                                for v in dataset])
580
541
        return scaled_data
581
542
 
582
543
    def add_data(self, data):
665
626
    # Markers, Ranges and Fill area (chm)
666
627
    # -------------------------------------------------------------------------
667
628
 
668
 
    def markers_to_url(self):        
 
629
    def markers_to_url(self):
669
630
        return 'chm=%s' % '|'.join([','.join(a) for a in self.markers])
670
631
 
671
632
    def add_marker(self, index, point, marker_type, colour, size, priority=0):
673
634
            str(size), str(priority)))
674
635
 
675
636
    def add_horizontal_range(self, colour, start, stop):
676
 
        self.markers.append(('r', colour, '0', str(start), str(stop)))
677
 
 
678
 
    def add_data_line(self, colour, data_set, size, priority=0):
679
 
        self.markers.append(('D', colour, str(data_set), '0', str(size), str(priority)))
680
 
 
681
 
    def add_marker_text(self, string, colour, data_set, data_point, size, priority=0):
682
 
        self.markers.append((str(string), colour, str(data_set), str(data_point), str(size), str(priority)))        
 
637
        self.markers.append(('r', colour, '1', str(start), str(stop)))
683
638
 
684
639
    def add_vertical_range(self, colour, start, stop):
685
 
        self.markers.append(('R', colour, '0', str(start), str(stop)))
 
640
        self.markers.append(('R', colour, '1', str(start), str(stop)))
686
641
 
687
642
    def add_fill_range(self, colour, index_start, index_end):
688
643
        self.markers.append(('b', colour, str(index_start), str(index_end), \
963
918
        return 'cht=gom'
964
919
 
965
920
 
966
 
class QRChart(Chart):
967
 
 
968
 
    def __init__(self, *args, **kwargs):
969
 
        Chart.__init__(self, *args, **kwargs)
970
 
        self.encoding = None
971
 
        self.ec_level = None
972
 
        self.margin = None
973
 
 
974
 
    def type_to_url(self):
975
 
        return 'cht=qr'
976
 
 
977
 
    def data_to_url(self, data_class=None):
978
 
        if not self.data:
979
 
            raise NoDataGivenException()
980
 
        return 'chl=%s' % urllib.quote(self.data[0])
981
 
 
982
 
    def get_url_bits(self, data_class=None):
983
 
        url_bits = Chart.get_url_bits(self, data_class=data_class)
984
 
        if self.encoding:
985
 
            url_bits.append('choe=%s' % self.encoding)
986
 
        if self.ec_level:
987
 
            url_bits.append('chld=%s|%s' % (self.ec_level, self.margin))
988
 
        return url_bits
989
 
 
990
 
    def set_encoding(self, encoding):
991
 
        self.encoding = encoding
992
 
 
993
 
    def set_ec(self, level, margin):
994
 
        self.ec_level = level
995
 
        self.margin = margin
996
 
 
997
 
 
998
921
class ChartGrammar(object):
999
922
 
1000
923
    def __init__(self):
1018
941
 
1019
942
    def parse_data(self, data):
1020
943
        self.chart.data = data
 
944
        print self.chart.data
1021
945
 
1022
946
    @staticmethod
1023
947
    def get_possible_chart_types():