Annotation of loncom/cgi/graph.png, revision 1.30
1.1 minaeibi 1: #!/usr/bin/perl
2: #
1.30 ! matthew 3: # $Id: graph.png,v 1.29 2003/10/27 21:21:08 matthew Exp $
1.5 minaeibi 4: #
5: # Copyright Michigan State University Board of Trustees
6: #
7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
8: #
9: # LON-CAPA is free software; you can redistribute it and/or modify
10: # it under the terms of the GNU General Public License as published by
11: # the Free Software Foundation; either version 2 of the License, or
12: # (at your option) any later version.
13: #
14: # LON-CAPA is distributed in the hope that it will be useful,
15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17: # GNU General Public License for more details.
18: #
19: # You should have received a copy of the GNU General Public License
20: # along with LON-CAPA; if not, write to the Free Software
21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22: #
23: # /home/httpd/cgi-bin/graph.gif
24: #
25: # http://www.lon-capa.org/
26: #
1.1 minaeibi 27: # The LearningOnline Network with CAPA
1.22 matthew 28: #
1.1 minaeibi 29: # A CGI script that dynamically outputs a graphical chart for lonstatistics.
1.5 minaeibi 30: #
31: ####
1.22 matthew 32:
33: =pod
34:
35: =head1 NAME
36:
37: graph.png
38:
39: =head1 SYNOPSIS
40:
41: produces plots based on input
42:
43: =head1 DESCRIPTION
44:
45: graph.png is a cgi-bin script which produces plots based on input data.
46:
47: The query string is expected to be as follows (without whitespace):
48:
49: escape(Plot title) & escape(X label)& escape(Y label) & Maximum Y value &
50: Number of bars & $data1 & $data2
51:
52: $data1 and $data2 are expected to be comma seperated lists of numbers.
53: escape( value ) means the values must be run through lonnet::escape.
54:
55: =cut
1.1 minaeibi 56:
57: use strict;
1.24 matthew 58: use lib '/home/httpd/lib/perl';
1.9 minaeibi 59: use GD::Graph::bars;
1.29 matthew 60: use GD::Graph::lines;
1.1 minaeibi 61: use GD::Graph::colour;
62: use GD::Graph::Data;
1.24 matthew 63: use LONCAPA::loncgi();
1.1 minaeibi 64:
1.21 matthew 65: sub unescape {
66: my $str=shift;
67: $str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
68: return $str;
69: }
70:
1.29 matthew 71: sub error {
72: my ($error) = @_;
73: my $Str = <<"END";
74: Content-type: text/html
75:
76: <html>
77: <head><title>Bad Graph</title></head>
78: <body>
79: <p>
80: There was an error producing the graph you requested.
81: </p><p>
82: $error
83: </p>
84: </body>
85: </html>
86: END
87: return $Str;
88: }
89:
90: my $id = $ENV{'QUERY_STRING'};
91:
92: #
93: # &get_env($name,$default)
94: sub get_env {
95: my $key = 'cgi.'.$id.'.'.(shift());
96: return shift if (! exists($ENV{$key}));
97: return $ENV{$key};
98: }
99:
1.24 matthew 100: if (! &LONCAPA::loncgi::check_cookie_and_load_env()) {
101: print <<END;
102: Content-type: text/html
103:
104: <html>
105: <head><title>Bad Cookie</title></head>
106: <body>
1.28 matthew 107: Your cookie information is incorrect.
1.24 matthew 108: </body>
109: </html>
110: END
1.26 albertel 111: exit;
1.24 matthew 112: }
113:
1.4 matthew 114: $|=1; # Autoflush after each print/write
1.1 minaeibi 115:
1.29 matthew 116: my $colordefaults = join(',',
117: ('#33ff00',
118: '#0033cc','#990000','#aaaa66','#663399','#ff9933',
119: '#66ccff','#ff9999','#cccc33','#660000','#33cc66',
120: ));
121:
122: my $height = &get_env('height',300);
123: my $width = &get_env('width', 400);
124: my $PlotType = &get_env('PlotType','bar');
125:
126: my %GraphSettings = (
127: title => &unescape(&get_env('title','')),
128: x_label => &unescape(&get_env('xlabel','')),
129: y_label => &unescape(&get_env('ylabel','')),
1.24 matthew 130: x_label_position => 0.5,
1.29 matthew 131: dclrs => [split(',',&get_env('Colors',
132: $colordefaults))],
1.24 matthew 133: fgclr => 'black',
134: boxclr => 'white',
135: accentclr => 'dblue',
136: valuesclr => '#ffff77',
137: l_margin => 10,
138: b_margin => 10,
139: r_margin => 10,
140: t_margin => 10,
141: transparent => 0,
1.29 matthew 142: );
1.24 matthew 143:
1.29 matthew 144: $GraphSettings{'x_label_skip'} = &get_env('xskip',1);
145: $GraphSettings{'x_tick_offset'} = &get_env('x_tick_offset',0);
1.30 ! matthew 146: $GraphSettings{'y_max_value'} = &get_env('Max',1);
1.29 matthew 147:
148: my $MyGraph;
149: if ($PlotType eq 'bar') {
150: # Pick up bar graph settings
151: $GraphSettings{'bar_width'} = &get_env('bar_width',undef);
152: $GraphSettings{'long_ticks'} = 1;
153: $GraphSettings{'tick_length'} = 0;
154: $GraphSettings{'x_ticks'} = 0;
155: $GraphSettings{'cumulate'} = 2;
156: $GraphSettings{'zero_axis'} = 1;
157: } else {
158: #
159: # X label skip setup
160: my $skip_x = &get_env('xskip',1);
161: my $x_tick_offset = &get_env('x_tick_offset',$skip_x-1);
162: my $zero_axis = &get_env('zero_axis',1);
163: #
164: # Fill up %GraphSettings
165: $GraphSettings{'long_ticks'} = 1;
166: $GraphSettings{'tick_length'} = 0;
167: $GraphSettings{'x_ticks'} = &get_env('x_ticks',0),;
168: $GraphSettings{'x_label_skip'} = $skip_x;
169: $GraphSettings{'x_tick_offset'} = $x_tick_offset;
170: $GraphSettings{'zero_axis'} = 1;
1.30 ! matthew 171: if (&get_env('two_axes',0)) {
! 172: $GraphSettings{'two_axes'} = 1;
! 173: $GraphSettings{'y1_max_value'} = &get_env('y1_max_value',0);
! 174: $GraphSettings{'y1_min_value'} = &get_env('y1_min_value',1);
! 175: $GraphSettings{'y2_max_value'} = &get_env('y2_max_value',1);
! 176: $GraphSettings{'y2_min_value'} = &get_env('y2_min_value',1);
! 177: }
1.29 matthew 178: }
179: #
180: # Pick up miscellanious values passed in by the user
181: #
182: # Create the plot and check it out
183: if ($PlotType eq 'bar') {
184: $MyGraph = GD::Graph::bars->new($width,$height);
185: } else {
186: $MyGraph = GD::Graph::lines->new($width,$height);
187: }
188: if (! defined($MyGraph)) {
189: print &error('Unable to create initial graph');
1.24 matthew 190: return;
191: }
1.1 minaeibi 192:
1.29 matthew 193: ##
194: ## Build the @Data array
195: my $NumSets = &get_env('NumSets');
196: my @Data; # stores the data for the graph
197: my @xlabels = split(',',&get_env('labels'));
198: push(@Data,\@xlabels);
199: for (my $i=1;$i<=$NumSets;$i++) {
200: push(@Data,[split(',',&get_env('data.'.$i))]);
201: }
1.24 matthew 202:
1.29 matthew 203: my $error = '';
204: if (! $MyGraph->set(%GraphSettings)) {
205: print &error($MyGraph->error);
1.24 matthew 206: return;
207: }
1.1 minaeibi 208:
1.29 matthew 209: my $plot = $MyGraph->plot(\@Data);
210: if (! defined($plot)) {
211: my $error = 'Unable to plot the data provided.';
1.30 ! matthew 212: # Debugging code:
! 213: # $error .= '<pre>'.join(',',@{$Data[0]}).'</pre>';
! 214: # $error .= '<pre>'.join(',',@{$Data[1]}).'</pre>';
! 215: # $error .= '<pre>'.join(',',@{$Data[2]}).'</pre>' if (ref($Data[2]));
! 216: # $error .= '<pre>'.join(',',@{$Data[3]}).'</pre>' if (ref($Data[3]));
1.29 matthew 217: print &error($error);
218: exit;
219: }
220:
1.24 matthew 221: my $BinaryData=$plot->png;
222: undef($MyGraph);
223: undef($plot);
224:
225: if (! defined($BinaryData)) {
1.29 matthew 226: print &error('Unable to render graph as image');
227: exit;
1.24 matthew 228: }
1.12 minaeibi 229:
1.16 albertel 230: # Tell the server we are sending a png graphic
1.1 minaeibi 231: print <<END;
1.16 albertel 232: Content-type: image/png
1.1 minaeibi 233:
234: END
235:
236: binmode(STDOUT);
1.16 albertel 237: #open IMG,"|pngtopnm|ppmtogif 2>/dev/null"; # convert into a gif image
238: #print IMG $BinaryData; # output image
239: #$|=1; # be sure to flush before closing
240: #close IMG;
241: print $BinaryData;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>