--- loncom/cgi/graph.png 2002/11/01 22:12:46 1.15 +++ loncom/cgi/graph.png 2003/10/29 15:18:09 1.31 @@ -1,6 +1,6 @@ #!/usr/bin/perl # -# $Id: graph.png,v 1.15 2002/11/01 22:12:46 minaeibi Exp $ +# $Id: graph.png,v 1.31 2003/10/29 15:18:09 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -25,104 +25,219 @@ # http://www.lon-capa.org/ # # The LearningOnline Network with CAPA -# Behrouz Minaei -# YEAR=2001 -# 9/13/01, 9/25/01, 10/6/01, 10/9/01, 12/25/01 -# YEAR=2002 -# 2/1/, 5/13, 5/15 +# # A CGI script that dynamically outputs a graphical chart for lonstatistics. # #### +=pod + +=head1 NAME + +graph.png + +=head1 SYNOPSIS + +produces plots from data stored in users environment. + +=head1 DESCRIPTION + +graph.png is a cgi-bin script which produces plots based on data stored +in the users environment. The users cookie is checked prior to producing +a plot. The query string is expected to be an identifier, $id. +The parameters defining the plot must be stored in the environment as +$ENV{'cgi.'.$id.'.'.$dataname}. Two types of plots can be produced, 'bar' +and 'xy'. The 'xy' graph can will 1 or 2 y-axes if the parameter +'two_axes' is set to false or true respectively. See perldoc GD::Graph and +loncommon::DrawBarGraph, loncommon::DrawXYGraph, and loncommon::DrawXYYGraph. + +=cut + use strict; +use lib '/home/httpd/lib/perl'; use GD::Graph::bars; +use GD::Graph::lines; use GD::Graph::colour; use GD::Graph::Data; +use LONCAPA::loncgi(); -$|=1; # Autoflush after each print/write -my ($Titr,$xlab,$ylab,$Max,$PNo,$data1,$data2)=split(/&/,$ENV{'QUERY_STRING'}); - -my @data11=split(/\,/,$data1); -my @data12=split(/\,/,$data2); +sub unescape { + my $str=shift; + $str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; + return $str; +} -my @xlabels; -for (my $nIdx=0; $nIdx<$PNo; $nIdx++ ) { - $xlabels[$nIdx]=$nIdx+1; -} +sub error { + my ($error) = @_; + my $Str = <<"END"; +Content-type: text/html + + +Bad Graph + +

+There was an error producing the graph you requested. +

+$error +

