Advertisement
Guest User

nicechart.py

a guest
Oct 2nd, 2012
106
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 25.95 KB | None | 0 0
  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()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement