Diff for /loncom/xml/lonplot.pm between versions 1.21 and 1.168

version 1.21, 2001/12/28 15:49:38 version 1.168, 2012/11/20 15:11:05
Line 25 Line 25
 #  #
 # http://www.lon-capa.org/  # http://www.lon-capa.org/
 #  #
 # 12/15/01 Matthew  
 # 12/17 12/18 12/19 12/20 12/21 12/27 Matthew  
   
   
 package Apache::lonplot;  package Apache::lonplot;
   
 use strict;  use strict;
   use warnings FATAL=>'all';
   no warnings 'uninitialized';
 use Apache::File;  use Apache::File;
 use Apache::response;  use Apache::response;
 use Apache::lonxml;  use Apache::lonxml;
 use Apache::edit;  use Apache::edit;
   use Apache::lonnet;
   use LONCAPA;
    
   
   use vars qw/$weboutputformat $version/;
   
   
 sub BEGIN {  
   &Apache::lonxml::register('Apache::lonplot',('plot'));  BEGIN {
       &Apache::lonxml::register('Apache::lonplot',('gnuplot'));
       #
       # Determine the version of GNUPLOT
       $weboutputformat = 'gif';
       my $versionstring = `gnuplot --version 2>/dev/null`;
       ($version) = ($versionstring =~ /^gnuplot ([\d.]+)/);
       if ($version >= 4) {
           $weboutputformat = 'png';
       }
       
 }  }
   
   
   =pod
   
 ##   ## 
 ## Description of data structures:  ## Description of data structures:
 ##  ##
Line 69  sub BEGIN { Line 92  sub BEGIN {
 ##        Tests used in checking the validitity of input         ##  ##        Tests used in checking the validitity of input         ##
 ##                                                               ##  ##                                                               ##
 ###################################################################  ###################################################################
   
   =cut
   
   my $max_str_len = 50;    # if a label, title, xlabel, or ylabel text
                            # is longer than this, it will be truncated.
   
   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 = 
       (
        lines          => 2,     # Maybe this will be used in the future
        linespoints    => 2,     # to check on whether or not they have 
        dots    => 2,     # supplied enough <data></data> fields
        points         => 2,     # to use the given line style.  But for
        steps    => 2,     # now there are more important things 
        fsteps    => 2,     # for me to deal with.
        histeps        => 2,
        errorbars    => 3,
        xerrorbars    => [3,4],
        yerrorbars    => [3,4],
        xyerrorbars    => [4,6],
        boxes          => 3,
        filledcurves   => 2,
        vector    => 4
       );    
   
 my $int_test       = sub {$_[0]=~s/\s+//g;$_[0]=~/^\d+$/};  my $int_test       = sub {$_[0]=~s/\s+//g;$_[0]=~/^\d+$/};
 my $real_test      =   my $real_test      = 
     sub {$_[0]=~s/\s+//g;$_[0]=~/^[+-]?\d*\.?\d*([eE][+-]\d+)?$/};      sub {$_[0]=~s/\s+//g;$_[0]=~/^[+-]?\d*\.?\d*([eE][+-]\d+)?$/};
 my $color_test     = sub {$_[0]=~s/\s+//g;$_[0]=~/^x[\da-f]{6}$/};  my $pos_real_test  =
       sub {$_[0]=~s/\s+//g;$_[0]=~/^[+]?\d*\.?\d*([eE][+-]\d+)?$/};
   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 $onoff_test     = sub {$_[0]=~/^(on|off)$/};
 my $key_pos_test   = sub {$_[0]=~/^(top|bottom|right|left|outside|below| )+$/};  my $key_pos_test   = sub {$_[0]=~/^(top|bottom|right|left|outside|below| )+$/};
 my $sml_test       = sub {$_[0]=~/^(small|medium|large)$/};  my $sml_test       = sub {$_[0]=~/^(\d+|small|medium|large)$/};
 my $linestyle_test = sub {$_[0]=~/^(lines|linespoints|dots|points|steps)$/};  my $linestyle_test = sub {exists($linestyles{$_[0]})};
 my $words_test     = sub {$_[0]=~s/\s+/ /g;$_[0]=~/^([\w\(\)]+ ?)+$/};  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                       ##  ##                      Attribute metadata                       ##
 ##                                                               ##  ##                                                               ##
 ###################################################################  ###################################################################
 my %plot_defaults =   my @gnuplot_edit_order = 
       qw/alttag bgcolor fgcolor height width texwidth fontface font texfont
       transparent grid samples 
       border align plotcolor plottype gridtype lmargin rmargin
       tmargin bmargin major_ticscale minor_ticscale boxwidth gridlayer fillstyle
       pattern solid/;
   
   my $margin_choices = ['default',0..20];
   
   my %gnuplot_defaults = 
     (      (
        alttag       => {
    default     => 'dynamically generated plot',
    test        => $words_test,
    description => 'Brief description of the plot',
         edit_type   => 'entry',
    size        => '40'
    },
      height       => {       height       => {
  default     => 200,   default     => 300,
  test        => $int_test,   test        => $int_test,
  description => 'vertical size of image (pixels)',   description => 'Height of image (pixels)',
  edit_type   => 'entry'         edit_type   => 'entry',
    size        => '10'
  },   },
      width        => {       width        => {
  default     => 200,   default     => 400,
  test        => $int_test,   test        => $int_test,
  description => 'horizontal size of image (pixels)',   description => 'Width of image (pixels)',
  edit_type   => 'entry'   edit_type   => 'entry',
    size        => '10'
  },   },
      bgcolor      => {       bgcolor      => {
  default     => 'xffffff',   default     => 'xffffff',
  test        => $color_test,    test        => $color_test, 
  description => 'background color of image (xffffff)',   description => 'Background color of image (xffffff)',
  edit_type   => 'entry'   edit_type   => 'entry',
    size        => '10',
            class       => 'colorchooser'
  },   },
      fgcolor      => {       fgcolor      => {
  default     => 'x000000',   default     => 'x000000',
  test        => $color_test,   test        => $color_test,
  description => 'foreground color of image (x000000)',   description => 'Foreground color of image (x000000)',
  edit_type   => 'entry'    edit_type   => 'entry',
    size        => '10',
            class       => 'colorchooser'
  },   },
      transparent  => {       transparent  => {
  default     => 'off',   default     => 'off',
  test        => $onoff_test,    test        => $onoff_test, 
  description => '',   description => 'Transparent image',
  edit_type   => 'on_off'   edit_type   => 'onoff'
  },   },
      grid         => {       grid         => {
    default     => 'on',
    test        => $onoff_test, 
    description => 'Display grid',
    edit_type   => 'onoff'
    },
        gridlayer    => {
  default     => 'off',   default     => 'off',
  test        => $onoff_test,    test        => $onoff_test, 
  description => '',   description => 'Display grid front layer over filled boxes or filled curves',
  edit_type   => 'on_off'   edit_type   => 'onoff'
    },
        box_border   => {
    default     => 'noborder',
    test        => sub {$_[0]=~/^(noborder|border)$/},
    description => 'Draw border for boxes',
    edit_type   => 'choice',
    choices     => ['border','noborder']
  },   },
      border       => {       border       => {
  default     => 'on',   default     => 'on',
  test        => $onoff_test,    test        => $onoff_test, 
  description => '',   description => 'Draw border around plot',
  edit_type   => 'on_off'   edit_type   => 'onoff'
  },   },
      font         => {       font         => {
  default     => 'medium',   default     => '9',
  test        => $sml_test,   test        => $sml_test,
  description => 'Size of font to use',   description => 'Font size to use in web output (pts)',
  edit_type   => 'choice',   edit_type   => 'choice',
  choices     => ['small','medium','large']   choices     => [['5','5 (small)'],'6','7','8',['9','9 (medium)'],'10',['11','11 (large)'],'12','15']
    },
        fontface     => {
           default     => 'sans-serif',
           test        => sub {$_[0]=~/^(sans-serif|serif|classic)$/},
           description => 'Type of font to use',
           edit_type   => 'choice',
           choices     => ['sans-serif','serif', 'classic']
           },
        samples      => {
    default     => '100',
    test        => $int_test,
    description => 'Number of samples for non-data plots',
    edit_type   => 'choice',
    choices     => ['100','200','500','1000','2000','5000']
  },   },
      align        => {       align        => {
  default     => 'left',   default     => 'middle',
  test        => sub {$_[0]=~/^(left|right|center)$/},   test        => sub {$_[0]=~/^(left|right|middle|center)$/},
  description => 'alignment for image in html',   description => 'Alignment for image in HTML',
  edit_type   => 'choice',   edit_type   => 'choice',
  choices     => ['left','right','center']   choices     => ['left','right','middle']
  }    },
        texwidth     => {
            default     => '93',
            test        => $int_test,
            description => 'Width of plot when printed (mm)',
            edit_type   => 'entry',
            size        => '5'
            },
        texfont      => {
            default     => '22',
            test        => $int_test,
            description => 'Font size to use in TeX output (pts):',
            edit_type   => 'choice',
            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/],
            },
        pattern      => {
    default     => '',
    test        => $int_test,
    description => 'Pattern value for boxes:',
    edit_type   => 'choice',
            choices     => [0,1,2,3,4,5,6]
            },
        solid        => {
            default     => 0,
            test        => $real_test,
            description => 'The density of fill style for boxes',
            edit_type   => 'entry',
            size        => '5'
            },
        fillstyle    => {
    default     => 'empty',
    test        => sub {$_[0]=~/^(empty|solid|pattern)$/},
    description => 'Filled style for boxes:',
    edit_type   => 'choice',
            choices     => ['empty','solid','pattern']
            },
        plottype     => {
    default     => 'Cartesian',
    test        => sub {$_[0]=~/^(Polar|Cartesian)$/},
    description => 'Plot type:',
    edit_type   => 'choice',
            choices     => ['Cartesian','Polar']
            },
        gridtype     => {
    default     => 'Cartesian',
    test        => sub {$_[0]=~/^(Polar|Cartesian|Linear-Log|Log-Linear|Log-Log)$/},
    description => 'Grid type:',
    edit_type   => 'choice',
            choices     => ['Cartesian','Polar','Linear-Log','Log-Linear','Log-Log']
            },
        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,
            },
        boxwidth     => {
    default     => '',
    test        => $real_test, 
    description => 'Width of boxes, default is auto',
    edit_type   => 'entry',
            size        => '5'
            },
        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'
            },
      );       );
   
 my %key_defaults =   my %key_defaults = 
Line 150  my %key_defaults = Line 373  my %key_defaults =
  default => '',   default => '',
  test => $words_test,   test => $words_test,
  description => 'Title of key',   description => 'Title of key',
  edit_type   => 'entry'   edit_type   => 'entry',
    size        => '40'
  },   },
      box   => {        box   => { 
  default => 'off',   default => 'off',
  test => $onoff_test,   test => $onoff_test,
  description => 'Draw a box around the key?',   description => 'Draw a box around the key?',
  edit_type   => 'on_off'   edit_type   => 'onoff'
  },   },
      pos   => {        pos   => { 
  default => 'top right',    default => 'top right', 
  test => $key_pos_test,    test => $key_pos_test, 
  description => 'position of the key on the plot',   description => 'Position of the key on the plot',
  edit_type   => 'choice',   edit_type   => 'choice',
  choices     => ['top left','top right','bottom left','bottom right',   choices     => ['top left','top right','bottom left','bottom right',
  'outside','below']   'outside','below']
Line 173  my %label_defaults = Line 397  my %label_defaults =
      xpos    => {       xpos    => {
  default => 0,   default => 0,
  test => $real_test,   test => $real_test,
  description => 'x position of label (graph coordinates)',   description => 'X position of label (graph coordinates)',
  edit_type   => 'entry'   edit_type   => 'entry',
    size        => '10'
  },   },
      ypos    => {       ypos    => {
  default => 0,    default => 0, 
  test => $real_test,   test => $real_test,
  description => 'y position of label (graph coordinates)',   description => 'Y position of label (graph coordinates)',
  edit_type   => 'entry'   edit_type   => 'entry',
    size        => '10'
  },   },
      justify => {       justify => {
  default => 'left',       default => 'left',    
Line 188  my %label_defaults = Line 414  my %label_defaults =
  description => 'justification of the label text on the plot',   description => 'justification of the label text on the plot',
  edit_type   => 'choice',   edit_type   => 'choice',
  choices     => ['left','right','center']   choices     => ['left','right','center']
        },
        rotate => {
            default => 0,
            test => $real_test,
            description => 'Rotation of label (degrees)',
            edit_type   => 'entry',
            size        => '10',
        }
        );
   
   my @tic_edit_order = ('location','mirror','start','increment','end',
                         'minorfreq');
   my %tic_defaults =
       (
        location => {
    default => 'border', 
    test => sub {$_[0]=~/^(border|axis)$/},
    description => 'Location of major tic marks',
    edit_type   => 'choice',
    choices     => ['border','axis']
    },
        mirror => {
    default => 'on', 
    test => $onoff_test,
    description => 'Mirror tics on opposite axis?',
    edit_type   => 'onoff'
    },
        start => {
    default => '-10.0',
    test => $real_test,
    description => 'Start major tics at',
    edit_type   => 'entry',
    size        => '10'
    },
        increment => {
    default => '1.0',
    test => $real_test,
    description => 'Place a major tic every',
    edit_type   => 'entry',
    size        => '10'
    },
        end => {
    default => ' 10.0',
    test => $real_test,
    description => 'Stop major tics at ',
    edit_type   => 'entry',
    size        => '10'
    },
        minorfreq => {
    default => '0',
    test => $int_test,
    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', 'xzero', 'yzero');
 my %axis_defaults =   my %axis_defaults = 
     (      (
      color     => {       color   => {
  default => 'x000000',    default => 'x000000', 
  test => $color_test,   test => $color_test,
  description => 'color of axes (x000000)',   description => 'Color of grid lines (x000000)',
  edit_type   => 'entry'   edit_type   => 'entry',
    size        => '10',
            class       => 'colorchooser'
  },   },
      xmin      => {       xmin      => {
  default => '-10.0',   default => '-10.0',
  test => $real_test,   test => $real_test,
  description => 'minimum x-value shown in plot',   description => 'Minimum x-value shown in plot',
  edit_type   => 'entry'   edit_type   => 'entry',
    size        => '10'
  },   },
      xmax      => {       xmax      => {
  default => ' 10.0',   default => ' 10.0',
  test => $real_test,   test => $real_test,
  description => 'maximum x-value shown in plot',     description => 'Maximum x-value shown in plot',  
  edit_type   => 'entry'   edit_type   => 'entry',
    size        => '10'
  },   },
      ymin      => {       ymin      => {
  default => '-10.0',   default => '-10.0',
  test => $real_test,   test => $real_test,
  description => 'minimum y-value shown in plot',     description => 'Minimum y-value shown in plot',  
  edit_type   => 'entry'   edit_type   => 'entry',
    size        => '10'
  },   },
      ymax      => {       ymax      => {
  default => ' 10.0',   default => ' 10.0',
  test => $real_test,   test => $real_test,
  description => 'maximum y-value shown in plot',     description => 'Maximum y-value shown in plot',  
  edit_type   => 'entry'   edit_type   => 'entry',
  },   size        => '10'
      linestyle => {          },
  default => 'points',       xformat      => {
  test => $linestyle_test,           default     => 'on',
  description => 'Style of the axis lines',           test        => sub {$_[0]=~/^(on|off|\d+(f|F|e|E))$/},
  edit_type   => 'choice',           description => 'X-axis number formatting',
  choices     => ['lines','linespoints','dots','points']           edit_type   => 'choice',
  }           choices     => ['on', 'off', '2e', '2f'],
            },
        yformat      => {
            default     => 'on',
            test        => sub {$_[0]=~/^(on|off|\d+(f|F|e|E))$/},
            description => 'Y-axis number formatting',
            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', 'arrowhead', 'arrowstyle', 
    'arrowlength', 'arrowangle', 'arrowbackangle'
       );
   
 my %curve_defaults =   my %curve_defaults = 
     (      (
      color     => {       color     => {
  default => 'x000000',   default => 'x000000',
  test => $color_test,   test => $color_test,
  description => 'color of curve (x000000)',   description => 'Color of curve (x000000)',
  edit_type   => 'entry'   edit_type   => 'entry',
    size        => '10',
    class       => 'colorchooser'
  },   },
      name      => {       name      => {
  default => '',   default => '',
  test => $words_test,   test => $words_test,
  description => 'name of curve to appear in key',   description => 'Name of curve to appear in key',
  edit_type   => 'entry'   edit_type   => 'entry',
    size        => '20'
  },   },
      linestyle => {       linestyle => {
  default => 'lines',   default => 'lines',
  test => $linestyle_test,   test => $linestyle_test,
  description => 'Style of the axis lines',   description => 'Plot with:',
  edit_type   => 'choice',   edit_type   => 'choice',
  choices     => ['lines','linespoints','dots','points','steps']   choices     => [keys(%linestyles)]
  }   },
        linewidth => {
            default     => 1,
            test        => $int_test,
            description => 'Line width (may not apply to all plot styles)',
            edit_type   => 'choice',
            choices     => [1,2,3,4,5,6,7,8,9,10]
            },
        linetype => {
            default     => 'solid',
            test        => sub {$_[0]=~/^(solid|dashed)$/},
            description => 'Line type (may not apply to all plot styles)',
            edit_type   => 'choice',
            choices     => ['solid', 'dashed']
            }, 
        pointsize => {
            default     => 1,
            test        => $pos_real_test,
            description => 'Point size (may not apply to all plot styles)',
            edit_type   => 'entry',
            size        => '5'
            },
        pointtype => {
            default     => 1,
            test        => $int_test,
            description => 'Point type (may not apply to all plot styles)',
            edit_type   => 'choice',
            choices     => [0,1,2,3,4,5,6]
            },
        limit     => {
            default     => 'closed',
    test        => sub {$_[0]=~/^(above|below|closed|x1|x2|y1|y2)$/},
            description => 'Point to fill -- for filledcurves',
            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'
        }
   
      );       );
   
 ###################################################################  ###################################################################
Line 260  my %curve_defaults = Line 657  my %curve_defaults =
 ##                    parsing and edit rendering                 ##  ##                    parsing and edit rendering                 ##
 ##                                                               ##  ##                                                               ##
 ###################################################################  ###################################################################
 my (%plot,%key,%axis,$title,$xlabel,$ylabel,@labels,@curves);  
   
 sub start_plot {  undef %Apache::lonplot::plot;
     %plot    = undef;   %key     = undef;   %axis   = undef;   my (%key,%axis,$title,$xlabel,$ylabel,@labels,@curves,%xtics,%ytics);
     $title   = undef;   $xlabel  = undef;   $ylabel = undef;  
     $#labels = -1;      $#curves = -1;  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);
       undef(@labels); undef(@curves);
       undef(%xtics);  undef(%ytics);
     #      #
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result='';      my $result='';
     if ($target eq 'web') {      &Apache::lonxml::register('Apache::lonplot',
  &Apache::lonxml::register('Apache::lonplot',       ('title','xlabel','ylabel','key','axis','label','curve',
       ('title','xlabel','ylabel','key','axis','label','curve'));        'xtics','ytics'));
  push (@Apache::lonxml::namespace,'plot');      push (@Apache::lonxml::namespace,'lonplot');
  ## Always evaluate the insides of the <plot></plot> tags      if ($target eq 'web' || $target eq 'tex') {
  my $inside = &Apache::lonxml::get_all_text("/plot",$$parser[-1]);   &get_attributes(\%Apache::lonplot::plot,\%gnuplot_defaults,$parstack,$safeeval,
  $inside=&Apache::run::evaluate($inside,$safeeval,$$parstack[-1]);  
  &Apache::lonxml::newparser($parser,\$inside);  
  ##-------------------------------------------------------  
  &get_attributes(\%plot,\%plot_defaults,$parstack,$safeeval,  
  $tagstack->[-1]);   $tagstack->[-1]);
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result .= &Apache::edit::tag_start($target,$token);   $result .= &Apache::edit::tag_start($target,$token,'GnuPlot');
  $result .= &edit_attributes($target,$token,\%plot_defaults);   $result .= &edit_attributes($target,$token,\%gnuplot_defaults,
       \@gnuplot_edit_order)
       .&Apache::edit::end_row()
       .&Apache::edit::start_spanning_row();
     } elsif ($target eq 'modified') {      } elsif ($target eq 'modified') {
  my $constructtag=&Apache::edit::get_new_args   my $constructtag=&Apache::edit::get_new_args
     ($token,$parstack,$safeeval,keys %plot_defaults);      ($token,$parstack,$safeeval,keys(%gnuplot_defaults));
   
  if ($constructtag) {   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);      $result = &Apache::edit::rebuild_tag($token);
     $result.= &Apache::edit::handle_insert();  
  }   }
     }      }
     return $result;      return $result;
 }  }
   
 sub end_plot {  sub end_gnuplot {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     pop @Apache::lonxml::namespace;      pop @Apache::lonxml::namespace;
     &Apache::lonxml::deregister('Apache::lonplot',      &Apache::lonxml::deregister('Apache::lonplot',
  ('title','xlabel','ylabel','key','axis','label','curve'));   ('title','xlabel','ylabel','key','axis','label','curve'));
     my $result = '';      my $result = '';
     if ($target eq 'web') {      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
       if ($target eq 'web' || $target eq 'tex' || $target eq 'grade' ||
    $target eq 'answer') {
         $randnumber=int(rand(1000));
       }
       if ($target eq 'web' || $target eq 'tex') {
  &check_inputs(); # Make sure we have all the data we need   &check_inputs(); # Make sure we have all the data we need
  ##   ##
  ## Determine filename   ## Determine filename
  my $tmpdir = '/home/httpd/perl/tmp/';   my $filename = $env{'user.name'}.'_'.$env{'user.domain'}.
  my $filename = $ENV{'user.name'}.'_'.$ENV{'user.domain'}.      '_'.time.'_'.$$.$randnumber.'_plot';
     '_'.time.'_'.$$.'_plot.data';  
  ## Write the plot description to the file   ## Write the plot description to the file
  my $fh=Apache::File->new(">$tmpdir$filename");   &write_gnuplot_file($tmpdir,$filename,$target);
  print $fh &write_gnuplot_file();   $filename = &escape($filename);
  close($fh);  
  ## return image tag for the plot   ## return image tag for the plot
  $result .= <<"ENDIMAGE";   if ($target eq 'web') {
 <img src    = "/cgi-bin/plot.gif?$filename"       $result .= <<"ENDIMAGE";
      width  = "$plot{'width'}"   <img src    = "/cgi-bin/plot.$weboutputformat?file=$filename.data" 
      height = "$plot{'height'}"       width  = "$Apache::lonplot::plot{'width'}"
      align  = "$plot{'align'}"       height = "$Apache::lonplot::plot{'height'}"
      alt    = "/cgi-bin/plot.gif?$filename" />       align  = "$Apache::lonplot::plot{'align'}"
        alt    = "$Apache::lonplot::plot{'alttag'}" />
 ENDIMAGE  ENDIMAGE
           } elsif ($target eq 'tex') {
       &Apache::lonxml::debug(" gnuplot wid = $Apache::lonplot::plot{'width'}");
       &Apache::lonxml::debug(" gnuplot ht  = $Apache::lonplot::plot{'height'}");
       #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{{'.$tmpdir.'}}'."\n";
       $result .= '\includegraphics[width='.$Apache::lonplot::plot{'texwidth'}.' mm]{'.&unescape($filename).'.eps}';
    }
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result.=&Apache::edit::tag_end($target,$token);   $result.=&Apache::edit::tag_end($target,$token);
     }      }
     return $result;      return $result;
 }  }
   
   
   ##--------------------------------------------------------------- xtics
   sub start_xtics {
       my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
       my $result='';
       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,
       \@tic_edit_order);
       } elsif ($target eq 'modified') {
    my $constructtag=&Apache::edit::get_new_args
       ($token,$parstack,$safeeval,keys(%tic_defaults));
    if ($constructtag) {
       $result = &Apache::edit::rebuild_tag($token);
    }
       }
       return $result;
   }
   
   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);
       }
       return $result;
   }
   
   ##--------------------------------------------------------------- ytics
   sub start_ytics {
       my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
       my $result='';
       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,
       \@tic_edit_order);
       } elsif ($target eq 'modified') {
    my $constructtag=&Apache::edit::get_new_args
       ($token,$parstack,$safeeval,keys(%tic_defaults));
    if ($constructtag) {
       $result = &Apache::edit::rebuild_tag($token);
    }
       }
       return $result;
   }
   
   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 <tic> 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 =
       (
        'classic'    => {
    face       => 'classic',
    file       => 'DejaVuSansMono-Bold',
    printname  => 'Helvetica',
    tex_no_file => 1,
        },
        'sans-serif' => {
    face       => 'sans-serif',
    file       => 'DejaVuSans',
    printname  => 'DejaVuSans',
        },
        'serif'      => {
    face       => 'serif',
    file       => 'DejaVuSerif',
    printname  => 'DejaVuSerif',
        },
        );
   
   sub get_font {
       my ($target) = @_;
       my ($size, $selected_font);
   
       if ( $Apache::lonplot::plot{'font'} =~ /^(small|medium|large)/) {
    $selected_font = $font_properties{'classic'};
    if ( $Apache::lonplot::plot{'font'} eq 'small') {
       $size = '5';
    } elsif ( $Apache::lonplot::plot{'font'} eq 'medium') {
       $size = '9';
    } elsif ( $Apache::lonplot::plot{'font'} eq 'large') {
       $size = '11';
    } else {
       $size = '9';
    }
       } else {
    $size = $Apache::lonplot::plot{'font'};
    $selected_font = $font_properties{$Apache::lonplot::plot{'fontface'}};
       }
       if ($target eq 'tex' && defined($Apache::lonplot::plot{'texfont'})) {
   # $selected_font = $font_properties{'classic'};
    $size = $Apache::lonplot::plot{'texfont'};
       }
       return ($size, $selected_font);
   }
   
 ##----------------------------------------------------------------- key  ##----------------------------------------------------------------- key
 sub start_key {  sub start_key {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result='';      my $result='';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
  &get_attributes(\%key,\%key_defaults,$parstack,$safeeval,   &get_attributes(\%key,\%key_defaults,$parstack,$safeeval,
     $tagstack->[-1]);      $tagstack->[-1]);
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result .= &Apache::edit::tag_start($target,$token);   $result .= &Apache::edit::tag_start($target,$token,'Plot Key');
  $result .= &edit_attributes($target,$token,\%key_defaults);   $result .= &edit_attributes($target,$token,\%key_defaults);
     } elsif ($target eq 'modified') {      } elsif ($target eq 'modified') {
  my $constructtag=&Apache::edit::get_new_args   my $constructtag=&Apache::edit::get_new_args
     ($token,$parstack,$safeeval,keys %key_defaults);      ($token,$parstack,$safeeval,keys(%key_defaults));
  if ($constructtag) {   if ($constructtag) {
     $result = &Apache::edit::rebuild_tag($token);      $result = &Apache::edit::rebuild_tag($token);
     $result.= &Apache::edit::handle_insert();  
  }   }
     }      }
     return $result;      return $result;
Line 349  sub start_key { Line 935  sub start_key {
 sub end_key {  sub end_key {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result = '';      my $result = '';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result.=&Apache::edit::tag_end($target,$token);   $result.=&Apache::edit::tag_end($target,$token);
     }      }
     return $result;      return $result;
 }  }
   
   sub parse_label {
       my ($target,$text) = @_;
       my $parser=HTML::LCParser->new(\$text);
       my $result;
       while (my $token=$parser->get_token) {
    if ($token->[0] eq 'S') {
       if ($token->[1] eq 'sub') {
    $result .= '_{';
       } elsif ($token->[1] eq 'sup') {
    $result .= '^{';
       } else {
    $result .= $token->[4];
       }
    } elsif ($token->[0] eq 'E') {
       if ($token->[1] eq 'sub'
    || $token->[1] eq 'sup') {
    $result .= '}';
       } else {
    $result .= $token->[2];
       }
    } elsif ($token->[0] eq 'T') {
       $result .= &replace_entities($target,$token->[1]);
    }
       }
       return $result;
   }
   
   #
   #  Note that there are severe restrictions on font selection in the
   # ps driver now.  later in life Gnuplot is supposed to support
   # utf-8 fonts in the posts script driver.  When this happens,
   # the tex entries with comments that include the word <FIX>
   # should be changed to print the correct glyphs rather than some
   # approximation or fallback of what is intended.
   
   my %lookup = 
      (  # Greek alphabet:
         
         '(Alpha|#913)'    => {'tex' => '{/Symbol A}', 'web' => "\x{391}"},
         '(Beta|#914)'    => {'tex' => '{/Symbol B}', 'web' => "\x{392}"},
         '(Chi|#935)'     => {'tex' => '{/Symbol C}', 'web' => "\x{3A7}"},
         '(Delta|#916)'   => {'tex' => '{/Symbol D}', 'web' => "\x{394}"},
         '(Epsilon|#917)' => {'tex' => '{/Symbol E}', 'web' => "\x{395}"},
         '(Phi|#934)'     => {'tex' => '{/Symbol F}', 'web' => "\x{3A6}"},
         '(Gamma|#915)'   => {'tex' => '{/Symbol G}', 'web' => "\x{393}"},
         '(Eta|#919)'     => {'tex' => '{/Symbol H}', 'web' => "\x{397}"},
         '(Iota|#921)'    => {'tex' => '{/Symbol I}', 'web' => "\x{399}"},
         '(Kappa|#922)'   => {'tex' => '{/Symbol K}', 'web' => "\x{39A}"},
         '(Lambda|#923)'  => {'tex' => '{/Symbol L}', 'web' => "\x{39B}"},
         '(Mu|#924)'      => {'tex' => '{/Symbol M}', 'web' => "\x{39C}"},
         '(Nu|#925)'      => {'tex' => '{/Symbol N}', 'web' => "\x{39D}"},
         '(Omicron|#927)' => {'tex' => '{/Symbol O}', 'web' => "\x{39F}"},
         '(Pi|#928)'      => {'tex' => '{/Symbol P}', 'web' => "\x{3A0}"},
         '(Theta|#920)'   => {'tex' => '{/Symbol Q}', 'web' => "\x{398}"},
         '(Rho|#929)'     => {'tex' => '{/Symbol R}', 'web' => "\x{3A1}"},
         '(Sigma|#931)'   => {'tex' => '{/Symbol S}', 'web' => "\x{3A3}"},
         '(Tau|#932)'     => {'tex' => '{/Symbol T}', 'web' => "\x{3A4}"},
         '(Upsilon|#933)' => {'tex' => '{/Symbol U}', 'web' => "\x{3A5}"},
         '(Omega|#937)'   => {'tex' => '{/Symbol W}', 'web' => "\x{3A9}"},
         '(Xi|#926)'      => {'tex' => '{/Symbol X}', 'web' => "\x{39E}"},
         '(Psi|#936)'     => {'tex' => '{/Symbol Y}', 'web' => "\x{3A8}"},
         '(Zeta|#918)'    => {'tex' => '{/Symbol Z}', 'web' => "\x{396}"},
         '(alpha|#945)'   => {'tex' => '{/Symbol a}', 'web' => "\x{3B1}"},
         '(beta|#946)'    => {'tex' => '{/Symbol b}', 'web' => "\x{3B2}"},
         '(chi|#967)'     => {'tex' => '{/Symbol c}', 'web' => "\x{3C7}"},
         '(delta|#948)'   => {'tex' => '{/Symbol d}', 'web' => "\x{3B4}"},
         '(epsilon|#949)' => {'tex' => '{/Symbol e}', 'web' => "\x{3B5}"},
         '(phi|#966)'     => {'tex' => '{/Symbol f}', 'web' => "\x{3C6}"},
         '(gamma|#947)'   => {'tex' => '{/Symbol g}', 'web' => "\x{3B3}"},
         '(eta|#951)'     => {'tex' => '{/Symbol h}', 'web' => "\x{3B7}"},
         '(iota|#953)'    => {'tex' => '{/Symbol i}', 'web' => "\x{3B9}"},
         '(kappa|#954)'   => {'tex' => '{/Symbol k}', 'web' => "\x{3BA}"},
         '(lambda|#955)'  => {'tex' => '{/Symbol k}', 'web' => "\x{3BB}"},
         '(mu|#956)'      => {'tex' => '{/Symbol m}', 'web' => "\x{3BC}"},
         '(nu|#957)'      => {'tex' => '{/Symbol n}', 'web' => "\x{3BD}"},
         '(omicron|#959)' => {'tex' => '{/Symbol o}', 'web' => "\x{3BF}"},
         '(pi|#960)'      => {'tex' => '{/Symbol p}', 'web' => "\x{3C0}"},
         '(theta|#952)'   => {'tex' => '{/Symbol q}', 'web' => "\x{3B8}"},
         '(rho|#961)'     => {'tex' => '{/Symbol r}', 'web' => "\x{3C1}"},
         '(sigma|#963)'   => {'tex' => '{/Symbol s}', 'web' => "\x{3C3}"},
         '(tau|#964)'     => {'tex' => '{/Symbol t}', 'web' => "\x{3C4}"},
         '(upsilon|#965)' => {'tex' => '{/Symbol u}', 'web' => "\x{3C5}"},
         '(omega|#969)'   => {'tex' => '{/Symbol w}', 'web' => "\x{3C9}"},
         '(xi|#958)'      => {'tex' => '{/Symbol x}', 'web' => "\x{3BE}"},
         '(psi|#968)'     => {'tex' => '{/Symbol y}', 'web' => "\x{3C8}"},
         '(zeta|#950)'    => {'tex' => '{/Symbol z}', 'web' => "\x{3B6}"},
         '(thetasym|#977)' => {'tex' => '{/Symbol \165}', 'web' => "\x{3d1}"},
         '(upsih|#978)'   => {'tex' => '{/Symbol \241}', 'web' => "\x{3d2}"},
         '(piv|#982)'     => {'tex' => '{/Symbol \166}', 'web' => "\x{3d6}"},
   
   
         # Punctuation:
         
         '(quot|#034)'   => {'tex' =>  '\42',            'web' => '\42'},
         '(amp|#038)'    => {'tex' =>  '\46',            'web' => '\46'},
         '(lt|#060)'     => {'tex' =>  '\74',            'web' => '\74'},
         '(gt|#062)'     => {'tex' =>  '\76',            'web' => '\76'},
         '#131'          => {'tex' =>  '{/Symbol \246}', 'web' => "\x{192}"},
         '#132'          => {'tex' => '{/Text \271}',    'web' => "\x{201e}"},
         '#133'          => {'tex' => '{/Symbol \274}',  'web'=> "\x{2026}"},
         '#134'          => {'tex' => '{/Text \262}',    'web' => "\x{2020}"},
         '#135'          => {'tex' => '{/Text \263}',    'web' => "\x{2021}"},
         '#136'          => {'tex' => '\\\\^',           'web' => '\\\\^'},
         '#137'          => {'tex' => '%o',              'web' => "\x{2030}"}, # Per Mille <FIX>
         '#138'          => {'tex' => 'S',               'web' => "\x{160}"}, # S-Caron <FIX>
         '#139'          => {'tex' => '<',               'web' => '<'},
         '#140'          => {'tex' => 'AE',              'web' => "\x{152}"}, # AE ligature <FIX>
         '#145'          => {'tex' => '\140',            'web' => "\x{2018}"},
         '#146'          => {'tex' => '\47',             'web' => "\x{2019}"},
         '#147'          => {'tex' => '\140\140',        'web' => "\x{201c}"}, # Left " <FIX>
         '#148'          => {'tex' => '\47\47',          'web' => '\\"'},      # Right " <FIX>
         '#149'          => {'tex' => '{/Symbol \267}',  'web' => "\x{2022}"},
         '#150'          => {'tex' => '{/Text \55}',     'web' => "\x{2013}"},  # en dash
         '#151'          => {'tex' => '{/Symbol \55}',   'web' => "\x{2014}"},  # em dash
         '#152'          => {'tex' => '\\\\~',           'web' => '\\\\~'},
         '#153'          => {'tex' => '{/Symbol \324}',  'web' => "\x{2122}"}, # trademark
   
         # Accented letters, and other furreign language glyphs.
   
         '#154'          => {'tex' => 's',               'web' => "\x{161}"}, # small s-caron no ps.
         '#155'          => {'tex' => '>',               'web' => '\76'},     # >
         '#156'          => {'tex' => '{/Text \366}',    'web' => "\x{153}"}, # oe ligature.<FIX>
         '#159',         => {'tex' => 'Y',               'web' => "\x{178}"}, # Y-umlaut - can't print <FIX>
         '(nbsp|#160)'   => {'tex' => ' ',               'web' => ' '},       # non breaking space.
         '(iexcl|#161)'  => {'tex' => '{/Text \241}',    'web' => "\x{a1}"},  # inverted !
         '(cent|#162)'   => {'tex' => '{/Text \242}',    'web' => "\x{a2}"},  # Cent currency.
         '(pound|#163)'  => {'tex' => '{/Text \243}',    'web' => "\x{a3}"},  # GB Pound currency.
         '(curren|#164)' => {'tex' => '{/ZapfDingbats \161}','web' => "\x{a4}"},  # Generic currency symb. <FIX>
         '(yen|#165)'    => {'tex' => '{/Text \245}',    'web' => "\x{a5}"},  # Yen currency.
         '(brvbar|#166)' => {'tex' => '{/Symbol \174}',  'web' => "\x{a6}"},  # Broken vert bar no print.
         '(sect|#167)'   => {'tex' => '{\247}',          'web' => "\x{a7}"},  # Section symbol.
         '(uml|#168)'    => {'tex' => '{\250}',          'web' => "\x{a8}"},  # 'naked' umlaut.
         '(copy|#169)'   => {'tex' => '{/Symbol \343}',  'web' => "\x{a9}"},  # Copyright symbol.
         '(ordf|#170)'   => {'tex' => '{/Text \343}',    'web' => "\x{aa}"},  # Feminine ordinal.
         '(laquo|#171)'  => {'tex' => '{/Text \253}',    'web' => "\x{ab}"},  # << quotes.
         '(not|#172)'    => {'tex' => '\254',            'web' => "\x{ac}"},  # Logical not.
         '(shy|#173)'    => {'tex' => '\255',               'web' => "\x{ad}"},  # soft hyphen.
         '(reg|#174)'    => {'tex' => '{/Symbol \342}',  'web' => "\x{ae}"},  # Registered tm.
         '(macr|#175)'   => {'tex' => '^{\255}',            'web' => "\x{af}"},  # 'naked' macron (overbar).
         '(deg|#176)'    => {'tex' => '{/Text \260}',    'web' => "\x{b0}"},  # Degree symbo..`
         '(plusmn|#177)' => {'tex' => '{/Symbol \261}',  'web' => "\x{b1}"},  # +/- symbol.
         '(sup2|#178)'   => {'tex' => '^2',              'web' => "\x{b2}"},  # Superscript 2.
         '(sup3|#179)'   => {'tex' => '^3',              'web' => "\x{b3}"},  # Superscript 3.
         '(acute|#180)'  => {'tex' => '{/Text \222}',    'web' => "\x{b4}"},  # 'naked' acute accent.
         '(micro|#181)'  => {'tex' => '{/Symbol \155}',  'web' => "\x{b5}"},  # Micro (small mu).
         '(para|#182)'   => {'tex' => '{/Text \266}',    'web' => "\x{b6}"},  # Paragraph symbol.
         '(middot|#183)' => {'tex' => '\267',            'web' => "\x{b7}"},  # middle dot
         '(cedil|#184)'  => {'tex' => '\233',            'web' => "\x{b8}"},  # 'naked' cedilla.
         '(sup1|#185)'   => {'tex' => '^1',              'web' => "\x{b9}"},  # superscript 1.
         '(ordm|#186)'   => {'tex' => '{\260}',          'web' => "\x{ba}"},  # masculine ordinal.
         '(raquo|#187)', => {'tex' => '\273',            'web' => "\x{bb}"},  # Right angle quotes.
         '(frac14|#188)' => {'tex' => '\274',            'web' => "\x{bc}"},  # 1/4.
         '(frac12|#189)' => {'tex' => '\275',            'web' => "\x{bd}"},  # 1/2.
         '(frac34|#190)' => {'tex' => '\276',            'web' => "\x{be}"},  # 3/4
         '(iquest|#191)' => {'tex' => '{/Text \277}',    'web' => "\x{bf}"},  # Inverted ?
         '(Agrave|#192)' => {'tex' => '\300',            'web' => "\x{c0}"},  # A Grave.
         '(Aacute|#193)' => {'tex' => '\301',            'web' => "\x{c1}"},  # A Acute.
         '(Acirc|#194)'  => {'tex' => '\302',            'web' => "\x{c2}"},  # A Circumflex.
         '(Atilde|#195)' => {'tex' => '\303',            'web' => "\x{c3}"},  # A tilde.
         '(Auml|#196)'   => {'tex' => '\304',            'web' => "\x{c4}"},  # A umlaut.
         '(Aring|#197)'  => {'tex' => '\305',            'web' => "\x{c5}"},  # A ring.
         '(AElig|#198)'  => {'tex' => '\306',            'web' => "\x{c6}"},  # AE ligature.
         '(Ccedil|#199)' => {'tex' => '\307',            'web' => "\x{c7}"},  # C cedilla
         '(Egrave|#200)' => {'tex' => '\310',            'web' => "\x{c8}"},  # E Accent grave.
         '(Eacute|#201)' => {'tex' => '\311',            'web' => "\x{c9}"},  # E acute accent.
         '(Ecirc|#202)'  => {'tex' => '\312',            'web' => "\x{ca}"},  # E Circumflex.
         '(Euml|#203)'   => {'tex' => '\313',            'web' => "\x{cb}"},  # E umlaut.
         '(Igrave|#204)' => {'tex' => '\314',            'web' => "\x{cc}"},  # I grave accent.
         '(Iacute|#205)' => {'tex' => '\315',            'web' => "\x{cd}"},  # I acute accent.
         '(Icirc|#206)'  => {'tex' => '\316',            'web' => "\x{ce}"},  # I circumflex.
         '(Iuml|#207)'   => {'tex' => '\317',            'web' => "\x{cf}"},  # I umlaut.
         '(ETH|#208)'    => {'tex' => '\320',            'web' => "\x{d0}"},  # Icelandic Cap eth.
         '(Ntilde|#209)' => {'tex' => '\321',            'web' => "\x{d1}"},  # Ntilde (enyan).
         '(Ograve|#210)' => {'tex' => '\322',            'web' => "\x{d2}"},  # O accent grave.
         '(Oacute|#211)' => {'tex' => '\323',            'web' => "\x{d3}"},  # O accent acute.
         '(Ocirc|#212)'  => {'tex' => '\324',            'web' => "\x{d4}"},  # O circumflex.
         '(Otilde|#213)' => {'tex' => '\325',            'web' => "\x{d5}"},  # O tilde.
         '(Ouml|#214)'   => {'tex' => '\326',            'web' => "\x{d6}"},  # O umlaut.
         '(times|#215)'  => {'tex' => '\327',            'web' => "\x{d7}"},  # Times symbol.
         '(Oslash|#216)' => {'tex' => '\330',            'web' => "\x{d8}"},  # O slash.
         '(Ugrave|#217)' => {'tex' => '\331',            'web' => "\x{d9}"},  # U accent grave.
         '(Uacute|#218)' => {'tex' => '\332',            'web' => "\x{da}"},  # U accent acute.
         '(Ucirc|#219)'  => {'tex' => '\333',            'web' => "\x{db}"},  # U circumflex.
         '(Uuml|#220)'   => {'tex' => '\334',            'web' => "\x{dc}"},  # U umlaut.
         '(Yacute|#221)' => {'tex' => '\335',            'web' => "\x{dd}"},  # Y accent acute.
         '(THORN|#222)'  => {'tex' => '\336',            'web' => "\x{de}"},  # Icelandic thorn.
         '(szlig|#223)'  => {'tex' => '\337',            'web' => "\x{df}"},  # German sharfes s.
         '(agrave|#224)' => {'tex' => '\340',            'web' => "\x{e0}"},  # a accent grave.
         '(aacute|#225)' => {'tex' => '\341',            'web' => "\x{e1}"},  # a grave.
         '(acirc|#226)'  => {'tex' => '\342',            'web' => "\x{e2}"},  # a circumflex.
         '(atilde|#227)' => {'tex' => '\343',            'web' => "\x{e3}"},  # a tilde.
         '(auml|#228)'   => {'tex' => '\344',            'web' => "\x{e4}"},  # a umlaut
         '(aring|#229)'  => {'tex' => '\345',            'web' => "\x{e5}"},  # a ring on top.
         '(aelig|#230)'  => {'tex' => '\346',            'web' => "\x{e6}"},  # ae ligature.
         '(ccedil|#231)' => {'tex' => '\347',            'web' => "\x{e7}"},  # C cedilla
         '(egrave|#232)' => {'tex' => '\350',            'web' => "\x{e8}"},  # e accent grave.
         '(eacute|#233)' => {'tex' => '\351',            'web' => "\x{e9}"},  # e accent acute.
         '(ecirc|#234)'  => {'tex' => '\352',            'web' => "\x{ea}" }, # e circumflex.
         '(euml|#235)'   => {'tex' => '\353',            'web' => "\x{eb}"},  # e umlaut.
         '(igrave|#236)' => {'tex' => '\354',            'web' => "\x{ec}"},  # i grave.
         '(iacute|#237)' => {'tex' => '\355',            'web' => "\x{ed}"},  # i acute.
         '(icirc|#238)'  => {'tex' => '\356',            'web' => "\x{ee}"},  # i circumflex.
         '(iuml|#239)'   => {'tex' => '\357',            'web' => "\x{ef}"},  # i umlaut.
         '(eth|#240)'    => {'tex' => '\360',            'web' => "\x{f0}"},  # Icelandic eth.
         '(ntilde|#241)' => {'tex' => '\361',            'web' => "\x{f1}"},  # n tilde.
         '(ograve|#242)' => {'tex' => '\362',            'web' => "\x{f2}"},  # o grave.
         '(oacute|#243)' => {'tex' => '\363',            'web' => "\x{f3}"},  # o acute.
         '(ocirc|#244)'  => {'tex' => '\364',            'web' => "\x{f4}"},  # o circumflex.
         '(otilde|#245)' => {'tex' => '\365',            'web' => "\x{f5}"},  # o tilde.
         '(ouml|#246)'   => {'tex' => '\366',            'web' => "\x{f6}"},  # o umlaut.
         '(divide|#247)' => {'tex' => '\367',            'web' => "\x{f7}"},  # division symbol
         '(oslash|#248)' => {'tex' => '\370',            'web' => "\x{f8}"},  # o slashed.
         '(ugrave|#249)' => {'tex' => '\371',            'web' => "\x{f9}"},  # u accent grave.
         '(uacute|#250)' => {'tex' => '\372',            'web' => "\x{fa}"},  # u acute.
         '(ucirc|#251)'  => {'tex' => '\373',            'web' => "\x{fb}"},  # u circumflex.
         '(uuml|#252)'   => {'tex' => '\374',            'web' => "\x{fc}"},  # u umlaut.
         '(yacute|#253)' => {'tex' => '\375',            'web' => "\x{fd}"},  # y acute accent.
         '(thorn|#254)'  => {'tex' => '\376',            'web' => "\x{fe}"},  # small thorn (icelandic).
         '(yuml|#255)'   => {'tex' => '\377',            'web' => "\x{ff}"},  # y umlaut.
         
         # Latin extended A entities:
   
         '(OElig|#338)'  => {'tex' => '{/Text \326}',   'web' => "\x{152}"},  # OE ligature.
         '(oelig|#339)'  => {'tex' => '{/Text \366}',   'web' => "\x{153}"},  # oe ligature.
         '(Scaron|#352)' => {'tex' => 'S',              'web' => "\x{160}"},  # S caron no printable.
         '(scaron|#353)' => {'tex' => 's',              'web' => "\x{161}"},  # s caron no printable.
         '(Yuml|#376)'   => {'tex' => 'Y',              'web' => "\x{178}"},  # Y umlaut - no printable.
   
         # Latin extended B.
   
         '(fnof|#402)'  => {'tex' =>'{/Symbol \246}',    'web' => "\x{192}"},  # f with little hook.
   
         # Standalone accents:
   
         '(circ|#710)'  => {'tex' => '^',               'web' => '^'},        # circumflex.
         '(tilde|#732)' => {'tex' => '~',               'web' => '~'},        # tilde.
   
         # General punctuation.  We're not able to make a distinction between
         # the various length spacings in the print version. (e.g. en/em/thin).
         # the various joiners will be empty strings in the print version too.
   
   
         '(ensp|#8194)'   => {'tex' => ' ',              'web' => "\x{2002}"}, # en space.
         '(emsp|#8195)'   => {'tex' => ' ',              'web' => "\x{2003}"}, # em space.
         '(thinsp|#8201)' => {'tex' => ' ',              'web' => "\x{2009}"}, # thin space.
         '(zwnj|#8204)'   => {'tex' => ' ',               'web' => "\x{200c}"}, # Zero width non joiner.
         '(zwj|#8205)'    => {'tex' => ' ',               'web' => "\x{200d}"}, # Zero width joiner.
         '(lrm|#8206)'    => {'tex' => ' ',               'web' => "\x{200e}"}, # Left to right mark
         '(rlm|#8207)'    => {'tex' => ' ',               'web' => "\x{200f}"}, # right to left mark.
         '(ndash|#8211)'  => {'tex' => '{/Text \55}',    'web' => "\x{2013}"}, # en dash.
         '(mdash|#8212)'  => {'tex' => '{/Symbol \55}',  'web' => "\x{2014}"}, # em dash.
         '(lsquo|#8216)'  => {'tex' => '{/Text \140}',   'web' => "\x{2018}"}, # Left single quote.
         '(rsquo|#8217)'  => {'tex' => '\47',            'web' => "\x{2019}"}, # Right single quote.
         '(sbquo|#8218)'  => {'tex' => '\54',             'web' => "\x{201a}"}, # Single low-9 quote.
         '(ldquo|#8220)'  => {'tex' => '\42',   'web' => "\x{201c}"}, # Left double quote.
         '(rdquo|#8221)'  => {'tex' => '\42',   'web' => "\x{201d}"}, # Right double quote.
         '(bdquo|#8222)'  => {'tex' => ',',              'web' => "\x{201e}"}, # Double low-9 quote.
         '(dagger|#8224)' => {'tex' => '+',   'web' => "\x{2020}"}, # Is this a dagger I see before me now?
         '(Dagger|#8225)' => {'tex' => '\261',   'web' => "\x{2021}"}, # it's handle pointing towards my heart?
         '(bull|#8226)'   => {'tex' => '\267',           'web' => "\x{2022}"}, # Bullet.
         '(hellep|#8230)' => {'tex' => '{/Symbol \274}',   'web' => "\x{2026}"}, # Ellipses.
         '(permil|#8240)' => {'tex' => '%_o',            'web' => "\x{2031}"}, # Per mille.
         '(prime|#8242)'  => {'tex' => '\264',           'web' => "\x{2032}"}, # Prime.
         '(Prime|#8243)'  => {'tex' => '{/Symbol \262}', 'web' => "\x{2033}"}, # double prime.
         '(lsaquo|#8249)' => {'tex' => '<',              'web' => "\x{2039}"}, # < quote.
         '(rsaquo|#8250)' => {'tex' => '\74',              'web' => "\x{203a}"}, # > quote.
         '(oline|#8254)'  => {'tex' => '{/Symbol \140}', 'web' => "\x{203e}"}, # Overline.
         '(frasl|#8260)'  => {'tex' => '/',              'web' => "\x{2044}"}, # Fraction slash.
         '(euro|#8364)'   => {'tex' => '{/Symbol \240}', 'web' => "\x{20ac}"}, # Euro currency.
         
         # Letter like symbols.
   
         '(weierp|#8472)'  => {'tex' => '{/Symbol \303}', 'web' => "\x{2118}"}, # Power set symbol
         '(image|#8465)'   => {'tex' => '{/Symbol \301}', 'web' => "\x{2111}"}, # Imaginary part
         '(real|#8476)'    => {'tex' => '{/Symbol \302}', 'web' => "\x{211c}"}, # Real part.
         '(trade|#8482)'   => {'tex' => '{/Symbol \344}', 'web' => "\x{2122}"}, # trademark symbol.
         '(alefsym|#8501)' => {'tex' => '{/Symbol \300}', 'web' => "\x{2135}"}, # Hebrew alef.
   
         # Arrows  of various types and directions.
         '(larr|#8592)'    => {'tex' => '{/Symbol \254}', 'web' => "\x{2190}"}, # <--
         '(uarr|#8593)'    => {'tex' => '{/Symbol \255}', 'web' => "\x{2191}"}, # up arrow.
         '(rarr|#8594)'    => {'tex' => '{/Symbol \256}', 'web' => "\x{2192}"}, # -->
         '(darr|#8595)'    => {'tex' => '{/Symbol \257}', 'web' => "\x{2193}"}, # down arrow.
         '(harr|#8596)'    => {'tex' => '{/Symbol \253}', 'web' => "\x{2194}"}, # <-->
         '(crarr|#8629)'   => {'tex' => '{/Symbol \277}', 'web' => "\x{21b5}"}, # corner arrow down and right.
         '(lArr|#8656)'    => {'tex' => '{/Symbol \334}', 'web' => "\x{21d0}"}, # <==
         '(uArr|#8657)'    => {'tex' => '{/Symbol \335}', 'web' => "\x{21d1}"}, # Up double arrow.
         '(rArr|#8658)'    => {'tex' => '{/Symbol \336}', 'web' => "\x{21d2}"}, # ==>
         '(dArr|#8659)'    => {'tex' => '{/Symbol \337}', 'web' => "\x{21d3}"}, # Down double arrow.
         '(hArr|#8660)'    => {'tex' => '{/Symbol \333}', 'web' => "\x{21d4}"}, # <==>
   
         # Mathematical operators. For some of these we do the best we can in printing.
   
         '(forall|#8704)'  => {'tex' => '{/Symbol \42}',   'web' => "\x{2200}"}, # For all.
         '(part|#8706)'    => {'tex' => '{/Symbol d}',     'web' => "\x{2202}"}, # partial derivative
         '(exist|#8707)'   => {'tex' => '{/Symbol \44}',   'web' => "\x{2203}"}, # There exists.
         '(empty|#8709)'   => {'tex' => '{/Symbol \306}',  'web' => "\x{2205}"}, # Null set.
         '(nabla|#8711)'   => {'tex' => '{/Symbol \321}',  'web' => "\x{2207}"}, # Gradient e.g.
         '(isin|#8712)'    => {'tex' => '{/Symbol \316}',  'web' => "\x{2208}"}, # Element of the set.
         '(notin|#8713)'   => {'tex' => '{/Symbol \317}',  'web' => "\x{2209}"}, # Not an element of
         '(ni|#8715)'      => {'tex' => '{/Symbol \47}',   'web' => "\x{220b}"}, # Contains as a member
         '(prod|#8719)'    => {'tex' => '{/Symbol \325}',  'web' => "\x{220f}"}, # Product 
         '(sum|#8721)'     => {'tex' => '{/Symbol \345}',  'web' => "\x{2211}"}, # Sum of.
         '(minus|#8722)'   => {'tex' => '{/Symbol \55}',   'web' => "\x{2212}"}, # - sign.
         '(lowast|#8727)'  => {'tex' => '*',               'web' => "\x{2217}"}, # * 
         '(radic|#8730)'   => {'tex' => '{/Symbol \326}',  'web' => "\x{221a}"}, # Square root. 
         '(prop|#8733)'    => {'tex' => '{/Symbol \265}',  'web' => "\x{221d}"}, # Proportional to.
         '(infin|#8734)'   => {'tex' => '{/Symbol \245}',  'web' => "\x{221e}"}, # Infinity.
         '(ang|#8736)'     => {'tex' => '{/Symbol \320}',  'web' => "\x{2220}"}, # Angle .
         '(and|#8743)'     => {'tex' => '{/Symbol \331}',  'web' => "\x{2227}"}, # Logical and.
         '(or|#8744)'      => {'tex' => '{/Symbol \332}',  'web' => "\x{2228}"}, # Logical or.
         '(cap|#8745)'     => {'tex' => '{/Symbol \307}',  'web' => "\x{2229}"}, # Set intersection.
         '(cup|#8746)'     => {'tex' => '{/Symbol \310}',  'web' => "\x{222a}"}, # Set union.
         '(int|8747)'      => {'tex' => '{/Symbol \362}',  'web' => "\x{222b}"}, # Integral.
   
         # Some gnuplot guru will have to explain to me why the next three
         # require the extra slashes... else they print very funkily.
   
         '(there4|#8756)'  => {'tex' => '{/Symbol \\\134}',  'web' => "\x{2234}"}, # Therefore triple dots.
         '(sim|#8764)'     => {'tex' => '\\\176',               'web' => "\x{223c}"}, # Simlar to.
         '(cong|#8773)'    => {'tex' => '{/Symbol \\\100}','web' => "\x{2245}"}, # Congruent to/with.
   
         '(asymp|#8776)'   => {'tex' => '{/Symbol \273}',  'web' => "\x{2248}"}, # Asymptotic to.
         '(ne|#8800)'      => {'tex' => '{/Symbol \271}',  'web' => "\x{2260}"}, # not equal to.
         '(equiv|#8801)'   => {'tex' => '{/Symbol \272}',  'web' => "\x{2261}"}, # Equivalent to.
         '(le|8804)'       => {'tex' => '{/Symbol \243}',  'web' => "\x{2264}"}, # Less than or equal to.
         '(ge|8805)'       => {'tex' => '{/Symbol \263}',  'web' => "\x{2265}"}, # Greater than or equal to
         '(sub|8834)'      => {'tex' => '{/Symbol \314}',  'web' => "\x{2282}"}, # Subset of.
         '(sup|8835)'      => {'tex' => '{/Symbol \311}',  'web' => "\x{2283}"}, # Super set of.
         '(nsub|8836)'     => {'tex' => '{/Symbol \313}',  'web' => "\x{2284}"}, # not subset of.
         '(sube|8838)'     => {'tex' => '{/Symbol \315}',  'web' => "\x{2286}"}, # Subset or equal.
         '(supe|8839)'     => {'tex' => '{/Symbol \312}',  'web' => "\x{2287}"}, # Superset or equal
         '(oplus|8853)'    => {'tex' => '{/Symbol \305}',  'web' => "\x{2295}"}, # O with plus inside
         '(otimes|8855)'   => {'tex' => '{/Symbol \304}',  'web' => "\x{2297}"}, # O with times.
         '(perp|8869)'     => {'tex' => '{/Symbol \136}',  'web' => "\x{22a5}"}, # Perpendicular.
         '(sdot|8901)'     => {'tex' => '{/Symbol \227}',  'web' => "\x{22c5}"}, # Dot operator.
   
         # Misc. technical symbols:
   
         '(lceil|8698)'    => {'tex' => '{/Symbol \351}',  'web' => "\x{2308}"}, # Left ceiling.
         '(rceil|8969)'    => {'tex' => '{/Symbol \371}',  'web' => "\x{2309}"}, # Right ceiling.
         '(lfloor|8970)'   => {'tex' => '{/Symbol \353}',  'web' => "\x{230a}"}, # Left floor.
         '(rfloor|8971)'   => {'tex' => '{/Symbol \373}',  'web' => "\x{230b}"}, # Right floor.
   
         # The gnuplot png font evidently does not have the big angle brackets at
         # positions 0x2329, 0x232a so use ordinary brackets.
   
         '(lang|9001)'     => {'tex' => '{/Symbol \341}',  'web' => '<'}, # Left angle bracket.
         '(rang|9002)'     => {'tex' => '{/Symbol \361}',  'web' => '>'}, # Right angle bracket.
   
         # Gemoetric shapes.
   
         '(loz|9674)'      => {'tex' => '{/Symbol \340}',  'web' => "\x{25ca}"}, # Lozenge.
   
         # Misc. symbols
   
         '(spades|9824)'   => {'tex' => '{/Symbol \252}', 'web' => "\x{2660}"}, 
         '(clubs|9827)'    => {'tex' => '{/Symbol \247}', 'web' => "\x{2663}"}, 
         '(hearts|9829)'   => {'tex' => '{/Symbol \251}', 'web' => "\x{2665}"}, 
         '(diams|9830)'    => {'tex' => '{/Symbol \250}', 'web' => "\x{2666}"}
   
       );
   
   
   sub replace_entities {
       my ($target,$text) = @_;
       $text =~ s{([_^~\{\}]|\\\\)}{\\\\$1}g;
       while (my ($re, $replace) = each(%lookup)) {
    my $repl = $replace->{$target};
    $text =~ s/&$re;/$replace->{$target}/g;
       }
       $text =~ s{(&)}{\\\\$1}g;
       return $text;
   }
   
 ##------------------------------------------------------------------- title  ##------------------------------------------------------------------- title
 sub start_title {  sub start_title {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result='';      my $result='';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
  $title = &Apache::lonxml::get_all_text("/title",$$parser[-1]);   $title = &Apache::lonxml::get_all_text("/title",$parser,$style);
    $title=&Apache::run::evaluate($title,$safeeval,$$parstack[-1]);
    $title =~ s/\n/ /g;
    if (length($title) > $max_str_len) {
       $title = substr($title,0,$max_str_len);
    }
    $title = &parse_label($target,$title);
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
    $result.=&Apache::edit::tag_start($target,$token,'Plot Title');
    my $text=&Apache::lonxml::get_all_text("/title",$parser,$style);
    $result.=&Apache::edit::editline('',$text,'',60);
     } elsif ($target eq 'modified') {      } elsif ($target eq 'modified') {
  my $text=$$parser[-1]->get_text("/function");   $result.=&Apache::edit::rebuild_tag($token);
  $result.=&Apache::edit::modifiedfield($token);   $result.=&Apache::edit::modifiedfield("/title",$parser);
     }      }
     return $result;      return $result;
 }  }
