plotting masters - a professional guide - Teil II

Grafische Interpolation und Bestapproximation von numerischen Wertepaaren: Wir wollen Punkte auf einer Zeichenebene über verschiedene Verfahren miteinander verbinden.

Herkömmliche Programmiertechnik mit PHP
Berlin Jun 09


Mit dem Erscheinen der Beta-Version wurden die «prototypischen Schlampereien» bei der Rechnung mit Gleitkommazahlen durch geeignete Rundungstechniken besser konditioniert.

Informelle Spezifikation

    Es ist nach einem kleinen aber flexiblem PHP-Programm zum Zeichnen von kartesischen Diagrammen gesucht. Wir folgen dabei einer intuitiven Vorgehensweise: Eine Zeichenebene dient als Container für unterschiedliche Diagrammtypen, so z.B. Linien-, Punkt- oder Kurvendiagramme. Jeder derartigen Komponente werden numerische Wertepaare übergeben, die dann über die jeweiligen Verfahren interpoliert oder approximiert werden. Wir wollen hier eine stückweise lineare Interpolation (Polygonzug), sowie eine natürliche Spline-Interpolation von Wertepaaren realisieren. Wir werden auch sehen, wie sich sogar Balkendiagramme mit diesem Kontext vertragen können.

Motivation

    Das folgende Programm zeigt, wie mit PHP die obige Anforderung umgesetzt werden kann. Der Programmumfang umfasst keine 1000 Zeilen. Somit ist der geübte Programmierer in der Lage, das Programm an die jeweiligen Bedürfnisse anzupassen.

Ausblick

    Neben den hier vorgestellten Interpolationsverfahren spielt ebenso die Ausgleichsrechnung (Bestapproximation) eine praktische Rolle, deren Graphen im Unterschied dazu nicht zwangsläufig durch alle Wertepaare hindurchgehen. Vielmehr ist man an einer bestmöglichen (gewichteten) Annäherung durch einen Graphen mit vorgegebenen Eigenschaften interessiert. Je nach freien Kapazitäten komme ich darauf zurück.

Beispiel 1

    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 2

    Durch die Angabe eines weiteren Parameters können wie eine sog. Sicht definieren. Dabei geben wir ein Array mit den jeweiligen Koordinaten des Sichtfensters an. Teile des Graphen, die teilweise außerhalb des Fensters liegen, werden abgeschnitten. Schauen wir uns folgendes Beispiel an. Mit

     1 
     2    include ("graph.php");
     3    
     4    # Zeichenebene
     5    $g = new Graph();
     6 
     7    # Komponenten
     8    $c1 = new GraphPoints(0x000000);
     9    $c2 = new GraphLinear(0x0000FF);
    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, 5);
    19    $c1->AddPoint(0, -2);
    20    $c1->AddPoint(1, 9);
    21    $c1->AddPoint(2, -4);
    22 
    23    $c2->AddPoint(-1, 5);
    24    $c2->AddPoint(0, -2);
    25    $c2->AddPoint(1, 9);
    26    $c2->AddPoint(2, -4);
    27 
    28    $c3->AddPoint(-1, 5);
    29    $c3->AddPoint(0, -2);
    30    $c3->AddPoint(1, 9);
    31    $c3->AddPoint(2, -4);
    32 


    und

    1 
    2    $image = $g->Draw(0x000000, 0xFFFFCF, 500, 250, 3, 5, "", "", 
    3                                         0, 0, array(-1, -2, 2, 8));
    4    header("Content-type: image/gif");
    5    imagegif($image);
    6 


    erhalten wir folgende Ausgabe



Beispiel 3

    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, definieren wir eine angemessene Sicht. Mit

    1 
    2    $c1 = new GraphBar(0x000000, 0x0000FF, 30);
    3    $image = $g->Draw(0x000000, 0xFFFFCF, 500, 250, 6, 9, "", "", 
    4                                          20, 0,array(-1, 0, 5, 9));
    5 


    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);
     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, "", "", 
    44                                          20, 0,array(-1, 0, 5, 9));
    45    header("Content-type: image/gif");
    46    imagegif($image);
    47 


    erhalten.


Beispiel 4

    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);
     9    $c2 = new GraphBar(0x000000, 0xFF0000, 15);
    10    $c3 = new GraphBar(0x000000, 0x0000FF, 15);
    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, "", "",  
    43                                          20, 0,array(-1, 0, 5, 9));
    44    header("Content-type: image/gif");
    45    imagegif($image);
    46 


    Als Ausgabe erhalten wir:



    Die Zeichnung von waagerechten Balken folgt.

