summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Owens <doctormo@gmail.com>2016-02-27 17:38:36 +0000
committerMartin Owens <doctormo@gmail.com>2016-02-27 17:38:36 +0000
commit380741fc91724ef40be2b6d938fd3d991bb28ccb (patch)
tree5cd7b86175e92733920a1c62ec306896fe899e27
parentFix miter-limit behavior to match SVG spec. (diff)
downloadinkscape-380741fc91724ef40be2b6d938fd3d991bb28ccb.tar.gz
inkscape-380741fc91724ef40be2b6d938fd3d991bb28ccb.zip
Remove Maren from AUTHORS (on request) and add nicecharts from upstream where it was abandoned
(bzr r14672)
-rw-r--r--AUTHORS1
-rw-r--r--share/extensions/nicechart.inx103
-rwxr-xr-xshare/extensions/nicechart.py718
3 files changed, 821 insertions, 1 deletions
diff --git a/AUTHORS b/AUTHORS
index baffedb20..665b32a1e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -65,7 +65,6 @@ Toine de Greef
Michael Grosberg
Bryce Harrington
Dale Harvey
-Maren Hachmann
Aurélio Adnauer Heckert
Carl Hetherington
Jos Hirth
diff --git a/share/extensions/nicechart.inx b/share/extensions/nicechart.inx
new file mode 100644
index 000000000..0ebcd8fca
--- /dev/null
+++ b/share/extensions/nicechart.inx
@@ -0,0 +1,103 @@
+<!--
+ nicechart.inx
+
+ Copyright 2011-2016
+
+ Christoph Sterz
+ Florian Weber
+ Maren Hachmann
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+-->
+
+<inkscape-extension>
+ <_name>NiceCharts</_name>
+ <id>org.inkscape.filter.nicechart</id>
+ <dependency type="executable" location="extensions">nicechart.py</dependency>
+ <dependency type="executable" location="extensions">inkex.py</dependency>
+ <param name="input_sections" type="notebook">
+ <page name="data_settings" _gui-text="Data">
+ <param name="input_type" type="notebook">
+ <page name="file" _gui-text="Data from file">
+ <_param name="desc" type="description">Enter the full path to a CSV file:</_param>
+ <param name="filename" type="string" _gui-text="File:"></param>
+ <param name="delimiter" type="string" _gui-text="Delimiter:">;</param>
+ <param name="col_key" type="int" _gui-text="Column that contains the keys:" min="0" max="10000">0</param>
+ <param name="col_val" type="int" _gui-text="Column that contains the values:" min="0" max="10000">1</param>
+ <param name="encoding" type="string" _gui-text="File encoding (e.g. utf-8):">utf-8</param>
+ <param name="headings" type="boolean" _gui-text="First line contains headings">false</param>
+ </page>
+ <page name="direct_input" _gui-text="Direct input">
+ <_param name="desc" type="description">Type in comma separated values:</_param>
+ <_param name="desc" type="description">(format like this: apples:3,bananas:5)</_param>
+ <param name="what" type="string" _gui-text="Data:">apples:3,bananas:5,oranges:10,pears:4</param>
+ </page>
+ </param>
+ </page>
+ <page name="description_settings" _gui-text="Labels">
+ <param type="string" name="font" _gui-text="Font:">sans-serif</param>
+ <param type="int" name="font-size" _gui-text="Font size:" min="0" max="10000">10</param>
+ <param type="string" name="font-color" _gui-text="Font color:">#000000</param>
+ </page>
+ <page name="chart_settings" _gui-text="Charts">
+ <param type="boolean" name="rotate" _gui-text="Draw horizontally">false</param>
+ <param name="bar-height" type="int" _gui-text="Bar length:" min="0" max="100000">100</param>
+ <param name="bar-width" type="int" _gui-text="Bar width:" min="0" max="100000">10</param>
+ <param name="pie-radius" type="int" _gui-text="Pie radius:" min="0" max="100000">100</param>
+ <param name="bar-offset" type="int" _gui-text="Bar offset:" min="0" max="100000">5</param>
+ <param name="stroke-width" type="float" min="0.1" max="100000.0" precision="2" _gui-text="Stroke width:">1</param>
+ <param name="text-offset" type="int" _gui-text="Offset between chart and labels:" min="0" max="100000">5</param>
+ <param name="heading-offset" type="int" _gui-text="Offset between chart and chart title:" min="-100000" max="100000">50</param>
+ <param name="segment-overlap" type="boolean" _gui-text="Work around aliasing effects (creates overlapping segments)">false</param>
+
+ <param name="colors" type="enum" _gui-text="Color scheme:">
+ <_item value="default">Default</_item>
+ <_item value="blue">Blue</_item>
+ <_item value="gray">Gray</_item>
+ <_item value="contrast">Contrast</_item>
+ <_item value="sap">SAP</_item>
+ </param>
+
+ <param type="string" name="colors_override" _gui-text="Custom colors:"></param>
+
+ <param type="boolean" name="reverse_colors" _gui-text="Reverse color scheme">false</param>
+ <param type="boolean" name="blur" _gui-text="Drop shadow">false</param>
+ </page>
+ <page name="value_settings" _gui-text="Values">
+ <param type="boolean" name="show_values" _gui-text="Show values">false</param>
+<!-- <param type="string" name="font" _gui-text="Font:">sans-serif</param>
+ <param type="int" name="font-size" _gui-text="Font size:" min="0" max="10000">10</param>
+ <param type="description" name="desc">Font color:</param>
+ <param type="string" name="font-color" _gui-text="Font color:">#000000</param>
+-->
+ </page>
+ </param>
+ <param name="type" type="enum" _gui-text="Chart type:">
+ <_item value="bar">Bar chart</_item>
+ <_item value="pie">Pie chart</_item>
+ <_item value="pie_abs">Pie chart (percentage)</_item>
+ <_item value="stbar">Stacked bar chart</_item>
+ </param>
+ <effect>
+ <object-type>all</object-type>
+ <effects-menu>
+ <submenu _name="Render"/>
+ </effects-menu>
+ </effect>
+ <script>
+ <command reldir="extensions" interpreter="python">nicechart.py</command>
+ </script>
+</inkscape-extension>
diff --git a/share/extensions/nicechart.py b/share/extensions/nicechart.py
new file mode 100755
index 000000000..d4a819ccc
--- /dev/null
+++ b/share/extensions/nicechart.py
@@ -0,0 +1,718 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# nicechart.py
+#
+# Copyright 2011-2016
+#
+# Christoph Sterz
+# Florian Weber
+# Maren Hachmann
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+# TODO / Ideas:
+# allow negative values for bar charts
+# show values for stacked bar charts
+# don't create a new layer for each chart, but a normal group
+# correct bar height for stacked bars (it's only half as high as it should be, double)
+# adjust position of heading
+# use aliasing workaround for stacked bars (e.g. let the rectangles overlap)
+
+# Example CSV file contents:
+'''
+Month;1978;1979;1980;1981
+January;2;1,3;0.1;2.3
+February;6.5;2.4;1.2;6.1
+March;7.4;6.7;7.9;4.7
+April;7.7;6.4;8.2;8.9
+May;10.9;11.7;18.7;11.1
+June;12.6;14.2;14.7;14.7
+July;16.5;15.5;17.5;15.1
+August;15.9;15.4;14.6;16.6
+September;14;14.5;13.2;15.3
+October;11.9;13.9;11.5;9.2
+November;6.7;8.5;7;6.6
+December;6.4;2.2;6.3;3.5
+'''
+# The extension creates one chart for a single value column in one go,
+# e.g. chart all temperatures for all months of the year 1978 into one chart.
+# (for this, select column 0 for labels and column 1 for values).
+# "1978" etc. can be used as heading (Need not be numeric. If not used delete the heading line.)
+# Month names can be used as labels
+# Values can be shown, in addition to labels (doesn't work with stacked bar charts)
+# Values can contain commas as decimal separator, as long as delimiter isn't comma
+# Negative values are not yet supported.
+
+
+import re
+import sys
+import math
+import inkex
+
+from simplestyle import *
+
+#www.sapdesignguild.org/goodies/diagram_guidelines/color_palettes.html#mss
+COLOUR_TABLE = {
+ "red": ["#460101", "#980101", "#d40000", "#f44800", "#fb8b00", "#eec73e", "#d9bb7a", "#fdd99b"],
+ "blue": ["#000442", "#0F1781", "#252FB7", "#3A45E1", "#656DDE", "#8A91EC"],
+ "gray": ["#222222", "#444444", "#666666", "#888888", "#aaaaaa", "#cccccc", "#eeeeee"],
+ "contrast": ["#0000FF", "#FF0000", "#00FF00", "#CF9100", "#FF00FF", "#00FFFF"],
+ "sap": ["#f8d753", "#5c9746", "#3e75a7", "#7a653e", "#e1662a", "#74796f", "#c4384f",
+ "#fff8a3", "#a9cc8f", "#b2c8d9", "#bea37a", "#f3aa79", "#b5b5a9", "#e6a5a5"]
+}
+
+def get_color_scheme(name="default"):
+ return COLOUR_TABLE.get(name.lower(), COLOUR_TABLE['red'])
+
+
+class NiceChart(inkex.Effect):
+ """
+ Inkscape extension that can draw pie charts and bar charts
+ (stacked, single, horizontally or vertically)
+ with optional drop shadow, from a csv file or from pasted text
+ """
+
+ def __init__(self):
+ """
+ Constructor.
+ Defines the "--what" option of a script.
+ """
+ # Call the base class constructor.
+ inkex.Effect.__init__(self)
+
+ # Define string option "--what" with "-w" shortcut and default chart values.
+ self.OptionParser.add_option('-w', '--what', action='store',
+ type='string', dest='what', default='22,11,67',
+ help='Chart Values')
+
+ # Define string option "--type" with "-t" shortcut.
+ self.OptionParser.add_option("-t", "--type", action="store",
+ type="string", dest="type", default='',
+ help="Chart Type")
+
+ # Define bool option "--blur" with "-b" shortcut.
+ self.OptionParser.add_option("-b", "--blur", action="store",
+ type="inkbool", dest="blur", default='True',
+ help="Blur Type")
+
+ # Define string option "--file" with "-f" shortcut.
+ self.OptionParser.add_option("-f", "--filename", action="store",
+ type="string", dest="filename", default='',
+ help="Name of File")
+
+ # Define string option "--input_type" with "-i" shortcut.
+ self.OptionParser.add_option("-i", "--input_type", action="store",
+ type="string", dest="input_type", default='file',
+ help="Chart Type")
+
+ # Define string option "--delimiter" with "-d" shortcut.
+ self.OptionParser.add_option("-d", "--delimiter", action="store",
+ type="string", dest="csv_delimiter", default=';',
+ help="delimiter")
+
+ # Define string option "--colors" with "-c" shortcut.
+ self.OptionParser.add_option("-c", "--colors", action="store",
+ type="string", dest="colors", default='default',
+ help="color-scheme")
+
+ # Define string option "--colors_override"
+ self.OptionParser.add_option("", "--colors_override", action="store",
+ type="string", dest="colors_override", default='',
+ help="color-scheme-override")
+
+
+ self.OptionParser.add_option("", "--reverse_colors", action="store",
+ type="inkbool", dest="reverse_colors", default='False',
+ help="reverse color-scheme")
+
+ self.OptionParser.add_option("-k", "--col_key", action="store",
+ type="int", dest="col_key", default='0',
+ help="column that contains the keys")
+
+
+ self.OptionParser.add_option("-v", "--col_val", action="store",
+ type="int", dest="col_val", default='1',
+ help="column that contains the values")
+
+ self.OptionParser.add_option("", "--encoding", action="store",
+ type="string", dest="encoding", default='utf-8',
+ help="encoding of the CSV file, e.g. utf-8")
+
+ self.OptionParser.add_option("", "--headings", action="store",
+ type="inkbool", dest="headings", default='False',
+ help="the first line of the CSV file consists of headings for the columns")
+
+ self.OptionParser.add_option("-r", "--rotate", action="store",
+ type="inkbool", dest="rotate", default='False',
+ help="Draw barchart horizontally")
+
+ self.OptionParser.add_option("-W", "--bar-width", action="store",
+ type="int", dest="bar_width", default='10',
+ help="width of bars")
+
+ self.OptionParser.add_option("-p", "--pie-radius", action="store",
+ type="int", dest="pie_radius", default='100',
+ help="radius of pie-charts")
+
+ self.OptionParser.add_option("-H", "--bar-height", action="store",
+ type="int", dest="bar_height", default='100',
+ help="height of bars")
+
+ self.OptionParser.add_option("-O", "--bar-offset", action="store",
+ type="int", dest="bar_offset", default='5',
+ help="distance between bars")
+
+ self.OptionParser.add_option("", "--stroke-width", action="store",
+ type="float", dest="stroke_width", default='1')
+
+ self.OptionParser.add_option("-o", "--text-offset", action="store",
+ type="int", dest="text_offset", default='5',
+ help="distance between bar and descriptions")
+
+ self.OptionParser.add_option("", "--heading-offset", action="store",
+ type="int", dest="heading_offset", default='50',
+ help="distance between chart and chart title")
+
+ self.OptionParser.add_option("", "--segment-overlap", action="store",
+ type="inkbool", dest="segment_overlap", default='False',
+ help="work around aliasing effects by letting pie chart segments overlap")
+
+ self.OptionParser.add_option("-F", "--font", action="store",
+ type="string", dest="font", default='sans-serif',
+ help="font of description")
+
+ self.OptionParser.add_option("-S", "--font-size", action="store",
+ type="int", dest="font_size", default='10',
+ help="font size of description")
+
+ self.OptionParser.add_option("-C", "--font-color", action="store",
+ type="string", dest="font_color", default='black',
+ help="font color of description")
+ #Dummy:
+ self.OptionParser.add_option("","--input_sections")
+
+ self.OptionParser.add_option("-V", "--show_values", action="store",
+ type="inkbool", dest="show_values", default='False',
+ help="Show values in chart")
+
+ def effect(self):
+ """
+ Effect behaviour.
+ Overrides base class' method and inserts a nice looking chart into SVG document.
+ """
+ # Get script's "--what" option value and process the data type --- i concess the if term is a little bit of magic
+ what = self.options.what
+ keys = []
+ values = []
+ orig_values = []
+ keys_present = True
+ pie_abs = False
+ cnt = 0
+ csv_file_name = self.options.filename
+ csv_delimiter = self.options.csv_delimiter
+ input_type = self.options.input_type
+ col_key = self.options.col_key
+ col_val = self.options.col_val
+ show_values = self.options.show_values
+ encoding = self.options.encoding.strip() or 'utf-8'
+ headings = self.options.headings
+ heading_offset = self.options.heading_offset
+
+ if input_type == "\"file\"":
+ csv_file = open(csv_file_name, "r")
+
+ for linenum, line in enumerate(csv_file):
+ value = line.decode(encoding).split(csv_delimiter)
+ #make sure that there is at least one value (someone may want to use it as description)
+ if len(value) >= 1:
+ # allow to parse headings as strings
+ if linenum == 0 and headings:
+ heading = value[col_val]
+ else:
+ keys.append(value[col_key])
+ # replace comma decimal separator from file by colon,
+ # to avoid file editing for people whose programs output
+ # values with comma
+ values.append(float(value[col_val].replace(",",".")))
+ csv_file.close()
+
+ elif input_type == "\"direct_input\"":
+ what = re.findall("([A-Z|a-z|0-9]+:[0-9]+\.?[0-9]*)", what)
+ for value in what:
+ value = value.split(":")
+ keys.append(value[0])
+ values.append(float(value[1]))
+
+ # warn about negative values (not yet supported)
+ for value in values:
+ if value < 0:
+ inkex.errormsg("Negative values are currently not supported!")
+ return
+
+ # Get script's "--type" option value.
+ charttype = self.options.type
+
+ if charttype == "pie_abs":
+ pie_abs = True
+ charttype = "pie"
+
+ # Get access to main SVG document element and get its dimensions.
+ svg = self.document.getroot()
+
+ # Get the page attibutes:
+ width = self.getUnittouu(svg.get('width'))
+ height = self.getUnittouu(svg.attrib['height'])
+
+ # Create a new layer.
+ layer = inkex.etree.SubElement(svg, 'g')
+ layer.set(inkex.addNS('label', 'inkscape'), 'Chart-Layer: %s' % (what))
+ layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
+
+ # Check if a drop shadow should be drawn:
+ draw_blur = self.options.blur
+
+ if draw_blur:
+ # Get defs of Document
+ defs = self.xpathSingle('/svg:svg//svg:defs')
+ if defs == None:
+ defs = inkex.etree.SubElement(self.document.getroot(), inkex.addNS('defs', 'svg'))
+
+ # Create new Filter
+ filt = inkex.etree.SubElement(defs,inkex.addNS('filter', 'svg'))
+ filtId = self.uniqueId('filter')
+ self.filtId = 'filter:url(#%s);' % filtId
+ for k, v in [('id', filtId), ('height', "3"),
+ ('width', "3"),
+ ('x', '-0.5'), ('y', '-0.5')]:
+ filt.set(k, v)
+
+ # Append Gaussian Blur to that Filter
+ fe = inkex.etree.SubElement(filt, inkex.addNS('feGaussianBlur', 'svg'))
+ fe.set('stdDeviation', "1.1")
+
+ # Set Default Colors
+ self.options.colors_override.strip()
+ if len(self.options.colors_override) > 0:
+ colors = self.options.colors_override
+ else:
+ colors = self.options.colors
+
+ if colors[0].isalpha():
+ colors = get_color_scheme(colors)
+ else:
+ colors = re.findall("(#[0-9a-fA-F]{6})", colors)
+ #to be sure we create a fallback:
+ if len(colors) == 0:
+ colors = get_color_scheme()
+
+ color_count = len(colors)
+
+ if self.options.reverse_colors:
+ colors.reverse()
+
+ # Those values should be self-explanatory:
+ bar_height = self.options.bar_height
+ bar_width = self.options.bar_width
+ bar_offset = self.options.bar_offset
+ # offset of the description in stacked-bar-charts:
+ # stacked_bar_text_offset=self.options.stacked_bar_text_offset
+ text_offset = self.options.text_offset
+ # prevents ugly aliasing effects between pie chart segments by overlapping
+ segment_overlap = self.options.segment_overlap
+
+ # get font
+ font = self.options.font
+ font_size = self.options.font_size
+ font_color = self.options.font_color
+
+ # get rotation
+ rotate = self.options.rotate
+
+ pie_radius = self.options.pie_radius
+ stroke_width = self.options.stroke_width
+
+ if charttype == "bar":
+ #########
+ ###BAR###
+ #########
+
+ # iterate all values, use offset to draw the bars in different places
+ offset = 0
+ color = 0
+
+ # Normalize the bars to the largest value
+ try:
+ value_max = max(values)
+ except ValueError:
+ value_max = 0.0
+
+ for x in range(len(values)):
+ orig_values.append(values[x])
+ values[x] = (values[x]/value_max) * bar_height
+
+ # Draw Single bars with their shadows
+ for value in values:
+
+ # draw drop shadow, if necessary
+ if draw_blur:
+ # Create shadow element
+ shadow = inkex.etree.Element(inkex.addNS("rect", "svg"))
+ # Set chart position to center of document. Make it horizontal or vertical
+ if not rotate:
+ shadow.set('x', str(width/2 + offset + 1))
+ shadow.set('y', str(height/2 - int(value) + 1))
+ shadow.set("width", str(bar_width))
+ shadow.set("height", str(int(value)))
+ else:
+ shadow.set('y', str(width/2 + offset + 1))
+ shadow.set('x', str(height/2 + 1))
+ shadow.set("height", str(bar_width))
+ shadow.set("width", str(int(value)))
+
+ # Set shadow blur (connect to filter object in xml path)
+ shadow.set("style", "filter:url(#filter)")
+
+ # Create rectangle element
+ rect = inkex.etree.Element(inkex.addNS('rect', 'svg'))
+
+ # Set chart position to center of document.
+ if not rotate:
+ rect.set('x', str(width/2 + offset))
+ rect.set('y', str(height/2 - int(value)))
+ rect.set("width", str(bar_width))
+ rect.set("height", str(int(value)))
+ else:
+ rect.set('y', str(width/2 + offset))
+ rect.set('x', str(height/2))
+ rect.set("height", str(bar_width))
+ rect.set("width", str(int(value)))
+
+ rect.set("style", "fill:" + colors[color % color_count])
+
+ # If keys are given, create text elements
+ if keys_present:
+ text = inkex.etree.Element(inkex.addNS('text', 'svg'))
+ if not rotate: #=vertical
+ text.set("transform", "matrix(0,-1,1,0,0,0)")
+ #y after rotation:
+ text.set("x", "-" + str(height/2 + text_offset))
+ #x after rotation:
+ text.set("y", str(width/2 + offset + bar_width/2 + font_size/3))
+ else: #=horizontal
+ text.set("y", str(width/2 + offset + bar_width/2 + font_size/3))
+ text.set("x", str(height/2 - text_offset))
+
+ 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;text-align:end;text-anchor:end;fill:"\
+ + font_color)
+
+ text.text = keys[cnt]
+
+ # Increase Offset and Color
+ #offset=offset+bar_width+bar_offset
+ color = (color + 1) % 8
+ # Connect elements together.
+ if draw_blur:
+ layer.append(shadow)
+ layer.append(rect)
+ if keys_present:
+ layer.append(text)
+
+ if show_values:
+ vtext = inkex.etree.Element(inkex.addNS('text', 'svg'))
+ if not rotate: #=vertical
+ vtext.set("transform", "matrix(0,-1,1,0,0,0)")
+ #y after rotation:
+ vtext.set("x", "-"+str(height/2+text_offset-value-text_offset-text_offset))
+ #x after rotation:
+ vtext.set("y", str(width/2+offset+bar_width/2+font_size/3))
+ else: #=horizontal
+ vtext.set("y", str(width/2+offset+bar_width/2+font_size/3))
+ vtext.set("x", str(height/2-text_offset+value+text_offset+text_offset))
+
+ vtext.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;text-align:start;text-anchor:start;fill:"\
+ + font_color)
+
+ vtext.text = str(int(orig_values[cnt]))
+ layer.append(vtext)
+
+ cnt = cnt+1
+ offset = offset + bar_width + bar_offset
+
+ # set x position for heading line
+ if not rotate:
+ heading_x = width/2 # TODO: adjust
+ else:
+ heading_x = width/2 # TODO: adjust
+
+
+ elif charttype == "pie":
+ #########
+ ###PIE###
+ #########
+ # Iterate all values to draw the different slices
+ color = 0
+
+ # Create the shadow first (if it should be created):
+ if draw_blur:
+ shadow = inkex.etree.Element(inkex.addNS("circle", "svg"))
+ shadow.set('cx', str(width/2))
+ shadow.set('cy', str(height/2))
+ shadow.set('r', str(pie_radius))
+ shadow.set("style", "filter:url(#filter);fill:#000000")
+ layer.append(shadow)
+
+
+ # Add a grey background circle with a light stroke
+ background = inkex.etree.Element(inkex.addNS("circle", "svg"))
+ background.set("cx", str(width/2))
+ background.set("cy", str(height/2))
+ background.set("r", str(pie_radius))
+ background.set("style", "stroke:#ececec;fill:#f9f9f9")
+ layer.append(background)
+
+ #create value sum in order to divide the slices
+ try:
+ valuesum = sum(values)
+
+ except ValueError:
+ valuesum = 0
+
+ if pie_abs:
+ valuesum = 100
+
+ num_values = len(values)
+
+ # Set an offsetangle
+ offset = 0
+
+ # Draw single slices
+ for i in range(num_values):
+ value = values[i]
+ # Calculate the PI-angles for start and end
+ angle = (2*3.141592) / valuesum * float(value)
+ start = offset
+ end = offset + angle
+
+ # proper overlapping
+ if segment_overlap:
+ if i != num_values-1:
+ end += 0.09 # add a 5° overlap
+ if i == 0:
+ start -= 0.09 # let the first element overlap into the other direction
+
+ #then add the slice
+ pieslice = inkex.etree.Element(inkex.addNS("path", "svg"))
+ pieslice.set(inkex.addNS('type', 'sodipodi'), 'arc')
+ pieslice.set(inkex.addNS('cx', 'sodipodi'), str(width/2))
+ pieslice.set(inkex.addNS('cy', 'sodipodi'), str(height/2))
+ pieslice.set(inkex.addNS('rx', 'sodipodi'), str(pie_radius))
+ pieslice.set(inkex.addNS('ry', 'sodipodi'), str(pie_radius))
+ pieslice.set(inkex.addNS('start', 'sodipodi'), str(start))
+ pieslice.set(inkex.addNS('end', 'sodipodi'), str(end))
+ pieslice.set("style", "fill:"+ colors[color % color_count] + ";stroke:none;fill-opacity:1")
+
+ #If text is given, draw short paths and add the text
+ if keys_present:
+ path = inkex.etree.Element(inkex.addNS("path", "svg"))
+ 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)))
+
+ path.set("style", "fill:none;stroke:"
+ + font_color + ";stroke-width:" + str(stroke_width)
+ + "px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1")
+ layer.append(path)
+ text = inkex.etree.Element(inkex.addNS('text', 'svg'))
+ text.set("x", str((width/2) + (pie_radius + text_offset) * math.cos(angle/2 + offset)))
+ text.set("y", str((height/2) + (pie_radius + text_offset) * math.sin(angle/2 + offset) + font_size/3))
+ 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
+ # check if it is right or left of the Pie
+ if math.cos(angle/2 + offset) > 0:
+ text.set("style", textstyle)
+ else:
+ text.set("style", textstyle + ";text-align:end;text-anchor:end")
+ text.text = keys[cnt]
+ if show_values:
+ text.text = text.text + "(" + str(values[cnt])
+
+ if pie_abs:
+ text.text = text.text + " %"
+
+ text.text = text.text + ")"
+
+ cnt = cnt + 1
+ layer.append(text)
+
+ # increase the rotation-offset and the colorcycle-position
+ offset = offset + angle
+ color = (color + 1) % 8
+
+ # append the objects to the extension-layer
+ layer.append(pieslice)
+
+ # set x position for heading line
+ heading_x = width/2 - pie_radius # TODO: adjust
+
+ elif charttype == "stbar":
+ #################
+ ###STACKED BAR###
+ #################
+ # Iterate over all values to draw the different slices
+ color = 0
+
+ #create value sum in order to divide the bars
+ try:
+ valuesum = sum(values)
+ except ValueError:
+ valuesum = 0.0
+
+ for value in values:
+ valuesum = valuesum + float(value)
+
+ # Init offset
+ offset = 0
+
+ if draw_blur:
+ # Create rectangle element
+ shadow = inkex.etree.Element(inkex.addNS("rect", "svg"))
+ # Set chart position to center of document.
+ if not rotate:
+ shadow.set('x', str(width/2))
+ shadow.set('y', str(height/2 - bar_height/2))
+ else:
+ shadow.set('x', str(width/2))
+ shadow.set('y', str(height/2))
+ # Set rectangle properties
+ if not rotate:
+ shadow.set("width", str(bar_width))
+ shadow.set("height", str(bar_height/2))
+ else:
+ shadow.set("width",str(bar_height/2))
+ shadow.set("height", str(bar_width))
+ # Set shadow blur (connect to filter object in xml path)
+ shadow.set("style", "filter:url(#filter)")
+ layer.append(shadow)
+
+ i = 0
+ # Draw Single bars
+ for value in values:
+
+ # Calculate the individual heights normalized on 100units
+ normedvalue = (bar_height / valuesum) * float(value)
+
+ # Create rectangle element
+ rect = inkex.etree.Element(inkex.addNS('rect', 'svg'))
+
+ # Set chart position to center of document.
+ if not rotate:
+ rect.set('x', str(width / 2 ))
+ rect.set('y', str(height / 2 - offset - normedvalue))
+ else:
+ rect.set('x', str(width / 2 + offset ))
+ rect.set('y', str(height / 2 ))
+ # Set rectangle properties
+ if not rotate:
+ rect.set("width", str(bar_width))
+ rect.set("height", str(normedvalue))
+ else:
+ rect.set("height", str(bar_width))
+ rect.set("width", str(normedvalue))
+ rect.set("style", "fill:" + colors[color % color_count])
+
+ #If text is given, draw short paths and add the text
+ # TODO: apply overlap workaround for visible gaps in between
+ if keys_present:
+ if not rotate:
+ path = inkex.etree.Element(inkex.addNS("path", "svg"))
+ path.set("d","m " + str((width + bar_width)/2) + ","
+ + str(height/2 - offset - (normedvalue / 2)) + " "
+ + str(bar_width/2 + text_offset) + ",0")
+ path.set("style", "fill:none;stroke:" + font_color
+ + ";stroke-width:" + str(stroke_width)
+ + "px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1")
+ layer.append(path)
+ text = inkex.etree.Element(inkex.addNS('text', 'svg'))
+ text.set("x", str(width/2 + bar_width + text_offset + 1))
+ text.set("y", str(height/ 2 - offset + font_size/3 - (normedvalue/2)))
+ 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)
+ text.text = keys[cnt]
+ cnt = cnt + 1
+ layer.append(text)
+ else:
+ path = inkex.etree.Element(inkex.addNS("path", "svg"))
+ path.set("d","m " + str((width)/2 + offset + normedvalue/2) + ","
+ + str(height / 2 + bar_width/2) + " 0,"
+ + str(bar_width/2 + (font_size * i) + text_offset)) #line
+ path.set("style", "fill:none;stroke:" + font_color
+ + ";stroke-width:" + str(stroke_width)
+ + "px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1")
+ layer.append(path)
+ text = inkex.etree.Element(inkex.addNS('text', 'svg'))
+ text.set("x", str((width)/2 + offset + normedvalue/2 - font_size/3))
+ text.set("y", str((height/2) + bar_width + (font_size * (i + 1)) + text_offset))
+ 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)
+ text.text = keys[color]
+ layer.append(text)
+
+ # Increase Offset and Color
+ offset = offset + normedvalue
+ color = (color + 1) % 8
+
+ # Draw rectangle
+ layer.append(rect)
+ i += 1
+
+ # set x position for heading line
+ if not rotate:
+ heading_x = width/2 + offset + normedvalue # TODO: adjust
+ else:
+ heading_x = width/2 + offset + normedvalue # TODO: adjust
+
+ if headings and input_type == "\"file\"":
+ headingtext = inkex.etree.Element(inkex.addNS('text', 'svg'))
+ headingtext.set("y", str(height/2 + heading_offset))
+ headingtext.set("x", str(heading_x))
+ headingtext.set("style", "font-size:" + str(font_size + 4)\
+ + "px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:"\
+ + font + ";-inkscape-font-specification:Bitstream Charter;text-align:end;text-anchor:end;fill:"\
+ + font_color)
+
+ headingtext.text = heading
+ layer.append(headingtext)
+
+ def getUnittouu(self, param):
+ try:
+ return inkex.unittouu(param)
+ except AttributeError:
+ return self.unittouu(param)
+
+if __name__ == '__main__':
+ # Create effect instance and apply it.
+ effect = NiceChart()
+ effect.affect()