Pastebin launched a little side project called HostCabi.net, check it out ;-)Don't like ads? PRO users don't see any ads ;-)
Guest

nicechart.py

By: a guest on Oct 2nd, 2012  |  syntax: Python  |  size: 25.95 KB  |  hits: 50  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
This paste has a previous version, view the difference. Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #!/usr/bin/env python
  2. # -*- coding: cp1252 -*-
  3.  
  4. #  nicechart.py
  5. #
  6. #  Copyright 2011
  7. #  
  8. #  Christoph Sterz
  9. #  Florian Weber
  10. #  
  11. #  This program is free software; you can redistribute it and/or modify
  12. #  it under the terms of the GNU General Public License as published by
  13. #  the Free Software Foundation; either version 3 of the License, or
  14. #  (at your option) any later version.
  15. #  
  16. #  This program is distributed in the hope that it will be useful,
  17. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19. #  GNU General Public License for more details.
  20. #  
  21. #  You should have received a copy of the GNU General Public License
  22. #  along with this program; if not, write to the Free Software
  23. #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  24. #  MA 02110-1301, USA.
  25. #  
  26. #  
  27.  
  28.  
  29.  
  30.  
  31. # These two lines are only needed if you don't put the script directly into
  32. # the installation directory (and only works for linux :()
  33. #import sys
  34. #sys.path.append('/usr/share/inkscape/extensions')
  35.  
  36. # We will use the inkex module with the predefined Effect base class.
  37. import inkex
  38. # The simplestyle module provides functions for style parsing.
  39. from simplestyle import *
  40. import math, re, nicechart_colors as nc_colors
  41. import sys # for debugging
  42.  
  43. csv_file_name=""
  44. logf = open('C:\temp\log.txt', 'w')
  45.  
  46. class NiceChart(inkex.Effect):
  47.         """ Create a bar, pie, or stacked chart from list of named data """
  48.        
  49.         def __init__(self):
  50.                 # Call the base class constructor.
  51.                 inkex.Effect.__init__(self)
  52.                
  53.                 # Define string option "--what" with "-w" shortcut and default chart values.
  54.                 self.OptionParser.add_option('-w', '--what', action = 'store',
  55.                           type = 'string', dest = 'what', default = '22,11,67',
  56.                           help = 'Chart Values')
  57.                
  58.                 # Define string option "--type" with "-t" shortcut.
  59.                 self.OptionParser.add_option("-t", "--type", action="store",
  60.                           type="string", dest="type", default='',
  61.                           help="Chart Type")
  62.                
  63.                 # Define bool option "--blur" with "-b" shortcut.
  64.                 self.OptionParser.add_option("-b", "--blur", action="store",
  65.                           type="inkbool", dest="blur", default='True',
  66.                           help="Blur Type")
  67.                
  68.                 # Define string option "--file" with "-f" shortcut.
  69.                 self.OptionParser.add_option("-f", "--filename", action="store",
  70.                           type="string", dest="filename", default='',
  71.                           help="Name of File")
  72.                
  73.                 # Define string option "--input_type" with "-i" shortcut.
  74.                 self.OptionParser.add_option("-i", "--input_type", action="store",
  75.                           type="string", dest="input_type", default='file',
  76.                           help="Chart Type")
  77.                
  78.                 # Define string option "--delimiter" with "-d" shortcut.
  79.                 self.OptionParser.add_option("-d", "--delimiter", action="store",
  80.                           type="string", dest="csv_delimiter", default=';',
  81.                           help="delimiter")
  82.                          
  83.                 # Define string option "--colors" with "-c" shortcut.
  84.                 self.OptionParser.add_option("-c", "--colors", action="store",
  85.                           type="string", dest="colors", default='default',
  86.                           help="color-scheme")
  87.                
  88.                 self.OptionParser.add_option("", "--reverse_colors", action="store",
  89.                           type="inkbool", dest="reverse_colors", default='False',
  90.                           help="reverse color-scheme")
  91.                
  92.                 self.OptionParser.add_option("-k", "--col_key", action="store",
  93.                           type="int", dest="col_key", default='0',
  94.                           help="column that contains the keys")
  95.                
  96.                
  97.                 self.OptionParser.add_option("-v", "--col_val", action="store",
  98.                           type="int", dest="col_val", default='1',
  99.                           help="column that contains the values")
  100.                          
  101.                 self.OptionParser.add_option("-r", "--rotate", action="store",
  102.                           type="inkbool", dest="rotate", default='False',
  103.                           help="Draw barchart horizontally")
  104.                        
  105.                 self.OptionParser.add_option("-W", "--bar-width", action="store",
  106.                         type="int", dest="bar_width", default='10',
  107.                         help="width of bars")
  108.                
  109.                 self.OptionParser.add_option("-p", "--pie-radius", action="store",
  110.                         type="int", dest="pie_radius", default='100',
  111.                         help="radius of pie-charts")
  112.  
  113.                 self.OptionParser.add_option("-q", "--pie-offset", action="store",
  114.                         type="int", dest="pie_offset", default='0',
  115.                         help="Rotation offset of pie-charts")
  116.                        
  117.                 self.OptionParser.add_option("-H", "--bar-height", action="store",
  118.                         type="int", dest="bar_height", default='100',
  119.                         help="height of bars")
  120.                        
  121.                 self.OptionParser.add_option("-O", "--bar-offset", action="store",
  122.                         type="int", dest="bar_offset", default='5',
  123.                         help="distance between bars")
  124.  
  125.                 self.OptionParser.add_option("-l", "--labels", action="store",
  126.                           type="inkbool", dest="labels", default='False',
  127.                           help="Initial line is a description")
  128.                
  129.                 self.OptionParser.add_option("", "--stroke-width", action="store",
  130.                         type="int", dest="stroke_width", default='2')
  131.                        
  132.                 self.OptionParser.add_option("-o", "--text-offset", action="store",
  133.                         type="int", dest="text_offset", default='5',
  134.                         help="distance between bar and descriptions")
  135.                        
  136.                 self.OptionParser.add_option("-F", "--font", action="store",
  137.                         type="string", dest="font", default='sans-serif',
  138.                         help="font of description")
  139.                        
  140.                 self.OptionParser.add_option("-S", "--font-size", action="store",
  141.                         type="int", dest="font_size", default='10',
  142.                         help="font size of description")
  143.                
  144.                 self.OptionParser.add_option("-C", "--font-color", action="store",
  145.                         type="string", dest="font_color", default='black',
  146.                         help="font color of description")
  147.                 #Dummy:
  148.                 self.OptionParser.add_option("","--input_sections")
  149.  
  150.  
  151.         def create_layer(self, title):
  152.                 """ Create a new (top level) named layer to put charts into """
  153.                 svg = self.document.getroot()
  154.                 layer = inkex.etree.SubElement(svg, 'g')
  155.                 layer.set(inkex.addNS('label', 'inkscape'), 'Chart-Layer: %s' % (title))
  156.                 layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
  157.                 return layer
  158.        
  159.         def create_blur_filter(self):
  160.                 """ Create a single reuseable filter for blur effect
  161.                    - gaussian blur
  162.                """
  163.                 xoffset = str(-0.5) # get from options
  164.                 yoffset = str(-0.5)
  165.                 blur_factor = str(1.1)
  166.                 # Get defs of Document
  167.                 defs = self.xpathSingle('/svg:svg//svg:defs')
  168.                 if defs == None:
  169.                         defs = inkex.etree.SubElement(self.document.getroot(),inkex.addNS('defs','svg'))
  170.                        
  171.                 # Create new Filter
  172.                 filt = inkex.etree.SubElement(defs,inkex.addNS('filter','svg'))
  173.                 filtId = self.uniqueId('filter')
  174.                 self.filtId = 'filter:url(#%s);' % filtId
  175.                 for k, v in [ ('id', filtId), ('height', "3"), ('width', "3"),
  176.                               ('x', xoffset), ('y', yoffset) ]:
  177.                         filt.set(k, v)
  178.                
  179.                 # Append Gaussian Blur to that Filter
  180.                 fe = inkex.etree.SubElement(filt,inkex.addNS('feGaussianBlur','svg'))
  181.                 fe.set('stdDeviation', blur_factor)
  182.                 return filtId
  183.  
  184.         def get_colors(self):
  185.                 """ get colors directly from UI, or use premade named sets
  186.                    - ideally use a dropdown to select premade sets.
  187.                    - ideally sample gradients to get color sets
  188.                """
  189.                 colors=self.options.colors # make copy so reverse operation is not persistent
  190.                 if(colors[0].isalpha()):
  191.                         colors=nc_colors.get_color_scheme(colors)
  192.                 else:
  193.                         colors=re.findall("(#[0-9a-fA-F]{6})",colors)
  194.                         #to be sure we create a fallback:
  195.                         if(len(colors)==0):
  196.                                 colors=nc_colors.get_color_scheme()
  197.                 # reverse ?
  198.                 colors = [c for c in colors] # safe copy
  199.                 if(self.options.reverse_colors):
  200.                         colors.reverse()
  201.                 return (colors, len(colors))
  202.  
  203.  
  204.         def make_chart(self, charttype, keys, values, title, blur_filter, layer=False ):
  205.                 logf.write("Create Chart: %s %s\n" % (charttype, title))
  206.                 logf.write(" layer : %s\n" % (layer))
  207.                 logf.write(" keys,values : %s %s\n" % (keys, values))
  208.                 #
  209.                 keys_present=False
  210.                 if keys: keys_present=True
  211.                
  212.                 # Get access to main SVG document element and get its dimensions.
  213.                 svg = self.document.getroot()
  214.                
  215.                 # Get the page attibutes for positioning
  216.                 width  = inkex.unittouu(svg.get('width'))
  217.                 height = inkex.unittouu(svg.attrib['height'])
  218.                
  219.                 if layer == False:
  220.                         # no layer supplied so make one (means its a direct single chart)
  221.                         layer = self.create_layer(title)
  222.                 # make group to hold this chart
  223.                 group = inkex.etree.SubElement(layer, 'g', {inkex.addNS('label','inkscape'):title })
  224.                
  225.                 # Get Colors
  226.                 Colors, color_count = self.get_colors()
  227.                 logf.write(" Colors:  %s\n" % Colors)
  228.                 #
  229.                 bar_height=self.options.bar_height
  230.                 bar_width=self.options.bar_width
  231.                 bar_offset=self.options.bar_offset
  232.                 #offset of the description in stacked-bar-charts:
  233.                 text_offset=self.options.text_offset
  234.                
  235.                 #get font
  236.                 font=self.options.font
  237.                 font_size=self.options.font_size
  238.                 font_color=self.options.font_color
  239.  
  240.                 #get bar chart orientation
  241.                 rotate = self.options.rotate
  242.                
  243.                 pie_radius = self.options.pie_radius
  244.                 pie_offset = self.options.pie_offset * 2*math.pi/360 # degrees to radians
  245.                 stroke_width = self.options.stroke_width
  246.  
  247.  
  248.                 if charttype=="bar" :
  249.                 #########
  250.                 ###BAR###
  251.                 #########
  252.                        
  253.                         #iterate all values, use offset to draw the bars in different places
  254.                         offset=0
  255.                         count=0
  256.                        
  257.                         # Normalize the bars to the largest value
  258.                         try:
  259.                                 value_max=max(values)
  260.                         except ValueError:
  261.                                 value_max=0.0
  262.  
  263.                         for i in range(len(values)):
  264.                                 values[i]=(values[i]/value_max)*bar_height
  265.                        
  266.                          
  267.                         # Draw Single bars with their shadows
  268.                         for value in values:
  269.                                
  270.                                 #draw blur, if it is wanted
  271.                                 if blur_filter :
  272.                                         # Create shadow element
  273.                                         shadow = inkex.etree.SubElement(group,inkex.addNS("rect","svg"))
  274.                                         # Set chart position to center of document. Make it horizontal or vertical
  275.                                         if not rotate :
  276.                                                 shadow.set('x', str(width / 2 + offset +1))
  277.                                                 shadow.set('y', str(height / 2 - int(value)+1))
  278.                                         else:
  279.                                                 shadow.set('y', str(width / 2 + offset +1))
  280.                                                 shadow.set('x', str(height / 2 +1))
  281.                                         # Set shadow properties
  282.                                         if not rotate :
  283.                                                 shadow.set("width", str(bar_width))
  284.                                                 shadow.set("height", str(int(value)))
  285.                                         else:
  286.                                                 shadow.set("height", str(bar_width))
  287.                                                 shadow.set("width", str(int(value)))
  288.                                         # Set shadow blur (connect to filter object in xml path)
  289.                                         shadow.set("style","filter:url(#%s)" % blur_filter)
  290.                                
  291.                                 # Create rectangle element
  292.                                 rect = inkex.etree.SubElement(group,inkex.addNS('rect','svg'))
  293.                                
  294.                                 # Set chart position to center of document.
  295.                                 if(not rotate):
  296.                                         rect.set('x', str(width/2+offset))
  297.                                         rect.set('y', str(height/2-int(value)))
  298.                                 else:
  299.                                         rect.set('y', str(width/2+offset))
  300.                                         rect.set('x', str(height/2))
  301.                                 # Set rectangle properties
  302.                                 if(not rotate):
  303.                                         rect.set("width", str(bar_width))
  304.                                         rect.set("height", str(int(value)))
  305.                                 else:
  306.                                         rect.set("height", str(bar_width))
  307.                                         rect.set("width", str(int(value)))
  308.                                        
  309.                                 rect.set("style","fill:"+Colors[count%color_count])
  310.                                
  311.                                 # Set shadow blur (connect to filter object in xml path)
  312.                                 if(blur_filter):
  313.                                         shadow.set("style","filter:url(#%s)" % blur_filter)
  314.                                
  315.                                 # If keys are given create text elements
  316.                                 if(keys_present):
  317.                                         text = inkex.etree.SubElement(group, inkex.addNS('text','svg'))
  318.                                         if(not rotate): #=vertical
  319.                                                 text.set("transform","matrix(0,-1,1,0,0,0)")
  320.                                                 #y after rotation:
  321.                                                 text.set("x", "-"+str(height/2+text_offset))
  322.                                                 #x after rotation:
  323.                                                 text.set("y", str(width/2+offset+bar_width/2+font_size/3))
  324.                                         else: #=horizontal
  325.                                                 text.set("y", str(width/2+offset+bar_width/2+font_size/3))
  326.                                                 text.set("x", str(height/2-text_offset))
  327.                                
  328.                                         text.set("style","font-size:"+str(font_size)\
  329.                                         +"px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:"\
  330.                                         +font+";-inkscape-font-specification:Bitstream   Charter;text-align:end;text-anchor:end;fill:"\
  331.                                         +font_color)
  332.  
  333.                                         text.text=keys[count]  
  334.  
  335.                                 # Increase Offset and Color
  336.                                 offset=offset+bar_width+bar_offset
  337.                                 count += 1
  338.                 #End Bar
  339.                
  340.                
  341.                
  342.                 elif(charttype=="pie"):
  343.                 #########
  344.                 ###PIE###
  345.                 #########
  346.                         # Iterate all values to draw the different slices
  347.                         count=0
  348.                        
  349.                         # Add a grey background circle
  350.                         background=inkex.etree.SubElement(group, inkex.addNS("circle","svg"))
  351.                         background.set("cx", str(width/2))
  352.                         background.set("cy", str(height/2))
  353.                         background.set("r", str(pie_radius))
  354.                         background.set("style","fill:#aaaaaa;stroke:none")
  355.                         logf.write(" made BG\n")
  356.                         #create value sum in order to divide the slices
  357.                         try:
  358.                                 valuesum=sum(values)
  359.                         except ValueError:
  360.                                 valuesum=0
  361.                        
  362.                         # Set an offsetangle
  363.                         offset=pie_offset
  364.                         logf.write(" valuesum, offset =%s %s:\n" % (valuesum, offset))
  365.                         # Draw single slices with their shadow
  366.                         for value in values:
  367.                                 # Calculate the PI-angles for start and end
  368.                                 angle=(2*math.pi)/valuesum*float(value)
  369.                                
  370.                                 # Create the shadow first (if it should be created):
  371.                                 if(blur_filter):
  372.                                         shadow=inkex.etree.SubElement(group, inkex.addNS("path","svg"))
  373.                                         shadow.set(inkex.addNS('type', 'sodipodi'), 'arc')
  374.                                         shadow.set(inkex.addNS('cx', 'sodipodi'), str(width/2))
  375.                                         shadow.set(inkex.addNS('cy', 'sodipodi'), str(height/2))
  376.                                         shadow.set(inkex.addNS('rx', 'sodipodi'), str(pie_radius))
  377.                                         shadow.set(inkex.addNS('ry', 'sodipodi'), str(pie_radius))
  378.                                         shadow.set(inkex.addNS('start', 'sodipodi'), str(offset))
  379.                                         shadow.set(inkex.addNS('end', 'sodipodi'), str(offset+angle))
  380.                                         shadow.set("style","filter:url(#%s);fill:#000000" % blur_filter)
  381.                                
  382.                                 #then add the slice
  383.                                 pieslice=inkex.etree.SubElement(group, inkex.addNS("path","svg"))
  384.                                 pieslice.set(inkex.addNS('type', 'sodipodi'), 'arc')
  385.                                 pieslice.set(inkex.addNS('cx', 'sodipodi'), str(width/2))
  386.                                 pieslice.set(inkex.addNS('cy', 'sodipodi'), str(height/2))
  387.                                 pieslice.set(inkex.addNS('rx', 'sodipodi'), str(pie_radius))
  388.                                 pieslice.set(inkex.addNS('ry', 'sodipodi'), str(pie_radius))
  389.                                 pieslice.set(inkex.addNS('start', 'sodipodi'), str(offset))
  390.                                 pieslice.set(inkex.addNS('end', 'sodipodi'), str(offset+angle))
  391.                                 pieslice.set("style","fill:"+Colors[count%color_count]+";stroke:none;fill-opacity:1")
  392.                                
  393.                                 #If text is given, draw short paths and add the text
  394.                                 if(keys_present):
  395.                                         path=inkex.etree.SubElement(group, inkex.addNS("path","svg"))
  396.                                         path.set("d","m "+str((width/2)+pie_radius*math.cos(angle/2+offset))+","+str((height/2)+pie_radius*math.sin(angle/2+offset))+" "+str((text_offset-2)*math.cos(angle/2+offset))+","+str((text_offset-2)*math.sin(angle/2+offset)))
  397.                                         path.set("style","fill:none;stroke:"+font_color+";stroke-width:"+str(stroke_width)+"px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1")
  398.                                         text=inkex.etree.SubElement(group, inkex.addNS("text","svg"))
  399.                                         text.set("x", str((width/2)+(pie_radius+text_offset)*math.cos(angle/2+offset)))
  400.                                         text.set("y", str((height/2)+(pie_radius+text_offset)*math.sin(angle/2+offset)+font_size/3))
  401.                                         textstyle="font-size:"+str(font_size)+"px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:"+font+";-inkscape-font-specification:Bitstream Charter;fill:"+font_color
  402.                                         #check if it is right or left of the Pie
  403.                                         if(math.cos(angle/2+offset)>0):
  404.                                                 text.set("style",textstyle)
  405.                                         else:
  406.                                                 text.set("style",textstyle+";text-align:end;text-anchor:end")
  407.                                         text.text=keys[count]
  408.                                
  409.                                 #increase the rotation-offset and the colorcycle-position
  410.                                 offset += angle
  411.                                 count += 1
  412.                                 logf.write(" chart: offset,color =%s   %s %s:\n" % (offset, count, count%color_count))
  413.                                
  414.                 #End Pie       
  415.  
  416.  
  417.  
  418.        
  419.                 elif(charttype=="stbar"):
  420.                 #################
  421.                 ###STACKED BAR###
  422.                 #################
  423.                         # Iterate all values to draw the different slices
  424.                         count=0
  425.                        
  426.                         #create value sum in order to divide the bars
  427.                         try:
  428.                                 valuesum=sum(values)
  429.                         except ValueError:
  430.                                 valuesum=0.0
  431.  
  432.                         for value in values:
  433.                                 valuesum=valuesum+float(value)
  434.                        
  435.                         # Init offset
  436.                         offset=0
  437.                         stack_index = len(values)-1 #loopcounter
  438.                        
  439.                         # Draw Single bars with their shadows
  440.                         for value in values:
  441.                                
  442.                                 # Calculate the individual heights normalized on 100units
  443.                                 normedvalue=(bar_height/valuesum)*float(value)
  444.                                
  445.                                 if(blur_filter):
  446.                                         # Create rectangle element
  447.                                         shadow = inkex.etree.SubElement(group,inkex.addNS("rect","svg"))
  448.                                         # Set chart position to center of document.
  449.                                         if(not rotate):
  450.                                                 shadow.set('x', str(width / 2 + 1))
  451.                                                 shadow.set('y', str(height / 2 - offset - (normedvalue)+1))
  452.                                         else:
  453.                                                 shadow.set('x', str(width / 2 + 1 + offset))
  454.                                                 shadow.set('y', str(height / 2 +1))
  455.                                         # Set rectangle properties
  456.                                         if(not rotate):
  457.                                                 shadow.set("width",str(bar_width))
  458.                                                 shadow.set("height", str((normedvalue)))
  459.                                         else:
  460.                                                 shadow.set("width",str((normedvalue)))
  461.                                                 shadow.set("height", str(bar_width))
  462.                                         # Set shadow blur (connect to filter object in xml path)
  463.                                         shadow.set("style","filter:url(#%s)" % blur_filter)
  464.                                
  465.                                 # Create rectangle element
  466.                                 rect = inkex.etree.SubElement(group,inkex.addNS('rect','svg'))
  467.                                
  468.                                 # Set chart position to center of document.
  469.                                 if( not rotate ):
  470.                                         rect.set('x', str(width / 2 ))
  471.                                         rect.set('y', str(height / 2 - offset - (normedvalue)))
  472.                                 else:
  473.                                         rect.set('x', str(width / 2 + offset ))
  474.                                         rect.set('y', str(height / 2 ))
  475.                                 # Set rectangle properties
  476.                                 if( not rotate ):
  477.                                         rect.set("width", str(bar_width))
  478.                                         rect.set("height", str((normedvalue)))
  479.                                 else:
  480.                                         rect.set("height", str(bar_width))
  481.                                         rect.set("width", str((normedvalue)))
  482.                                 rect.set("style","fill:"+Colors[count%color_count])
  483.                                
  484.                                 #If text is given, draw short paths and add the text
  485.                                 if(keys_present):
  486.                                         if(not rotate):
  487.                                                 path=inkex.etree.SubElement(group,inkex.addNS("path","svg"))
  488.                                                 path.set("d","m "+str((width+bar_width)/2)+","+str(height / 2 - offset - (normedvalue / 2))+" "+str(bar_width/2+text_offset)+",0")
  489.                                                 path.set("style","fill:none;stroke:"+font_color+";stroke-width:"+str(stroke_width)+"px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1")
  490.                                                 text = inkex.etree.SubElement(group,inkex.addNS('text','svg'))
  491.                                                 text.set("x", str(width/2+bar_width+text_offset+1))
  492.                                                 text.set("y", str(height / 2 - offset + font_size/3 - (normedvalue / 2)))
  493.                                                 text.set("style","font-size:"+str(font_size)+"px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:"+font+";-inkscape-font-specification:Bitstream Charter;fill:"+font_color)
  494.                                                 text.text=keys[color]
  495.                                         else:
  496.                                                 path=inkex.etree.SubElement(group,inkex.addNS("path","svg"))
  497.                                                 path.set("d","m "+str((width)/2+offset+normedvalue/2)+","
  498.                                                         +str(height / 2 + bar_width/2)
  499.                                                         +" 0,"+str(bar_width/2+(font_size*stack_index)+text_offset)) #line
  500.                                                 path.set("style","fill:none;stroke:"+font_color+";stroke-width:"+str(stroke_width)+"px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1")
  501.                                                 text = inkex.etree.SubElement(group,inkex.addNS('text','svg'))
  502.                                                 text.set("x", str((width)/2+offset+normedvalue/2-font_size/3))
  503.                                                 text.set("y", str((height/2)+bar_width+(font_size*(stack_index+1))+text_offset ))
  504.                                                 text.set("style","font-size:"+str(font_size)+"px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:"+font+";-inkscape-font-specification:Bitstream Charter;fill:"+font_color)
  505.                                                 text.text=keys[count]
  506.                                
  507.                                 # Increase Offset and Color
  508.                                 offset=offset+normedvalue
  509.                                 count += 1
  510.                                
  511.                                 stack_index-=1 #loopcounter
  512.  
  513.                                
  514.         def extract_data(self, csv_data):
  515.                 """ Expecting csv data in one of several forms.
  516.                    - first line has descriptions or not.
  517.                      If so then first is title of graph, subsequent column headers are labels
  518.                    - if more than one column after col_val then treat as new charts
  519.                    - blank line is separator. new layer of graphs.
  520.                """
  521.                 data = []
  522.                 csv_delimiter=self.options.csv_delimiter
  523.                 col_key=self.options.col_key
  524.                 col_val=self.options.col_val
  525.                 desc = self.options.labels
  526.                 #
  527.                 label = ""
  528.                 titles = []
  529.                 keys = []
  530.                 values = []
  531.                 started = False
  532.                 for line in csv_data:
  533.                         line = line.strip()
  534.                         items = line.split(csv_delimiter)
  535.                         size = len(items)
  536.                         sys.stderr.write(" items: %s\n" % items)
  537.                         foo = [i for i in items] # cheap copy
  538.                         # remove dummy if all lines not same length (thanks XLS!!)
  539.                         if size > 1:
  540.                                 count = foo.count('')
  541.                                 for i in range(count):
  542.                                         foo.remove('')
  543.                         items = foo
  544.                         size = len(items)
  545.                         sys.stderr.write("Line = %d, %s\n"% (size,items))
  546.                         if items[0] == '':
  547.                                 # blank line so start again
  548.                                 if not started:
  549.                                         pass
  550.                                 else:
  551.                                         #we have something to save so we can start a new chart.
  552.                                         data.append([titles,keys,values])
  553.                                         keys = []
  554.                                         values = []
  555.                                         started = False
  556.                                         sys.stderr.write("Saving chart, false start\n")
  557.                         else: # process valid lines
  558.                                 if not started and desc:
  559.                                         sys.stderr.write("Grab labels\n")
  560.                                         # first line so grab labels if applicable
  561.                                         label = items[0]
  562.                                         if len(items)>1:
  563.                                             titles = [label, items[col_val:]]
  564.                                             for i in range(len(items[col_val:])):
  565.                                                     values.append([])
  566.                                             sys.stderr.write(" values: %s\n" % values)
  567.                                 else: # process line normally
  568.                                         sys.stderr.write("process line %s\n" % items[col_key])
  569.                                         keys.append(items[col_key])
  570.                                         for idx,item  in enumerate(items[col_val:]):
  571.                                                 #sys.stderr.write(" idx,item: %s %s = %s %s\n" % (idx,item, values[idx], values))
  572.                                                 values[idx].append(float(item.replace('$','').replace('%','')))
  573.                                         sys.stderr.write(" values=%s\n" % values)
  574.                                 #
  575.                                 started = True # started a block (we may have already started).
  576.                                 sys.stderr.write(" started=True\n")
  577.                 # all done so store last set of charts
  578.                 if values != []:
  579.                         data.append([titles,keys,values])
  580.                         titles = []
  581.                         keys = []
  582.                         values = []
  583.                 return data
  584.                                
  585.  
  586.        
  587.         def effect(self):
  588.                 """
  589.                 Effect behaviour.
  590.                 Overrides base class' method and inserts a nice looking chart into SVG document.
  591.                 """
  592.                 # Get script's "--what" option value and process the data type --- i confess the if term is a little bit of magic
  593.                 what = self.options.what
  594.                 keys=[]
  595.                 values=[]
  596.                
  597.                 csv_file_name=self.options.filename
  598.                 csv_delimiter=self.options.csv_delimiter
  599.                 input_type=self.options.input_type
  600.                 col_key=self.options.col_key
  601.                 col_val=self.options.col_val
  602.  
  603.                 blur_filter = False
  604.                 if self.options.blur:
  605.                         blur_filter = self.create_blur_filter()
  606.                
  607.                 if(input_type=="\"file\""):
  608.                         csv_file=open(csv_file_name,"r")
  609.                         csv_data = csv_file.readlines()
  610.                         csv_file.close()
  611.                         data = self.extract_data(csv_data)
  612.                         # Get script's "--type" option value.
  613.                         charttype=self.options.type
  614.                         logf.write("\nData: %s\n\n" % data)
  615.                         unique = 0
  616.                         for (titles,keys,values) in data:
  617.                                 # make chart for each piece of data
  618.                                 layer = self.create_layer(titles[0])
  619.                                 for idx,dataset in enumerate(values):
  620.                                         sys.stderr.write("\nMaking: %d %s\n %s\n %s\n" % (idx, charttype, keys, dataset))
  621.                                         logf.write("\nMaking: %d %s\n %s\n %s\n" % (idx, charttype, keys, dataset))
  622.                                         #if unique == 0:
  623.                                         self.make_chart(charttype, keys, dataset, titles[1][idx]+"_"+str(unique), blur_filter, layer)
  624.                                 unique += 1
  625.                 elif(input_type=="\"direct_input\""):
  626.                         what=re.findall("([A-Z|a-z|0-9]+:[0-9]+\.?[0-9]*)",what)
  627.                         for value in what:
  628.                                 value=value.split(":")
  629.                                 keys.append(value[0])
  630.                                 values.append(float(value[1]))
  631.                         # Get script's "--type" option value.
  632.                         charttype=self.options.type
  633.                         #
  634.                         self.make_chart(charttype, keys, values, self.options.what)
  635.                
  636.  
  637.  
  638. # Create effect instance and apply it.
  639. effect = NiceChart()
  640. effect.affect()