+ + +END + return $Str; +} +my $id = $ENV{'QUERY_STRING'}; +# +# usage: &get_env($name,$default) +sub get_env { + my $key = 'cgi.'.$id.'.'.(shift()); + return shift if (! exists($ENV{$key})); + return $ENV{$key}; +} -my @data =(\@xlabels,\@data11,\@data12); +if (! &LONCAPA::loncgi::check_cookie_and_load_env()) { + print < +Bad Cookie + +Your cookie information is incorrect. + + +END + exit; +} -my $Range1; -my $Range2; +$|=1; # Autoflush after each print/write -if ($xlab=~/^Concepts$/){ - $Range1=270; - $Range2=200; +## +## Set up the plot +## +my $colordefaults = join(',', + ('#33ff00', + '#0033cc','#990000','#aaaa66','#663399','#ff9933', + '#66ccff','#ff9999','#cccc33','#660000','#33cc66', + )); + +my $height = &get_env('height',300); +my $width = &get_env('width', 400); +my $PlotType = &get_env('PlotType','bar'); + +my %GraphSettings = ( + title => &unescape(&get_env('title','')), + x_label => &unescape(&get_env('xlabel','')), + y_label => &unescape(&get_env('ylabel','')), + x_label_position => 0.5, + dclrs => [split(',',&get_env('Colors', + $colordefaults))], + fgclr => 'black', + boxclr => 'white', + accentclr => 'dblue', + valuesclr => '#ffff77', + l_margin => 10, + b_margin => 10, + r_margin => 10, + t_margin => 10, + transparent => 0, + ); + +$GraphSettings{'x_label_skip'} = &get_env('xskip',1); +$GraphSettings{'x_tick_offset'} = &get_env('x_tick_offset',0); +$GraphSettings{'y_max_value'} = &get_env('y_max_value',1); + +my $MyGraph; +if ($PlotType eq 'bar') { + # Pick up bar graph settings + $GraphSettings{'bar_width'} = &get_env('bar_width',undef); + $GraphSettings{'long_ticks'} = 1; + $GraphSettings{'tick_length'} = 0; + $GraphSettings{'x_ticks'} = 0; + $GraphSettings{'cumulate'} = 2; + $GraphSettings{'zero_axis'} = 1; +} else { + # + # X label skip setup + my $skip_x = &get_env('xskip',1); + my $x_tick_offset = &get_env('x_tick_offset',$skip_x-1); + my $zero_axis = &get_env('zero_axis',1); + # + # Fill up %GraphSettings + $GraphSettings{'long_ticks'} = 1; + $GraphSettings{'tick_length'} = 0; + $GraphSettings{'x_ticks'} = &get_env('x_ticks',0),; + $GraphSettings{'x_label_skip'} = $skip_x; + $GraphSettings{'x_tick_offset'} = $x_tick_offset; + $GraphSettings{'zero_axis'} = 1; + if (&get_env('two_axes',0)) { + $GraphSettings{'two_axes'} = 1; + $GraphSettings{'y1_max_value'} = &get_env('y1_max_value',0); + $GraphSettings{'y1_min_value'} = &get_env('y1_min_value',1); + $GraphSettings{'y2_max_value'} = &get_env('y2_max_value',1); + $GraphSettings{'y2_min_value'} = &get_env('y2_min_value',1); + } +} +# +# Pick up miscellanious values passed in by the user +# +# Create the plot and check it out +if ($PlotType eq 'bar') { + $MyGraph = GD::Graph::bars->new($width,$height); } else { - $Range1=450;#250+30*$PNo; - $Range2=200; + $MyGraph = GD::Graph::lines->new($width,$height); +} +if (! defined($MyGraph)) { + print &error('Unable to create initial graph'); + return; } +## +## Build the @Data array +my $NumSets = &get_env('NumSets'); +my @Data; # stores the data for the graph +my @xlabels = split(',',&get_env('labels')); +push(@Data,\@xlabels); +for (my $i=1;$i<=$NumSets;$i++) { + push(@Data,[split(',',&get_env('data.'.$i))]); +} -my $MyGraph = GD::Graph::bars->new($Range1,$Range2); +my $error = ''; +if (! $MyGraph->set(%GraphSettings)) { + print &error($MyGraph->error); + return; +} -$MyGraph->set( - x_label => $xlab, - y_label => $ylab, - long_ticks => 1, - tick_length => 0, - x_ticks => 0, - title => $Titr, - y_max_value => $Max, -# y_tick_number => $ytic, - y_label_skip => 1, - - dclrs => [ qw( lgreen dgreen lyellow lpurple cyan lorange)], - - bar_spacing => 10, - cumulate => 2, - zero_axis => 1, - -# legend_placement => 'RT', - - fgclr => 'black', - boxclr => 'white', - accentclr => 'dblue', - valuesclr => '#ffff77', - l_margin => 10, - b_margin => 10, - r_margin => 10, - t_margin => 10, - - transparent => 0, -) or warn $MyGraph->error; - -#if ($xlab=~/^Concepts$/){ -# $MyGraph->set_legend( 'Correct Answers', 'Incorrect Answers'); -#} +my $plot = $MyGraph->plot(\@Data); +if (! defined($plot)) { + my $error = 'Unable to plot the data provided.'; +# Debugging code: +# $error .= '
'.join(',',@{$Data[0]}).'
'; +# $error .= '
'.join(',',@{$Data[1]}).'
'; +# $error .= '
'.join(',',@{$Data[2]}).'
' if (ref($Data[2])); +# $error .= '
'.join(',',@{$Data[3]}).'
' if (ref($Data[3])); + print &error($error); + exit; +} +my $BinaryData=$plot->png; +undef($MyGraph); +undef($plot); + +if (! defined($BinaryData)) { + print &error('Unable to render graph as image'); + exit; +} -# Tell the server we are sending a gif graphic +# Tell the server we are sending a png graphic print <set_y_label_font('/home/httpd/cgi-bin/cetus.ttf', 16); -#$MyGraph->set_x_label_font('/home/httpd/cgi-bin/cetus.ttf', 16); -#$MyGraph->set_y_axis_font('/home/httpd/cgi-bin/cetus.ttf', 12); -#$MyGraph->set_x_axis_font('/home/httpd/cgi-bin/cetus.ttf', 12); -#$MyGraph->set_title_font('/home/httpd/cgi-bin/cetus.ttf', 18); -#$MyGraph->set_legend_font('/home/httpd/cgi-bin/cetus.ttf', 10); -#$MyGraph->set_values_font('/home/httpd/cgi-bin/cetus.ttf', 10); - - -my $BinaryData=$MyGraph->plot(\@data)->png; -undef $MyGraph; binmode(STDOUT); -open IMG,"|pngtopnm|ppmtogif 2>/dev/null"; # convert into a gif image -print IMG $BinaryData; # output image -$|=1; # be sure to flush before closing -close IMG; +#open IMG,"|pngtopnm|ppmtogif 2>/dev/null"; # convert into a gif image +#print IMG $BinaryData; # output image +#$|=1; # be sure to flush before closing +#close IMG; +print $BinaryData; 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.