Tortendiagramme erstellen
Installation • Anwendungsfragen • PDF-Export • DTP • Sonstiges |
Die Schwierigkeit ein Tortendiagramm in Scribus zu erzeugen besteht darin – selbst wenn es einen Weg gäbe mit den verschiedenen Zeichenwerkzeugen von Scribus eines zu erstellen – daß die Programmierung dafür viel zu aufwendig wäre. Wir brauchen also eine elegantere Lösung. Diese Lösung heißt SVG (Scaleable Vector Graphics).
Es funktioniert nicht einen Kreis zu zeichnen und anschließend zu teilen, denn wir wollen Segmente in verschiedenen Größen und jedes davon mit einer andern Füllfarbe. Auf dieser Seite zeige ich wie die notwendigen Informationen für das Python-Skript weiter unten zusammengestellt werden.
SVG-Spezifikationen und Bögen zeichnen
Für ausführliche Informationen über die SVG-Spezifikationen siehe hier
Die erste Zeile legt die Richtungen fest. M ist der Befehl für den Ausgangspunkt – der Kreis(Torten)mittelpunkt – und dieser liegt X=200 und Y=200 (links oben) in unserem SVG-Arbeitsraum. Alle folgenden Befehle in diesem Beispiel sind relativ zu diesem Ausgangspunkt. Mit dem Befehl I (X=150 und Y=0) wird eine Linie 150 Einheiten horizontal nach rechts gezogen, in der Vertikalen ändert sich nichts. (Für diese erste Linie hätte auch der h-Befehl – er zeichnet eine horizontale Linie – benutzt werden können, aber das Skript soll nicht nur für Segmente mit einer horizontalen Linie gelten)
Nun zeichnen wir mit dem a Befehl den Bogen. Die Radien X und Y sind beide auf 150 gesetzt – wären sie nicht gleich dann hätten wir elliptischen Bogen. Als nächstes folgen drei Nullen von denen nur die mittlere für unser Tortendiagramm verändert werden muß: da wir nur zwei Punkte auf einem hypothetischen Kreis brauchen, müßen wir festlegen ob wir die kurze oder die lange Strecke um den Kreis herum gehen wollen. Die Null in der Mitte wählt den kurzen Weg (unser Tortenstück ist kleiner als die halbe Torte)
Nun der komplizierte Teil: die letzen zwei Zahlen (-39, -97) sind relative Abstände vom Punkt 2 zu Punkt 3 – kartesische X,Y-Koordinaten auf dem Monitor. Das z zum Schluß gibt an daß die Figur geschlossen werden soll – zurück zu Punkt 1.
Und woher bekommen wir diese relativen Angaben zu unserem Bogen? -> Trigonometrie
Verschüttete Trigonometriekenntisse reaktivieren
Was repräsentieren Tortendiagramme? Tortendiagramme zeigen uns anschaulich die einzelnen Elemente einer Werteliste, wobei die Größe eines Tortenstückes vom jeweiligen Wert auf der Liste abhängt – die gesamte Torte entspricht der Summe dieser Werte. Um nun herauszufinden wie groß das Tortenstück angezeigt werden soll, mußt Du den einzelnen Wert durch die Summe aller Werte auf der Liste teilen. Da die Torte 360° umfaßt, sieht die Formel so aus:
Winkel= [(Wert)/Summe aller Werte] × 360
heraus kommt dabei der Winkel den das betreffende Tortenstück abdeckt.
Beispiel: Wert=25, Summe aller Werte=100 (der Wert entspricht also einem Viertel -> ein Viertelkreis für das Segment (90°)
[(25/100)] * 360 = 90
Wie geht es mit dem nächsten Segment weiter? Wir bleiben bei unserer Startlinie als X-Achse für unsere Berechnungen. Für die folgenden Segmente gilt weiterhin unser Anfangspunkt. Wir brauchen nicht die Winkel für jedes Segment wissen, wir brauchen nur die "Eck"punkte der Bögen für unsere SVG-Berechnung.
Addiere den Wert des ersten Tortenstückes zum Wert des zweiten hinzu und teile diese Summe durch die gesamte Torte (360°) für die Unterteilung der Torte Winkel = [(Wert1 + Wert2)/Summe aller Werte] × 360 |
Wenn wir nun die Sinus- und Cosinusformel von weiter oben mit diesem stumpfen Winkel benutzen, erhalten wir als Ergebnis die X,Y-Koordinaten für den Punkt 4.
Wir können uns rund um die Torte arbeiten und mit den relativen Berechnungen für alle Punkte die Koordinaten ermitteln wie in piechart.py. Vom mathematischen standpunkt aus erhält man genauere Ergebnisse wenn immer vom gleichen Startpunkt aus gerechnet wird. Bei aufeinanderfolgenden Berechnungen bei denen der Ausgangspunkt jedesmal verschoben ist, addieren sich Fehler durch geringfügige Ungenauigkeiten – als Ergebnis könnte beim letzten Kreissegment eine Lücke oder eine Überlappung auftreten.
piechart.py benutzen
Wenn Du piechart.py startest (Script > Scripte für Scribus) öffnet sich ein Eingabefenster mit der Frage nach einem Namen für die zu speichernde SVG-Datei. An den Namen den Du eingibst wird automatisch .svg angehängt.
Das nächste Eingabefenster erwartet die Daten – die Werte aus denen die Torte berechnet und erstellt wird. Sobald Du einen Wert eingegeben hast und OK klickst (oder die Eingabe-Taste drückst) erscheint dasselbe Eingabefenster (leer) wieder, solange bis Du eine 0 oder Du die Eingabezeile leer läßt und OK Klickst/die Eingabe-Taste drückst.
Ein Meldungsfenster teilt Dir mit daß die Datei (im Skript-Ordner) erstellt wurde.
Einen undokumentierten importSVG() Befehl habe ich auskommentiert, da dies nicht in den Scribus-Versionen < 1.3.x funktioniert. Darüberhinaus auch wenn es in den 1.3.x -Versionen funktioniert – die neu eingefügte Seite hat eine andere Größe als das schon geöffnete Dokument – dieser Befehl ist also im Moment nicht sehr nützlich. Da es sich um einen undokumentierten Befehl handelt ist nicht klar ob andere Parameter dieses Verhalten korrigieren würden.
Einige Beispiele | ||||
---|---|---|---|---|
Hier sind zwei Ausgabebeispiele aus gleichen Daten. Die rechte Torte erhälst Du wenn im Skript die Rahmenfarbe (bordercolor) auf none gesetzt wird, die Linienstärke (stroke-width) auf 0, oder den Form-Rahmen in Scribus ganz normal bearbeitest. | ||||
Dieses letzte Beispiel kann ganz einfach in Scribus nachgearbeitet werden: Zuerst löse die Gruppierung des SVGs auf - Kontextmenü (Rechtsklick auf das Objekt) > Gruppierung auflösen, Tastaturkürzel: Strg+U. |
|
Versuche das nicht zu Hause (in der Schule / bei der Arbeit)
Eine Bemerkung zum Zusammenhang von Ästhetik und genauer Darstellung:
Manchmal sieht man gekippte Tortensegmente, wahrscheinlich um es "besser aussehen" zu lassen. Dieses Beispiel zeigt was passiert wenn Du das tust. In beiden Abbildungen sind die Segmente jeweils aus den gleichen Daten erstellt. Obwohl die Segmente die gleiche Größe haben sollten sind sie klar erkennbar auf der rechten Seite ungleich – die Position des Segmentes auf dem Kreis beeinflußt die Darstellungsgröße. |
piechartDE.py
Das englische Original liegt hier: piechart.py Im folgenden Skript sind die Fensterbezeichnungen, Meldungen und Kommentare übersetzt. Abspeichern als piechartDE.py (In Windows C:\Programme\Scribus 1.3.x\share\scripts - prüfe auch ob dieser Pfad in den Allgemeinen Einstellungen > Allgemein als Pfad für die Skripte gesetzt ist). In diesen Ordner werden auch die erzeugten SVGs gespeichert.
#!/usr/bin/env python # File piechart.py # Created 2006-05-29 # Gregory Pittman # Übersetzung der Captions, Meldungen, Kommentare # 04. Februar 2007 Uchiki # Erstellt automatisch ein Tortendiagramm als SVG-Datei # aus einer Werteliste # Skript funktioniert unter Scribus Versionen 1.2.4.1 und 1.3.x ########################################## from __future__ import division import math import scribus # Wir erstellen eine Liste L, geben Werte ein, und kopieren die Liste zum Ende in eine Datei L = ['<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n'] L.append('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"\n') L.append('"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n') L.append('<svg width="20cm" height="20cm" xmlns="http://www.w3.org/2000/svg" version="1.1">\n') svgfile = scribus.valueDialog('SVG Datei','Name der SVG-Datei\n".svg" wird automatisch angehängt') svgfile = svgfile + '.svg' sectors = [] while 1: newvalue = scribus.valueDialog('Dateneingabe','Werte für die einzelnen Segmente des Tortendiagrammes eingeben\n- zum Beenden 0 eingeben oder leere Eingabezeile') if (newvalue == ''): newvalue = '0' newnum = float(newvalue) if newnum == 0:break sectors.append(newnum) total = 0 i = 0 seg = 0 radius = 150 startx = 200 # X-Koordinate (Monitor) des Anfangspunktes : Mittelpunkt der Torte starty = 200 # Y-Koordinate (Monitor) des Anfangspunktes : Mittelpunkt der Torte lastx = radius # Start Koordinaten des lasty = 0 # ersten Bogens # Falls Dir die Farben nicht gefallen -- hier kannst Du andere angeben # Wenn Du mehr als 9 Farben brauchst, kannst Du die Liste um so viele wie Du willst erweitern colors = ['red','blue','yellow','magenta','orange','slateblue','slategrey','greenyellow','wheat'] bordercolor = 'black' for n in sectors: total = total + n # im voraus zu berechnen, da wir die Summe für die folgende Schleife # brauchen for n in sectors: arc = "0" # zeichnet kurzen Bogen (< 180 Grad) seg = n/total * 360 + seg # aktueller Winkel plus alle vorausgegangenen if ((n/total * 360) > 180): # für den Fall das dieses Segment > 180 Grad ist arc = "1" radseg = math.radians(seg) # Konvertierung zu radians für Cosinus-, Sinusfunktion nextx = int(math.cos(radseg) * radius) nexty = int(math.sin(radseg) * radius) # Das Minuszeichen steht hier (-(lasty)), da in unserer Berechnung der Y-Wert des Graphen die # positiven Zahlen 'nach oben' bedeuten, auf dem Monitor jedoch bedeuten sie 'nach unten'. L.append('<path d="M '+str(startx)+','+str(starty) + ' l '+str(lastx)+','+str(-(lasty))+' a' + str(radius) + ',' + str(radius) + ' 0 ' + arc + ',0 '+str(nextx - lastx)+','+str(-(nexty - lasty))+ ' z" \n') L.append('fill="'+colors[i]+'" stroke="' + bordercolor + '" stroke-width="2" stroke-linejoin="round" />\n') # Wir schreiben die XML-Befehle für jedes Segment einzeln und vergessen die alten Punkte die # nicht mehr gebraucht werden; nextx wird zu lastx für das darauffolgende Segment lastx = nextx lasty = nexty i += 1 L.append('</svg>') # End-Tag für die SVG-Datei output = open(svgfile,'w') # Wir haben alles berechnet und die Liste L output.writelines(L) # mit unseren Befehlen erstellt, jetzt wird output.close() # alles in eine Datei geschrieben. endmessage = svgfile + ' wurde erstellt\nund im Script-Ordner gespeichert' scribus.messageBox("Fertig",endmessage,icon=0,button1=1) # Meldungsfenster zur Information # if scribus.haveDoc(): # Die letzte Anweisung ist auskommentiert - sie erstellt # scribus.importSVG(svgfile) # eine neue Seite. Dies funktioniert aber nicht # bei Scribus-Versionen vor <1.3.x # Die SVG-Datei wird trotzdem gespeichert und kann # manuell importiert werden.
Noch mehr davon
Was ist mit einer Legende für unser Tortendiagramm? Ganz einfach:
- nach lasty = 0 füge folgende Zeile ein:
ykey = 25
- vor der Zeile lastx = nextx füge diese zwei Zeilen ein:
L.append('<rect x="375" y="'+ str(ykey) + '" width="40" height="30" fill="'+colors[i] + '" stroke="black" stroke-width="1"/>\n') ykey = ykey + 35
Wenn Du nun das abgeänderte Skript laufen läßt erhälst Du das:
In der Scribus-Dokumentation findest Du die Empfehlung Texte (z.B. die Werte, oder welche Art Daten dargestellt werden) zu diesem Kreisdiagramm in Scribus einzufügen – vor allem für den evtl. PDF-Export ist das besser (Textauflösung) |
Wenn Du keine Legende (oder einzelne Legendeneinträge) willst, kannst Du wie weiter oben beschrieben die Gruppierung für das SVG auflösen und entsprechend bearbeiten. Möglich wäre auch ein weiteres Eingabefenster zu Beginn des Skriptes einzufügen und abzufragen ob eine Legende gewünscht wird. Dazu wandle die L.append('<rect... Anweisung in eine if -Bedingung (abhängig von der Eingabe) um. Wenn Du keine Legende erstellen willst, spielen die Zuweisung und die Veränderungen in der ykey-Variablen keine Rolle.
Noch mehr?
Sicher, aber das ist Deine "Hausaufgabe"
Schau Dir diesen Skriptausschnitt aus Creating a Graph, Part 2 an:
caption = "Scale for this graph\n\n" "X: " + str(xmark) + "units/mark\n" + "Y: " caption = caption + str(ymark) + "units/mark\n" + str(xscale) + " pts/unit (X)\n" caption = caption + str(yscale) + " pts/unit (Y)" # These caption statements can be combined to one line S = scribus.createText(200, 120, 150, 80) scribus.setTextColor("Blue", S) scribus.setText(caption, S) scribus.setTextAlignment(1, S) scribus.setFont("Nimbus Roman No9 L Bold", S) scribus.setFontSize(8, S)
Mit ein paar Veränderungen kannst Du einen Textrahmen zu piechart.py/piechartDE.py hinzufügen. In diesem stehen dann die Zahlen die Du eingibst, sowie der prozentuale Wert den diese Zahlen repräsentieren – für den Fall das Du das neben dem Tortendiagramm brauchst. Dieser Rahmen wird jedoch in Scribus erzeugt und nicht der SVG-Datei hinzugefügt.