--- loncom/xml/lonplot.pm 2009/03/18 14:05:19 1.148.2.2 +++ loncom/xml/lonplot.pm 2013/02/04 17:23:44 1.173 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Dynamic plot # -# $Id: lonplot.pm,v 1.148.2.2 2009/03/18 14:05:19 raeburn Exp $ +# $Id: lonplot.pm,v 1.173 2013/02/04 17:23:44 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -26,6 +26,9 @@ # http://www.lon-capa.org/ # + + + package Apache::lonplot; use strict; @@ -57,6 +60,8 @@ BEGIN { } +=pod + ## ## Description of data structures: ## @@ -88,14 +93,21 @@ BEGIN { ## ## ################################################################### +=cut + my $max_str_len = 50; # if a label, title, xlabel, or ylabel text # is longer than this, it will be truncated. -my %linetypes = +my %linetypes = # For png use these linetypes. ( solid => 1, dashed => 0 ); +my %ps_linetypes = # For ps the line types are different! + ( + solid => 0, + dashed => 7 + ); my %linestyles = ( @@ -120,13 +132,22 @@ my $real_test = sub {$_[0]=~s/\s+//g;$_[0]=~/^[+-]?\d*\.?\d*([eE][+-]\d+)?$/}; my $pos_real_test = sub {$_[0]=~s/\s+//g;$_[0]=~/^[+]?\d*\.?\d*([eE][+-]\d+)?$/}; -my $color_test = sub {$_[0]=~s/\s+//g;$_[0]=~/^x[\da-fA-F]{6}$/}; +my $color_test; +if ($version < 4.6) { + $color_test = sub {$_[0]=~s/\s+//g;$_[0]=~s/^\#/x/;$_[0]=~/^x[\da-fA-F]{6}$/}; +} else { + $color_test = sub {$_[0]=~s/\s+//g;$_[0]=~s/^x/#/;$_[0]=~/^\#[\da-fA-F]{6}$/}; +} my $onoff_test = sub {$_[0]=~/^(on|off)$/}; my $key_pos_test = sub {$_[0]=~/^(top|bottom|right|left|outside|below| )+$/}; my $sml_test = sub {$_[0]=~/^(\d+|small|medium|large)$/}; my $linestyle_test = sub {exists($linestyles{$_[0]})}; my $words_test = sub {$_[0]=~s/\s+/ /g;$_[0]=~/^([\w~!\@\#\$\%^&\*\(\)-=_\+\[\]\{\}:\;\'<>,\.\/\?\\]+ ?)+$/}; +my $arrowhead_test = sub{$_[0]=~/^(nohead|head|heads| )+$/}; +my $arrowstyle_test= sub{$_[0]=~/^(filled|empty|nofilled)+$/}; +my $degree_test = sub{&$pos_real_test($_[0]) && ($_[0] <= 360.0)}; + ################################################################### ## ## ## Attribute metadata ## @@ -169,14 +190,16 @@ my %gnuplot_defaults = test => $color_test, description => 'Background color of image (xffffff)', edit_type => 'entry', - size => '10' + size => '10', + class => 'colorchooser' }, fgcolor => { default => 'x000000', test => $color_test, description => 'Foreground color of image (x000000)', edit_type => 'entry', - size => '10' + size => '10', + class => 'colorchooser' }, transparent => { default => 'off', @@ -445,10 +468,16 @@ my %tic_defaults = description => 'Number of minor tics per major tic mark', edit_type => 'entry', size => '10' - }, + }, + rotate => { + default => 'off', + test => $onoff_test, + description => 'Rotate tic label by 90 degrees if on', + edit_type => 'onoff' + } ); -my @axis_edit_order = ('color','xmin','xmax','ymin','ymax','xformat', 'yformat'); +my @axis_edit_order = ('color','xmin','xmax','ymin','ymax','xformat', 'yformat', 'xzero', 'yzero'); my %axis_defaults = ( color => { @@ -456,7 +485,8 @@ my %axis_defaults = test => $color_test, description => 'Color of grid lines (x000000)', edit_type => 'entry', - size => '10' + size => '10', + class => 'colorchooser' }, xmin => { default => '-10.0', @@ -500,10 +530,29 @@ my %axis_defaults = edit_type => 'choice', choices => ['on', 'off', '2e', '2f'], }, - + + xzero => { + default => 'off', + test => sub {$_[0]=~/^(off|line|thick-line|dotted)$/}, + description => 'Show x-zero (y=0) axis', + edit_type => 'choice', + choices => ['off', 'line', 'thick-line', 'dotted'], + }, + + yzero => { + default => 'off', + test => sub {$_[0]=~/^(off|line|thick-line|dotted)$/}, + description => 'Show y-zero (x=0) axis', + edit_type => 'choice', + choices => ['off', 'line', 'thick-line', 'dotted'], + }, ); -my @curve_edit_order = ('color','name','linestyle','linewidth','linetype','pointtype','pointsize','limit'); + +my @curve_edit_order = ('color','name','linestyle','linewidth','linetype', + 'pointtype','pointsize','limit', 'arrowhead', 'arrowstyle', + 'arrowlength', 'arrowangle', 'arrowbackangle' + ); my %curve_defaults = ( @@ -512,7 +561,8 @@ my %curve_defaults = test => $color_test, description => 'Color of curve (x000000)', edit_type => 'entry', - size => '10' + size => '10', + class => 'colorchooser' }, name => { default => '', @@ -563,6 +613,43 @@ my %curve_defaults = edit_type => 'choice', choices => ['above', 'below', 'closed','x1','x2','y1','y2'] }, + arrowhead => { + default => 'head', + test => $arrowhead_test, + description => 'Vector arrow head type', + edit_type => 'choice', + choices => ['nohead', 'head', 'heads'] + }, + arrowstyle => { + default => 'filled', + test => $arrowstyle_test, + description => 'Vector arrow head style', + edit_type => 'choice', + choices => ['filled', 'empty', 'nofilled'] + }, + arrowlength => { + default => 0.02, + test => $pos_real_test, + description => "Length of vector arrow (only applies to vector plots)", + edit_type => 'entry', + size => '5' + }, + arrowangle => { + default => 10.0, + test => $degree_test, + description => 'Angle of arrow branches to arrow body (only applies to vector plots)', + edit_type => 'entry', + size => '5' + }, + + arrowbackangle => { + default => 90.0, + test => $degree_test, + descripton => 'Angle of arrow back lines to branches.', + edit_type => 'entry', + size => '5' + } + ); ################################################################### @@ -574,6 +661,8 @@ my %curve_defaults = undef %Apache::lonplot::plot; my (%key,%axis,$title,$xlabel,$ylabel,@labels,@curves,%xtics,%ytics); +my $current_tics; # Reference to the current tick hash + sub start_gnuplot { undef(%Apache::lonplot::plot); undef(%key); undef(%axis); undef($title); undef($xlabel); undef($ylabel); @@ -598,7 +687,18 @@ sub start_gnuplot { } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args ($token,$parstack,$safeeval,keys(%gnuplot_defaults)); + if ($constructtag) { + # + # The color chooser does not prepent x to the color values + # Do that here: + # + foreach my $attribute ('bgcolor', 'fgcolor') { + my $value = $token->[2]{$attribute}; + if (defined $value && !($value =~ /^x/)) { + $token->[2]{$attribute} = 'x' . $value; + } + } $result = &Apache::edit::rebuild_tag($token); } } @@ -612,6 +712,8 @@ sub end_gnuplot { ('title','xlabel','ylabel','key','axis','label','curve')); my $result = ''; my $randnumber; + my $tmpdir =LONCAPA::tempdir(); # Where temporary files live: + # need to call rand everytime start_script would evaluate, as the # safe space rand number generator and the global rand generator # are not separate @@ -623,7 +725,6 @@ sub end_gnuplot { &check_inputs(); # Make sure we have all the data we need ## ## Determine filename - my $tmpdir = '/home/httpd/perl/tmp/'; my $filename = $env{'user.name'}.'_'.$env{'user.domain'}. '_'.time.'_'.$$.$randnumber.'_plot'; ## Write the plot description to the file @@ -644,7 +745,7 @@ ENDIMAGE #might be inside the safe space, register the URL for later &Apache::lonxml::register_ssi("/cgi-bin/plot.gif?file=$filename.data&output=eps"); $result = "%DYNAMICIMAGE:$Apache::lonplot::plot{'width'}:$Apache::lonplot::plot{'height'}:$Apache::lonplot::plot{'texwidth'}\n"; - $result .= '\graphicspath{{/home/httpd/perl/tmp/}}'."\n"; + $result .= '\graphicspath{{'.$tmpdir.'}}'."\n"; $result .= '\includegraphics[width='.$Apache::lonplot::plot{'texwidth'}.' mm]{'.&unescape($filename).'.eps}'; } } elsif ($target eq 'edit') { @@ -661,6 +762,8 @@ sub start_xtics { if ($target eq 'web' || $target eq 'tex') { &get_attributes(\%xtics,\%tic_defaults,$parstack,$safeeval, $tagstack->[-1]); + $current_tics = \%xtics; + &Apache::lonxml::register('Apache::lonplot', 'tic'); } elsif ($target eq 'edit') { $result .= &Apache::edit::tag_start($target,$token,'xtics'); $result .= &edit_attributes($target,$token,\%tic_defaults, @@ -679,6 +782,7 @@ sub end_xtics { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result = ''; if ($target eq 'web' || $target eq 'tex') { + &Apache::lonxml::deregister('Apache::lonplot', 'tic'); } elsif ($target eq 'edit') { $result.=&Apache::edit::tag_end($target,$token); } @@ -692,6 +796,8 @@ sub start_ytics { if ($target eq 'web' || $target eq 'tex') { &get_attributes(\%ytics,\%tic_defaults,$parstack,$safeeval, $tagstack->[-1]); + $current_tics = \%ytics; + &Apache::lonxml::register('Apache::lonplot', 'tic'); } elsif ($target eq 'edit') { $result .= &Apache::edit::tag_start($target,$token,'ytics'); $result .= &edit_attributes($target,$token,\%tic_defaults, @@ -710,12 +816,55 @@ sub end_ytics { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result = ''; if ($target eq 'web' || $target eq 'tex') { + &Apache::lonxml::deregister('Apache::lonplot', 'tic'); } elsif ($target eq 'edit') { $result.=&Apache::edit::tag_end($target,$token); } return $result; } + +##---------------------------------------------------------------- +# +# Tic handling: +# The tag allows users to specify exact Tic positions and labels +# for each axis. In this version we only support level 0 tics (major tic). +# Each tic has associated with it a position and a label +# $current_tics is a reference to the current tick description hash. +# We add elements to an array in that has: ticspecs whose elements +# are 'pos' - the tick position and 'label' - the tic label. +# + + +sub start_tic { + my ($target, $token, $tagstack, $parstack, $parser, $safeeval, $style) = @_; + + my $result = ''; + if ($target eq 'web' || $target eq 'tex') { + my $tic_location = &Apache::lonxml::get_param('location', $parstack, $safeeval); + my $tic_label = &Apache::lonxml::get_all_text('/tic', $parser); + + # Tic location must e a real: + + if (!&$real_test($tic_location)) { + &Apache::lonxml::warning("Tic location: $tic_location must be a real number"); + } else { + + if (!defined $current_tics->{'ticspecs'}) { + $current_tics->{'ticspecs'} = []; + } + my $ticspecs = $current_tics->{'ticspecs'}; + push (@$ticspecs, {'pos' => $tic_location, 'label' => $tic_label}); + } + } + + return $result; +} + +sub end_tic { + return ''; +} + ##-----------------------------------------------------------------font my %font_properties = ( @@ -1328,6 +1477,13 @@ sub start_curve { my $constructtag=&Apache::edit::get_new_args ($token,$parstack,$safeeval,keys(%curve_defaults)); if ($constructtag) { + # + # Fix up the color attribute as jcolor does not prepend an x + # + my $value = $token->[2]{'color'}; + if (defined $value && !($value =~ /^x/)) { + $token->[2]{'color'} = 'x' . $value; + } $result = &Apache::edit::rebuild_tag($token); } } @@ -1363,6 +1519,8 @@ sub start_function { $style); $function = &Apache::run::evaluate($function,$safeeval,$$parstack[-1]); $function=~s/\^/\*\*/gs; + $function=~ s/^\s+//; # Trim leading + $function=~ s/\s+$//; # And trailing whitespace. $curves[-1]->{'function'} = $function; } elsif ($target eq 'edit') { $result .= &Apache::edit::tag_start($target,$token,'Gnuplot compatible curve function'); @@ -1474,7 +1632,17 @@ sub start_axis { } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args ($token,$parstack,$safeeval,keys(%axis_defaults)); + if ($constructtag) { + # + # Fix up the color attribute since jchooser does not + # prepend an x to the color: + # + my $value = $token->[2]{'color'}; + if (defined $value && !($value =~ /^x/)) { + $token->[2]{'color'} = 'x' . $value; + } + $result = &Apache::edit::rebuild_tag($token); } } @@ -1532,6 +1700,65 @@ sub get_attributes{ } return ; } +## +# Generate tic mark specifications. +# +# @param type - type of tics (xtics or ytics). +# @param spec - Reference to a hash that contains the tic specification. +# @param target - 'tex' if hard copy target. +# +# @return string - the tic specification command. +# +sub generate_tics { + my ($type, $spec, $target) = @_; + my $result = ''; + + + if ((ref($spec) eq 'HASH') && (keys(%{$spec}) > 0)) { + + + + # Major tics: - If there are 'ticspecs' these override any other + # specifications: + + + + $result .= "set $type $spec->{'location'} "; + $result .= ($spec->{'mirror'} eq 'on') ? 'mirror ' : 'nomirror '; + if ($spec->{'rotate'} eq 'on') { + $result .= ' rotate '; + } + if (defined $spec->{'ticspecs'}) { + $result .= '( '; + my @ticspecs; + my $ticinfo = $spec->{'ticspecs'}; + foreach my $tic (@$ticinfo) { + push(@ticspecs, '"' . $tic->{'label'} . '" ' . $tic->{'pos'} ); + } + $result .= join(', ', (@ticspecs)); + $result .= ' )'; + } else { + $result .= "$spec->{'start'}, "; + $result .= "$spec->{'increment'}, "; + $result .= "$spec->{'end'} "; + } + if ($target eq 'tex' ) { + $result .= 'font "Helvetica,22"'; + } + $result .= "\n"; + + # minor frequency: + + if ($spec->{'minorfreq'} != 0) { + $result .= "set m$type $spec->{'minorfreq'}\n"; + } + } elsif ($target eq 'tex' ) { + $result .= "set $type font " . '"Helvetica,22"' ."\n"; + } + + + return $result; +} ##------------------------------------------------------- write_gnuplot_file sub write_gnuplot_file { @@ -1567,6 +1794,7 @@ sub write_gnuplot_file { $curve->{'color'} : $Apache::lonplot::plot{'fgcolor'} ); } + # set term if ($target eq 'web') { $gnuplot_input .= 'set terminal png enhanced nocrop '; @@ -1579,7 +1807,7 @@ sub write_gnuplot_file { # set output $gnuplot_input .= "set output\n"; } elsif ($target eq 'tex') { - $gnuplot_input .= "set term postscript eps enhanced $Apache::lonplot::plot{'plotcolor'} solid "; + $gnuplot_input .= "set term postscript eps enhanced $Apache::lonplot::plot{'plotcolor'} dash "; if (!$font_properties->{'tex_no_file'}) { $gnuplot_input .= 'fontfile "'.$Apache::lonnet::perlvar{'lonFontsDir'}. @@ -1587,11 +1815,12 @@ sub write_gnuplot_file { } $gnuplot_input .= ' "'.$font_properties->{'printname'}.'" '; $gnuplot_input .= $fontsize; - $gnuplot_input .= "\nset output \"/home/httpd/perl/tmp/". + $gnuplot_input .= "\nset output \"".$tmpdir. &unescape($filename).".eps\"\n"; $gnuplot_input .= "set encoding iso_8859_1\n"; # Get access to extended font. } + $gnuplot_input .= "set encoding utf8\n"; # cartesian or polar plot? if (lc($Apache::lonplot::plot{'plottype'}) eq 'polar') { $gnuplot_input .= 'set polar'.$/; @@ -1659,8 +1888,8 @@ sub write_gnuplot_file { $gnuplot_input .= "set samples $Apache::lonplot::plot{'samples'}\n"; # title, xlabel, ylabel # titles - my $extra_space_x = ($xtics{'location'} eq 'axis') ? ' 0, -0.5 ' : ''; - my $extra_space_y = ($ytics{'location'} eq 'axis') ? ' -0.5, 0 ' : ''; + my $extra_space_x = ($xtics{'location'} eq 'axis') ? ' offset 0, -0.5 ' : ''; + my $extra_space_y = ($ytics{'location'} eq 'axis') ? ' offset -0.5, 0 ' : ''; if ($target eq 'tex') { $gnuplot_input .= "set title \"$title\" font \"".$font_properties->{'printname'}.",".$fontsize."pt\"\n" if (defined($title)) ; @@ -1672,42 +1901,10 @@ sub write_gnuplot_file { $gnuplot_input .= "set ylabel \"$ylabel\" $extra_space_y \n" if (defined($ylabel)); } # tics - if (%xtics) { - $gnuplot_input .= "set xtics $xtics{'location'} "; - $gnuplot_input .= ( $xtics{'mirror'} eq 'on'?"mirror ":"nomirror "); - $gnuplot_input .= "$xtics{'start'}, "; - $gnuplot_input .= "$xtics{'increment'}, "; - $gnuplot_input .= "$xtics{'end'} "; - if ($target eq 'tex') { - $gnuplot_input .= 'font "Helvetica,22"'; # Needed in iso 8859-1 enc. - } - $gnuplot_input .= "\n"; - if ($xtics{'minorfreq'} != 0) { - $gnuplot_input .= "set mxtics ".$xtics{'minorfreq'}."\n"; - } - } else { - if ($target eq 'tex') { - $gnuplot_input .= 'set xtics font "Helvetica,22"'."\n"; # needed in iso 8859-1 enc - } - } - if (%ytics) { - $gnuplot_input .= "set ytics $ytics{'location'} "; - $gnuplot_input .= ( $ytics{'mirror'} eq 'on'?"mirror ":"nomirror "); - $gnuplot_input .= "$ytics{'start'}, "; - $gnuplot_input .= "$ytics{'increment'}, "; - $gnuplot_input .= "$ytics{'end'} "; - if ($target eq 'tex') { - $gnuplot_input .= 'font "Helvetica,22"'; # Needed in iso-8859-1 encoding. - } - $gnuplot_input .= "\n"; - if ($ytics{'minorfreq'} != 0) { - $gnuplot_input .= "set mytics ".$ytics{'minorfreq'}."\n"; - } - } else { - if ($target eq 'tex') { - $gnuplot_input .= 'set ytics font "Helvetica,22"'."\n"; # Needed for iso 8859-1 enc. - } - } + $gnuplot_input .= &generate_tics('xtics', \%xtics, $target); + + $gnuplot_input .= &generate_tics('ytics', \%ytics, $target); + # axis if (%axis) { if ($axis{'xformat'} ne 'on') { @@ -1728,6 +1925,26 @@ sub write_gnuplot_file { } $gnuplot_input .= "set xrange \[$axis{'xmin'}:$axis{'xmax'}\]\n"; $gnuplot_input .= "set yrange \[$axis{'ymin'}:$axis{'ymax'}\]\n"; + if ($axis{'xzero'} ne 'off') { + $gnuplot_input .= "set xzeroaxis "; + if ($axis{'xzero'} eq 'line' || $axis{'xzero'} eq 'thick-line') { + $gnuplot_input .= "lt -1 "; + if ($axis{'xzero'} eq 'thick-line') { + $gnuplot_input .= "lw 3 "; + } + } + $gnuplot_input .= "\n"; + } + if ($axis{'yzero'} ne 'off') { + $gnuplot_input .= "set yzeroaxis "; + if ($axis{'yzero'} eq 'line' || $axis{'yzero'} eq 'thick-line') { + $gnuplot_input .= "lt -1 "; + if ($axis{'yzero'} eq 'thick-line') { + $gnuplot_input .= "lw 3 "; + } + } + $gnuplot_input .= "\n"; + } } # Key if (%key) { @@ -1759,40 +1976,37 @@ sub write_gnuplot_file { $gnuplot_input .="\n"; } # curves - $gnuplot_input .= 'plot '; + # + # Each curve will have its very own linestyle. + # (This should work just fine in web rendition I think). + # The line_xxx variables will hold the elements of the line style. + # type (solid/dashed), color, width + # + my $linestyle_index = 50; + my $line_width = ''; + my $plots = ''; + + # If arrows are needed there will be an arrow style for each as well: + # + + my $arrow_style_index = 50; + for (my $i = 0;$i<=$#curves;$i++) { $curve = $curves[$i]; - $gnuplot_input.= ', ' if ($i > 0); + my $plot_command = ''; + my $plot_type = ''; + if ($i > 0) { + $plot_type = ', '; + } if ($target eq 'tex') { $curve->{'linewidth'} *= 2; } + $line_width = $curve->{'linewidth'}; if (exists($curve->{'function'})) { - $gnuplot_input.= + $plot_type .= $curve->{'function'}.' title "'. $curve->{'name'}.'" with '. $curve->{'linestyle'}; - - if (($curve->{'linestyle'} eq 'points') || - ($curve->{'linestyle'} eq 'linespoints') || - ($curve->{'linestyle'} eq 'errorbars') || - ($curve->{'linestyle'} eq 'xerrorbars') || - ($curve->{'linestyle'} eq 'yerrorbars') || - ($curve->{'linestyle'} eq 'xyerrorbars')) { - $gnuplot_input.=' pointtype '.$curve->{'pointtype'}; - $gnuplot_input.=' pointsize '.$curve->{'pointsize'}; - } elsif ($curve->{'linestyle'} eq 'filledcurves') { - $gnuplot_input.= ' '.$curve->{'limit'}; - } elsif ($curve->{'linetype'} ne '' && - $curve->{'linestyle'} eq 'lines') { - $gnuplot_input.= ' linetype '; - $gnuplot_input.= $linetypes{$curve->{'linetype'}}; - $gnuplot_input.= ' linecolor rgb "'; - # convert color from xaaaaaa to #aaaaaa - $curve->{'color'} =~ s/^x/#/; - $gnuplot_input.= $curve->{'color'}.'"'; - } - $gnuplot_input.= ' linewidth '.$curve->{'linewidth'}; - } elsif (exists($curve->{'data'})) { # Store data values in $datatext my $datatext = ''; @@ -1813,34 +2027,77 @@ sub write_gnuplot_file { print $fh $datatext; close($fh); # generate gnuplot text - $gnuplot_input.= '"'.$datafilename.'" title "'. + $plot_type .= '"'.$datafilename.'" title "'. $curve->{'name'}.'" with '. $curve->{'linestyle'}; - if (($curve->{'linestyle'} eq 'points') || - ($curve->{'linestyle'} eq 'linespoints') || - ($curve->{'linestyle'} eq 'errorbars') || - ($curve->{'linestyle'} eq 'xerrorbars') || - ($curve->{'linestyle'} eq 'yerrorbars') || - ($curve->{'linestyle'} eq 'xyerrorbars')) { - $gnuplot_input.=' pointtype '.$curve->{'pointtype'}; - $gnuplot_input.=' pointsize '.$curve->{'pointsize'}; - } elsif ($curve->{'linestyle'} eq 'filledcurves') { - $gnuplot_input.= ' '.$curve->{'limit'}; - } elsif ($curve->{'linetype'} ne '' && - $curve->{'linestyle'} eq 'lines') { - $gnuplot_input.= ' linetype '; - $gnuplot_input.= $linetypes{$curve->{'linetype'}}; - $gnuplot_input.= ' linecolor rgb "'; - # convert color from xaaaaaa to #aaaaaa - $curve->{'color'} =~ s/^x/#/; - $gnuplot_input.= $curve->{'color'}.'"'; - } - $gnuplot_input.= ' linewidth '.$curve->{'linewidth'}; } + my $pointtype = ''; + my $pointsize = ''; + + # Figure out the linestyle: + + my $lt = $curve->{'linetype'} ne '' ? $curve->{'linetype'} + : 'solid'; # Line type defaults to solid. + # The mapping of lt -> the actual gnuplot line type depends on the target: + + if ($target eq 'tex') { + $lt = $ps_linetypes{$lt}; + } else { + $lt = $linetypes{$lt} + } + + my $color = $curve->{'color'}; + $color =~ s/^x/#/; # Convert xhex color -> #hex color. + + + if (($curve->{'linestyle'} eq 'points') || + ($curve->{'linestyle'} eq 'linespoints') || + ($curve->{'linestyle'} eq 'errorbars') || + ($curve->{'linestyle'} eq 'xerrorbars') || + ($curve->{'linestyle'} eq 'yerrorbars') || + ($curve->{'linestyle'} eq 'xyerrorbars')) { + + $pointtype =' pointtype '.$curve->{'pointtype'}; + $pointsize =' pointsize '.$curve->{'pointsize'}; + } elsif ($curve->{'linestyle'} eq 'filledcurves') { + $plot_command.= ' '.$curve->{'limit'}; + } elsif ($curve->{'linestyle'} eq 'vector') { + + # Create the arrow head style add it to + # $gnuplot_input..and ensure it gets + # Selected in the plot command. + + $gnuplot_input .= "set style arrow $arrow_style_index "; + $gnuplot_input .= ' ' . $curve->{'arrowhead'}; + $gnuplot_input .= ' size ' . $curve->{'arrowlength'}; + $gnuplot_input .= ','.$curve->{'arrowangle'}; + $gnuplot_input .= ',' . $curve->{'arrowbackangle'}; + $gnuplot_input .= ' ' . $curve->{'arrowstyle'} . " ls $linestyle_index\n"; + + + $plot_command .= " arrowstyle $arrow_style_index "; + $arrow_style_index++; + } + + my $style_command = "set style line $linestyle_index $pointtype $pointsize linetype $lt linewidth $line_width lc rgb '$color'\n"; + $gnuplot_input .= $style_command; + + # The condition below is because gnuplot lumps the linestyle in with the + # arrowstyle _sigh_. + + if ($curve->{'linestyle'} ne 'vector') { + $plot_command.= " ls $linestyle_index"; + } + + $plots .= $plot_type . ' ' . $plot_command; + $linestyle_index++; # Each curve get a unique linestyle. } + $gnuplot_input .= 'plot '.$plots; # Write the output to a file. - open (my $fh,">$tmpdir$filename.data"); - binmode($fh, ":utf8"); + + # &Apache::lonnet::logthis($gnuplot_input); # uncomment to log the gnuplot input. + open (my $fh, "> $tmpdir$filename.data"); + binmode($fh, ':utf8'); print $fh $gnuplot_input; close($fh); # That's all folks. @@ -1887,7 +2144,8 @@ sub edit_attributes { if ($defaults->{$attr}->{'edit_type'} eq 'entry') { $result .= &Apache::edit::text_arg ($description,$attr,$token, - $defaults->{$attr}->{'size'}); + $defaults->{$attr}->{'size'}, + $defaults->{$attr}->{'class'}); } elsif ($defaults->{$attr}->{'edit_type'} eq 'choice') { $result .= &Apache::edit::select_or_text_arg ($description,$attr,$defaults->{$attr}->{'choices'},$token); @@ -2016,3 +2274,118 @@ sub insert_data { __END__ +=head1 NAME + +Apache::lonplot.pm + +=head1 SYNOPSIS + +XML-based plotter of graphs + +This is part of the LearningOnline Network with CAPA project +described at http://www.lon-capa.org. + + +=head1 SUBROUTINES (parsing and edit rendering) + +=over + +=item start_gnuplot() + +=item end_gnuplot() + +=item start_xtics() + +=item end_xtics() + +=item start_ytics() + +=item end_ytics() + +=item get_font() + +=item start_key() + +=item end_key() + +=item parse_label() + +=item replace_entities() + +=item start_title() + +=item end_title() + +=item start_xlabel() + +=item end_xlabel() + +=item start_ylabel() + +=item end_label() + +=item start_curve() + +=item end_curve() + +=item start_function() + +=item end_function() + +=item start_data() + +=item end_data() + +=item start_axis() + +=item end_axis + +=back + +=head1 SUBROUTINES (Utility) + +=over + +=item set_defaults() + +=item get_attributes() + +=item write_gnuplot_file() + +=item check_inputs() + +=item edit_attributes() + +=back + +=head1 SUBROUTINES (Insertion functions for editing plots) + +=over + +=item insert_gnuplot() + +=item insert_tics() + +=item insert_xtics() + +=item insert_key() + +=item insert_axis() + +=item insert_title() + +=item insert_xlabel() + +=item insert_ylabel() + +=item insert_label() + +=item insert_curve() + +=item insert_function() + +=item insert_data() + +=back + +=cut