--- loncom/xml/lonplot.pm 2003/10/24 17:35:32 1.92 +++ loncom/xml/lonplot.pm 2005/02/24 22:01:40 1.105 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Dynamic plot # -# $Id: lonplot.pm,v 1.92 2003/10/24 17:35:32 matthew Exp $ +# $Id: lonplot.pm,v 1.105 2005/02/24 22:01:40 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -25,11 +25,6 @@ # # http://www.lon-capa.org/ # -# 12/15/01 Matthew -# 12/17 12/18 12/19 12/20 12/21 12/27 12/28 12/30 12/31 Matthew -# 01/01/02 Matthew -# 01/02 01/03 01/04 01/07 01/08 01/09 Matthew -# 01/21 02/05 02/06 2/28Matthew package Apache::lonplot; @@ -41,8 +36,17 @@ use Apache::response; use Apache::lonxml; use Apache::edit; +use vars qw/$weboutputformat $versionstring/; + BEGIN { - &Apache::lonxml::register('Apache::lonplot',('gnuplot')); + &Apache::lonxml::register('Apache::lonplot',('gnuplot')); + # + # Determine the version of GNUPLOT + $weboutputformat = 'gif'; + $versionstring = `gnuplot --version 2>/dev/null`; + if ($versionstring =~ /^gnuplot 4/) { + $weboutputformat = 'png'; + } } ## @@ -115,39 +119,10 @@ my $words_test = sub {$_[0]=~s/\s+/ ################################################################### my @gnuplot_edit_order = qw/alttag bgcolor fgcolor height width font transparent grid samples - border align texwidth texfont plottype/; + border align texwidth texfont plotcolor plottype lmargin rmargin tmargin + bmargin major_ticscale minor_ticscale/; -my $gnuplot_help_text = <<"ENDPLOTHELP"; -

-The gnuplot tag allows an author to design a plot which can -be created on the fly. This is intended for use in homework problems -where each student needs to see a distinct plot. It can be used in -conjunction with a script tag to generate random plots. -

-A gnuplot tag can contain the following sub-tags: -

-
-
Plot Label -
Allows you to place text at a given (x,y) coordinate on the plot. -
Plot Title -
The title of the plot -
Plot Xlabel -
The label on the horizontal axis of the plot -
Plot Ylabel -
The label on the vertical axis of the plot -
Plot Axes -
allows specification of the x and y ranges displayed in the plot -
Plot Key -
Lists the functions displayed in the plot. -
Plot Curve -
Sets the data used in the plot. -
Plot Tics -
Allows specification of the x and y coordinate 'tics' on the axes. -This is mostly used to adjust the grid lines when a grid is displayed. -
-If you are having trouble with your plot, please read the help -available on Plot Curve. -ENDPLOTHELP +my $margin_choices = ['default',0..20]; my %gnuplot_defaults = ( @@ -237,14 +212,63 @@ my %gnuplot_defaults = test => $int_test, description => 'Font size to use in TeX output (pts):', edit_type => 'choice', - choices => [qw/10 12 14 16 18 20 22 24 26 28 30 32 34 36/], + choices => [qw/8 10 12 14 16 18 20 22 24 26 28 30 32 34 36/], + }, + plotcolor => { + default => 'monochrome', + test => sub {$_[0]=~/^(monochrome|color|colour)$/}, + description => 'Color setting for printing:', + edit_type => 'choice', + choices => [qw/monochrome color colour/], }, plottype => { default => 'Cartesian', test => sub {$_[0]=~/^(Polar|Cartesian)$/}, description => 'Plot type:', edit_type => 'choice', - choices => ['Polar','Cartesian'] + choices => ['Cartesian','Polar'] + }, + lmargin => { + default => 'default', + test => sub {$_[0]=~/^(default|\d+)$/}, + description => 'Left margin width (pts):', + edit_type => 'choice', + choices => $margin_choices, + }, + rmargin => { + default => 'default', + test => sub {$_[0]=~/^(default|\d+)$/}, + description => 'Right margin width (pts):', + edit_type => 'choice', + choices => $margin_choices, + }, + tmargin => { + default => 'default', + test => sub {$_[0]=~/^(default|\d+)$/}, + description => 'Top margin width (pts):', + edit_type => 'choice', + choices => $margin_choices, + }, + bmargin => { + default => 'default', + test => sub {$_[0]=~/^(default|\d+)$/}, + description => 'Bottom margin width (pts):', + edit_type => 'choice', + choices => $margin_choices, + }, + major_ticscale => { + default => '1', + test => $real_test, + description => 'Size of major tic marks (plot coordinates)', + edit_type => 'entry', + size => '5' + }, + minor_ticscale => { + default => '0.5', + test => $real_test, + description => 'Size of minor tic mark (plot coordinates)', + edit_type => 'entry', + size => '5' }, ); @@ -339,7 +363,7 @@ my %tic_defaults = minorfreq => { default => '0', test => $int_test, - description => 'Number of minor tics between major tic marks', + description => 'Number of minor tics per major tic mark', edit_type => 'entry', size => '10' }, @@ -385,37 +409,6 @@ my %axis_defaults = } ); -my $curve_help_text = <<"ENDCURVEHELP"; -The curve tag is where you set the data to be plotted by gnuplot. -There are two ways of entering the information: -
-
Curve Data -
Using a data tag you can specify the numbers used to produce -the plot. -