Beispiel 5

    Eine andere Möglichkeit die zu interpolierenden Punkte anzugeben besteht darin, diese durch eine Funktion berechnen zu lassen. In unserem Fall wollen wir die berechneten Punkte stückweise linear interpolieren. Hierfür definieren wir die Funktionalität durch Evaluate und übergeben eine Instanz an GraphFunction gefolgt von den zu interpolierenden Intervallgrenzen.

     1 
     2    # Zeichenebene
     3    $g = new Graph();
     4 
     5    # Beispielfunktionen
     6    class FuncSin implements Func 
     7    {
     8       public function Evaluate($x)
     9       {
    10          return sin($x); 
    11       }    
    12    }
    13    class FuncCos implements Func 
    14    {
    15       public function Evaluate($x)
    16       {
    17          return cos($x); 
    18       }    
    19    }
    20    class FuncPol implements Func 
    21    {
    22       private $grad = 0;
    23       private $coeff = array();
    24       
    25       public function __construct($coeff = array())
    26       {
    27          $this->grad = sizeOf($coeff);
    28          $this->coeff = $coeff;
    29       }
    30       public function Evaluate($x)
    31       {
    32          $y = 0;
    33          for ($g = 0; $g < $this->grad; $g++)
    34          $y += $this->coeff[$this->grad-$g-1] * pow($x, $g);
    35          return $y; 
    36       }    
    37    }
    38 
    39    # Komponenten
    40    $c1 = new GraphFunction(0x0000FF, new FuncSin(), -4, 3);
    41    $c2 = new GraphFunction(0xFF0000, new FuncCos(), -4, 3);
    42    $c3 = new GraphFunction(0x00FF00, 
    43          new FuncPol(array(1/20, 3/20, -9/20, -27/20,-2/20,3)), -4, 3);
    44    
    45    # Komponenten binden
    46    $g->AddComponent($c1);
    47    $g->AddComponent($c2);
    48    $g->AddComponent($c3);
    49      
    50    # Ausgabe
    51    $image = $g->Draw(0x000000, 0xFFFFCF, 500, 250, 7, 6);
    52    header("Content-type: image/gif");
    53    imagegif($image);
    54 
    55 


    Als Ausgabe erhalten wir:



Ratings


Sehr gutes Tutorial nur leider fehlt am Ende der komplette Code,
es währe nett wenn sie den noch nachreichen könnten, vielen Dank und weiter so :)
Written by Saerdna09 At 17.11.2009 14:47:25

Interessantes Tutorial. Hier steckt viel KnowHow und Leidenschaft drin ;)
Written by admin At 29.09.2009 14:47:50

Here you can write a comment


Please enter at least 10 characters.
Loading... Please wait.
* Pflichtangabe

Related topics

abhängige Listen

In einem Formular sollen neben mehreren anderen Eingabefeldern auch zwei Listen (Select-Felder) zum Einsatz kommen. Dabei soll der Inhalt der zweiten Liste vom gewählten Wert der ersten Liste abhängig verändert werden. ...

Patrick_PQ

Autor : Patrick_PQ
Category: mySQL-Tutorials

Einfaches News-Script

Das hier ist ein kleines Tutorial, um zu zeigen wie so ein News-Script aussehen kann. Im Grunde ist es nichts anderes als ein Gästebuch, in welches jedoch nur der Webmaster (oder sonstige authorisierte Personen) etwas eintragen kann. Natürlich kann man ...

pik

Autor : pik
Category: PHP-Tutorials

PHP cURL Tutorial: Using cURL to Make HTTP Requests

cURL is a powerful PHP extension that allows you to communicate with different servers using various protocols, including HTTP, HTTPS, FTP, and more. ...

TheMax

Autor : TheMax
Category: PHP-Tutorials

Programmierung - SQL

Dieser SQL-Kurs wendet sich vor allem an Programmierer, die mit Hilfe von SQL auf Datebaken zugreifen, und an alle, die Datenbanken neu entwerfen, erweitern oder abändern wollen ...

webmaster205@

Autor : webmaster205@
Category: mySQL-Tutorials

Reguläre Ausdrücke

In diesem Tutorial wird erklärt, wie reguläre Ausdrücke aufgebaut sind, was die Metacharaktere (Zeichen mit spezieller Bedeutung) eines Patterns bedeuten, und wie man das ganze in PHP umsetzt. Es werden nur die wichtigsten Teile erklärt, für weiterführend ...

webmaster2@

Autor : webmaster2@
Category: PHP-Tutorials

How to effectively perform complex queries with SQL queries in MySQLi?

This MySQL tutorial explains how to efficiently perform complex SQL queries in MySQLi. We will look at various aspects of database querying and learn specific methods to fully utilise the power of MySQLi. ...

TheMax

Autor : TheMax
Category: mySQL-Tutorials

Variablen über mehrere Seiten hinweg verwenden - der Session-Befehl macht 's möglich!

Oberste Voraussetzung um Session-Befehle korrekt auszuführen ist, dass der Provider a) PHP und b) das speichern von Sessions auf dem Server überhaupt erlaubt. Wird der Session-Befehl unterstützt jedoch nicht das direkte speichern von Sessions bzw. Sess ...

ndo@

Autor : ndo@
Category: PHP-Tutorials

Umfragenscript

Dieses Tutorial zeigt wie man mit eine Umfragescript mit einen TXT-Datenbank erstellen kann. ...

kiliandreissig@

Autor : kiliandreissig@
Category: PHP-Tutorials

Publish a tutorial

Share your knowledge with other developers worldwide

Share your knowledge with other developers worldwide

You are a professional in your field and want to share your knowledge, then sign up now and share it with our PHP community

learn more

Publish a tutorial