Perl :: Aufgabe #9 :: Lösung #2
2 Lösungen

#9
CSV-Datei auslesen und aus den Daten eine Tabelle und ein Diagramm erzeugen (CGI)
Fortgeschrittener - Perl
von Gustl
- 16.08.2012 um 10:36 Uhr
Erstellen Sie ein Perl- Skript, das die angehängte CSV- Datei (EUR/USD Dollarkurs von einem Jahr) in ein Array einliest. Diese eingelesenen Werte sollen in einer Tabelle dargestellt werden und sich in einem Linien-, Punkt- oder Balkendiagramm widerspiegeln.
In dem Diagramm soll nur jeder vierte Wert ausgegeben werden.
Das Datum soll in folgendes Format konvertiert werden: DD.MM.YY (16.08.12)
In dem Diagramm soll nur jeder vierte Wert ausgegeben werden.
Das Datum soll in folgendes Format konvertiert werden: DD.MM.YY (16.08.12)
#2

von Gustl (6560 Punkte)
- 16.09.2012 um 19:19 Uhr
Meine Lösung ist vielleicht nicht ganz ausgereift, aber es kann zumindest ein dynamisches Diagramm erstellt werden, welches mit canvas/javascript dargestellt wird. Beim Datum habe ich das Jahr noch abgeschnitten.
Perl-Code
Hier ein Link zur Ausgabe (Diagramm + Tabelle)

