tags:

views:

753

answers:

4

Hi

I am writing a small program in Perl for my assignment and I am new to Perl.

Code that I have written provides me with exactly the same values I need, but I am getting this error while creating bar chart.

Invalid data set: 0 at line 67

Line 67 is marked with a comment in the code below.

The values stored in x-axis are:

40 44 48 52 64 76 83 104 105 148 149 249 431 665 805 1420 1500

And y_axis are:

16 1  1 6 1 1 1 1 1 1 1 1 1 1 1 2 5

Here's my code:

use GD::Graph::bars;

open(CHECKBOOK,"c:\\Perl\\bin\\ip_packet_trace1.txt");

my $counter = -1;
my @sizearray = {};
while ($record = <CHECKBOOK>) {
    @array = split(/\t/,$record);
    $counter++;
    $sizearray[$counter] = $array[6];

}

$counter++;

my @array1 = sort {$a <=> $b} @sizearray;
print "$counter\n";
print "@array1\n";


my @freq = {0...0};

foreach $elem (@array1){

    my $s = $freq[$elem]+1;

    $freq[$elem] = $s;
}


my $size = @freq;
my @x_axis = {};
my @y_axis = {};

my $count2 = -1;


for($i = 1; $i < $size; $i++){

    my $elem = $freq[$i];

    if($elem  and $elem > 0  ){

        $count2++;

        $x_axis[$count2] =  $i;

        $y_axis[$count2] = $elem;
    }

}


print "@x_axis \n";
print "@y_axis \n";




my $mygraph = GD::Graph::bars->new(500, 300); # line 67

$mygraph->set(x_label     => 'Month',

y_label     => 'Number of Hits',

title       => 'Number of Hits in Each Month in 2002',

) or warn $mygraph->error;

my @data = {@x_axis,@y_axis};



my $myimage = $mygraph->plot(\@data) or die $mygraph->error;

open(IMG, '>C:\\image\\file.gif') or die $!;

binmode IMG;

print IMG $myimage->gif;

close IMG;
+1  A: 

I'm not really sure what I'm looking at, but one thing jumps out at me: you are initializing your arrays as hash references:

hektor ~ $ perl -e '@sizearray = {}; print @sizearray, "\n"'
HASH(0x8031c0)

If all you want is an empty array, you can say simply this:

my @sizearray;

If you want to make clear it's new and empty, you want parentheses; see below. (As Brad says in his comment, however, this is redundant. You should probably get used to seeing and writing the simpler version.)

my @sizearray = ();

Arrays store ordered lists and lists go in parentheses. See perldoc perldata for more.

Telemachus
`my @sizearray;` is exactly the same as my `@sizearray = ();`
Brad Gilbert
I know, but some people seem to like the visual reminder of `@sizearray = ();` Maybe this is just their legacy of other languages, and I don't do it myself. I just meant that if he insisted, () won't break things as {} does. I'll put a note though.
Telemachus
+2  A: 

Please use strict and use warnings. Many of the troublesome things you have going on in this code will be flagged for you if you use these pragmas.

You are also expending a lot of effort to append to the end of your arrays. You can use push to do this without knowing the index of the last item. Using push like this will let you simplify your code quite a bit.

Use () to make an empty array (well list really). Use [] to make an array reference. use {} to make a hash reference. You've been using hash refs in a number of places.

It is also best to use lexical filehandles instead of global filehandles. Using global file handles is using unnecessary global variables, which is asking for trouble. Also check for success on your calls to open.

open( my $fh, '<', 'path/to/file)
    or die "Unable to open data file - $!\n";

When you are working with data structures, Data::Dumper is a useful module to see what's going on.

use Data::Dumper;

my $foo = {
  bar => [ 0..5],
  baz => { a..z },
};

my @qux = ( [qw/a b c d/], [0..5] );

print Dumper $foo;
print Dumper \@qux;

Also, take a look at perldsc and perlreftut they have good examples of how to work with references and nested data structures.

daotoad
+2  A: 

I think your assignment of @data is probably to blame.

my @data = {@x_axis,@y_axis};

This creates an array with one element. That one element is a hash. The GD::Graph documentation shows that you need an array of arrays. This is where, as daotoad stated, Data::Dumper comes in handy. Try out the following:

use Data::Dumper;
my @x_axis = 1...100;
my @y_axis = "a"..."z";
my @data = {@x_axis,@y_axis};
warn Dumper(\@data);

You can see how the data is being interpreted, and see that it is not the same as the GD::Graph example:

@data = ( 
    ["1st","2nd","3rd","4th","5th","6th","7th", "8th", "9th"],
    [    1,    2,    5,    6,    3,  1.5,    1,     3,     4],
    [ sort { $a <=> $b } (1, 2, 5, 6, 3, 1.5, 1, 3, 4) ]
  );
Jack M.
A: 

K. I tested and altered you code. The below code works. The array part that everyone mentioned was important, but not your only problem. The example in cpan, was of an anonymous array, so instead of passing @data 2 arrays, you just needed to pass 2 references to @data.

#!/usr/bin/perl
#
use GD::Graph::bars;

my $size = @freq;
my @x_axis = qw(40 44 48 52 64 76 83 104 105 148 149 249 431 665 805 1420 1500);
my @y_axis = qw(16 1  1 6 1 1 1 1 1 1 1 1 1 1 1 2 5);

my $mygraph = GD::Graph::bars->new(500, 300); # line 67
$mygraph->set(x_label     => 'Month',
            y_label     => 'Number of Hits',
            title       => 'Number of Hits in Each Month in 2002',
) or warn $mygraph->error;
my @data = (\@x_axis,\@y_axis); # the important part.
my $myimage = $mygraph->plot(\@data) or die $mygraph->error;

open(IMG, '>helping_graph.gif') or die $!;
binmode IMG;
print IMG $myimage->gif;
close IMG;
J.J.