Diff for /loncom/xml/lonplot.pm between versions 1.120 and 1.170

version 1.120, 2007/07/30 21:50:29 version 1.170, 2012/12/05 19:30:28
Line 26 Line 26
 # http://www.lon-capa.org/  # http://www.lon-capa.org/
 #  #
   
   
   
   
 package Apache::lonplot;  package Apache::lonplot;
   
 use strict;  use strict;
Line 36  use Apache::response; Line 39  use Apache::response;
 use Apache::lonxml;  use Apache::lonxml;
 use Apache::edit;  use Apache::edit;
 use Apache::lonnet;  use Apache::lonnet;
 use lib '/home/httpd/lib/perl/';  
 use LONCAPA;  use LONCAPA;
     
   
 use vars qw/$weboutputformat $versionstring/;  use vars qw/$weboutputformat $version/;
   
   
   
Line 49  BEGIN { Line 51  BEGIN {
     #      #
     # Determine the version of GNUPLOT      # Determine the version of GNUPLOT
     $weboutputformat = 'gif';      $weboutputformat = 'gif';
     $versionstring = `gnuplot --version 2>/dev/null`;      my $versionstring = `gnuplot --version 2>/dev/null`;
     if ($versionstring =~ /^gnuplot 4/) {      ($version) = ($versionstring =~ /^gnuplot ([\d.]+)/);
       if ($version >= 4) {
         $weboutputformat = 'png';          $weboutputformat = 'png';
     }      }
           
 }  }
   
   
   =pod
   
 ##   ## 
 ## Description of data structures:  ## Description of data structures:
 ##  ##
