View difference between Paste ID: 6b8jcanU and
SHOW: | | - or go back to the newest paste.
1-
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()