# -*- coding: utf-8 -*-
#
# Copyright 2011-2016
#
# Christoph Sterz
# Florian Weber
# Maren Hachmann
#
# 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 *
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"]
}
"""
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
"""
"""
Constructor.
Defines the "--what" option of a script.
"""
# Call the base class constructor.
# Define string option "--what" with "-w" shortcut and default chart values.
help='Chart Values')
# Define string option "--type" with "-t" shortcut.
help="Chart Type")
# Define bool option "--blur" with "-b" shortcut.
help="Blur Type")
# Define string option "--file" with "-f" shortcut.
help="Name of File")
# Define string option "--input_type" with "-i" shortcut.
help="Chart Type")
# Define string option "--delimiter" with "-d" shortcut.
help="delimiter")
# Define string option "--colors" with "-c" shortcut.
help="color-scheme")
# Define string option "--colors_override"
help="color-scheme-override")
help="reverse color-scheme")
help="column that contains the keys")
help="column that contains the values")
help="encoding of the CSV file, e.g. utf-8")
help="the first line of the CSV file consists of headings for the columns")
help="Draw barchart horizontally")
help="width of bars")
help="radius of pie-charts")
help="height of bars")
help="distance between bars")
help="distance between bar and descriptions")
help="distance between chart and chart title")
help="work around aliasing effects by letting pie chart segments overlap")
help="font of description")
help="font size of description")
help="font color of description")
#Dummy:
help="Show values in chart")
"""
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
keys = []
values = []
orig_values = []
cnt = 0
if input_type == "\"file\"":
#make sure that there is at least one value (someone may want to use it as description)
# allow to parse headings as strings
else:
# replace comma decimal separator from file by colon,
# to avoid file editing for people whose programs output
# values with comma
elif input_type == "\"direct_input\"":
# warn about negative values (not yet supported)
if value < 0:
return
# Get script's "--type" option value.
if charttype == "pie_abs":
charttype = "pie"
# Get access to main SVG document element and get its dimensions.
# Get the page attibutes:
# Create a new layer.
# Check if a drop shadow should be drawn:
if draw_blur:
# Get defs of Document
if defs == None:
# Create new Filter
('width', "3"),
('x', '-0.5'), ('y', '-0.5')]:
# Append Gaussian Blur to that Filter
# Set Default Colors
else:
else:
#to be sure we create a fallback:
# Those values should be self-explanatory:
# offset of the description in stacked-bar-charts:
# stacked_bar_text_offset=self.options.stacked_bar_text_offset
# prevents ugly aliasing effects between pie chart segments by overlapping
# get font
# get rotation
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:
except ValueError:
value_max = 0.0
# Draw Single bars with their shadows
# draw drop shadow, if necessary
if draw_blur:
# Create shadow element
# Set chart position to center of document. Make it horizontal or vertical
if not rotate:
else:
# Set shadow blur (connect to filter object in xml path)
# Create rectangle element
# Set chart position to center of document.
if not rotate:
else:
# If keys are given, create text elements
if keys_present:
if not rotate: #=vertical
#y after rotation:
#x after rotation:
else: #=horizontal
+ "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)
# Increase Offset and Color
#offset=offset+bar_width+bar_offset
# Connect elements together.
if draw_blur:
if keys_present:
if show_values:
if not rotate: #=vertical
#y after rotation:
#x after rotation:
else: #=horizontal
+ "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)
# set x position for heading line
if not rotate:
else:
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:
# Add a grey background circle with a light stroke
#create value sum in order to divide the slices
try:
except ValueError:
valuesum = 0
if pie_abs:
valuesum = 100
# Set an offsetangle
offset = 0
# Draw single slices
for i in range(num_values):
# Calculate the PI-angles for start and end
# proper overlapping
if segment_overlap:
if i != num_values-1:
if i == 0:
#then add the slice
#If text is given, draw short paths and add the text
if keys_present:
+ "px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1")
text.set("y", str((height/2) + (pie_radius + text_offset) * math.sin(angle/2 + offset) + font_size/3))
+ "px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:" \
# check if it is right or left of the Pie
else:
if show_values:
if pie_abs:
# increase the rotation-offset and the colorcycle-position
# append the objects to the extension-layer
# set x position for heading line
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:
except ValueError:
valuesum = 0.0
# Init offset
offset = 0
if draw_blur:
# Create rectangle element
# Set chart position to center of document.
if not rotate:
else:
# Set rectangle properties
if not rotate:
else:
# Set shadow blur (connect to filter object in xml path)
i = 0
# Draw Single bars
# Calculate the individual heights normalized on 100units
# Create rectangle element
# Set chart position to center of document.
if not rotate:
else:
# Set rectangle properties
if not rotate:
else:
#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:
+ "px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1")
+ "px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:"
else:
+ "px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1")
+ "px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:"
# Increase Offset and Color
# Draw rectangle
i += 1
# set x position for heading line
if not rotate:
else:
+ "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)
try:
except AttributeError:
if __name__ == '__main__':
# Create effect instance and apply it.