/+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-08-23 07:31:12 UTC
  • Revision ID: git-v1:d25980565dd2640f4d700e85f0fab48a685c8ed7
Fixed bug where the module would download twice (#7) (Evan Lezar)

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,
52
50
 
53
51
 
54
52
# Exception Classes
117
115
    def scale_value(cls, value, range):
118
116
        scaled = cls.int_scale_value(value, range)
119
117
        clipped = cls.clip_value(scaled)
 
118
        Data.check_clip(scaled, clipped)
 
119
        return clipped
 
120
 
 
121
    @staticmethod
 
122
    def check_clip(scaled, clipped):
120
123
        if clipped != scaled:
121
124
            warnings.warn('One or more of of your data points has been '
122
125
                'clipped because it is out of range.')
123
 
        return clipped
124
126
 
125
127
 
126
128
class SimpleData(Data):
168
170
        # map index
169
171
        scaled = cls.float_scale_value(value, range)
170
172
        clipped = cls.clip_value(scaled)
 
173
        Data.check_clip(scaled, clipped)
171
174
        return clipped
172
175
 
173
176
 
288
291
    LINEAR_STRIPES = 'ls'
289
292
 
290
293
    def __init__(self, width, height, title=None, legend=None, colours=None,
291
 
            auto_scale=True, x_range=None, y_range=None):
 
294
            auto_scale=True, x_range=None, y_range=None,
 
295
            colours_within_series=None):
292
296
        if type(self) == Chart:
293
297
            raise AbstractClassException('This is an abstract class')
294
298
        assert(isinstance(width, int))
298
302
        self.data = []
299
303
        self.set_title(title)
300
304
        self.set_legend(legend)
 
305
        self.set_legend_position(None)
301
306
        self.set_colours(colours)
 
307
        self.set_colours_within_series(colours_within_series)
302
308
 
303
309
        # Data for scaling.
304
310
        self.auto_scale = auto_scale  # Whether to automatically scale data
341
347
            url_bits.append('chtt=%s' % self.title)
342
348
        if self.legend:
343
349
            url_bits.append('chdl=%s' % '|'.join(self.legend))
 
350
        if self.legend_position:
 
351
            url_bits.append('chdlp=%s' % (self.legend_position))
344
352
        if self.colours:
345
 
            url_bits.append('chco=%s' % ','.join(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))
346
356
        ret = self.fill_to_url()
347
357
        if ret:
348
358
            url_bits.append(ret)
349
359
        ret = self.axis_to_url()
350
360
        if ret:
351
 
            url_bits.append(ret)
 
361
            url_bits.append(ret)                    
352
362
        if self.markers:
353
 
            url_bits.append(self.markers_to_url())
 
363
            url_bits.append(self.markers_to_url())        
354
364
        if self.line_styles:
355
365
            style = []
356
366
            for index in xrange(max(self.line_styles) + 1):
374
384
            raise BadContentTypeException('Server responded with a ' \
375
385
                'content-type of %s' % opener.headers['content-type'])
376
386
 
377
 
        open(file_name, 'wb').write(urllib.urlopen(self.get_url()).read())
 
387
        open(file_name, 'wb').write(opener.read())
378
388
 
379
389
    # Simple settings
380
390
    # -------------------------------------------------------------------------
394
404
        else:
395
405
            self.legend = None
396
406
 
 
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
 
397
413
    # Chart colours
398
414
    # -------------------------------------------------------------------------
399
415
 
407
423
                _check_colour(col)
408
424
        self.colours = colours
409
425
 
 
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
 
410
436
    # Background/Chart colours
411
437
    # -------------------------------------------------------------------------
412
438
 
472
498
        else:
473
499
            return ExtendedData
474
500
 
 
501
    def _filter_none(self, data):
 
502
        return [r for r in data if r is not None]
 
503
 
475
504
    def data_x_range(self):
476
505
        """Return a 2-tuple giving the minimum and maximum x-axis
477
506
        data range.
478
507
        """
479
508
        try:
480
 
            lower = min([min(s) for type, s in self.annotated_data()
 
509
            lower = min([min(self._filter_none(s))
 
510
                         for type, s in self.annotated_data()
481
511
                         if type == 'x'])
482
 
            upper = max([max(s) for type, s in self.annotated_data()
 
512
            upper = max([max(self._filter_none(s))
 
513
                         for type, s in self.annotated_data()
483
514
                         if type == 'x'])
484
515
            return (lower, upper)
485
516
        except ValueError:
490
521
        data range.
491
522
        """
492
523
        try:
493
 
            lower = min([min(s) for type, s in self.annotated_data()
 
524
            lower = min([min(self._filter_none(s))
 
525
                         for type, s in self.annotated_data()
494
526
                         if type == 'y'])
495
 
            upper = max([max(s) + 1 for type, s in self.annotated_data()
 
527
            upper = max([max(self._filter_none(s)) + 1
 
528
                         for type, s in self.annotated_data()
496
529
                         if type == 'y'])
497
530
            return (lower, upper)
498
531
        except ValueError:
518
551
        if x_range is None:
519
552
            x_range = self.data_x_range()
520
553
            if x_range and x_range[0] > 0:
521
 
                x_range = (0, x_range[1])
 
554
                x_range = (x_range[0], x_range[1])
522
555
        self.scaled_x_range = x_range
523
556
 
524
557
        # Determine the y-axis range for scaling.
525
558
        if y_range is None:
526
559
            y_range = self.data_y_range()
527
560
            if y_range and y_range[0] > 0:
528
 
                y_range = (0, y_range[1])
 
561
                y_range = (y_range[0], y_range[1])
529
562
        self.scaled_y_range = y_range
530
563
 
531
564
        scaled_data = []
536
569
                scale_range = y_range
537
570
            elif type == 'marker-size':
538
571
                scale_range = (0, max(dataset))
539
 
            scaled_data.append([data_class.scale_value(v, scale_range)
540
 
                                for v in 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)
541
580
        return scaled_data
542
581
 
543
582
    def add_data(self, data):
626
665
    # Markers, Ranges and Fill area (chm)
627
666
    # -------------------------------------------------------------------------
628
667
 
629
 
    def markers_to_url(self):
 
668
    def markers_to_url(self):        
630
669
        return 'chm=%s' % '|'.join([','.join(a) for a in self.markers])
631
670
 
632
671
    def add_marker(self, index, point, marker_type, colour, size, priority=0):
634
673
            str(size), str(priority)))
635
674
 
636
675
    def add_horizontal_range(self, colour, start, stop):
637
 
        self.markers.append(('r', colour, '1', str(start), str(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)))        
638
683
 
639
684
    def add_vertical_range(self, colour, start, stop):
640
 
        self.markers.append(('R', colour, '1', str(start), str(stop)))
 
685
        self.markers.append(('R', colour, '0', str(start), str(stop)))
641
686
 
642
687
    def add_fill_range(self, colour, index_start, index_end):
643
688
        self.markers.append(('b', colour, str(index_start), str(index_end), \
918
963
        return 'cht=gom'
919
964
 
920
965
 
 
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
 
921
998
class ChartGrammar(object):
922
999
 
923
1000
    def __init__(self):
941
1018
 
942
1019
    def parse_data(self, data):
943
1020
        self.chart.data = data
944
 
        print self.chart.data
945
1021
 
946
1022
    @staticmethod
947
1023
    def get_possible_chart_types():