Browse Source

Updated SVG to fix some bugs. Compatability is about 90% with Ruby version.

pull/8/head
SANDIA\jaraco 19 years ago
parent
commit
c5a5d445c8
  1. 47
      Plot.py
  2. 121
      __init__.py
  3. 13
      testing.py

47
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)

121
__init__.py

@ -67,54 +67,52 @@ Jason R. Coombs <jaraco@jaraco.com>
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()

13
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()
Loading…
Cancel
Save