Line 373  sub start_title { Line 1343  sub start_title {
 sub end_title {  sub end_title {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result = '';      my $result = '';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
    $result.=&Apache::edit::tag_end($target,$token);
     }      }
     return $result;      return $result;
 }  }
Line 382  sub end_title { Line 1353  sub end_title {
 sub start_xlabel {  sub start_xlabel {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result='';      my $result='';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
  $xlabel = &Apache::lonxml::get_all_text("/xlabel",$$parser[-1]);   $xlabel = &Apache::lonxml::get_all_text("/xlabel",$parser,$style);
    $xlabel=&Apache::run::evaluate($xlabel,$safeeval,$$parstack[-1]);
    $xlabel =~ s/\n/ /g;
    if (length($xlabel) > $max_str_len) {
       $xlabel = substr($xlabel,0,$max_str_len);
    }
    $xlabel = &parse_label($target,$xlabel);
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
    $result.=&Apache::edit::tag_start($target,$token,'Plot Xlabel');
    my $text=&Apache::lonxml::get_all_text("/xlabel",$parser,$style);
    $result.=&Apache::edit::editline('',$text,'',60);
     } elsif ($target eq 'modified') {      } elsif ($target eq 'modified') {
  my $text=$$parser[-1]->get_text("/function");   $result.=&Apache::edit::rebuild_tag($token);
  $result.=&Apache::edit::modifiedfield($token);   $result.=&Apache::edit::modifiedfield("/xlabel",$parser);
     }      }
     return $result;      return $result;
 }  }
