<?php
$top = 110;
$bottom = 45;
date_default_timezone_set( "America/Los_Angeles" );
class Temperature_Graph
{
public $image;
public $black;
public $white;
public $red;
public $blue;
public $green;
public $brightgreen;
public $violet;
public $gray;
public $image_width = 950;
public $image_height = 1200;
public $hi_temp_degrees_F = 110;
public $lo_temp_degrees_F = 45;
public $range_in_degrees_F;
public $pixels_per_degree;
public $zero;
public $font;
public function __construct()
{
global $top, $bottom, $begin, $end;
$this->font = "..\\php\\extras\\fonts\\ttf\\Vera.ttf";
$this->hi_temp_degrees_F = intval( $top ) + 2;
$this->lo_temp_degrees_F = intval( $bottom ) - 2;
$this->range_in_degrees_F = $this->hi_temp_degrees_F - $this->lo_temp_degrees_F;
$this->pixels_per_degree = $this->image_height / $this->range_in_degrees_F;
$this->zero = $this->hi_temp_degrees_F * $this->pixels_per_degree + 10;
$this->image = imagecreatetruecolor( $this->image_width, $this->image_height );
$this->black = imagecolorallocate( $this->image, 0, 0, 0 );
$this->gray = imagecolorallocate( $this->image, 200, 200, 200 );
$this->darkgray = imagecolorallocate( $this->image, 80, 80, 80 );
$this->white = imagecolorallocate( $this->image, 255, 255, 255 );
$this->red = imagecolorallocate( $this->image, 255, 50, 50 );
$this->blue = imagecolorallocate( $this->image, 50, 50, 255 );
$this->green = imagecolorallocate( $this->image, 0, 150, 0 );
$this->brightgreen = imagecolorallocate( $this->image, 0, 255, 0 );
$this->violet = imagecolorallocate( $this->image, 255, 50, 255 );
imagefill( $this->image, 0, 0, $this->white );
$high_tick = $this->zero - $this->hi_temp_degrees_F * $this->pixels_per_degree;
$tick_degrees = $this->hi_temp_degrees_F;
for( $tick_y = $high_tick; $tick_y < $this->image_height; $tick_y += 1 * $this->pixels_per_degree )
{
imageline( $this->image, 10, $tick_y, 20, $tick_y, $this->black );
if( $tick_degrees % 10 == 0 )
{
imageline( $this->image, 10, $tick_y, 40, $tick_y, $this->black );
imagettftext( $this->image, 10, 0, 15, $tick_y+12, $this->black, $this->font,
$tick_degrees . " \xC2\xB0F" );
}
$tick_degrees -= 1;
}
imagerectangle( $this->image, 10, 10, $this->image_width-1, $this->image_height-1, $this->black );
imagettftext( $this->image, 10, 0, 70, $this->image_height-32, $this->blue, $this->font,
"Min " . ($bottom+3) . " \xC2\xB0F" );
imagettftext( $this->image, 10, 0, 450, $this->image_height-32, $this->red, $this->font,
"Max " . ($top-3) . " \xC2\xB0F" );
imagettftext( $this->image, 10, 0, 750, $this->image_height-32, $this->darkgray, $this->font,
"Gray is 95% confidence level " );
imagettftext( $this->image, 14, 0, 420, 30, $this->black, $this->font, "Temperature" );
imagettftext( $this->image, 10, 0, 70, 50, $this->black, $this->font, "Begin " . $begin );
imagettftext( $this->image, 10, 0, 685, 50, $this->black, $this->font, "End " . $end );
}
public function plot_sample( $column, $time, $mean, $std_dev, $min_temp, $max_temp )
{
$mean_y = $this->zero - $mean * $this->pixels_per_degree;
$min_temp_y = $this->zero - $min_temp * $this->pixels_per_degree;
$max_temp_y = $this->zero - $max_temp * $this->pixels_per_degree;
$x = $column * 12 + 60;
$y = $mean_y - $std_dev * 1.959964 * $this->pixels_per_degree;
$x2 = $x + 6;
$y2 = $mean_y + $std_dev * 1.959964 * $this->pixels_per_degree;
//
// Draw the box around the standard deviation
//
imagefilledrectangle( $this->image, $x, $y, $x2, $y2, $this->gray );
imagerectangle( $this->image, $x, $y, $x2, $y2, $this->black );
//
// Draw the whiskers for the min_temp and max_temp
//
imageline( $this->image, $x+1, $min_temp_y, $x2-1, $min_temp_y, $this->blue );
imageline( $this->image, $x+1, $max_temp_y, $x2-1, $max_temp_y, $this->red );
imageline( $this->image, $x+3, $min_temp_y, $x+3, $mean_y, $this->blue );
imageline( $this->image, $x+3, $mean_y, $x+3, $max_temp_y, $this->red );
//
// Draw the line for the mean
//
imageline( $this->image, $x-1, $mean_y-1, $x2+1, $mean_y-1, $this->black );
imageline( $this->image, $x-2, $mean_y, $x2+2, $mean_y, $this->black );
imageline( $this->image, $x-1, $mean_y+1, $x2+1, $mean_y+1, $this->black );
if( $column % 3 == 0 )
{
$hour = substr( $time, 11, 2 );
imageline( $this->image, $x+2, $this->image_height, $x+2, $this->image_height-10, $this->black );
imagettftext( $this->image, 10, 0, $x+4, $this->image_height-2, $this->black,
$this->font, $hour );
}
}
public function __destruct()
{
header( 'Content-Type: image/png' );
imagepng( $this->image );
imagedestroy( $this->image );
}
}
class Read_Database_Temperatures
{
public $mysqli;
public $selected;
public $select;
public function __construct()
{
$db_name = "temperature";
//
// This program can be called with optional arguments:
// --database=foo the name of the database to use
//
$options = getopt( "", [ "database::" ] );
if( $options )
{
foreach( array_keys( $options ) as $key )
{
if( $key == "database" )
{
$db_name = $options[$key];
}
}
}
$this->mysqli = new mysqli( 'localhost', 'root', '', $db_name )
or die( 'Could not connect: ' . mysqli_error() );
$this->mysqli->select_db( $db_name )
or die( "Could not select database $db_name" );
//
// Last 24 hours
//
// $this->select =
// "SELECT id, mean, std_dev, min_temp, max_temp, reg_date FROM temps"
// . " WHERE reg_date >= (CURTIME() - INTERVAL 1 DAY)";
//
// Yesterday
//
$this->mysqli->query( "SET time_zone='-8:00';" )
or die( 'Select failed: ' . $this->mysqli->error );
$this->select =
"SELECT id, mean, std_dev, min_temp, max_temp, reg_date FROM temps"
. " WHERE DATE(reg_date) = (CURDATE() - 1)";
$this->selected = $this->mysqli->query( $this->select )
or die( 'Select failed: ' . $this->mysqli->error );
}
public function output()
{
if( $this->selected->num_rows > 0 )
{
global $top, $bottom, $begin, $end;
$columns = array();
$samples = array();
$samples_per_period = 20 * 60;
$PACTZ = new DateTimeZone('America/Los_Angeles');
$yesterday = new DateTime( 'yesterday midnight', $PACTZ );
$period_start = $yesterday->getTimeStamp();
$top = -99999;
$bottom = 100000;
$num = 0;
$sum = 0;
$variance = 0;
for( $y = 0; ; $y++ )
{
$period_end = $period_start + (20 * 60);
$num_samples = 0;
$min_val = 99999;
$max_val = -99999;
$sum = 0;
$row = 0;
for( $x = 0; ; $x++ )
{
$row = $this->selected->fetch_assoc();
if( ! $row )
break;
$sample_time = strtotime( $row["reg_date"] );
if( $sample_time > $period_end )
break;
$sum += $row["mean"];
$samples[$x] = $row["mean"];
if( $y == 0 && $x == 0 )
$begin = $row["reg_date"];
$end = $row["reg_date"];
$num_samples++;
}
$mean = $sum / $num_samples;
for( $x = 0; $x < $num_samples; $x++ )
{
$variance += ($samples[$x] - $mean) * ($samples[$x] - $mean);
if( $samples[$x] < $min_val )
$min_val = $samples[$x];
if( $samples[$x] > $max_val )
$max_val = $samples[$x];
if( $samples[$x] < $bottom )
$bottom = $samples[$x];
if( $samples[$x] > $top )
$top = $samples[$x];
}
$variance /= $num_samples - 1;
$std_dev = sqrt( $variance );
$columns[$num] = array( $num, $end, $mean, $std_dev, $min_val, $max_val );
$num++;
$period_start = $period_end;
if( ! $row )
break;
}
//
// Leave a little room at the top and bottom
//
$bottom -= 3;
$top += 3;
$graph = new Temperature_Graph();
for( $x = 0; $x < $num; $x++ )
{
$c = $columns[ $x ];
$graph->plot_sample( $c[0], $c[1], $c[2], $c[3], $c[4], $c[5] );
}
}
}
}
$db = new Read_Database_Temperatures();
$db->output();
?>