From c5a5d445c884ddf45a5ff23203ee609a1a171cbc Mon Sep 17 00:00:00 2001 From: "SANDIA\\jaraco" Date: Thu, 29 Dec 2005 01:56:44 +0000 Subject: [PATCH] Updated SVG to fix some bugs. Compatability is about 90% with Ruby version. --- Plot.py | 47 +++++++++++--------- __init__.py | 121 ++++++++++++++++++++++++++-------------------------- testing.py | 13 ++++++ 3 files changed, 100 insertions(+), 81 deletions(-) create mode 100644 testing.py diff --git a/Plot.py b/Plot.py index 0dce543..1269c76 100644 --- a/Plot.py +++ b/Plot.py @@ -1,6 +1,6 @@ #!/usr/bin/env python import SVG -from itertools import izip, count +from itertools import izip, count, chain def get_pairs( i ): i = iter( i ) @@ -96,10 +96,6 @@ class Plot( SVG.Graph ): Copyright 2004 Sean E. Russell This software is available under the Ruby license[LICENSE.txt]""" - show_data_points = True - area_fill = True - stacked = True - top_align = right_align = top_font = right_font = 1 @@ -118,11 +114,12 @@ class Plot( SVG.Graph ): area_fill = False """Show a small circle on the graph where the line goes from one point to the next.""" - show_data_points = False + show_data_points = True "Set the minimum value of the X axis" min_x_value = None "Set the minimum value of the Y axis" min_y_value = None + stacked = False @apply def scale_x_divisions(): @@ -185,7 +182,7 @@ class Plot( SVG.Graph ): def get_data_values( self, axis ): min_value, max_value, scale_division = self.data_range( axis ) - return float_range( *self.data_range( axis ) ) + return tuple( float_range( *self.data_range( axis ) ) ) def get_x_values( self ): return self.get_data_values( 'x' ) def get_y_values( self ): return self.get_data_values( 'y' ) @@ -198,26 +195,28 @@ class Plot( SVG.Graph ): def field_size( self, axis ): size = { 'x': 'width', 'y': 'height' }[axis] side = { 'x': 'right', 'y': 'top' }[axis] - values = get_data_values( axis ) + values = self.get_data_values( axis ) data_index = getattr( self, '%s_data_index' % axis ) - max_d = max( map( lambda set: max( set['data'][data_index] ), self.data ) ) + max_d = max( chain( *map( lambda set: set['data'][data_index], self.data ) ) ) dx = float( max_d - values[-1] ) / ( values[-1] - values[-2] ) graph_size = getattr( self, 'graph_%s' % size ) side_font = getattr( self, '%s_font' % side ) side_align = getattr( self, '%s_align' % side ) - result = float( graph_size ) - font_size*2*side_font / \ + result = ( float( graph_size ) - self.font_size*2*side_font ) / \ ( len( values ) + dx - side_align ) + for key,val in vars().items(): print key, val return result - def field_width( self ): return field_size( 'x' ) - def field_height( self ): return field_size( 'y' ) + def field_width( self ): return self.field_size( 'x' ) + def field_height( self ): return self.field_size( 'y' ) def draw_data( self ): self.load_transform_parameters() for line, data in izip( count(1), self.data ): x_start, y_start = self.transform_output_coordinates( - self.data['data'][self.x_data_index][0], - self.data['data'][self.y_data_index][0] ) + ( data['data'][self.x_data_index][0], + data['data'][self.y_data_index][0] ) + ) data_points = zip( *data['data'] ) graph_points = self.get_graph_points( data_points ) lpath = self.get_lpath( graph_points ) @@ -231,30 +230,36 @@ class Plot( SVG.Graph ): 'd': 'M%(x_start)d %(y_start)d %(lpath)s' % vars(), 'class': 'line%(line)d' % vars() } ) self.graph.appendChild( path ) - self.draw_data_points( self, line, data_points, graph_points ) + self.draw_data_points( line, data_points, graph_points ) del self.__transform_parameters def load_transform_parameters( self ): "Cache the parameters necessary to transform x & y coordinates" x_min, x_max, x_div = self.x_range() y_min, y_max, y_div = self.y_range() - x_step = ( float( self.graph_width ) - font_size*2 ) / \ + x_step = ( float( self.graph_width ) - self.font_size*2 ) / \ ( x_max - x_min ) - y_step = ( float( self.graph_height ) - font_size*2 ) / \ + y_step = ( float( self.graph_height ) - self.font_size*2 ) / \ ( y_max - y_min ) self.__transform_parameters = dict( vars() ) + del self.__transform_parameters['self'] def get_graph_points( self, data_points ): return map( self.transform_output_coordinates, data_points ) - def get_lpath( self, data_points ): + def get_lpath( self, points ): points = map( lambda p: "%d %d" % p, points ) return 'L' + ' '.join( points ) def transform_output_coordinates( self, (x,y) ): - vars().update( self.__transform_parameters ) + x_min = self.__transform_parameters['x_min'] + x_step = self.__transform_parameters['x_step'] + y_min = self.__transform_parameters['y_min'] + y_step = self.__transform_parameters['y_step'] + #locals().update( self.__transform_parameters ) + #vars().update( self.__transform_parameters ) x = ( x - x_min ) * x_step - y = self.graph_height() - ( y - y_min ) * y_step + y = self.graph_height - ( y - y_min ) * y_step return x,y def draw_data_points( self, line, data_points, graph_points ): @@ -270,7 +275,7 @@ class Plot( SVG.Graph ): self.graph.appendChild( circle ) if self.show_data_values: self.add_popup( gx, gy, self.format( dx, dy ) ) - self.make_datapoint_text( gx, gy-6, y ) + self.make_datapoint_text( gx, gy-6, dy ) def format( self, x, y ): return '(%0.2f, %0.2f)' % (x,y) diff --git a/__init__.py b/__init__.py index 30075a2..b81d2c2 100644 --- a/__init__.py +++ b/__init__.py @@ -67,54 +67,52 @@ Jason R. Coombs Copyright 2005 Sandia National Laboratories """ - defaults = { - 'width': 500, - 'height': 300, - 'show_x_guidelines': False, - 'show_y_guidelines': True, - 'show_data_values': True, - 'min_scale_value': 0, - 'show_x_labels': True, - 'stagger_x_labels': False, - 'rotate_x_labels': False, - 'step_x_labels': 1, - 'step_include_first_x_label': True, - 'show_y_labels': True, - 'rotate_y_labels': False, - 'stagger_y_labels': False, - 'scale_integers': False, - 'show_x_title': False, - 'x_title': 'X Field names', - 'show_y_title': False, - 'y_title_text_direction': 'bt', - 'y_title': 'Y Scale', - 'show_graph_title': False, - 'graph_title': 'Graph Title', - 'show_graph_subtitle': False, - 'graph_subtitle': 'Graph Subtitle', - 'key': True, - 'key_position': 'right', # 'bottom' or 'right', - - 'font_size': 12, - 'title_font_size': 16, - 'subtitle_font_size': 14, - 'x_label_font_size': 12, - 'x_title_font_size': 14, - 'y_label_font_size': 12, - 'y_title_font_size': 14, - 'key_font_size': 10, - - 'no_css': False, - 'add_popups': False, - } - #__slots__ = tuple( defaults ) + ( '__dict__', '__weakref__' ) + width= 500 + height= 300 + show_x_guidelines= False + show_y_guidelines= True + show_data_values= True + min_scale_value= 0 + show_x_labels= True + stagger_x_labels= False + rotate_x_labels= False + step_x_labels= 1 + step_include_first_x_label= True + show_y_labels= True + rotate_y_labels= False + stagger_y_labels= False + step_include_first_y_label= True + step_y_labels= 1 + scale_integers= False + show_x_title= False + x_title= 'X Field names' + show_y_title= False + y_title_text_direction= 'bt' + y_title= 'Y Scale' + show_graph_title= False + graph_title= 'Graph Title' + show_graph_subtitle= False + graph_subtitle= 'Graph Subtitle' + key= True + key_position= 'right' # 'bottom' or 'right', + + font_size= 12 + title_font_size= 16 + subtitle_font_size= 14 + x_label_font_size= 12 + x_title_font_size= 14 + y_label_font_size= 12 + y_title_font_size= 14 + key_font_size= 10 + + no_css= False + add_popups= False + + top_align = top_font = right_align = right_font = 0 def __init__( self, config ): """Initialize the graph object with the graph settings. You won't instantiate this class directly; see the subclass for options.""" - self.top_align = self.top_font = self.right_align = self.right_font = 0 - self.load_config() - self.load_config( config ) self.clear_data() def load_config( self, config = None ): @@ -172,12 +170,12 @@ Copyright 2005 Sandia National Laboratories self.draw_titles() self.draw_legend() self.draw_data() - self.graph.add_element( self.foreground ) + self.graph.appendChild( self.foreground ) self.style() data = self._doc.toprettyxml() - if self.compress: + if hasattr( self, 'compress' ) and self.compress: if __have_zlib: data = zlib.compress( data ) else: @@ -231,7 +229,7 @@ Copyright 2005 Sandia National Laboratories def add_popup( self, x, y, label ): "Adds pop-up point information to a graph." txt_width = len( label ) * self.font_size * 0.6 + 10 - tx = x + [5,-5](x+txt_width > width) + tx = x + [5,-5][int(x+txt_width > self.width)] t = self._create_element( 'text' ) anchor = ['start', 'end'][x+txt_width > self.width] style = 'fill: #000; text-anchor: %s;' % anchor @@ -329,10 +327,10 @@ Copyright 2005 Sandia National Laboratories start = int( not self.step_include_first_x_label ) labels = islice( labels, start, None, self.step_x_labels ) map( self.draw_x_label, labels ) - self.draw_x_guidelines( self.field_width, count ) + self.draw_x_guidelines( self.field_width(), count ) def draw_x_label( self, label ): - label_width = self.field_width + label_width = self.field_width() index, label = label text = self._create_element( 'text', { 'class': 'xAxisLabels' } ) text.appendChild( self._doc.createTextNode( label ) ) @@ -369,7 +367,7 @@ Copyright 2005 Sandia National Laboratories return 0 def get_field_width( self ): - return float( self.graph_width - font_size*2*right_font ) / \ + return float( self.graph_width - self.font_size*2*self.right_font ) / \ ( len( self.get_x_labels() ) - self.right_align ) field_width = property( get_field_width ) @@ -386,18 +384,19 @@ Copyright 2005 Sandia National Laboratories labels = enumerate( iter( labels ) ) start = int( not self.step_include_first_y_label ) - labels = itertools.islice( labels, start, None, self.step_y_labels ) + labels = islice( labels, start, None, self.step_y_labels ) map( self.draw_y_label, labels ) - self.draw_y_guidelines( self.field_height, count ) + self.draw_y_guidelines( self.field_height(), count ) def get_y_offset( self ): - result = self.graph_height + self.y_label_offset( self.label_height ) + #result = self.graph_height + self.y_label_offset( label_height ) + result = self.graph_height + self.y_label_offset( self.field_height() ) if self.rotate_y_labels: result += self.font_size/1.2 return result y_offset = property( get_y_offset ) def draw_y_label( self, label ): - label_height = self.field_height + label_height = self.field_height() index, label = label text = self._create_element( 'text', { 'class': 'yAxisLabels' } ) text.appendChild( self._doc.createTextNode( label ) ) @@ -434,7 +433,7 @@ Copyright 2005 Sandia National Laboratories start = label_height*count stop = self.graph_height path = self._create_element( 'path', { - 'd': 'M %(start)s h%(stop)s' % vars(), + 'd': 'M %(start)s 0 v%(stop)s' % vars(), 'class': 'guideLines' } ) self.graph.appendChild( path ) @@ -474,7 +473,7 @@ Copyright 2005 Sandia National Laboratories def draw_legend( self ): if self.key: group = self._create_element( 'g' ) - root.appendChild( group ) + self.root.appendChild( group ) for key_count, key_name in enumerate( self.keys() ): y_offset = ( self.KEY_BOX_SIZE * key_count ) + (key_count * 5 ) @@ -483,10 +482,10 @@ Copyright 2005 Sandia National Laboratories 'y': str( y_offset ), 'width': str( self.KEY_BOX_SIZE ), 'height': str( self.KEY_BOX_SIZE ), - 'class': 'key%s' % key_count + 1, + 'class': 'key%s' % (key_count + 1), } ) group.appendChild( rect ) - text = group.self._create_element( 'text', { + text = self._create_element( 'text', { 'x': str( self.KEY_BOX_SIZE + 5 ), 'y': str( y_offset + self.KEY_BOX_SIZE ), 'class': 'keyText' } ) @@ -494,8 +493,8 @@ Copyright 2005 Sandia National Laboratories group.appendChild( text ) if self.key_position == 'right': - x_offset = self.graph_width, self.border_left + 10 - y_offset = border_top + 20 + x_offset = self.graph_width + self.border_left + 10 + y_offset = self.border_top + 20 if self.key_position == 'bottom': raise NotImplementedError group.setAttribute( 'transform', 'translate(%(x_offset)d %(y_offset)d)' % vars() ) @@ -557,6 +556,7 @@ Copyright 2005 Sandia National Laboratories defs = self._create_element( 'defs' ) self.add_defs( defs ) + self.root.appendChild( defs ) if not hasattr( self, 'style_sheet' ) and not self.no_css: self.root.appendChild( self._doc.createComment( ' include default stylesheet if none specified ' ) ) style = self._create_element( 'style', { 'type': 'text/css' } ) @@ -571,6 +571,7 @@ Copyright 2005 Sandia National Laboratories 'x': '0', 'y': '0', 'class': 'svgBackground' } ) + self.root.appendChild( rect ) def calculate_graph_dimensions( self ): self.calculate_left_margin() diff --git a/testing.py b/testing.py new file mode 100644 index 0000000..f8e4466 --- /dev/null +++ b/testing.py @@ -0,0 +1,13 @@ +import sys, os +sys.path.insert( 0, 'c:\documents and settings\jaraco\my documents\projects\jaraco' ) +import SVG +from SVG import Plot +reload( SVG ) +reload( Plot ) +g = Plot.Plot({}) +data1 = [ 1, 25, 2, 30, 3, 45 ] +g.add_data( { 'data': data1, 'title': 'foo' } ) +res = g.burn() +f = open( r'c:\sample.svg', 'w' ) +f.write( res ) +f.close()