Line 395  sub start_xlabel { Line 1375  sub start_xlabel {
 sub end_xlabel {  sub end_xlabel {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result = '';      my $result = '';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
    $result.=&Apache::edit::tag_end($target,$token);
     }      }
     return $result;      return $result;
 }  }
Line 405  sub end_xlabel { Line 1386  sub end_xlabel {
 sub start_ylabel {  sub start_ylabel {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result='';      my $result='';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
  $ylabel = &Apache::lonxml::get_all_text("/ylabel",$$parser[-1]);   $ylabel = &Apache::lonxml::get_all_text("/ylabel",$parser,$style);
    $ylabel = &Apache::run::evaluate($ylabel,$safeeval,$$parstack[-1]);
    $ylabel =~ s/\n/ /g;
    if (length($ylabel) > $max_str_len) {
       $ylabel = substr($ylabel,0,$max_str_len);
    }
    $ylabel = &parse_label($target,$ylabel);
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
    $result .= &Apache::edit::tag_start($target,$token,'Plot Ylabel');
    my $text = &Apache::lonxml::get_all_text("/ylabel",$parser,$style);
    $result .= &Apache::edit::editline('',$text,'',60);
     } elsif ($target eq 'modified') {      } elsif ($target eq 'modified') {
  my $text=$$parser[-1]->get_text("/function");   $result.=&Apache::edit::rebuild_tag($token);
  $result.=&Apache::edit::modifiedfield($token);   $result.=&Apache::edit::modifiedfield("/ylabel",$parser);
     }      }
     return $result;      return $result;
 }  }
