Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

use GD::Graph::lines; use GD::Graph::Map; @data = ( [ qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) ], [ reverse(4, 3, 5, 6, 3, 1.5, -1, -3, -4, -6, -7, -8)], [ (4, 3, 5, 6, 3, 1.5, -1, -3, -4, -6, -7, -8)], [ (2, 2, 2, 5, 5, 4.5,1.5, 2, 3, 5, 4, 3)], );
Instead of sticking with the hardcoded values above, I would like to read in the data from different files. ( data in a comma delimited format )

eg.

10,20,30,40
open IN, "<header_data.dat"; @myheader = <IN>; close IN; open IN, "<daily_data1.dat"; @mydata1 = <IN>; close IN; open IN, "<daily_data2.dat"; @mydata2 = <IN>; close IN; open IN, "<daily_data3.dat"; @mydata3 = <IN>; close IN;
Once the data is in the arrays, I should be able to just push the exisiting arrays
onto @data inorder to plot it. I do not understand what kind of data is used by
@data ( array of refs or array of scalar values ).

How do I store the incomming data inorder to plot it ?

$my_graph = new GD::Graph::lines(); $my_graph->set( x_label => 'Month', y_label => 'Measure of success', title => 'A Multiple Line Graph', y_max_value => 8, y_min_value => -8, y_tick_number => 16, y_label_skip => 2, box_axis => 0, line_width => 3, zero_axis_only => 1, x_label_position => 1, y_label_position => 1, x_label_skip => 3, x_tick_offset => 2, ); $my_graph->set_legend("Us", "Them", "Others"); open PNG, ">sample52.png"; binmode PNG; #only for Windows like platforms print PNG ($my_graph->plot(\@data))->png; close PNG; $map = new GD::Graph::Map($my_graph, info => '%l'); $HTML = $map->imagemap("sample52.png", \@data); __END__

Replies are listed 'Best First'.
Re: Graphing basics..
by Ovid (Cardinal) on Feb 28, 2003 at 02:30 UTC

    Here's a little snippet that I came up with that will put the correct data in @data. It was an interesting little problem and I wanted to play with it. You may have to tweak it to get it to do exactly what you want, but it should give you a headstart. There are a few things in there which may be confusing, so feel free to ask questions.

    use strict; # returns the data as an array ref my $data = get_graph_data('header_data.dat', 'daily_data*.dat'); sub get_graph_data { my ($header,$file_name_format) = @_; my @dailies = glob($file_name_format); my @data; @dailies = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, get_number_in_string($_) ] } @dailies; foreach my $file ( $header, @dailies ) { local *IN; open IN, "< $file" or die "Cannot open ($file) for reading: $ +!"; push @data => [<IN>]; close IN or die "Cannot close ($file): $!"; } return \@data; } sub get_number_in_string { # returns the first instance of one or more digits in string my $string = shift || ''; my ($number) = $string =~ /^([[:digit:]]+)$/; return $number; }

    Cheers,
    Ovid

    New address of my CGI Course.
    Silence is Evil (feel free to copy and distribute widely - note copyright text)

      Thank you guys, I will get back with you tomorrow.
Re: Graphing basics..
by Anonymous Monk on Feb 28, 2003 at 01:48 UTC
    @data is an array of references to arrays. The first array reference is the labels. Each following array reference is another curve.

    What you need to do is write code to produce that kind of data structure from your incoming data, and then graph it. Before you can do that you need to specify better what your incoming data looks like. Is each file a different curve? If so then just push another anonymous array onto your building data structure. Is each file one data point on all curves? If so then be prepared to push an item onto each array reference.

    Whatever the answer is, you may find references quick reference useful if you have not dealt with references before.

Re: Graphing basics..
by tall_man (Parson) on Feb 28, 2003 at 05:32 UTC
    I assume from your example there are a known number of files (say 3), each with one line of comma-separated items (the same number in each).

    Here is a simple way to get the given lines into @data (not tested). It's a lot like the one by Ovid but simpler because I don't have to sort file names.

    use strict; sub split_file_line { my $file = shift; open(IN, "<".$file) || die "cannot open $file: $!"; my @items = split /,/,chomp($_ = <IN>); close IN; return \@items; } my @data = (); my @files = qw(header_data.dat); my $nfiles = 3; for (my $i = 1; $i <= $nfiles; $i++) { push @files,"daily_data${i}.dat"; } foreach my $file (@files) { push @data, split_file_line($file); }
      Guys thank you for the input. The references were confusing me at first once I understood what kind of data is required and how to push it onto @data it made alot more sense.

      use GD::Graph::lines; use GD::Graph::Map; use GD::Graph::Data; my ( @hyd,@aut,@fil,@cli,@mis,@days,@std,@files ); @data = (); @files = ( "work_days.dat","std.dat","hyd_daily.dat","aut_daily.dat"," +cli_daily.dat","mis_daily.dat"); sub split_file_line { my $file = shift; open IN, "<$file" || die "cannot open $file: $!"; my $temp = <IN>; my @items = ( split /,/,$temp ); close IN; return \@items; } foreach (@files) { push @data, split_file_line($_); } $my_graph = GD::Graph::lines->new(600,600); $my_graph->set( x_label => 'Working Days ', y_label => '% Percentage', title => 'Orders on Time ', y_max_value => 200, y_min_value => 0, y_tick_number => 20, y_label_skip => 1, box_axis => 0, line_width => 5 ); open PNG, ">p.png"; binmode PNG; #only for Windows like platforms print PNG $my_graph->plot(\@data)->png; close PNG; $map = new GD::Graph::Map($my_graph, info => '%l'); open HTML, ">p.html"; print HTML "<HTML><BODY BGCOLOR=white><CENTER>\n". ($map->imagemap("parker.png", $ref)). "</CENTER></BODY></HTML>"; close HTML; __END__