-By default, two data tags will be available in a plot. The -first will specify X coordinates of the data and the second will -give the Y coordinates of the data. When working with a linestyle that -requires more than two data sets, inserting another data tag is -required. Unfortunately, you must make sure the data tags appear -in the order gnuplot expects the data. -

-Specifying the data should usually be done with a perl variable or array, -such as \@Xdata and \@Ydata. You may also specify numerical data seperated -by commas. Again, the order of the data tags is important. The -first tag will be the X data and the second will be the Y data. -

-
Curve Function -
The function tag allows you to specify the curve to be -plotted as a formula that gnuplot can understand. Be careful using this -tag. It is surprisingly easy to give gnuplot a function it cannot deal -with properly. Be explicit: 2*sin(2*3.141592*x/4) will work but -2sin(2*3.141592x/4) will not. If you do not receive any errors in the -gnuplot data but still do not have an image produced, it is likely there -is an error in your function tag. -
-ENDCURVEHELP - my @curve_edit_order = ('color','name','linestyle','pointtype','pointsize'); my %curve_defaults = @@ -489,8 +482,6 @@ sub start_gnuplot { $tagstack->[-1]); } elsif ($target eq 'edit') { $result .= &Apache::edit::tag_start($target,$token,'GnuPlot'); - $result .= &make_javascript(); - $result .= &help_win($gnuplot_help_text); $result .= &edit_attributes($target,$token,\%gnuplot_defaults, \@gnuplot_edit_order); } elsif ($target eq 'modified') { @@ -512,7 +503,7 @@ sub end_gnuplot { my $randnumber; # need to call rand everytime start_script would evaluate, as the # safe space rand number generator and the global rand generator - # are not seperate + # are not separate if ($target eq 'web' || $target eq 'tex' || $target eq 'grade' || $target eq 'answer') { $randnumber=int(rand(1000)); @@ -530,7 +521,7 @@ sub end_gnuplot { ## return image tag for the plot if ($target eq 'web') { $result .= <<"ENDIMAGE"; -get_text("/title"); $result.=&Apache::edit::rebuild_tag($token); - $result.=&Apache::edit::modifiedfield($token); + $result.=&Apache::edit::modifiedfield("/title",$parser); } return $result; } @@ -693,9 +683,8 @@ sub start_xlabel { &Apache::edit::start_spanning_row(). &Apache::edit::editline('',$text,'',60); } elsif ($target eq 'modified') { - my $text=$$parser[-1]->get_text("/xlabel"); $result.=&Apache::edit::rebuild_tag($token); - $result.=&Apache::edit::modifiedfield($token); + $result.=&Apache::edit::modifiedfield("/xlabel",$parser); } return $result; } @@ -728,9 +717,8 @@ sub start_ylabel { &Apache::edit::start_spanning_row(). &Apache::edit::editline('',$text,'',60); } elsif ($target eq 'modified') { - my $text=$$parser[-1]->get_text("/ylabel"); $result.=&Apache::edit::rebuild_tag($token); - $result.=&Apache::edit::modifiedfield($token); + $result.=&Apache::edit::modifiedfield("/ylabel",$parser); } return $result; } @@ -770,8 +758,7 @@ sub start_label { &Apache::edit::get_new_args ($token,$parstack,$safeeval,keys(%label_defaults)); $result.=&Apache::edit::rebuild_tag($token); - my $text=$$parser[-1]->get_text("/label"); - $result.=&Apache::edit::modifiedfield($token); + $result.=&Apache::edit::modifiedfield("/label",$parser); } return $result; } @@ -799,7 +786,6 @@ sub start_curve { push (@curves,\%curve); } elsif ($target eq 'edit') { $result .= &Apache::edit::tag_start($target,$token,'Curve'); - $result .= &help_win($curve_help_text); $result .= &edit_attributes($target,$token,\%curve_defaults, \@curve_edit_order); } elsif ($target eq 'modified') { @@ -849,8 +835,7 @@ sub start_function { &Apache::edit::editline('',$text,'',60); } elsif ($target eq 'modified') { $result.=&Apache::edit::rebuild_tag($token); - my $text=$$parser[-1]->get_text("/function"); - $result.=&Apache::edit::modifiedfield($token); + $result.=&Apache::edit::modifiedfield("/function",$parser); } return $result; } @@ -892,7 +877,7 @@ sub start_data { my @data; if ($datatext =~ /,/) { # comma deliminated @data = split /,/,$datatext; - } else { # Assume it's space seperated. + } else { # Assume it's space separated. @data = split / /,$datatext; } for (my $i=0;$i<=$#data;$i++) { @@ -927,8 +912,7 @@ sub start_data { &Apache::edit::editline('',$text,'',60); } elsif ($target eq 'modified') { $result.=&Apache::edit::rebuild_tag($token); - my $text=$$parser[-1]->get_text("/data"); - $result.=&Apache::edit::modifiedfield($token); + $result.=&Apache::edit::modifiedfield("/data",$parser); } return $result; } @@ -1022,6 +1006,24 @@ sub write_gnuplot_file { my $gnuplot_input = ''; my $curve; my $pt = $plot{'texfont'}; + # + # Check to be sure we do not have any empty curves + my @curvescopy; + foreach my $curve (@curves) { + if (exists($curve->{'function'})) { + if ($curve->{'function'} !~ /^\s*$/) { + push(@curvescopy,$curve); + } + } elsif (exists($curve->{'data'})) { + foreach my $data (@{$curve->{'data'}}) { + if (scalar(@$data) > 0) { + push(@curvescopy,$curve); + last; + } + } + } + } + @curves = @curvescopy; # Collect all the colors my @Colors; push @Colors, $plot{'bgcolor'}; @@ -1034,7 +1036,7 @@ sub write_gnuplot_file { } # set term if ($target eq 'web') { - $gnuplot_input .= 'set term gif '; + $gnuplot_input .= 'set term '.$weboutputformat .' '; $gnuplot_input .= 'transparent ' if ($plot{'transparent'} eq 'on'); $gnuplot_input .= $plot{'font'} . ' '; $gnuplot_input .= 'size '.$plot{'width'}.','.$plot{'height'}.' '; @@ -1042,7 +1044,7 @@ sub write_gnuplot_file { # set output $gnuplot_input .= "set output\n"; } elsif ($target eq 'tex') { - $gnuplot_input .= "set term postscript eps monochrome solid \"Helvetica\" $pt \n"; + $gnuplot_input .= "set term postscript eps $plot{'plotcolor'} solid \"Helvetica\" $pt \n"; $gnuplot_input .= "set output \"/home/httpd/perl/tmp/". &Apache::lonnet::unescape($filename).".eps\"\n"; } @@ -1052,6 +1054,22 @@ sub write_gnuplot_file { } else { # Assume Cartesian } + # margin + if (lc($plot{'lmargin'}) ne 'default') { + $gnuplot_input .= 'set lmargin '.$plot{'lmargin'}.$/; + } + if (lc($plot{'rmargin'}) ne 'default') { + $gnuplot_input .= 'set rmargin '.$plot{'rmargin'}.$/; + } + if (lc($plot{'tmargin'}) ne 'default') { + $gnuplot_input .= 'set tmargin '.$plot{'tmargin'}.$/; + } + if (lc($plot{'bmargin'}) ne 'default') { + $gnuplot_input .= 'set bmargin '.$plot{'bmargin'}.$/; + } + # tic scales + $gnuplot_input .= 'set ticscale '. + $plot{'major_ticscale'}.' '.$plot{'minor_ticscale'}.$/; # grid $gnuplot_input .= 'set grid'.$/ if ($plot{'grid'} eq 'on'); # border @@ -1111,7 +1129,11 @@ sub write_gnuplot_file { my $label; foreach $label (@labels) { $gnuplot_input .= 'set label "'.$label->{'text'}.'" at '. - $label->{'xpos'}.','.$label->{'ypos'}.' '.$label->{'justify'}.' font "Helvetica,'.$pt.'pt"'.$/ ; + $label->{'xpos'}.','.$label->{'ypos'}.' '.$label->{'justify'}; + if ($target eq 'tex') { + $gnuplot_input .=' font "Helvetica,'.$pt.'pt"' ; + } + $gnuplot_input .= $/; } if ($target eq 'tex') { $gnuplot_input .="set size 1,".$plot{'height'}/$plot{'width'}*1.38; @@ -1222,10 +1244,10 @@ sub edit_attributes { ($description,$attr,$token, $defaults->{$attr}->{'size'}); } elsif ($defaults->{$attr}->{'edit_type'} eq 'choice') { - $result .= &Apache::edit::select_arg + $result .= &Apache::edit::select_or_text_arg ($description,$attr,$defaults->{$attr}->{'choices'},$token); } elsif ($defaults->{$attr}->{'edit_type'} eq 'onoff') { - $result .= &Apache::edit::select_arg + $result .= &Apache::edit::select_or_text_arg ($description,$attr,['on','off'],$token); } $result .= '
'; @@ -1345,40 +1367,6 @@ sub insert_data { } ##---------------------------------------------------------------------- -# Javascript functions to display help for tags - -sub make_javascript { - my $helpwindowwidth = 400; - my $helpwindowheight = 400; - my $result = ''; - $result.=<<"ENDFUNCTION"; - -ENDFUNCTION - return $result; -} - -sub help_win { - my ($helptext)=@_; - $helptext =~ s/\n/ /g; - $helptext =~ s/\'/\\\'/g; - my $result = ''; - $result.=<<"ENDWIN"; -
-help -

-ENDWIN - return $result; -} -##---------------------------------------------------------------------- 1; __END__