Line 418  sub start_ylabel { Line 1408  sub start_ylabel {
 sub end_ylabel {  sub end_ylabel {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result = '';      my $result = '';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
    $result.=&Apache::edit::tag_end($target,$token);
     }      }
     return $result;      return $result;
 }  }
Line 428  sub end_ylabel { Line 1419  sub end_ylabel {
 sub start_label {  sub start_label {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result='';      my $result='';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
  my %label;   my %label;
  &get_attributes(\%label,\%label_defaults,$parstack,$safeeval,   &get_attributes(\%label,\%label_defaults,$parstack,$safeeval,
     $tagstack->[-1]);      $tagstack->[-1]);
  $label{'text'} = &Apache::lonxml::get_all_text("/label",$$parser[-1]);   my $text = &Apache::lonxml::get_all_text("/label",$parser,$style);
  if (! &$words_test($label{'text'})) {   $text = &Apache::run::evaluate($text,$safeeval,$$parstack[-1]);
     # I should probably warn about it, too.   $text =~ s/\n/ /g;
     $label{'text'} = 'Illegal text';   $text = substr($text,0,$max_str_len) if (length($text) > $max_str_len);
  }   $label{'text'} = &parse_label($target,$text);
  push(@labels,\%label);   push(@labels,\%label);
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result .= &Apache::edit::tag_start($target,$token);   $result .= &Apache::edit::tag_start($target,$token,'Plot Label');
  $result .= &edit_attributes($target,$token,\%label_defaults);   $result .= &edit_attributes($target,$token,\%label_defaults);
    my $text = &Apache::lonxml::get_all_text("/label",$parser,$style);
    $result .= &Apache::edit::end_row().
       &Apache::edit::start_spanning_row().
       &Apache::edit::editline('',$text,'',60);
     } elsif ($target eq 'modified') {      } elsif ($target eq 'modified') {
  my $constructtag=&Apache::edit::get_new_args   &Apache::edit::get_new_args
     ($token,$parstack,$safeeval,keys %label_defaults);      ($token,$parstack,$safeeval,keys(%label_defaults));
  if ($constructtag) {   $result.=&Apache::edit::rebuild_tag($token);
     $result = &Apache::edit::rebuild_tag($token);   $result.=&Apache::edit::modifiedfield("/label",$parser);
     $result.= &Apache::edit::handle_insert();  
  }  
  my $text=$$parser[-1]->get_text("/function");  
  $result.=&Apache::edit::modifiedfield($token);  
     }      }
     return $result;      return $result;
 }  }