#!/usr/bin/perl use strict; use POSIX; my ($one_ref_array, $two_ref_array) = read_csv_file( "eur_usd1.csv"); my @array_table = @$one_ref_array; my @array_diagramm = @$two_ref_array; make_html_table( \@array_diagramm, "tabelle.html"); make_html_diagramm( \@array_diagramm, "diagramm.html", 400, 800); # Liest die csv-datei ein # 1. Paramter: Pfad von csv-Datei # 2. Paramter: jeder x Eintrag wird dem Array für das Diagramm hinzugefügt sub read_csv_file{ my $csv_file = $_[0]; my (@arr_table, @arr_diagramm); my @head_table; my $i = 0; # csv-Datei öffnen open(CSV,$csv_file) or die "Die Datei $csv_file konnte nicht geoeffnet werden."; while(<CSV>){ # Spaltennamen auslesen if($i == 0){ chomp($_); @head_table = split(/;/,$_); } # Inhalt auslesen und in table-array und diagramm-array hinzufügen else{ chomp($_); my @line_array = split(/;/,$_); my $hash_ref; for(my $x = 0; $x < scalar(@line_array); $x++){ if($head_table[$x] eq "Datum"){ $hash_ref->{$head_table[$x]} = convert_datum($line_array[$x]); } else{ $hash_ref->{$head_table[$x]} = $line_array[$x]; $hash_ref->{$head_table[$x]} =~ tr/,/\./; } } push( @arr_table, $hash_ref ); push( @arr_diagramm, $hash_ref ); } $i++; } close CSV; return (\@arr_table, \@arr_diagramm); } sub make_html_table{ my @arr_diagramm = @{$_[0]}; my $file = $_[1]; open(TABLE_HTML,">".$file); print TABLE_HTML " <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'> <html xmlns='http://www.w3.org/1999/xhtml'> <head> <meta http-equiv='Content-Type' content='text/html; charset=utf-8' /> <link rel='stylesheet' href='style.css' type='text/css' /> </head> <body>"; print TABLE_HTML "<table cellspacing='1' cellpadding='0'><tr>"; my $hashref = $arr_diagramm[0]; for my $key_th (keys %$hashref) { print TABLE_HTML "<th>".$key_th."</th>"; } print TABLE_HTML "</tr>"; foreach (@arr_diagramm){ print TABLE_HTML "<tr>"; for my $key (keys %$_) { print TABLE_HTML "<td>".$_->{$key}."</td>"; } print TABLE_HTML "</tr>"; } print TABLE_HTML "</table></body></html>"; close TABLE_HTML; } sub convert_datum{ my $datum = shift; my @date_array = split(/-/,$datum); my $year = substr($date_array[0],2,2); return $date_array[2].".".$date_array[1].".".$year; } sub make_html_diagramm{ my @arr_diagramm = @{$_[0]}; my $file = $_[1]; my $hoehe = $_[2]; my $width = $_[3]; my $x_hoehe_bedarf_top = 50; my $y_breite_bedarf_left = 20; my $x_hoehe_bedarf = 40; my $y_breite_bedarf = 70; my $hoehe_diagramm = $hoehe - $x_hoehe_bedarf - $x_hoehe_bedarf_top; my $width_diagramm = $width - $y_breite_bedarf - $y_breite_bedarf_left; # max und min werte ermitteln my $max_wert = get_max(\@arr_diagramm); my $min_wert = get_min(\@arr_diagramm); # differnez von max und min werte my $diff = floor(($max_wert - $min_wert) * 1000); # y schritt (zb. schritt = 6, pro 6px +1 wert) my $schritt = $hoehe_diagramm / $diff; # x schritt my $schritt_left = $width_diagramm / scalar(@arr_diagramm); my $left = 0 - $y_breite_bedarf_left; foreach(@arr_diagramm){ $left += $schritt_left; $_->{x} = $left; print "\nleft: ".$left; $_->{y} = ($_->{Schlusskurs} - $min_wert) * 1000 * $schritt; if($_->{Datum} =~ /(.{6})/){ $_->{Datum} = $1; } } # Beschriftungen und Hintergrundlinien # y-achse my $y_desc_abstand = $hoehe_diagramm / 25; for(my $i = $hoehe_diagramm; $i >= 1; $i-- ){ if( ($hoehe_diagramm / $i) >= $y_desc_abstand){ $y_desc_abstand = $i; last; } } my $y_desc_anzahl = $hoehe_diagramm/$y_desc_abstand; my $step_y_desc = $diff/$y_desc_anzahl; $y_desc_anzahl = floor($y_desc_anzahl); my @y_desc; foreach(0..($y_desc_anzahl)){ my $hashref; $hashref->{desc} = int( (($min_wert*1000) + ($step_y_desc * $_)))/1000; $hashref->{y} = $hoehe_diagramm + $x_hoehe_bedarf_top - ($y_desc_abstand * $_); print $hashref->{y}." ".$hashref->{desc}."\n"; push(@y_desc, $hashref); } # x-achse my $x_teiler = ($width - $y_breite_bedarf_left) / scalar(@arr_diagramm); print "\nteiler vor: ".$x_teiler; for(my $i = 1; $i >= 1; $i *= 2){ if($x_teiler >= (50/$i) ){ $x_teiler = $i; last; } } print "\nteiler nach: ".$x_teiler; print "\nMin: ".$min_wert; print "\nMax: ".$max_wert; print "\nSchritt: ".$schritt; print "\nDiff: ".$diff; print "\ndesc_anzahl: ".$y_desc_anzahl; print "\ndesc_abstand: ".$y_desc_abstand; print "\nstep_y_desc: ".$step_y_desc; print "\nscalar: ".scalar(@arr_diagramm); print "\nhoehe_diagramm: ".$hoehe_diagramm; open(DIAGRAMM_HTML,">".$file); print DIAGRAMM_HTML "<!doctype html> <html lang='de' xml:lang='de'> <head> <meta charset='utf-8'> <link rel='stylesheet' href='style.css' type='text/css' /> </head> <body> <canvas id='canvasLinie' width='".($width)."' height='".($hoehe)."' style='border: 1px solid silver;'> ein Browser unterstützt das Canvas-Element nicht. </canvas> <script type='text/javascript'> var canvas = document.getElementById('canvasLinie'); var context = canvas.getContext('2d'); context.lineWidth = 0.4;"; for(my $i = 0; $i < scalar(@arr_diagramm); $i++ ){ if($i == 0){ print DIAGRAMM_HTML "context.moveTo(".(($width-$y_breite_bedarf)-$arr_diagramm[$i]->{x}- $y_breite_bedarf_left).", ".(($hoehe-$x_hoehe_bedarf)-$arr_diagramm[$i]->{y}).");"; } else{ print DIAGRAMM_HTML "context.lineTo(".(($width-$y_breite_bedarf)-$arr_diagramm[$i]->{x}- $y_breite_bedarf_left).", ".(($hoehe-$x_hoehe_bedarf)-$arr_diagramm[$i]->{y}).");"; } } print DIAGRAMM_HTML "context.stroke();"; print DIAGRAMM_HTML "var y_lines = canvas.getContext('2d');"; print DIAGRAMM_HTML "y_lines.lineWidth = 0.2;"; foreach(@y_desc){ print DIAGRAMM_HTML "y_lines.fillText('".$_->{desc}."',".($width-60+5).",".($_->{y}+2).");\n"; print DIAGRAMM_HTML "y_lines.moveTo(".$y_breite_bedarf_left.",".($_->{y})."); context.lineTo(".($width-60).",".($_->{y}).");\n"; } print DIAGRAMM_HTML "y_lines.stroke();"; print DIAGRAMM_HTML "var x_lines = canvas.getContext('2d');"; print DIAGRAMM_HTML "x_lines.lineWidth = 0.2;"; for(my $i = 0; $i < scalar(@arr_diagramm); $i += $x_teiler ){ print DIAGRAMM_HTML "x_lines.fillText('".$arr_diagramm[$i]->{Datum}."',".(($width-$y_breite_bedarf)- $y_breite_bedarf_left-$arr_diagramm[$i]->{x}-13).",".($hoehe-$x_hoehe_bedarf+24).");\n"; print DIAGRAMM_HTML "x_lines.moveTo(".(($width-$y_breite_bedarf)- $y_breite_bedarf_left-$arr_diagramm[$i]->{x}).",".$x_hoehe_bedarf_top.");context.lineTo(".(($width-$y_breite_bedarf)- $y_breite_bedarf_left-$arr_diagramm[$i]->{x}).",".($hoehe-$x_hoehe_bedarf+10).");\n"; } print DIAGRAMM_HTML "x_lines.stroke();"; print DIAGRAMM_HTML "var head = canvas.getContext('2d'); head.font=\"18px Verdana\"; head.fillText(\"Euro / US Dollar - Kurs (EUR/USD)\", 30, 33);</script> </body> </html>"; close DIAGRAMM_HTML; } sub get_max{ my @arr_diagramm = @{$_[0]}; my $max = 0; foreach(@arr_diagramm) { $max = $_->{Schlusskurs} if ($_->{Schlusskurs} > $max && $_->{Schlusskurs} > 0 ); } return $max; } sub get_min{ my @arr_diagramm = @{$_[0]}; my $min = 10000; foreach(@arr_diagramm) { $min = $_->{Schlusskurs} if ($_->{Schlusskurs} < $min && $_->{Schlusskurs} > 0 ); } return $min; }
Hier ein Link zur Ausgabe (Diagramm + Tabelle)
Kommentare:
Für diese Lösung gibt es noch keinen Kommentar
Seite 1 von 0
1