I create line graphs on the fly using gd::graph. I would like to have a moving average and also a smothed graph. With a smooth graph, data2002 for May would not spike as much. The moving average could go back 2 and 6 months. I take my values from a MySQL select where I select between epoch time stamps. I store the rows returned and dynamicly generate the labels.
This code below works and creates a graph using values between two epoch time stamps. It would be much nicer if I had totals for every minute yet were displayed as an hour. You see the problem is that it sums up the rows for each hour and then uses hours for labels. If only I could have hours as labels and then minutes as values it would show better. Any potential problems with running that many select statement on a MySql table? What if I went back every minute (or 5 minutes) for a week? I've had alot of help with pieces of this from the forum and tutorials on the net. Here it is all together. Any advice. Thanks
Code:
#!/usr/bin/perl -w
use strict;
use GD::Graph::mixed;
use GD::Graph::colour qw( :files );
use GD::Text;
use Time::Local;
use DBI;
# Set value -can be dynamicly set to go back x hours
my $set = 48;
my @matrix;
my @xLabels;
my @avDown;
my @avUp;
my @down;
my @up;
my @data;
# for (my $count=0; $count<8; $count++) # counts 0 to -7
for (my $count=0; $count<$set; $count++) # counts 0 to -7
{
my $neg = -1;
my $negative_count = $count * $neg;
my $negative_count_less = $negative_count - 1;
# Finds top of the hour
my $sid = 60*60; #seconds in 1 hr
# grab this moment
my $time = time;
my $top_of_hour = $time - ($time % $sid);
# go back x many hrs
my $period_days= $negative_count; # period in days
# set period in seconds (hrs)
my $period = 60*60 * $period_days;
# set epoch date
my $start_of_day_period_one = ($period + $top_of_hour);
# parse date for human use
my @dayofweek = (qw(Sun Mon Tue Wed Th Fri Sat));
my @monthnames = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec));
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = localtime($start_of_day_period_one);
$year += 1900;
$mday = "0$mday" if ($mday < 10);
$hour = " $hour"if ($hour < 10);
my $interval_one = "$monthnames[$mon] $mday $hour:00";
#################################################################################
# Finds top of hour for today
my $sid = 60*60; #seconds in hr
my $time = time;
my $top_of_hour = $time - ($time % $sid);
# go back x many days
my $period_days= $negative_count_less; # period in days
# set period in seconds
my $period = 60*60 * $period_days;
# set epoch date
my $start_of_day_period_two = ($period + $top_of_hour);
# parse date for human use
my @dayofweek = (qw(Sun Mon Tue Wed Th Fri Sat));
my @monthnames = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec));
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = localtime($start_of_day_period_two);
$year += 1900;
my $interval_two = "$monthnames[$mon] $mday $hour:00";
###########################################################################################
my $db = ""; # Database name
my $localhost = ""; # localhost
my $username = ""; # Username
my $password = ""; # Password
############## prints all rows - dumps data ##################
# connect to DB
my $dbh = DBI->connect ("DBI:mysql:$db:$localhost",
"$username","$password")
|| die "Could not connect to database: "
. DBI-> errstr; # display error
# $start_of_day_period_one $start_of_day_period_two
my $sql = qq{ SELECT id FROM data where time_stamp BETWEEN $start_of_day_period_two and $start_of_day_period_one};
my $sth = $dbh->prepare( $sql );
$sth->execute();
# for capturing number of rows
my $rv = $sth->execute || die $sth->errstr;
## Set Vars ########
my $num = 0; # if no row is returned
my $zero = "0E0";
if ($rv == $zero){
push ( @matrix , [ $interval_one, $num ] );
next;
}
push ( @matrix , [ $interval_one, $rv ] );
# Don't need the database connection anymore
$sth->finish();
$dbh->disconnect();
} # end of for (my $count=1; $count<8; $count++) # counts -1 to -7
for my $row (@matrix) {
print "Val: @$row[0] Day: @$row[1]\n";
}
#
# Put test data into labels array, value array
my @xlabels = ();
my @avDown = ();
for my $row (@matrix) {
push @xlabels, @$row[1];
push @avDown, @$row[0];
}
####################################################
# example
#my @data = ( ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
# [ 17, 19, 26, 38, 56, 64, 67, 53, 40, 29, 21, 13],
# [ 19, 24, 27, 41, 56, 69, 75, 60, 44, 33, 22, 15] );
my @avDown_rev;
my @xlabels_rev;
my @avDown_rev = reverse(@avDown);
my @xlabels_rev = reverse(@xlabels);
my @data = (
[(@avDown_rev)],
[@xlabels_rev],
);
my $graph = GD::Graph::lines->new( 700, 300 );
########################
GD::Graph::colour::read_rgb( "/usr/X11R6/lib/X11/rgb.txt" ) or
die( "Can't read colours" );
$graph->set( title => "Statistics",
t_margin => 10,
b_margin => 10,
l_margin => 10,
r_margin => 10,
x_label => "Hours",
x_label_position => 0.5,
x_labels_vertical => 1,
y_label => "Counts per Hour",
y_max_value => 100,
y_tick_number => 10,
y_label_skip => 1,
dclrs => [ qw(coral LightYellow4 orange1 orange2) ],
line_width => 1,
long_ticks => 1,
markers => [ 5, 5 ],
boxclr => 'LightGoldenrodYellow',
fgclr => 'khaki',
legend_placement => "BT" );
$graph->set_legend( "Total");
GD::Text->font_path( "/usr/lib/X11/fonts/truetype/" );
$graph->set_title_font( "luximr", 16 );
$graph->set_legend_font( "luximr", 10 );
$graph->set_x_axis_font( "luximr", 9 );
$graph->set_x_label_font( "luximr", 11 );
$graph->set_y_axis_font( "luximr", 9 );
$graph->set_y_label_font( "luximr", 11 );
################################
my $image = $graph->plot(\@data) or die $graph->error;