Line 457  sub start_label { Line 1448  sub start_label {
 sub end_label {  sub end_label {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result = '';      my $result = '';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result.=&Apache::edit::tag_end($target,$token);   $result.=&Apache::edit::tag_end($target,$token);
     }      }
Line 468  sub end_label { Line 1459  sub end_label {
 sub start_curve {  sub start_curve {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result='';      my $result='';
     if ($target eq 'web') {      &Apache::lonxml::register('Apache::lonplot',('function','data'));
       push (@Apache::lonxml::namespace,'curve');
       if ($target eq 'web' || $target eq 'tex') {
  my %curve;   my %curve;
  &get_attributes(\%curve,\%curve_defaults,$parstack,$safeeval,   &get_attributes(\%curve,\%curve_defaults,$parstack,$safeeval,
     $tagstack->[-1]);      $tagstack->[-1]);
  push (@curves,\%curve);   push (@curves,\%curve);
  &Apache::lonxml::register('Apache::lonplot',('function','data'));  
  push (@Apache::lonxml::namespace,'curve');  
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result .= &Apache::edit::tag_start($target,$token);   $result .= &Apache::edit::tag_start($target,$token,'Curve');
  $result .= &edit_attributes($target,$token,\%curve_defaults);   $result .= &edit_attributes($target,$token,\%curve_defaults,
                                       \@curve_edit_order)
       .&Apache::edit::end_row()
       .&Apache::edit::start_spanning_row();
   
     } elsif ($target eq 'modified') {      } elsif ($target eq 'modified') {
  my $constructtag=&Apache::edit::get_new_args   my $constructtag=&Apache::edit::get_new_args
     ($token,$parstack,$safeeval,keys %label_defaults);      ($token,$parstack,$safeeval,keys(%curve_defaults));
  if ($constructtag) {   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);      $result = &Apache::edit::rebuild_tag($token);
     $result.= &Apache::edit::handle_insert();  
  }   }
     }      }
     return $result;      return $result;
Line 492  sub start_curve { Line 1493  sub start_curve {
 sub end_curve {  sub end_curve {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result = '';      my $result = '';
     if ($target eq 'web') {      pop @Apache::lonxml::namespace;
  pop @Apache::lonxml::namespace;      &Apache::lonxml::deregister('Apache::lonplot',('function','data'));
  &Apache::lonxml::deregister('Apache::lonplot',('function','data'));      if ($target eq 'web' || $target eq 'tex') {
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result.=&Apache::edit::tag_end($target,$token);   $result.=&Apache::edit::tag_end($target,$token);
     }      }
Line 505  sub end_curve { Line 1506  sub end_curve {
 sub start_function {  sub start_function {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result='';      my $result='';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
  if (exists($curves[-1]->{'data'})) {   if (exists($curves[-1]->{'data'})) {
     &Apache::lonxml::warning('Use of <function> precludes use of <data>.  The <data> will be omitted in favor of the <function> declaration.');      &Apache::lonxml::warning
                   ('Use of the <b>curve function</b> tag precludes use of '.
                    ' the <b>curve data</b> tag.  '.
                    'The curve data tag will be omitted in favor of the '.
                    'curve function declaration.');
     delete $curves[-1]->{'data'} ;      delete $curves[-1]->{'data'} ;
  }   }
  $curves[-1]->{'function'} =           my $function = &Apache::lonxml::get_all_text("/function",$parser,
     &Apache::lonxml::get_all_text("/function",$$parser[-1]);       $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') {      } elsif ($target eq 'edit') {
  $result.=&Apache::edit::tag_start($target,$token);   $result .= &Apache::edit::tag_start($target,$token,'Gnuplot compatible curve function');
  my $text=&Apache::lonxml::get_all_text("/function",$$parser[-1]);   my $text = &Apache::lonxml::get_all_text("/function",$parser,$style);
  $result.='</td></tr><tr><td colspan="3">'.   $result .= &Apache::edit::editline('',$text,'',60);
     &Apache::edit::editfield('',$text,'',20,1).      } elsif ($target eq 'modified') {
     &Apache::edit::end_table();   $result.=&Apache::edit::rebuild_tag($token);
     } elsif ($target eq 'modified') {   $result.=&Apache::edit::modifiedfield("/function",$parser);
  # Why do I do this?  
  my $text=$$parser[-1]->get_text("/function");  
  $result.=&Apache::edit::modifiedfield($token);  
     }      }
     return $result;      return $result;
 }  }
Line 529  sub start_function { Line 1536  sub start_function {
 sub end_function {  sub end_function {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result = '';      my $result = '';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
    $result .= &Apache::edit::end_table();
     }      }
     return $result;      return $result;
 }  }
Line 539  sub end_function { Line 1547  sub end_function {
 sub start_data {  sub start_data {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result='';      my $result='';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
  if (exists($curves[-1]->{'function'})) {   if (exists($curves[-1]->{'function'})) {
     &Apache::lonxml::warning('Use of <data> precludes use of .'.      &Apache::lonxml::warning
     '<function>.  The <function> will be omitted in favor of '.                  ('Use of the <b>curve function</b> tag precludes use of '.
             'the <data> declaration.');                   ' the <b>curve data</b> tag.  '.
                    'The curve function tag will be omitted in favor of the '.
                    'curve data declaration.');
     delete($curves[-1]->{'function'});      delete($curves[-1]->{'function'});
  }   }
  my $datatext = &Apache::lonxml::get_all_text("/data",$$parser[-1]);   my $datatext = &Apache::lonxml::get_all_text("/data",$parser,$style);
  $datatext =~ s/\s+/ /g;     $datatext=&Apache::run::evaluate($datatext,$safeeval,$$parstack[-1]);
    # Deal with cases where we're given an array...
    if ($datatext =~ /^\@/) {
       $datatext = &Apache::run::run('return "'.$datatext.'"',
     $safeeval,1);
    }
    $datatext =~ s/\s+/ /g;
  # Need to do some error checking on the @data array -    # Need to do some error checking on the @data array - 
  # make sure it's all numbers and make sure each array    # make sure it's all numbers and make sure each array 
  # is of the same length.   # is of the same length.
  my @data;   my @data;
  if ($datatext =~ /,/) {   if ($datatext =~ /,/) { # comma deliminated
     @data = split /,/,$datatext;      @data = split /,/,$datatext;
  } else { # Assume it's space seperated.   } else { # Assume it's space separated.
     @data = split / /,$datatext;      @data = split / /,$datatext;
  }   }
  for (my $i=0;$i<=$#data;$i++) {   for (my $i=0;$i<=$#data;$i++) {
     # Check that it's non-empty      # Check that it's non-empty
     if (! defined($data[$i])) {      if (! defined($data[$i])) {
  &Apache::lonxml::warning(   &Apache::lonxml::warning(
     'undefined <data> value.  Replacing with '.      'undefined curve data value.  Replacing with '.
     ' pi/e = 1.15572734979092');      ' pi/e = 1.15572734979092');
  $data[$i] = 1.15572734979092;   $data[$i] = 1.15572734979092;
     }      }
     # Check that it's a number      # Check that it's a number
     if (! &$real_test($data[$i]) & ! &$int_test($data[$i])) {      if (! &$real_test($data[$i]) & ! &$int_test($data[$i])) {
  &Apache::lonxml::warning(   &Apache::lonxml::warning(
     'Bad <data> value of '.$data[$i].'  Replacing with '.      'Bad curve data value of '.$data[$i].'  Replacing with '.
     ' pi/e = 1.15572734979092');      ' pi/e = 1.15572734979092');
  $data[$i] = 1.15572734979092;   $data[$i] = 1.15572734979092;
     }      }
  }   }
    # complain if the number of data points is not the same as
    # in previous sets of data.
    if (($curves[-1]->{'data'}) && ($#data != $#{$curves[-1]->{'data'}->[0]})){
       &Apache::lonxml::warning
    ('Number of data points is not consistent with previous '.
    'number of data points');
    }
  push  @{$curves[-1]->{'data'}},\@data;   push  @{$curves[-1]->{'data'}},\@data;
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
    $result .= &Apache::edit::tag_start($target,$token,'Comma or space deliminated curve data');
    my $text = &Apache::lonxml::get_all_text("/data",$parser,$style);
    $result .= &Apache::edit::editline('',$text,'',60);
     } elsif ($target eq 'modified') {      } elsif ($target eq 'modified') {
  my $text=$$parser[-1]->get_text("/data");   $result.=&Apache::edit::rebuild_tag($token);
  $result.=&Apache::edit::modifiedfield($token);   $result.=&Apache::edit::modifiedfield("/data",$parser);
     }      }
     return $result;      return $result;
 }  }
Line 585  sub start_data { Line 1611  sub start_data {
 sub end_data {  sub end_data {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result = '';      my $result = '';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
    $result .= &Apache::edit::end_table();
     }      }
     return $result;      return $result;
 }  }
Line 595  sub end_data { Line 1622  sub end_data {
 sub start_axis {  sub start_axis {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result='';      my $result='';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
  &get_attributes(\%axis,\%axis_defaults,$parstack,$safeeval,   &get_attributes(\%axis,\%axis_defaults,$parstack,$safeeval,
  $tagstack->[-1]);   $tagstack->[-1]);
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result .= &Apache::edit::tag_start($target,$token);   $result .= &Apache::edit::tag_start($target,$token,'Plot Axes');
  $result .= &edit_attributes($target,$token,\%axis_defaults);   $result .= &edit_attributes($target,$token,\%axis_defaults,
       \@axis_edit_order);
     } elsif ($target eq 'modified') {      } 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);
    }
     }      }
     return $result;      return $result;
 }  }
Line 609  sub start_axis { Line 1652  sub start_axis {
 sub end_axis {  sub end_axis {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result = '';      my $result = '';
     if ($target eq 'web') {      if ($target eq 'web' || $target eq 'tex') {
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result.=&Apache::edit::tag_end($target,$token);   $result.=&Apache::edit::tag_end($target,$token);
     } elsif ($target eq 'modified') {      } elsif ($target eq 'modified') {
  my $constructtag=&Apache::edit::get_new_args  
     ($token,$parstack,$safeeval,keys %axis_defaults);  
  if ($constructtag) {  
     $result = &Apache::edit::rebuild_tag($token);  
     $result.= &Apache::edit::handle_insert();  
  }  
     }      }
     return $result;      return $result;
 }  }
Line 633  sub end_axis { Line 1670  sub end_axis {
 sub set_defaults {  sub set_defaults {
     my ($var,$defaults) = @_;      my ($var,$defaults) = @_;
     my $key;      my $key;
     foreach $key (keys %$defaults) {      foreach $key (keys(%$defaults)) {
  $var->{$key} = $defaults->{$key}->{'default'};   $var->{$key} = $defaults->{$key}->{'default'};
     }      }
 }  }
Line 641  sub set_defaults { Line 1678  sub set_defaults {
 ##------------------------------------------------------------------- misc  ##------------------------------------------------------------------- misc
 sub get_attributes{  sub get_attributes{
     my ($values,$defaults,$parstack,$safeeval,$tag) = @_;      my ($values,$defaults,$parstack,$safeeval,$tag) = @_;
     foreach my $attr (keys %{$defaults}) {      foreach my $attr (keys(%{$defaults})) {
  $values->{$attr} =    if ($attr eq 'texwidth' || $attr eq 'texfont') {
     &Apache::lonxml::get_param($attr,$parstack,$safeeval);      $values->{$attr} = 
    &Apache::lonxml::get_param($attr,$parstack,$safeeval,undef,1);
    } else {
       $values->{$attr} = 
    &Apache::lonxml::get_param($attr,$parstack,$safeeval);
    }
  if ($values->{$attr} eq '' | !defined($values->{$attr})) {   if ($values->{$attr} eq '' | !defined($values->{$attr})) {
     $values->{$attr} = $defaults->{$attr}->{'default'};      $values->{$attr} = $defaults->{$attr}->{'default'};
     next;      next;
Line 658  sub get_attributes{ Line 1700  sub get_attributes{
     }      }
     return ;      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 (defined %$spec) {
   
   
   
    # 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";
    }
       } else {
    $result .= "set $type font " . '"Helvetica,22"' ."\n";
       }
       
       
       return $result;
   }
   
 ##------------------------------------------------------- write_gnuplot_file  ##------------------------------------------------------- write_gnuplot_file
 sub write_gnuplot_file {  sub write_gnuplot_file {
       my ($tmpdir,$filename,$target)= @_;
       my ($fontsize, $font_properties) =  &get_font($target);
     my $gnuplot_input = '';      my $gnuplot_input = '';
     my $curve;      my $curve;
       #
       # 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      # Collect all the colors
     my @Colors;      my @Colors;
     push @Colors, $plot{'bgcolor'};      push @Colors, $Apache::lonplot::plot{'bgcolor'};
     push @Colors, $plot{'fgcolor'};       push @Colors, $Apache::lonplot::plot{'fgcolor'}; 
     push @Colors, (defined($axis{'color'})?$axis{'color'}:$plot{'fgcolor'});      push @Colors, (defined($axis{'color'})?$axis{'color'}:$Apache::lonplot::plot{'fgcolor'});
     foreach $curve (@curves) {      foreach $curve (@curves) {
  push @Colors, ($curve->{'color'} ne '' ?    push @Colors, ($curve->{'color'} ne '' ? 
        $curve->{'color'}       :          $curve->{'color'}       : 
        $plot{'fgcolor'}        );         $Apache::lonplot::plot{'fgcolor'}        );
     }      }
       
     # set term      # set term
     $gnuplot_input .= 'set term gif ';      if ($target eq 'web') {
     $gnuplot_input .= 'transparent ' if ($plot{'transparent'} eq 'on');   $gnuplot_input .= 'set terminal png enhanced nocrop ';
     $gnuplot_input .= $plot{'font'} . ' ';   $gnuplot_input .= 'transparent ' if ($Apache::lonplot::plot{'transparent'} eq 'on');
     $gnuplot_input .= 'size '.$plot{'width'}.','.$plot{'height'}.' ';   $gnuplot_input .= 'font "'.$Apache::lonnet::perlvar{'lonFontsDir'}.
     $gnuplot_input .= "@Colors\n";      '/'.$font_properties->{'file'}.'.ttf" ';
    $gnuplot_input .= $fontsize;
    $gnuplot_input .= ' size '.$Apache::lonplot::plot{'width'}.','.$Apache::lonplot::plot{'height'}.' ';
    $gnuplot_input .= "@Colors\n";
    # set output
    $gnuplot_input .= "set output\n";
       } elsif ($target eq 'tex') {
    $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'}.
    '/'.$font_properties->{'file'}.'.pfb" ';
    }
    $gnuplot_input .= ' "'.$font_properties->{'printname'}.'" ';
    $gnuplot_input .= $fontsize;
    $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'.$/;
       } else {
           # Assume Cartesian
       }
       # cartesian or polar grid?
       if (lc($Apache::lonplot::plot{'gridtype'}) eq 'polar') {
           $gnuplot_input .= 'set grid polar'.$/;
       } elsif (lc($Apache::lonplot::plot{'gridtype'}) eq 'linear-log') {
           $gnuplot_input .= 'set logscale x'.$/;
       } elsif (lc($Apache::lonplot::plot{'gridtype'}) eq 'log-linear') {
           $gnuplot_input .= 'set logscale y'.$/;
       } elsif (lc($Apache::lonplot::plot{'gridtype'}) eq 'log-log') {
           $gnuplot_input .= 'set logscale x'.$/;
           $gnuplot_input .= 'set logscale y'.$/;
       } else {
           # Assume Cartesian
       }
       # solid or pattern for boxes?
       if (lc($Apache::lonplot::plot{'fillstyle'}) eq 'solid') {
           $gnuplot_input .= 'set style fill solid '.
       $Apache::lonplot::plot{'solid'}.$Apache::lonplot::plot{'box_border'}.$/;
       } elsif (lc($Apache::lonplot::plot{'fillstyle'}) eq 'pattern') {
           $gnuplot_input .= 'set style fill pattern '.$Apache::lonplot::plot{'pattern'}.$Apache::lonplot::plot{'box_border'}.$/;
       } elsif (lc($Apache::lonplot::plot{'fillstyle'}) eq 'empty') {
       }
       # margin
       if (lc($Apache::lonplot::plot{'lmargin'}) ne 'default') {
           $gnuplot_input .= 'set lmargin '.$Apache::lonplot::plot{'lmargin'}.$/;
       }
       if (lc($Apache::lonplot::plot{'rmargin'}) ne 'default') {
           $gnuplot_input .= 'set rmargin '.$Apache::lonplot::plot{'rmargin'}.$/;
       }
       if (lc($Apache::lonplot::plot{'tmargin'}) ne 'default') {
           $gnuplot_input .= 'set tmargin '.$Apache::lonplot::plot{'tmargin'}.$/;
       }
       if (lc($Apache::lonplot::plot{'bmargin'}) ne 'default') {
           $gnuplot_input .= 'set bmargin '.$Apache::lonplot::plot{'bmargin'}.$/;
       }
   
       # tic scales
       if ($version > 4) {
    $gnuplot_input .= 'set tics scale '.
       $Apache::lonplot::plot{'major_ticscale'}.', '.$Apache::lonplot::plot{'minor_ticscale'}.$/;
       } else {
       $gnuplot_input .= 'set ticscale '.
       $Apache::lonplot::plot{'major_ticscale'}.' '.$Apache::lonplot::plot{'minor_ticscale'}.$/;
       }
       #boxwidth
       if (lc($Apache::lonplot::plot{'boxwidth'}) ne '') {
    $gnuplot_input .= 'set boxwidth '.$Apache::lonplot::plot{'boxwidth'}.$/;
       }
       # gridlayer
       $gnuplot_input .= 'set grid noxtics noytics front '.$/ 
    if ($Apache::lonplot::plot{'gridlayer'} eq 'on');
   
     # grid      # grid
     $gnuplot_input .= 'set grid'.$/ if ($plot{'grid'} eq 'on');      $gnuplot_input .= 'set grid'.$/ if ($Apache::lonplot::plot{'grid'} eq 'on');
     # border      # border
     $gnuplot_input .= ($plot{'border'} eq 'on'?      $gnuplot_input .= ($Apache::lonplot::plot{'border'} eq 'on'?
        'set border'.$/           :         'set border'.$/           :
        'set noborder'.$/         );    # title, xlabel, ylabel         'set noborder'.$/         );
     $gnuplot_input .= "set output\n";      # sampling rate for non-data curves
     $gnuplot_input .= "set title  \"$title\"\n"  if (defined($title)) ;      $gnuplot_input .= "set samples $Apache::lonplot::plot{'samples'}\n";
     $gnuplot_input .= "set xlabel \"$xlabel\"\n" if (defined($xlabel));      # title, xlabel, ylabel
     $gnuplot_input .= "set ylabel \"$ylabel\"\n" if (defined($ylabel));      # titles
     if (defined(%axis)) {      my $extra_space_x = ($xtics{'location'} eq 'axis') ? ' 0, -0.5 ' : '';
       my $extra_space_y = ($ytics{'location'} eq 'axis') ? ' -0.5, 0 ' : '';
   
       if ($target eq 'tex') {
    $gnuplot_input .= "set title  \"$title\"          font \"".$font_properties->{'printname'}.",".$fontsize."pt\"\n" if (defined($title)) ;
    $gnuplot_input .= "set xlabel \"$xlabel\" $extra_space_x font \"".$font_properties->{'printname'}.",".$fontsize."pt\"\n" if (defined($xlabel));
    $gnuplot_input .= "set ylabel \"$ylabel\" $extra_space_y font \"".$font_properties->{'printname'}.",".$fontsize."pt\"\n" if (defined($ylabel));
       } else {
           $gnuplot_input .= "set title  \"$title\"          \n" if (defined($title)) ;
           $gnuplot_input .= "set xlabel \"$xlabel\" $extra_space_x \n" if (defined($xlabel));
           $gnuplot_input .= "set ylabel \"$ylabel\" $extra_space_y \n" if (defined($ylabel));
       }
       # tics
       $gnuplot_input .= &generate_tics('xtics', \%xtics, $target);
   
       $gnuplot_input .= &generate_tics('ytics', \%ytics, $target);
   
       # axis
       if (%axis) {
           if ($axis{'xformat'} ne 'on') {
               $gnuplot_input .= "set format x ";
               if ($axis{'xformat'} eq 'off') {
                   $gnuplot_input .= "\"\"\n";
               } else {
                   $gnuplot_input .= "\"\%.".$axis{'xformat'}."\"\n";
               }
           }
           if ($axis{'yformat'} ne 'on') {
               $gnuplot_input .= "set format y ";
               if ($axis{'yformat'} eq 'off') {
                   $gnuplot_input .= "\"\"\n";
               } else {
                   $gnuplot_input .= "\"\%.".$axis{'yformat'}."\"\n";
               }
           }
  $gnuplot_input .= "set xrange \[$axis{'xmin'}:$axis{'xmax'}\]\n";   $gnuplot_input .= "set xrange \[$axis{'xmin'}:$axis{'xmax'}\]\n";
  $gnuplot_input .= "set yrange \[$axis{'ymin'}:$axis{'ymax'}\]\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      # Key
     if (defined(%key)) {      if (%key) {
  $gnuplot_input .= 'set key '.$key{'pos'}.' ';   $gnuplot_input .= 'set key '.$key{'pos'}.' ';
  if ($key{'title'} ne '') {   if ($key{'title'} ne '') {
     $gnuplot_input .= 'title "'.$key{'title'}.'" ';      $gnuplot_input .= 'title "'.$key{'title'}.'" ';
Line 706  sub write_gnuplot_file { Line 1960  sub write_gnuplot_file {
     my $label;      my $label;
     foreach $label (@labels) {      foreach $label (@labels) {
  $gnuplot_input .= 'set label "'.$label->{'text'}.'" at '.   $gnuplot_input .= 'set label "'.$label->{'text'}.'" at '.
     $label->{'xpos'}.','.$label->{'ypos'}.' '.$label->{'justify'}.$/ ;                            $label->{'xpos'}.','.$label->{'ypos'};
           if ($label->{'rotate'} ne '') {
               $gnuplot_input .= ' rotate by '.$label->{'rotate'};
           }
           $gnuplot_input .= ' '.$label->{'justify'};
   
           if ($target eq 'tex') {
       $gnuplot_input .=' font "'.$font_properties->{'printname'}.','.$fontsize.'pt"' ;
           }
           $gnuplot_input .= $/;
       }
       if ($target eq 'tex') {
           $gnuplot_input .="set size 1,".$Apache::lonplot::plot{'height'}/$Apache::lonplot::plot{'width'}*1.38;
           $gnuplot_input .="\n";
     }      }
     # curves      # curves
     $gnuplot_input .= 'plot ';      #
     my $datatext = '';      # 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   = '';
   
       # If arrows are needed there will be an arrow style for each as well:
       #
   
       my $arrow_style_index = 50;
   
       my $plot_command;
       my $plot_type;
   
     for (my $i = 0;$i<=$#curves;$i++) {      for (my $i = 0;$i<=$#curves;$i++) {
  $curve = $curves[$i];   $curve = $curves[$i];
  $gnuplot_input.= ', ' if ($i > 0);   $plot_command.= ', ' if ($i > 0);
    if ($target eq 'tex') {
       $curve->{'linewidth'} *= 2;
    }
    $line_width = $curve->{'linewidth'};
  if (exists($curve->{'function'})) {   if (exists($curve->{'function'})) {
     $gnuplot_input.=       $plot_type    = 
  $curve->{'function'}.' title "'.   $curve->{'function'}.' title "'.
  $curve->{'name'}.'" with '.   $curve->{'name'}.'" with '.
  $curve->{'linestyle'};                  $curve->{'linestyle'};
  } elsif (exists($curve->{'data'})) {   } elsif (exists($curve->{'data'})) {
     $gnuplot_input.= '\'-\' title "'.      # Store data values in $datatext
  $curve->{'name'}.'" with '.      my $datatext = '';
  $curve->{'linestyle'};      #   get new filename
       my $datafilename = "$tmpdir/$filename.data.$i";
       my $fh=Apache::File->new(">$datafilename");
       # Compile data
     my @Data = @{$curve->{'data'}};      my @Data = @{$curve->{'data'}};
     my @Data0 = @{$Data[0]};      my @Data0 = @{$Data[0]};
     for (my $i =0; $i<=$#Data0; $i++) {      for (my $i =0; $i<=$#Data0; $i++) {
Line 732  sub write_gnuplot_file { Line 2021  sub write_gnuplot_file {
  }   }
  $datatext .= $/;   $datatext .= $/;
     }      }
     $datatext .=$/;      #   write file
       print $fh $datatext;
       close($fh);
       #   generate gnuplot text
       $plot_type = '"'.$datafilename.'" title "'.
    $curve->{'name'}.'" with '.
    $curve->{'linestyle'};
    }
    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.   
   
    my $style_command = "set style line $linestyle_index $pointtype $pointsize linetype $lt linewidth $line_width lc rgb '$color'\n";
    $gnuplot_input .= $style_command;
   
   
   
    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++;
    }
   
   
   
   
    # The condition below is because gnuplot lumps the linestyle in with the 
    # arrowstyle _sigh_.
   
    if ($curve->{'linestyle'} ne 'vector') {
       $plot_command.= " ls $linestyle_index";
    }
   
    $gnuplot_input .= 'plot ' . $plot_type . ' ' . $plot_command . "\n";
    $linestyle_index++; # Each curve get a unique linestyle.
     }      }
     $gnuplot_input .= $/.$datatext;      # Write the output to a file.
     return $gnuplot_input;  
       # &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.
       return ;
 }  }
   
 #---------------------------------------------- check_inputs  #---------------------------------------------- check_inputs
 sub check_inputs {  sub check_inputs {
     ## Note: no inputs, no outputs - this acts only on global variables.      ## Note: no inputs, no outputs - this acts only on global variables.
     ## Make sure we have all the input we need:      ## Make sure we have all the input we need:
     if (! defined(%plot  )) { &set_defaults(\%plot,\%plot_defaults); }      if (! %Apache::lonplot::plot) { &set_defaults(\%Apache::lonplot::plot,\%gnuplot_defaults); }
     if (! defined(%key   )) {} # No key for this plot, thats okay      if (! %key ) {} # No key for this plot, thats okay
     if (! defined(%axis  )) { &set_defaults(\%axis,\%axis_defaults); }  #    if (! %axis) { &set_defaults(\%axis,\%axis_defaults); }
     if (! defined($title )) {} # No title for this plot, thats okay      if (! defined($title )) {} # No title for this plot, thats okay
     if (! defined($xlabel)) {} # No xlabel for this plot, thats okay      if (! defined($xlabel)) {} # No xlabel for this plot, thats okay
     if (! defined($ylabel)) {} # No ylabel for this plot, thats okay      if (! defined($ylabel)) {} # No ylabel for this plot, thats okay
Line 757  sub check_inputs { Line 2123  sub check_inputs {
     my $curve;      my $curve;
     foreach $curve (@curves) {      foreach $curve (@curves) {
  if (!defined($curve->{'function'})&&!defined($curve->{'data'})){   if (!defined($curve->{'function'})&&!defined($curve->{'data'})){
     &Apache::lonxml::warning("One of the curves specified did not contain any <data> or <function> declarations\n");      &Apache::lonxml::warning("One of the curves specified did not contain any curve data or curve function declarations\n");
     return '';      return '';
  }   }
     }      }
Line 765  sub check_inputs { Line 2131  sub check_inputs {
   
 #------------------------------------------------ make_edit  #------------------------------------------------ make_edit
 sub edit_attributes {  sub edit_attributes {
     my ($target,$token,$defaults) = @_;      my ($target,$token,$defaults,$keys) = @_;
     my $result;      my ($result,@keys);
     foreach my $attr (%$defaults) {      if ($keys && ref($keys) eq 'ARRAY') {
           @keys = @$keys;
       } else {
    @keys = sort(keys(%$defaults));
       }
       foreach my $attr (@keys) {
    # append a ' ' to the description if it doesn't have one already.
    my $description = $defaults->{$attr}->{'description'};
    $description .= ' ' if ($description !~ / $/);
  if ($defaults->{$attr}->{'edit_type'} eq 'entry') {   if ($defaults->{$attr}->{'edit_type'} eq 'entry') {
     $result .= &Apache::edit::text_arg(      $result .= &Apache::edit::text_arg
                  $defaults->{$attr}->{'description'},   ($description,$attr,$token,
  $attr,   $defaults->{$attr}->{'size'},
  $token);   $defaults->{$attr}->{'class'});
  } elsif ($defaults->{$attr}->{'edit_type'} eq 'choice') {   } elsif ($defaults->{$attr}->{'edit_type'} eq 'choice') {
     $result .= &Apache::edit::select_arg(      $result .= &Apache::edit::select_or_text_arg
  $defaults->{$attr}->{'description'},   ($description,$attr,$defaults->{$attr}->{'choices'},$token);
  $attr,   } elsif ($defaults->{$attr}->{'edit_type'} eq 'onoff') {
  $defaults->{$attr}->{'choices'},      $result .= &Apache::edit::select_or_text_arg
  $token);   ($description,$attr,['on','off'],$token);
  }   }
    $result .= '<br />';
     }      }
     return $result;      return $result;
 }  }
Line 791  sub edit_attributes { Line 2166  sub edit_attributes {
 ##                                                               ##  ##                                                               ##
 ###################################################################  ###################################################################
   
 #------------------------------------------------ insert_xxxxxxx  sub insert_gnuplot {
 sub insert_plot {      my $result = '';
     my $result;  
     #  plot attributes      #  plot attributes
     $result .= '<plot ';      $result .= "\n<gnuplot ";
     foreach my $attr (%plot_defaults) {      foreach my $attr (keys(%gnuplot_defaults)) {
  $result .= '     '.$attr.' "'.$plot_defaults{$attr}->{'default'}.   $result .= "\n     $attr=\"$gnuplot_defaults{$attr}->{'default'}\"";
     "\"\n";      }
     }      $result .= ">";
     $result .= ">\n";      # Add the components (most are commented out for simplicity)
     # Add the components      # $result .= &insert_key();
     $result .= &insert_key();      # $result .= &insert_axis();
     $result .= &insert_axis();      # $result .= &insert_title();    
     $result .= &insert_label();          # $result .= &insert_xlabel();    
     $result .= &insert_curve();      # $result .= &insert_ylabel();    
     $result .= &insert_function();      
     $result .= "</curve>\n";  
     $result .= &insert_curve();      $result .= &insert_curve();
     $result .= &insert_data();          # close up the <gnuplot>
     $result .= "</curve>\n";      $result .= "\n</gnuplot>";
     # close up the <plot>      return $result;
     $result .= "</plot>\n";  }
   
   sub insert_tics {
       my $result;
       $result .= &insert_xtics() . &insert_ytics;
       return $result;
   }
   
   sub insert_xtics {
       my $result;
       $result .= "\n    <xtics ";
       foreach my $attr (keys(%tic_defaults)) {
    $result .= "\n        $attr=\"$tic_defaults{$attr}->{'default'}\" ";
       }
       $result .= "/>";
       return $result;
   }
   
   sub insert_ytics {
       my $result;
       $result .= "\n    <ytics ";
       foreach my $attr (keys(%tic_defaults)) {
    $result .= "\n        $attr=\"$tic_defaults{$attr}->{'default'}\" ";
       }
       $result .= "/>";
     return $result;      return $result;
 }  }
   
 sub insert_key {  sub insert_key {
     my $result;      my $result;
     $result .= '    <key ';      $result .= "\n    <key ";
     foreach my $attr (%key_defaults) {      foreach my $attr (keys(%key_defaults)) {
  $result .= '         '.$attr.' "'.$key_defaults{$attr}->{'default'}.   $result .= "\n         $attr=\"$key_defaults{$attr}->{'default'}\"";
     "\"\n";  
     }      }
     $result .= "   />\n";      $result .= " />";
     return $result;      return $result;
 }  }
   
 sub insert_axis{  sub insert_axis{
     my $result;      my $result;
     $result .= '    <axis ';      $result .= "\n    <axis ";
     foreach my $attr (%axis_defaults) {     foreach my $attr (keys(%axis_defaults)) {
  $result .= '         '.$attr.' "'.$axis_defaults{$attr}->{'default'}.   $result .= "\n         $attr=\"$axis_defaults{$attr}->{'default'}\"";
     "\"\n";  
     }      }
     $result .= "   />\n";      $result .= " />";
     return $result;      return $result;
 }  }
   
   sub insert_title  { return "\n    <title></title>"; }
   sub insert_xlabel { return "\n    <xlabel></xlabel>"; }
   sub insert_ylabel { return "\n    <ylabel></ylabel>"; }
   
 sub insert_label {  sub insert_label {
     my $result;      my $result;
     $result .= '    <label ';      $result .= "\n    <label ";
     foreach my $attr (%label_defaults) {      foreach my $attr (keys(%label_defaults)) {
  $result .= '         '.$attr.' "'.   $result .= "\n         $attr=\"".
     $label_defaults{$attr}->{'default'}."\"\n";              $label_defaults{$attr}->{'default'}."\"";
     }      }
     $result .= "   ></label>\n";      $result .= "></label>";
     return $result;      return $result;
 }  }
   
 sub insert_curve {  sub insert_curve {
     my $result;      my $result;
     $result .= '    <curve ';      $result .= "\n    <curve ";
     foreach my $attr (%curve_defaults) {      foreach my $attr (keys(%curve_defaults)) {
  $result .= '         '.$attr.' "'.   $result .= "\n         $attr=\"".
     $curve_defaults{$attr}->{'default'}."\"\n";      $curve_defaults{$attr}->{'default'}."\"";
     }      }
     $result .= "    >\n";      $result .= " >";
       $result .= &insert_data().&insert_data()."\n    </curve>";
 }  }
   
 sub insert_function {  sub insert_function {
     my $result;      my $result;
     $result .= "<function></function>\n";      $result .= "\n        <function></function>";
     return $result;      return $result;
 }  }
   
 sub insert_data {  sub insert_data {
     my $result;      my $result;
     $result .= "     <data></data>\n";      $result .= "\n        <data></data>";
     $result .= "     <data></data>\n";  
     return $result;      return $result;
 }  }
   
Line 877  sub insert_data { Line 2275  sub insert_data {
 __END__  __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

Removed from v.1.21  
changed lines
  Added in v.1.168


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
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.