Line 88  BEGIN { Line 93  BEGIN {
 ##                                                               ##  ##                                                               ##
 ###################################################################  ###################################################################
   
   =cut
   
 my $max_str_len = 50;    # if a label, title, xlabel, or ylabel text  my $max_str_len = 50;    # if a label, title, xlabel, or ylabel text
                          # is longer than this, it will be truncated.                           # 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 =   my %linestyles = 
     (      (
      lines          => 2,     # Maybe this will be used in the future       lines          => 2,     # Maybe this will be used in the future
Line 114  my $real_test      = Line 132  my $real_test      =
     sub {$_[0]=~s/\s+//g;$_[0]=~/^[+-]?\d*\.?\d*([eE][+-]\d+)?$/};      sub {$_[0]=~s/\s+//g;$_[0]=~/^[+-]?\d*\.?\d*([eE][+-]\d+)?$/};
 my $pos_real_test  =  my $pos_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-fA-F]{6}$/};  my $color_test;
   if ($version < 4.6) {
       $color_test = sub {$_[0]=~s/\s+//g;$_[0]=~s/^\#/x/;$_[0]=~/^x[\da-fA-F]{6}$/};
   } else {
       $color_test = sub {$_[0]=~s/\s+//g;$_[0]=~s/^x/#/;$_[0]=~/^\#[\da-fA-F]{6}$/};
   }
 my $onoff_test     = sub {$_[0]=~/^(on|off)$/};  my $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]=~/^(\d+|small|medium|large)$/};  my $sml_test       = sub {$_[0]=~/^(\d+|small|medium|large)$/};
 my $linestyle_test = sub {exists($linestyles{$_[0]})};  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 @gnuplot_edit_order =   my @gnuplot_edit_order = 
     qw/alttag bgcolor fgcolor height width fontface font transparent grid samples       qw/alttag bgcolor fgcolor height width texwidth fontface font texfont
     border align texwidth texfont plotcolor plottype gridtype lmargin rmargin      transparent grid samples 
       border align plotcolor plottype gridtype lmargin rmargin
     tmargin bmargin major_ticscale minor_ticscale boxwidth gridlayer fillstyle      tmargin bmargin major_ticscale minor_ticscale boxwidth gridlayer fillstyle
     pattern solid/;      pattern solid/;
   
Line 162  my %gnuplot_defaults = Line 190  my %gnuplot_defaults =
  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'   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'   size        => '10',
            class       => 'colorchooser'
  },   },
      transparent  => {       transparent  => {
  default     => 'off',   default     => 'off',
Line 205  my %gnuplot_defaults = Line 235  my %gnuplot_defaults =
      font         => {       font         => {
  default     => '9',   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     => [['5','5 (small)'],'7',['9','9 (medium)'],'10','12',['15','15 (large)']]   choices     => [['5','5 (small)'],'6','7','8',['9','9 (medium)'],'10',['11','11 (large)'],'12','15']
  },   },
      fontface     => {       fontface     => {
         default     => 'sans-serif',          default     => 'sans-serif',
Line 384  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',
      }       }
      );       );
   
Line 431  my %tic_defaults = Line 468  my %tic_defaults =
  description => 'Number of minor tics per major tic mark',   description => 'Number of minor tics per major tic mark',
  edit_type   => 'entry',   edit_type   => 'entry',
  size        => '10'   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');  my @axis_edit_order = ('color','xmin','xmax','ymin','ymax','xformat', 'yformat', 'xzero', 'yzero');
 my %axis_defaults =   my %axis_defaults = 
     (      (
      color   => {       color   => {
Line 442  my %axis_defaults = Line 485  my %axis_defaults =
  test => $color_test,   test => $color_test,
  description => 'Color of grid lines (x000000)',   description => 'Color of grid lines (x000000)',
  edit_type   => 'entry',   edit_type   => 'entry',
  size        => '10'   size        => '10',
            class       => 'colorchooser'
  },   },
      xmin      => {       xmin      => {
  default => '-10.0',   default => '-10.0',
Line 471  my %axis_defaults = Line 515  my %axis_defaults =
  description => 'Maximum y-value shown in plot',     description => 'Maximum y-value shown in plot',  
  edit_type   => 'entry',   edit_type   => 'entry',
  size        => '10'   size        => '10'
  }          },
        xformat      => {
            default     => 'on',
            test        => sub {$_[0]=~/^(on|off|\d+(f|F|e|E))$/},
            description => 'X-axis number formatting',
            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','pointtype','pointsize','limit');  
   my @curve_edit_order = ('color','name','linestyle','linewidth','linetype',
    'pointtype','pointsize','limit', 'arrowhead', 'arrowstyle', 
    'arrowlength', 'arrowangle', 'arrowbackangle'
       );
   
 my %curve_defaults =   my %curve_defaults = 
     (      (
Line 483  my %curve_defaults = Line 561  my %curve_defaults =
  test => $color_test,   test => $color_test,
  description => 'Color of curve (x000000)',   description => 'Color of curve (x000000)',
  edit_type   => 'entry',   edit_type   => 'entry',
  size        => '10'   size        => '10',
    class       => 'colorchooser'
  },   },
      name      => {       name      => {
  default => '',   default => '',
Line 495  my %curve_defaults = Line 574  my %curve_defaults =
      linestyle => {       linestyle => {
  default => 'lines',   default => 'lines',
  test => $linestyle_test,   test => $linestyle_test,
  description => 'Line style',   description => 'Plot with:',
  edit_type   => 'choice',   edit_type   => 'choice',
  choices     => [keys(%linestyles)]   choices     => [keys(%linestyles)]
  },   },
      linewidth => {       linewidth => {
          default     => 4,           default     => 1,
          test        => $int_test,           test        => $int_test,
          description => 'Line width (may not apply to all line styles)',           description => 'Line width (may not apply to all plot styles)',
          edit_type   => 'choice',           edit_type   => 'choice',
          choices     => [1,2,3,4,5,6,7,8,9,10]           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 => {       pointsize => {
          default     => 1,           default     => 1,
          test        => $pos_real_test,           test        => $pos_real_test,
          description => 'Point size (may not apply to all line styles)',           description => 'Point size (may not apply to all plot styles)',
          edit_type   => 'entry',           edit_type   => 'entry',
          size        => '5'           size        => '5'
          },           },
      pointtype => {       pointtype => {
          default     => 1,           default     => 1,
          test        => $int_test,           test        => $int_test,
          description => 'Point type (may not apply to all line styles)',           description => 'Point type (may not apply to all plot styles)',
          edit_type   => 'choice',           edit_type   => 'choice',
          choices     => [0,1,2,3,4,5,6]           choices     => [0,1,2,3,4,5,6]
          },           },
      limit     => {       limit     => {
          default     => 'closed',           default     => 'closed',
  test        => sub {$_[0]=~/^(closed|x1|x2|y1|y2)$/},   test        => sub {$_[0]=~/^(above|below|closed|x1|x2|y1|y2)$/},
          description => 'Point to fill -- for filledcurves',           description => 'Point to fill -- for filledcurves',
          edit_type   => 'choice',           edit_type   => 'choice',
          choices     => ['closed','x1','x2','y1','y2']           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 538  my %curve_defaults = Line 661  my %curve_defaults =
 undef %Apache::lonplot::plot;  undef %Apache::lonplot::plot;
 my (%key,%axis,$title,$xlabel,$ylabel,@labels,@curves,%xtics,%ytics);  my (%key,%axis,$title,$xlabel,$ylabel,@labels,@curves,%xtics,%ytics);
   
   my $current_tics; # Reference to the current tick hash
   
 sub start_gnuplot {  sub start_gnuplot {
     undef(%Apache::lonplot::plot);   undef(%key);    undef(%axis);      undef(%Apache::lonplot::plot);   undef(%key);    undef(%axis);
     undef($title);  undef($xlabel); undef($ylabel);      undef($title);  undef($xlabel); undef($ylabel);
Line 562  sub start_gnuplot { Line 687  sub start_gnuplot {
     } 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(%gnuplot_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);
  }   }
     }      }
Line 576  sub end_gnuplot { Line 712  sub end_gnuplot {
  ('title','xlabel','ylabel','key','axis','label','curve'));   ('title','xlabel','ylabel','key','axis','label','curve'));
     my $result = '';      my $result = '';
     my $randnumber;      my $randnumber;
       my $tmpdir =LONCAPA::tempdir(); # Where temporary files live:
   
     # need to call rand everytime start_script would evaluate, as the      # need to call rand everytime start_script would evaluate, as the
     # safe space rand number generator and the global rand generator       # safe space rand number generator and the global rand generator 
     # are not separate      # are not separate
Line 587  sub end_gnuplot { Line 725  sub end_gnuplot {
  &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.'_'.$$.$randnumber.'_plot';
  ## Write the plot description to the file   ## Write the plot description to the file
Line 608  ENDIMAGE Line 745  ENDIMAGE
     #might be inside the safe space, register the URL for later      #might be inside the safe space, register the URL for later
     &Apache::lonxml::register_ssi("/cgi-bin/plot.gif?file=$filename.data&output=eps");      &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  = "%DYNAMICIMAGE:$Apache::lonplot::plot{'width'}:$Apache::lonplot::plot{'height'}:$Apache::lonplot::plot{'texwidth'}\n";
     $result .= '\graphicspath{{/home/httpd/perl/tmp/}}'."\n";      $result .= '\graphicspath{{'.$tmpdir.'}}'."\n";
     $result .= '\includegraphics[width='.$Apache::lonplot::plot{'texwidth'}.' mm]{'.&unescape($filename).'.eps}';      $result .= '\includegraphics[width='.$Apache::lonplot::plot{'texwidth'}.' mm]{'.&unescape($filename).'.eps}';
  }   }
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
Line 625  sub start_xtics { Line 762  sub start_xtics {
     if ($target eq 'web' || $target eq 'tex') {      if ($target eq 'web' || $target eq 'tex') {
  &get_attributes(\%xtics,\%tic_defaults,$parstack,$safeeval,   &get_attributes(\%xtics,\%tic_defaults,$parstack,$safeeval,
     $tagstack->[-1]);      $tagstack->[-1]);
    $current_tics = \%xtics;
    &Apache::lonxml::register('Apache::lonplot', 'tic');
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result .= &Apache::edit::tag_start($target,$token,'xtics');   $result .= &Apache::edit::tag_start($target,$token,'xtics');
  $result .= &edit_attributes($target,$token,\%tic_defaults,   $result .= &edit_attributes($target,$token,\%tic_defaults,
Line 643  sub end_xtics { Line 782  sub end_xtics {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;      my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result = '';      my $result = '';
     if ($target eq 'web' || $target eq 'tex') {      if ($target eq 'web' || $target eq 'tex') {
    &Apache::lonxml::deregister('Apache::lonplot', 'tic');
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result.=&Apache::edit::tag_end($target,$token);   $result.=&Apache::edit::tag_end($target,$token);
     }      }
Line 656  sub start_ytics { Line 796  sub start_ytics {
     if ($target eq 'web' || $target eq 'tex') {      if ($target eq 'web' || $target eq 'tex') {
  &get_attributes(\%ytics,\%tic_defaults,$parstack,$safeeval,   &get_attributes(\%ytics,\%tic_defaults,$parstack,$safeeval,
     $tagstack->[-1]);      $tagstack->[-1]);
    $current_tics = \%ytics;
    &Apache::lonxml::register('Apache::lonplot', 'tic');
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result .= &Apache::edit::tag_start($target,$token,'ytics');   $result .= &Apache::edit::tag_start($target,$token,'ytics');
  $result .= &edit_attributes($target,$token,\%tic_defaults,   $result .= &edit_attributes($target,$token,\%tic_defaults,
Line 674  sub end_ytics { Line 816  sub end_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' || $target eq 'tex') {      if ($target eq 'web' || $target eq 'tex') {
    &Apache::lonxml::deregister('Apache::lonplot', 'tic');
     } 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;
 }  }
   
   
   ##----------------------------------------------------------------
   #
   #  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  ##-----------------------------------------------------------------font
 my %font_properties =  my %font_properties =
     (      (
Line 687  my %font_properties = Line 872  my %font_properties =
  face       => 'classic',   face       => 'classic',
  file       => 'DejaVuSansMono-Bold',   file       => 'DejaVuSansMono-Bold',
  printname  => 'Helvetica',   printname  => 'Helvetica',
    tex_no_file => 1,
      },       },
      'sans-serif' => {       'sans-serif' => {
  face       => 'sans-serif',   face       => 'sans-serif',
Line 701  my %font_properties = Line 887  my %font_properties =
      );       );
   
 sub get_font {  sub get_font {
       my ($target) = @_;
     my ($size, $selected_font);      my ($size, $selected_font);
   
     if ( $Apache::lonplot::plot{'font'} =~ /^(small|medium|large)/) {      if ( $Apache::lonplot::plot{'font'} =~ /^(small|medium|large)/) {
Line 710  sub get_font { Line 897  sub get_font {
  } elsif ( $Apache::lonplot::plot{'font'} eq 'medium') {   } elsif ( $Apache::lonplot::plot{'font'} eq 'medium') {
     $size = '9';      $size = '9';
  } elsif ( $Apache::lonplot::plot{'font'} eq 'large') {   } elsif ( $Apache::lonplot::plot{'font'} eq 'large') {
     $size = '15';      $size = '11';
  } else {   } else {
     $size = '9';      $size = '9';
  }   }
     } else {      } else {
    $size = $Apache::lonplot::plot{'font'};
  $selected_font = $font_properties{$Apache::lonplot::plot{'fontface'}};   $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);      return ($size, $selected_font);
 }  }
   
Line 750  sub end_key { Line 942  sub end_key {
     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)=@_;
Line 761  sub start_title { Line 1328  sub start_title {
  if (length($title) > $max_str_len) {   if (length($title) > $max_str_len) {
     $title = substr($title,0,$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');   $result.=&Apache::edit::tag_start($target,$token,'Plot Title');
  my $text=&Apache::lonxml::get_all_text("/title",$parser,$style);   my $text=&Apache::lonxml::get_all_text("/title",$parser,$style);
Line 792  sub start_xlabel { Line 1360  sub start_xlabel {
  if (length($xlabel) > $max_str_len) {   if (length($xlabel) > $max_str_len) {
     $xlabel = substr($xlabel,0,$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');   $result.=&Apache::edit::tag_start($target,$token,'Plot Xlabel');
  my $text=&Apache::lonxml::get_all_text("/xlabel",$parser,$style);   my $text=&Apache::lonxml::get_all_text("/xlabel",$parser,$style);
Line 824  sub start_ylabel { Line 1393  sub start_ylabel {
  if (length($ylabel) > $max_str_len) {   if (length($ylabel) > $max_str_len) {
     $ylabel = substr($ylabel,0,$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');   $result .= &Apache::edit::tag_start($target,$token,'Plot Ylabel');
  my $text = &Apache::lonxml::get_all_text("/ylabel",$parser,$style);   my $text = &Apache::lonxml::get_all_text("/ylabel",$parser,$style);
Line 857  sub start_label { Line 1427  sub start_label {
  $text = &Apache::run::evaluate($text,$safeeval,$$parstack[-1]);   $text = &Apache::run::evaluate($text,$safeeval,$$parstack[-1]);
  $text =~ s/\n/ /g;   $text =~ s/\n/ /g;
  $text = substr($text,0,$max_str_len) if (length($text) > $max_str_len);   $text = substr($text,0,$max_str_len) if (length($text) > $max_str_len);
  $label{'text'} = $text;   $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,'Plot Label');   $result .= &Apache::edit::tag_start($target,$token,'Plot Label');
Line 907  sub start_curve { Line 1477  sub start_curve {
  my $constructtag=&Apache::edit::get_new_args   my $constructtag=&Apache::edit::get_new_args
     ($token,$parstack,$safeeval,keys(%curve_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);
  }   }
     }      }
Line 941  sub start_function { Line 1518  sub start_function {
         my $function = &Apache::lonxml::get_all_text("/function",$parser,          my $function = &Apache::lonxml::get_all_text("/function",$parser,
      $style);       $style);
  $function = &Apache::run::evaluate($function,$safeeval,$$parstack[-1]);   $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;    $curves[-1]->{'function'} = $function; 
     } elsif ($target eq 'edit') {      } elsif ($target eq 'edit') {
  $result .= &Apache::edit::tag_start($target,$token,'Gnuplot compatible curve function');   $result .= &Apache::edit::tag_start($target,$token,'Gnuplot compatible curve function');
Line 1011  sub start_data { Line 1591  sub start_data {
  }   }
  # complain if the number of data points is not the same as   # complain if the number of data points is not the same as
  # in previous sets of data.   # in previous sets of data.
  if (($curves[-1]->{'data'}) && ($#data != $#{@{$curves[-1]->{'data'}->[0]}})){   if (($curves[-1]->{'data'}) && ($#data != $#{$curves[-1]->{'data'}->[0]})){
     &Apache::lonxml::warning      &Apache::lonxml::warning
  ('Number of data points is not consistent with previous '.   ('Number of data points is not consistent with previous '.
  'number of data points');   'number of data points');
Line 1052  sub start_axis { Line 1632  sub start_axis {
     } 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(%axis_defaults));      ($token,$parstack,$safeeval,keys(%axis_defaults));
   
  if ($constructtag) {   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);      $result = &Apache::edit::rebuild_tag($token);
  }   }
     }      }
Line 1110  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 ($tmpdir,$filename,$target)= @_;
     my ($fontsize, $font_properties) =  &get_font();      my ($fontsize, $font_properties) =  &get_font($target);
     my $gnuplot_input = '';      my $gnuplot_input = '';
     my $curve;      my $curve;
     my $pt = $Apache::lonplot::plot{'texfont'};  
     #      #
     # Check to be sure we do not have any empty curves      # Check to be sure we do not have any empty curves
     my @curvescopy;      my @curvescopy;
Line 1146  sub write_gnuplot_file { Line 1794  sub write_gnuplot_file {
        $curve->{'color'}       :          $curve->{'color'}       : 
        $Apache::lonplot::plot{'fgcolor'}        );         $Apache::lonplot::plot{'fgcolor'}        );
     }      }
       
     # set term      # set term
     if ($target eq 'web') {      if ($target eq 'web') {
  $gnuplot_input .= 'set terminal png enhanced nocrop ';   $gnuplot_input .= 'set terminal png enhanced nocrop ';
Line 1158  sub write_gnuplot_file { Line 1807  sub write_gnuplot_file {
  # set output   # set output
  $gnuplot_input .= "set output\n";   $gnuplot_input .= "set output\n";
     } elsif ($target eq 'tex') {      } elsif ($target eq 'tex') {
  $gnuplot_input .= "set term postscript eps enhanced $Apache::lonplot::plot{'plotcolor'} solid ";   $gnuplot_input .= "set term postscript eps enhanced $Apache::lonplot::plot{'plotcolor'} dash ";
  $gnuplot_input .=   if (!$font_properties->{'tex_no_file'}) {
     'fontfile "'.$Apache::lonnet::perlvar{'lonFontsDir'}.      $gnuplot_input .=
     '/'.$font_properties->{'file'}.'.pfb" ';   'fontfile "'.$Apache::lonnet::perlvar{'lonFontsDir'}.
    '/'.$font_properties->{'file'}.'.pfb" ';
    }
  $gnuplot_input .= ' "'.$font_properties->{'printname'}.'" ';   $gnuplot_input .= ' "'.$font_properties->{'printname'}.'" ';
  $gnuplot_input .= $fontsize;   $gnuplot_input .= $fontsize;
  $gnuplot_input .= "\nset output \"/home/httpd/perl/tmp/".   $gnuplot_input .= "\nset output \"".$tmpdir.
     &unescape($filename).".eps\"\n";      &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?      # cartesian or polar plot?
     if (lc($Apache::lonplot::plot{'plottype'}) eq 'polar') {      if (lc($Apache::lonplot::plot{'plottype'}) eq 'polar') {
         $gnuplot_input .= 'set polar'.$/;          $gnuplot_input .= 'set polar'.$/;
Line 1207  sub write_gnuplot_file { Line 1861  sub write_gnuplot_file {
     if (lc($Apache::lonplot::plot{'bmargin'}) ne 'default') {      if (lc($Apache::lonplot::plot{'bmargin'}) ne 'default') {
         $gnuplot_input .= 'set bmargin '.$Apache::lonplot::plot{'bmargin'}.$/;          $gnuplot_input .= 'set bmargin '.$Apache::lonplot::plot{'bmargin'}.$/;
     }      }
   
     # tic scales      # tic scales
     $gnuplot_input .= 'set ticscale '.      if ($version > 4) {
         $Apache::lonplot::plot{'major_ticscale'}.' '.$Apache::lonplot::plot{'minor_ticscale'}.$/;   $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      #boxwidth
     if (lc($Apache::lonplot::plot{'boxwidth'}) ne '') {      if (lc($Apache::lonplot::plot{'boxwidth'}) ne '') {
  $gnuplot_input .= 'set boxwidth '.$Apache::lonplot::plot{'boxwidth'}.$/;   $gnuplot_input .= 'set boxwidth '.$Apache::lonplot::plot{'boxwidth'}.$/;
Line 1228  sub write_gnuplot_file { Line 1888  sub write_gnuplot_file {
     $gnuplot_input .= "set samples $Apache::lonplot::plot{'samples'}\n";      $gnuplot_input .= "set samples $Apache::lonplot::plot{'samples'}\n";
     # title, xlabel, ylabel      # title, xlabel, ylabel
     # titles      # titles
       my $extra_space_x = ($xtics{'location'} eq 'axis') ? ' offset 0, -0.5 ' : '';
       my $extra_space_y = ($ytics{'location'} eq 'axis') ? ' offset -0.5, 0 ' : '';
   
     if ($target eq 'tex') {      if ($target eq 'tex') {
  $gnuplot_input .= "set title  \"$title\"  font \"".$font_properties->{'printname'}.",".$pt."pt\"\n" if (defined($title)) ;   $gnuplot_input .= "set title  \"$title\"          font \"".$font_properties->{'printname'}.",".$fontsize."pt\"\n" if (defined($title)) ;
  $gnuplot_input .= "set xlabel \"$xlabel\" font \"".$font_properties->{'printname'}.",".$pt."pt\"\n" if (defined($xlabel));   $gnuplot_input .= "set xlabel \"$xlabel\" $extra_space_x font \"".$font_properties->{'printname'}.",".$fontsize."pt\"\n" if (defined($xlabel));
  $gnuplot_input .= "set ylabel \"$ylabel\" font \"".$font_properties->{'printname'}.",".$pt."pt\"\n" if (defined($ylabel));   $gnuplot_input .= "set ylabel \"$ylabel\" $extra_space_y font \"".$font_properties->{'printname'}.",".$fontsize."pt\"\n" if (defined($ylabel));
     } else {      } else {
         $gnuplot_input .= "set title  \"$title\"  \n" if (defined($title)) ;          $gnuplot_input .= "set title  \"$title\"          \n" if (defined($title)) ;
         $gnuplot_input .= "set xlabel \"$xlabel\" \n" if (defined($xlabel));          $gnuplot_input .= "set xlabel \"$xlabel\" $extra_space_x \n" if (defined($xlabel));
         $gnuplot_input .= "set ylabel \"$ylabel\" \n" if (defined($ylabel));          $gnuplot_input .= "set ylabel \"$ylabel\" $extra_space_y \n" if (defined($ylabel));
     }      }
     # tics      # tics
     if (%xtics) {          $gnuplot_input .= &generate_tics('xtics', \%xtics, $target);
  $gnuplot_input .= "set xtics $xtics{'location'} ";  
  $gnuplot_input .= ( $xtics{'mirror'} eq 'on'?"mirror ":"nomirror ");      $gnuplot_input .= &generate_tics('ytics', \%ytics, $target);
  $gnuplot_input .= "$xtics{'start'}, ";  
  $gnuplot_input .= "$xtics{'increment'}, ";  
  $gnuplot_input .= "$xtics{'end'}\n";  
         if ($xtics{'minorfreq'} != 0) {  
             $gnuplot_input .= "set mxtics ".$xtics{'minorfreq'}."\n";  
         }   
     }  
     if (%ytics) {      
  $gnuplot_input .= "set ytics $ytics{'location'} ";  
  $gnuplot_input .= ( $ytics{'mirror'} eq 'on'?"mirror ":"nomirror ");  
  $gnuplot_input .= "$ytics{'start'}, ";  
  $gnuplot_input .= "$ytics{'increment'}, ";  
         $gnuplot_input .= "$ytics{'end'}\n";  
         if ($ytics{'minorfreq'} != 0) {  
             $gnuplot_input .= "set mytics ".$ytics{'minorfreq'}."\n";  
         }   
     }  
     # axis      # axis
     if (%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 (%key) {      if (%key) {
Line 1277  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') {          if ($target eq 'tex') {
     $gnuplot_input .=' font "'.$font_properties->{'printname'}.','.$pt.'pt"' ;      $gnuplot_input .=' font "'.$font_properties->{'printname'}.','.$fontsize.'pt"' ;
         }          }
         $gnuplot_input .= $/;          $gnuplot_input .= $/;
     }      }
Line 1288  sub write_gnuplot_file { Line 1976  sub write_gnuplot_file {
         $gnuplot_input .="\n";          $gnuplot_input .="\n";
     }      }
     # curves      # curves
     $gnuplot_input .= 'plot ';      #
       # Each curve will have its very own linestyle.
       # (This should work just fine in web rendition I think).
       #  The line_xxx variables will hold the elements of the line style.
       #  type (solid/dashed), color, width
       #
       my $linestyle_index = 50;
       my $line_width   = '';
       my $plots;
   
       # If arrows are needed there will be an arrow style for each as well:
       #
   
       my $arrow_style_index = 50;
   
     for (my $i = 0;$i<=$#curves;$i++) {      for (my $i = 0;$i<=$#curves;$i++) {
  $curve = $curves[$i];   $curve = $curves[$i];
  $gnuplot_input.= ', ' if ($i > 0);   my $plot_command;
    my $plot_type = ', ' if ($i > 0);
  if ($target eq 'tex') {   if ($target eq 'tex') {
     $curve->{'linewidth'} *= 2;      $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'};
             $gnuplot_input.= ' linewidth '.$curve->{'linewidth'};  
   
             if (($curve->{'linestyle'} eq 'points')      ||  
                 ($curve->{'linestyle'} eq 'linespoints') ||  
                 ($curve->{'linestyle'} eq 'errorbars')   ||  
                 ($curve->{'linestyle'} eq 'xerrorbars')  ||  
                 ($curve->{'linestyle'} eq 'yerrorbars')  ||  
                 ($curve->{'linestyle'} eq 'xyerrorbars')) {  
                 $gnuplot_input.=' pointtype '.$curve->{'pointtype'};  
                 $gnuplot_input.=' pointsize '.$curve->{'pointsize'};  
             } elsif ($curve->{'linestyle'} eq 'filledcurves') {   
                 $gnuplot_input.= ' '.$curve->{'limit'};  
             }  
  } elsif (exists($curve->{'data'})) {   } elsif (exists($curve->{'data'})) {
     # Store data values in $datatext      # Store data values in $datatext
     my $datatext = '';      my $datatext = '';
Line 1333  sub write_gnuplot_file { Line 2024  sub write_gnuplot_file {
     print $fh $datatext;      print $fh $datatext;
     close($fh);      close($fh);
     #   generate gnuplot text      #   generate gnuplot text
     $gnuplot_input.= '"'.$datafilename.'" title "'.      $plot_type .= '"'.$datafilename.'" title "'.
  $curve->{'name'}.'" with '.   $curve->{'name'}.'" with '.
  $curve->{'linestyle'};   $curve->{'linestyle'};
             $gnuplot_input.= ' linewidth '.$curve->{'linewidth'};  
             if (($curve->{'linestyle'} eq 'points')      ||  
                 ($curve->{'linestyle'} eq 'linespoints') ||  
                 ($curve->{'linestyle'} eq 'errorbars')   ||  
                 ($curve->{'linestyle'} eq 'xerrorbars')  ||  
                 ($curve->{'linestyle'} eq 'yerrorbars')  ||  
                 ($curve->{'linestyle'} eq 'xyerrorbars')) {  
                 $gnuplot_input.=' pointtype '.$curve->{'pointtype'};  
                 $gnuplot_input.=' pointsize '.$curve->{'pointsize'};  
             } elsif ($curve->{'linestyle'} eq 'filledcurves') {   
                 $gnuplot_input.= ' '.$curve->{'limit'};  
             }  
  }   }
    my $pointtype = '';
    my $pointsize = '';
   
    # Figure out the linestyle:
   
    my $lt = $curve->{'linetype'} ne '' ? $curve->{'linetype'} 
                   : 'solid'; # Line type defaults to solid.
    # The mapping of lt -> the actual gnuplot line type depends on the target:
   
    if ($target eq 'tex') {
       $lt = $ps_linetypes{$lt};
    } else {
       $lt = $linetypes{$lt}
    }
   
    my $color = $curve->{'color'};
    $color =~ s/^x/#/;        # Convert xhex color -> #hex color.   
   
   
    if (($curve->{'linestyle'} eq 'points')      ||
       ($curve->{'linestyle'} eq 'linespoints') ||
       ($curve->{'linestyle'} eq 'errorbars')   ||
       ($curve->{'linestyle'} eq 'xerrorbars')  ||
       ($curve->{'linestyle'} eq 'yerrorbars')  ||
       ($curve->{'linestyle'} eq 'xyerrorbars')) {
       
       $pointtype =' pointtype '.$curve->{'pointtype'};
       $pointsize =' pointsize '.$curve->{'pointsize'};
    } elsif ($curve->{'linestyle'} eq 'filledcurves') { 
       $plot_command.= ' '.$curve->{'limit'};
    } elsif ($curve->{'linestyle'} eq 'vector') {
   
       # Create the arrow head style add it to 
       # $gnuplot_input..and ensure it gets
       # Selected in the plot command.
   
       $gnuplot_input .= "set style arrow $arrow_style_index ";
       $gnuplot_input .= ' ' . $curve->{'arrowhead'};
       $gnuplot_input .= ' size ' . $curve->{'arrowlength'};
       $gnuplot_input .= ','.$curve->{'arrowangle'};
       $gnuplot_input .= ',' . $curve->{'arrowbackangle'}; 
       $gnuplot_input .=  ' ' . $curve->{'arrowstyle'} . " ls $linestyle_index\n";
   
   
       $plot_command  .= "  arrowstyle $arrow_style_index ";
       $arrow_style_index++;
    }
   
           my $style_command = "set style line $linestyle_index $pointtype $pointsize linetype $lt linewidth $line_width lc rgb '$color'\n";
           $gnuplot_input .= $style_command;
   
    # The condition below is because gnuplot lumps the linestyle in with the 
    # arrowstyle _sigh_.
   
    if ($curve->{'linestyle'} ne 'vector') {
       $plot_command.= " ls $linestyle_index";
    }
   
    $plots .= $plot_type . ' ' . $plot_command;
    $linestyle_index++; # Each curve get a unique linestyle.
     }      }
       $gnuplot_input .= 'plot '.$plots;
     # Write the output to a file.      # Write the output to a file.
     my $fh=Apache::File->new(">$tmpdir$filename.data");  
       # &Apache::lonnet::logthis($gnuplot_input); # uncomment to log the gnuplot input.
       open (my $fh, "> $tmpdir$filename.data");
       binmode($fh, ':utf8');
     print $fh $gnuplot_input;      print $fh $gnuplot_input;
     close($fh);      close($fh);
     # That's all folks.      # That's all folks.
Line 1398  sub edit_attributes { Line 2141  sub edit_attributes {
  if ($defaults->{$attr}->{'edit_type'} eq 'entry') {   if ($defaults->{$attr}->{'edit_type'} eq 'entry') {
     $result .= &Apache::edit::text_arg      $result .= &Apache::edit::text_arg
  ($description,$attr,$token,   ($description,$attr,$token,
  $defaults->{$attr}->{'size'});   $defaults->{$attr}->{'size'},
    $defaults->{$attr}->{'class'});
  } elsif ($defaults->{$attr}->{'edit_type'} eq 'choice') {   } elsif ($defaults->{$attr}->{'edit_type'} eq 'choice') {
     $result .= &Apache::edit::select_or_text_arg      $result .= &Apache::edit::select_or_text_arg
  ($description,$attr,$defaults->{$attr}->{'choices'},$token);   ($description,$attr,$defaults->{$attr}->{'choices'},$token);
Line 1527  sub insert_data { Line 2271  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.120  
changed lines
  Added in v.1.170


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>