Wieviel Plattenplatz hat Michael Schilli zuhause noch auf seinem
Rechner frei? Diese Frage interessiert definitiv niemanden.
Doch heute soll es darum gehen, Daten mit dem
Chart-Package von David Bonner augenfreundlich anzuzeigen -
und das gleich auf vier verschiedene Arten!
Und da kommt die Ausgabe des df-Kommandos, das unter Linux
die Auslastung der konfigurierten Platten-Partitionen auflistet,
gerade recht:
Filesystem 1024-blocks Used Available Capacity Mounted on
/dev/hda2 839001 597769 197888 71% /
/dev/hda1 806144 457376 348768 57% /mnt1
/dev/hdc5 1249696 1213472 36224 97% /mnt2
Abbildung 1 zeigt, was das unten vorgestellte
CGI-Skript space.pl mit dem Chart-Modul
(siehe Kasten Installation) daraus produziert:
|
| Abb.1: Plattenplatzauslastung per CGI |
So funktioniert's: Die Zeilen 5 und 6 ziehen Lincoln Steins
praktische CGI-Library und erzeugen ein CGI-Objekt $q, das den
CGI-Kleinkram wie die Ausgabe des Headers, das Lesen der
Eingabeparameter oder auch die Ausgabe einzelner Tags
vereinfacht. Der in Zeile 9 definierte (Pseudo-)Signal-Handler läßt
space.pl, falls es fehlerbedingt auf eine die-Anweisung
läuft, nicht einfach abbrechen und den Web-Server ein unschönes
Internal Server Error yada yada yada anzeigen, sondern gibt
die detaillierte Fehlermeldung formatiert als HTML-Seite aus.
Wenn space.pl keinen CGI-Parameter mit dem
Namen graph mitbekommt (was beim ersten Aufruf der Fall ist),
verzweigt Zeile 23 zu den Anweisungen ab Zeile 25, die
zunächst den HTTP-Header und die HTML-Startsequenz ausgeben, und dann,
über die for-Schleife von Zeile 26, in etwa folgendes:
<IMG SRC="/cgi-bin/space.pl?graph=bars" ... >
<IMG SRC="/cgi-bin/space.pl?graph=stackedbars" ... > <BR>
<IMG SRC="/cgi-bin/space.pl?graph=pie" ... >
<IMG SRC="/cgi-bin/space.pl?graph=linespoints" ... >
space.pl gibt also eine HTML-Seite aus, die
<IMG>-Tags enthält. Diese fordern wiederum GIF-Bilder an,
die dynamisch erzeugt werden - und zwar von niemand anderem als
space.pl selbst: Die in den Tags verpackten space.pl-Requests übergeben
- nach der GET-Methode - Werte für den Parameter graph.
Falls graph z.B. den Wert "bars" führt, springt space.pl von
Zeile 35 nach 37, holt das Chart::Bars-Paket aus der Chart-Sammlung
herein, malt die
entsprechende Graphik, gibt sie mitsamt einem passenden HTTP-Header
aus und - verabschiedet sich.
Das df-Kommando aus Zeile 12 liefert
die eingangs vorgestellten Rohdaten für die Darstellung.
Die Zeilen 14 bis 18 modeln sie in folgende Arrays um:
@filesystems = ("/", "/mnt1", "/mnt1");
@freespace = (197.888, 348.768, 36.224);
@usedspace = (597.769, 457.376, 1213.472);
Der Array @filesystems enthält also die (Verzeichnis-)Namen der
verfügbaren Dateisysteme. In der gleichen Reihenfolge stehen
in @freespace die Anzahl der in jedem dieser Dateisysteme
verfügbaren Bytes, in @usedspace die der verbrauchten.
Nun geht's an die Darstellung, abhängig vom verlangten Graphiktyp.
Für eine einfache Graphik, die, wie in Abbildung 1 links oben,
den verfübaren Plattenplatz pro Dateisystem als
Säule ausgibt, erzeugt Zeile 38 ein Chart::Bars-Objekt,
mit den Pixel-Ausmaßen 200 x 200.
Die nachfolgend aufgerufenen Methoden vervollständigen
den Graphen nach und nach, bis
ihn schließlich eine letzte als GIF-Bild ausspuckt.
Zeile 39 setzt die Überschrift, die hier - zu Demonstrationszwecken -
Chart::Bars heissen soll.
Die add_dataset-Methode in Zeile 40 legt die X-Werte der Graphik
fest: die Namen der Dateisysteme. Zeile 41 schließlich gibt die
zugehörigen Y-Werte an: die Hoehe der einzelnen Balken.
Ist nicht mehr angegeben, normiert Chart::Bars
selbständig den Graphen, zeichnet die Achsen und alles was
dazugehört. Der Datensatz (die Menge aller X- und Y-Werte) erhält
in der 'Legende' rechts im Bild automatisch den Namen ``Dataset 1'' zugewiesen.
Die cgi_gif()-Methode in Zeile 42 gibt das GIF samt passendem
CGI-Header aus - Ende Banane!
Die Chart::StackedBars-Graphik in Abbildung 1 rechts oben zeigt
die etwas mehr aufgemotzte Darstellung zweier Datensätze, nicht,
wie Chart::Bars
es tun würde, neben-, sondern übereinander. So kommt neben
den Teilbeträgen (freie und belegte Bytes) auch die Summe
(Plattenkapazität) der Dateisysteme zum Vorschein.
Die erste add_dataset-Methode fügt, wie gehabt, die X-Werte
(Dateisysteme) ein, die zweite die verbrauchten Bytes und die
dritte die freien.
Zur Verschönerung setzt space.pl in den Zeilen
48 bis 54 noch zusätzliche
Parameter wie x_label/y_label
(Beschriftung für die X bzw. Y-Achse), legend_labels (eine
Referenz auf ein Array mit sinnvollen Bezeichnungen für die
Datensätze statt des sonst automatisch gewählten "Dataset N")
und max_val (den in Y-Richtung maximal dargestellten
Wert).
Ist grid_lines auf "True" gesetzt, zeichnet Chart ein Gitter
in den Graphenbereich, das die Zuordnung der Y-Werte vereinfacht.
Die Farben für die Datensätze bestimmt
colors, eine Referenz auf einen Array von Arrayreferenzen
(hier zeigt sich, wer seine Hausaufgaben gemacht hat)
mit den RGB-Werten der entsprechenden Farben. [255,0,0] ist
hierbei schlichtes Rot, [0,255,0] reines Grün.
Die freien und die belegten Bytes auf der "/"-Partition ergeben
(wer hätte das gedacht?)
zusammen 100% - ein Anwendungsfall für eine simple Kuchengraphik
mit zwei Anteilen!
Zeile 64 erzeugt das notwendige Chart::Pie-Objekt,
Zeile 66 setzt die
Beschriftung der Anteile und Zeile 67 deren Werte. Der Graph links unten
in Abbildung 1 zeigt die relative Auslastung der ersten Partition.
Für die Plattenplatz-Anzeige etwas absurd, aber für andere Anwendungsfälle ganz
praktisch ist Chart::LinesPoints, das Linien mit Stützpunkten zeichnet.
Analog hierzu arbeiten Chart::Lines bzw. Chart::Points, die entweder nur Linien
oder nur Punkte malen. In jedem Fall zeichnet der erste Datensatz
(Zeile 77) für die diskreten Werte auf der X-Achse und der zweite
(Zeile 78) für die Höhe der Stützpunkte verantwortlich. Der Graph
rechts unten in Abbildung 1 zeigt das Ergebnis.
Insgesamt ist Chart ein ausgesprochen praktisches Modul und
David Bonner hat versprochen, bald 3D-Effekte einzuführen, sodaß
die Anzeige noch (!) ansprechender zu werden verspricht - cool!
Die Chart-Distribution von David Bonner benutzt die Routinen
der GD-Library von Lincoln D. Stein. Deswegen sind zwei
Distributionen zu installieren:
chart-0.94.tar.gz und GD-1.14.tar.gz.
Am einfachsten geht das natürlich mit dem letztens vorgestellten
CPAN-Saugrüssel CPAN.pm. Als root führt
perl -MCPAN -e shell
cpan> install LDS/GD-1.14.tar.gz
...
cpan> install DBONNER/chart-0.94.tar.gz
...
den gesamten Installationsprozeß automatisch durch. Manuell müssen
LDS/GD-1.14.tar.gz und DBONNER/chart-0.94.tar.gz aus z. B.
ftp://ftp.gmd.de/packages/CPAN/modules/by-authors/
geholt, mit tar zxfv entpackt und mit perl Makefile.PL und
make install (als root) installiert werden. Und los geht's!
space.pl
01 #!/usr/bin/perl
02 ######################################################################
03 # space.pl
04 # Michael Schilli, 1998 (mschilli@perlmeister.com)
05 ######################################################################
06
07 $df_command = "/bin/df"; # df-Kommando listet File-Systeme
08
09 use CGI;
10 $q = CGI->new(); # CGI-Objekt
11
12 # 'die'-Anweisungen enden hier
13 $SIG{__DIE__} = sub { print $q->header; print $q->h1(@_); exit 0; };
14
15 # Plattenbelegung über df-Kommando ermitteln
16 open(PIPE, "$df_command|") || die "$df_command: command not found";
17 while(<PIPE>) {
18 $count++ || next; # Erste Zeile ignorieren
19 my ($drive, $total, $used, $free, $perc, $mount) = split(' ', $_);
20 push(@mounts, $mount);
21 push(@used, $used/1000);
22 push(@free, $free/1000);
23 }
24 close(PIPE) || die "$df_command failed";
25
26 # Ohne Parameter aufgerufen - HTML-Seite ausgeben
27 if(!defined $q->param("graph")) {
28
29 print $q->header, $q->start_html(-title => 'Chart Test');
30 for (qw/bars stackedbars pie linespoints/) {
31 print $q->img({src => "$ENV{SCRIPT_NAME}?graph=$_",
32 border => 3,
33 hspace => 3,
34 vspace => 3}), "\n";
35 print $q->br if $gcount++ % 2;
36 }
37 print $q->end_html;
38
39 } elsif($q->param("graph") eq "bars") { # Balkengraphik
40
41 use Chart::Bars;
42 my $g = Chart::Bars->new(200,200); # Objekt erzeugen
43 $g->set('title' => 'Chart::Bars'); # Titel setzen
44 $g->add_dataset(@mounts); # Werte auf X-Achse
45 $g->add_dataset(@free); # Balkenhöhe
46 $g->cgi_gif(); # Gif ausgeben
47
48 } elsif($q->param("graph") eq "stackedbars") {
49
50 use Chart::StackedBars;
51 my $g = Chart::StackedBars->new(200,200);
52 $g->set ('title' => 'Chart::StackedBars');
53 $g->set('x_label' => "File Systems");
54 $g->set('y_label' => "Mega Bytes");
55 $g->set('legend_labels' => ["free", "used"]);
56 $g->set('grid_lines' => "true");
57 $g->set('max_val' => 1500);
58 $g->set('colors' => [[255,0,0], [0,255,0]]);
59 $g->add_dataset(@mounts);
60 $g->add_dataset(@used);
61 $g->add_dataset(@free);
62 $g->set('legend_labels' => ["free", "used"]);
63 $g->cgi_gif();
64
65 } elsif($q->param("graph") eq "pie") { # Kuchengraphik
66
67 use Chart::Pie;
68 my $g = Chart::Pie->new(200,200); # Objekt erzeugen
69 $g->set ('title' => 'Chart::Pie'); # Titel setzen
70 $g->add_dataset("used","free"); # Anteil-Beschreibung
71 $g->add_dataset($free[0],$used[0]); # Werte-Satz
72 $g->cgi_gif(); # Gif ausgeben
73
74 # Linien mit
75 # Stützpunkten
76 } elsif($q->param("graph") eq "linespoints") {
77
78 use Chart::LinesPoints;
79 my $g = Chart::LinesPoints->new(200,200);
80 $g->set ('title' => 'Chart::LinesPoints');
81 $g->add_dataset(@mounts); # X-Achsen-Werte
82 $g->add_dataset(@used); # Höhe
83 $g->cgi_gif(); # Gif ausgeben
84
85 # Gestaffelte Balken
86 }
![]() |
Michael Schilliarbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com. |