plotting masters - a professional guide - Teil IGrafische Interpolation und Bestapproximation von numerischen Wertepaaren. Mit anderen Worten: Wir wollen Punkte auf einer Zeichenebene über verschiedene Verfahren miteinander verbinden. Die beispielorientierte Anwendung (Teil I) ist einfach und für jeden verständlich. Die formale Umsetzung (Teil II + III) sowie das individuelle Erweiterungspotential richtet sich hingegen an fortgeschrittene Programmierer.
1
1
mit PHP 1. Fassung Berlin Jun 09 Daniel Krompass X.P. 2. Fassung Berlin Sep 09 Daniel Krompass Prototyp 3. Fassung Berlin Feb 10 Daniel Krompass Release ![]() Ich habe mehr Werkzeuge, als meine Freundin Schuhe hat.
Bevor es los geht, möchte ich mich bei den Plattformbetreibern für das regelmäßige Update meiner Dokumentation bedanken. Mit dem Erscheinen der Release-Version wurden die «prototypischen Schlampereien» bei der Rechnung mit Gleitkommazahlen durch geeignete Rundungstechniken besser konditioniert. Die diesbezüglich korrigierte Dokumentation zu Teil II) folgt in Kürze. Aus dem Inhalt:
Informelle Spezifikation
Zielgruppe
Hintergrund
Motivation
Ein wissenschaftlicher Schachzug brächte eine Technologie hervor, die auf Grund des vorhandenen Potenzials alle bisherigen Techniken überholt. Ob der König am Leben bleibt, muss noch entschieden werden. Ausblick
Teil I
|
|||||||||||||||||||||||||
| Id | Name | Gehalt |
| 1 | Martin A. | 3.230,00 |
| 2 | Theresa B. | 3.032,00 |
| 3 | Andrea C. | 1.897,00 |
| 4 | Günter D. | 2.980,00 |
Wie gehabt generieren wir wieder unseren Graphen in üblicher Form.
1
2 $g = new Graph();
3 $c1 = new GraphNaturalSpline(0xFF0000);
4 $c2 = new GraphPoints(0x000000);
5 $g->AddComponent($c1);
6 $g->AddComponent($c2);
7
Die Werte lesen wir über eine entsprechende mySQL-Anweisung aus der obigen Datentabelle aus. Mehr zum Thema mySQL findet man unter http://www.php-resource.de/tutorials/tutorial,27 oder http://www.php-resource.de/tutorials/tutorial,44. Wir probieren zunächst einen offensichtlichen Ansatz:
Zuerst überlegen wir uns, wie wir unsere Map-Funktion so definieren, dass wir auf der X-Achse die Namen der jeweilgen Mitarbeiter zu stehen haben. Wir müssen also von einer Zahl auf den zugehörigen Namen eindeutig schließen können. Es bietet sich dabei die Assoziation zwischen der Id-Nummer und dem zugehörigen Namen an.
1
2 function ToEmployer($item)
3 {
4 $result = mysql_query("SELECT Name
5 FROM mitarbeiter
6 WHERE Id = $item");
7
8 return mysql_result($result, 0, 0);
9 }
10
Sodann lesen wir die Werte aus der Datentabelle mit
1
2 $result = mysql_query("SELECT Id, Name, Gehalt
3 FROM mitarbeiter");
4 for ($i = 0; $row = mysql_fetch_array($result); $i++)
5 {
6 $c1->AddPoint((int)$row[0], (int)$row[2]);
7 $c2->AddPoint((int)$row[0], (int)$row[2]);
8 }
9
aus und erhalten mit
1
2 $image = $g->Draw(0x000000, 0xFFFFCF, 600, 350, 3, 5, "ToEmployer", "ToCurrency");
3 header("Content-type: image/gif");
4 imagegif($image);
5

Wenn Sie nun eine spezielle Sortierung z.B. ORDER BY Gehalt ASC fordern, dann hätte dies keine Auswirkungen auf die grafische Ausgabe. Das liegt daran, dass der Spline seinen Kurvenzug unabhängig von der Einfügereihenfolge der Knotenpunkte zeichnet. Achten Sie stets darauf, dass jede mathematische Funktion strikt von links nach rechts gezeichnet wird. Insbesondere werden alle Punkte stets nach ihrem X-Wert aufsteigend sortiert, bevor diese zur Brechnung herangezogen werden. Wir können also nicht mit der Id aus der Datentabelle als X-Wert sinnvoll arbeiten, und müssen daher eine eigene Id auf Programmebene erzeugen:
1
2 $result = mysql_query("SELECT Id, Name, Gehalt
3 FROM mitarbeiter2
4 ORDER BY Gehalt ASC");
5
6 for ($i = 0; $row = mysql_fetch_array($result); $i++)
7 {
8 $mitarbeiter[$i] = $row[1];
9 $c1->AddPoint($i, (int)$row[2]);
10 $c2->AddPoint($i, (int)$row[2]);
11 }
12
13 function ToEmployer($item)
14 {
15 global $mitarbeiter;
16 return $mitarbeiter[$item];
17 }
18
Nun erhalten wir jede gewünschte Sortierung «richtig» gezeichnet.
Beispiel 4
-
Ein etwas abtrünniges Beispiel - Polygonzüge
1
2 # Zeichenebene
3 $g = new Graph();
4
5 # Komponenten
6 $c1 = new GraphLinear(0x0000FF);
7 $c2 = new GraphLinear(0xFF0000);
8
9 # Komponenten binden
10 $g->AddComponent($c1);
11 $g->AddComponent($c2);
12
13 # Werte hinzufügen
14 $c1->AddPoint(0, 2);
15 $c1->AddPoint(1, 2);
16 $c1->AddPoint(2, 3);
17 $c1->AddPoint(2, 4);
18 $c1->AddPoint(1, 5);
19 $c1->AddPoint(0, 5);
20 $c1->AddPoint(-1, 4);
21 $c1->AddPoint(-1, 3);
22 $c1->AddPoint(0, 2);
23
24 $c2->AddPoint(0, 2);
25 $c2->AddPoint(0, 1);
26 $c2->AddPoint(-1, 0);
27 $c2->AddPoint(-2, 0);
28 $c2->AddPoint(-3, 1);
29 $c2->AddPoint(-3, 2);
30 $c2->AddPoint(-2, 3);
31 $c2->AddPoint(-1, 3);
32
33 # Ausgabe
34 $image = $g->Draw(0x000000, 0xFFFFCF, 600, 350, 5, 5);
35 header("Content-type: image/gif");
36 imagegif($image);
37
Wir erhalten:

Der Sinn von sog. Linienzügen zeigt sich bei praktischen Vorgängen, die einen senkrechten Anstieg zur Folge haben. Dies können z.B. Gehalts- oder Auszahlungsänderungen sein. Wir betrachten ein Beispiel:
1
2 include ("graph.php");
3
4 # Zeichenebene
5 $g = new Graph();
6
7 # Komponenten
8 $c1 = new GraphLinear(0x0000FF);
9 $c2 = new GraphLinear(0xFF0000);
10
11 # Komponenten binden
12 $g->AddComponent($c1);
13 $g->AddComponent($c2);
14
15 # Werte hinzufügen
16 $c1->AddPoint(0, 4);
17 $c1->AddPoint(1, 4);
18 $c1->AddPoint(1, 3);
19 $c1->AddPoint(2, 3);
20 $c1->AddPoint(2, 4);
21 $c1->AddPoint(2.5, 4);
22 $c1->AddPoint(2.5, -2);
23 $c1->AddPoint(3.5, -2);
24 $c1->AddPoint(3.5, 6);
25
26 $c2->AddPoint(-1, 0);
27 $c2->AddPoint(-1, 2);
28 $c2->AddPoint(0, 2);
29 $c2->AddPoint(0, 0);
30 $c2->AddPoint(1, 0);
31 $c2->AddPoint(1, 2);
32 $c2->AddPoint(2, 2);
33 $c2->AddPoint(2, 0);
34 $c2->AddPoint(3, 0);
35 $c2->AddPoint(3, 2);
36 $c2->AddPoint(4, 2);
37 $c2->AddPoint(4, 0);
38
39 # Ausgabe
40 $image = $g->Draw(0x000000, 0xFFFFCF, 500, 250, 5, 4, "ToDate", "ToCurrency");
41 header("Content-type: image/gif");
42 imagegif($image);
43
Wir erhalten:

Beispiel 5 (fortgeschritten)
-
Es gibt Fälle, bei denen es nicht erwünscht ist, dass der kleinste Y-Wert stets auf der X-Achse, oder der kleinste X-Wert stets auf der Y-Achse liegt. Wir werden weiter unten weitere Probleme ansprechen, die mit den folgenden Verfahren gelöst werden können. Um die Achsenbeschriftungen (nicht die Achsen selbst), und somit auch den gesamten Graphen horizontal und/oder vertikal zu stauchen (unsinnigerweise auch strecken), können zwei weitere Parameter für die X- bzw. Y-Stauchung angegeben werden. Mit
1
2 # Zeichenebene
3 $g = new Graph();
4
5 # Komponenten
6 $c1 = new GraphPoints(0x000000);
7 $c2 = new GraphLinear(0x0000FF);
8 $c3 = new GraphNaturalSpline(0xFF0000);
9
10 # Komponenten binden
11 $g->AddComponent($c1);
12 $g->AddComponent($c2);
13 $g->AddComponent($c3);
14
15 # Wertepaare
16 $c1->AddPoint(-1, 5);
17 $c1->AddPoint(0, -2);
18 $c1->AddPoint(1, 9);
19 $c1->AddPoint(2, -4);
20
21 $c2->AddPoint(-1, 5);
22 $c2->AddPoint(0, -2);
23 $c2->AddPoint(1, 9);
24 $c2->AddPoint(2, -4);
25
26 $c3->AddPoint(-1, 5);
27 $c3->AddPoint(0, -2);
28 $c3->AddPoint(1, 9);
29 $c3->AddPoint(2, -4);
30
und
1
2 $image = $g->Draw(0x000000, 0xFFFFCF, 600, 350, 3, 7, "", "", 50, 50);
3 header("Content-type: image/gif");
4 imagegif($image);
5
erhalten wir eine horizontale und eine vertikale Stauchung von 50 Pixel.
Beispiel 6 (fortgeschritten)
-
Auch die X- und Y-Basis (kleinster X- und Y-Wert) einer Komponente kann über zwei weitere Parameter verschoben werden. Mit
1
2 # Zeichenebene
3 $g = new Graph();
4
5 # Komponenten
6 $c1 = new GraphPoints(0x000000);
7 $c2 = new GraphLinear(0x0000FF);
8 $c3 = new GraphNaturalSpline(0xFF0000, 1, 2);
9
10 # Komponenten binden
11 $g->AddComponent($c1);
12 $g->AddComponent($c2);
13 $g->AddComponent($c3);
14
15 # Wertepaare
16 $c1->AddPoint(-1, 5);
17 $c1->AddPoint(0, -2);
18 $c1->AddPoint(1, 9);
19 $c1->AddPoint(2, -4);
20
21 $c2->AddPoint(-1, 5);
22 $c2->AddPoint(0, -2);
23 $c2->AddPoint(1, 9);
24 $c2->AddPoint(2, -4);
25
26 $c3->AddPoint(-1, 5);
27 $c3->AddPoint(0, -2);
28 $c3->AddPoint(1, 9);
29 $c3->AddPoint(2, -4);
30
und
1
2 $image = $g->Draw(0x000000, 0xFFFFCF, 600, 350, 3, 7, "", "", 50, 50);
3 header("Content-type: image/gif");
4 imagegif($image);
5
erhalten wir eine Verschiebung

Im Grunde passiert nichts weiter, als dass das X oder Y-Minimum um den angegebenen Wert (hier x=1, y=2) vermindert wird. Wir erhalten einen entsprechenden Abstand zu den Achsen.
Beispiel 7 (fortgeschritten)
-
Die sog. Balkendiagramme sind etwas artfremd, und lassen sich daher nicht so offensichtlich in den vorgegeben mathematischen Kontext sinnvoll einbinden. Die beiden zuletzt vorgestellten Verfahrenstechniken werden uns dabei helfen. Betrachten wir zunächst in gewohnter Weise:
1
2 # Zeichenebene
3 $g = new Graph();
4
5 # Komponenten
6 $c1 = new GraphBar(0x000000, 0x0000FF, 30);
7
8 # Komponenten binden
9 $g->AddComponent($c1);
10
11 # Wertepaare
12 $c1->AddPoint(-1, 4);
13 $c1->AddPoint(0, 7);
14 $c1->AddPoint(1, 2);
15 $c1->AddPoint(2, 9);
16 $c1->AddPoint(3, 8);
17 $c1->AddPoint(4, 4);
18 $c1->AddPoint(5, 2);
19
20 # Ausgabe
21 $image = $g->Draw(0x000000, 0xFFFFCF, 500, 250, 6, 7);
22 header("Content-type: image/gif");
23 imagegif($image);
24
Der Konstruktor nimmt zwei RGB-Farbwerte für den links-recht-Farbverlauf, sowie die Balkenbreite von 30 Pixel entgegen. Als Ausgabe erhalten wir:

Es fallen zwei unschöne Dinge auf. Der linke Balken überschneidet unsere Y-Achse und es fehlen zwei Balken. Das erste Problem lösen wir mit einer horizontalen Stauchung von - sagen wir 20 Pixel. Mit
1
2 $image = $g->Draw(0x000000, 0xFFFFCF, 500, 250, 6, 7, "", "", 20, 0);
3
erhalten wir:

Damit unsere kleinsten Balken sichtbar werden, erniedrigen wir die Y-Basis der Komponente um 2, d.h. der kleinste Y-Wert wird um 2 weiter minimiert. Mit
1
2 $c1 = new GraphBar(0x000000, 0x0000FF, 30, 0, 2);
3 $image = $g->Draw(0x000000, 0xFFFFCF, 500, 250, 6, 9, "", "", 20, 0);
4
und den entsprechenden Wertepaaren erhalten wir die gewünschte Ausgabe:

Achten Sie auf die Werte der Y-Achse. Natürlich bleibt die multible Anwendung mit
1
2 include ("graph.php");
3
4 # Zeichenebene
5 $g = new Graph();
6
7 # Komponenten
8 $c1 = new GraphBar(0x000000, 0x0000FF, 30, 0, 2);
9 $c2 = new GraphPoints(0x000000);
10 $c3 = new GraphNaturalSpline(0xFF0000);
11
12 # Komponenten binden
13 $g->AddComponent($c1);
14 $g->AddComponent($c2);
15 $g->AddComponent($c3);
16
17 # Wertepaare
18 $c1->AddPoint(-1, 4);
19 $c1->AddPoint(0, 7);
20 $c1->AddPoint(1, 2);
21 $c1->AddPoint(2, 9);
22 $c1->AddPoint(3, 8);
23 $c1->AddPoint(4, 4);
24 $c1->AddPoint(5, 2);
25
26 $c2->AddPoint(-1, 4);
27 $c2->AddPoint(0, 7);
28 $c2->AddPoint(1, 2);
29 $c2->AddPoint(2, 9);
30 $c2->AddPoint(3, 8);
31 $c2->AddPoint(4, 4);
32 $c2->AddPoint(5, 2);
33
34 $c3->AddPoint(-1, 4);
35 $c3->AddPoint(0, 7);
36 $c3->AddPoint(1, 2);
37 $c3->AddPoint(2, 9);
38 $c3->AddPoint(3, 8);
39 $c3->AddPoint(4, 4);
40 $c3->AddPoint(5, 2);
41
42 # Ausgabe
43 $image = $g->Draw(0x000000, 0xFFFFCF, 500, 250, 6, 5, "", "", 20, 0);
44 header("Content-type: image/gif");
45 imagegif($image);
46
erhalten.
Beispiel 8 (fortgeschritten)
-
Eine Modifikation der Klasse GraphBar (siehe Teil II - Implementierungsdetails) ermöglicht Balkendiagramme zu zeichnen, deren «Fuss» nicht zwangsläufig auf der X-Achse liegt. Vielmehr wollen wir von einem gegebenen Punkt aus nicht nach «unten» zur X-Achse hin, sondern in einer vorgegebenen Länge nach «oben» zeichnen. Man betrachte dazu folgendes Szenario und man achte auf die Unterschiede der Methode AddPoint, denn das optionale dritte Argument gibt die Balkenlänge an.
1
2 include ("graph.php");
3
4 # Zeichenebene
5 $g = new Graph();
6
7 # Komponenten
8 $c1 = new GraphBar(0x000000, 0xFFFF00, 15, 0, 2);
9 $c2 = new GraphBar(0x000000, 0xFF0000, 15, 0, 2);
10 $c3 = new GraphBar(0x000000, 0x0000FF, 15, 0, 2);
11
12 # Komponenten binden
13 $g->AddComponent($c1);
14 $g->AddComponent($c2);
15 $g->AddComponent($c3);
16
17 # Werte hinzufügen
18 $c1->AddPoint(-1, 4);
19 $c1->AddPoint(0, 7);
20 $c1->AddPoint(1, 2);
21 $c1->AddPoint(2, 9);
22 $c1->AddPoint(7, 4);
23 $c1->AddPoint(8, 7);
24 $c1->AddPoint(9, 2);
25 $c1->AddPoint(10, 9);
26
27 $c2->AddPoint(-1, 4, 4);
28 $c2->AddPoint(0, 7, 2);
29 $c2->AddPoint(1, 2, 3);
30 $c2->AddPoint(2, 9, 5);
31 $c2->AddPoint(3, 4, 4);
32 $c2->AddPoint(4, 7, 2);
33 $c2->AddPoint(5, 2, 3);
34 $c2->AddPoint(6, 9, 5);
35
36 $c3->AddPoint(7, 5, 4);
37 $c3->AddPoint(8, 8, 2);
38 $c3->AddPoint(9, 3, 3);
39 $c3->AddPoint(10, 10, 5);
40
41 # Ausgabe
42 $image = $g->Draw(0x000000, 0xFFFFCF, 500, 250, 5, 4, "", "", 20, 0);
43 header("Content-type: image/gif");
44 imagegif($image);
45
Als Ausgabe erhalten wir:

Die Zeichnung von waagerechten Balken folgt.
|
||
![]() EVAMasters |
Status Premium Mitglied Beruf Mitglied seit: letzte Aktivität |
Tutorial bewerten
Hat Ihnen dieses Tutorial gefallen? Dann bewerten Sie es jetzt! Fünf Sterne bedeutet "Sehr gut", ein Stern "Unzureichend".
aktuelle Artikel
PHP 5.3.2 60 Fehler weniger |
500. Artikel bei phphatesme.com22.02.2010 | |

|30.01.2010 |




