home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / octave-1.1.1p1-base.tgz / octave-1.1.1p1-base.tar / fsf / octave / src / tree-plot.cc < prev    next >
C/C++ Source or Header  |  1995-01-30  |  22KB  |  1,236 lines

  1. // tree-plot.cc                                         -*- C++ -*-
  2. /*
  3.  
  4. Copyright (C) 1992, 1993, 1994, 1995 John W. Eaton
  5.  
  6. This file is part of Octave.
  7.  
  8. Octave is free software; you can redistribute it and/or modify it
  9. under the terms of the GNU General Public License as published by the
  10. Free Software Foundation; either version 2, or (at your option) any
  11. later version.
  12.  
  13. Octave is distributed in the hope that it will be useful, but WITHOUT
  14. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with Octave; see the file COPYING.  If not, write to the Free
  20. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22. */
  23.  
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #endif
  27.  
  28. #include <sys/types.h>
  29. #ifdef HAVE_UNISTD_H
  30. #include <unistd.h>
  31. #endif
  32. #include <string.h>
  33. #include <iostream.h>
  34. #include <strstream.h>
  35. #include <fstream.h>
  36.  
  37. #include "SLStack.h"
  38. #include "procstream.h"
  39.  
  40. #include "user-prefs.h"
  41. #include "tree-base.h"
  42. #include "tree-expr.h"
  43. #include "tree-cmd.h"
  44. #include "tree-const.h"
  45. #include "tree-plot.h"
  46. #include "load-save.h"
  47. #include "help.h"
  48. #include "error.h"
  49. #include "gripes.h"
  50. #include "utils.h"
  51. #include "defun.h"
  52.  
  53. extern "C"
  54. {
  55. #include <readline/tilde.h>
  56. }
  57.  
  58. // The number of lines we\'ve plotted so far.
  59. static int plot_line_count = 0;
  60.  
  61. // Is this a parametric plot?  Makes a difference for 3D plotting.
  62. static int parametric_plot = 0;
  63.  
  64. // The gnuplot terminal type.
  65. static char *gnuplot_terminal_type = 0;
  66.  
  67. // Should the graph window be cleared before plotting the next line?
  68. static int clear_before_plotting = 1;
  69.  
  70. // List of files to delete when we exit or crash.
  71. static SLStack <char *> tmp_files;
  72.  
  73. // Pipe to gnuplot.
  74. static oprocstream plot_stream;
  75.  
  76. // Use shortest possible abbreviations to minimize trouble caused by
  77. // gnuplot's fixed-length command line buffer.
  78.  
  79. #ifndef GNUPLOT_COMMAND_PLOT  
  80. #define GNUPLOT_COMMAND_PLOT   "pl"
  81. #endif
  82.  
  83. #ifndef GNUPLOT_COMMAND_REPLOT 
  84. #define GNUPLOT_COMMAND_REPLOT "rep"
  85. #endif
  86.  
  87. #ifndef GNUPLOT_COMMAND_SPLOT 
  88. #define GNUPLOT_COMMAND_SPLOT  "sp"
  89. #endif
  90.  
  91. #ifndef GNUPLOT_COMMAND_USING
  92. #define GNUPLOT_COMMAND_USING  "u"
  93. #endif
  94.  
  95. #ifndef GNUPLOT_COMMAND_WITH 
  96. #define GNUPLOT_COMMAND_WITH   "w"
  97. #endif
  98.  
  99. #ifndef GNUPLOT_COMMAND_TITLE
  100. #define GNUPLOT_COMMAND_TITLE  "t"
  101. #endif
  102.  
  103. static void
  104. open_plot_stream (void)
  105. {
  106.   static int initialized = 0;
  107.  
  108.   if (! plot_stream.is_open ())
  109.     {
  110.       initialized = 0;
  111.  
  112.       plot_line_count = 0;
  113.  
  114.       char *plot_prog = user_pref.gnuplot_binary;
  115.       if (plot_prog)
  116.     {
  117.       plot_stream.open (plot_prog);
  118.       if (! plot_stream.is_open ())
  119.         {
  120.           warning ("plot: unable to open pipe to `%s'",
  121.                plot_prog);
  122.  
  123.           if (strcmp (plot_prog, "gnuplot") != 0)
  124.         {
  125.           warning ("having trouble finding plotting program.");
  126.           warning ("trying again with `gnuplot'");
  127.           goto last_chance;
  128.         }
  129.         }
  130.     }
  131.       else
  132.     {
  133.     last_chance:
  134.  
  135.       plot_stream.open ("gnuplot");
  136.  
  137.       if (! plot_stream.is_open ())
  138.         error ("plot: unable to open pipe to `%s'", plot_prog);
  139.     }
  140.     }
  141.  
  142.   if (! initialized)
  143.     {
  144.       initialized = 1;
  145.       plot_stream << "set data style lines\n";
  146.  
  147.       if (gnuplot_terminal_type)
  148.     plot_stream << "set term " << gnuplot_terminal_type << "\n";
  149.     }
  150. }
  151.  
  152. static int
  153. send_to_plot_stream (const char *cmd)
  154. {
  155. // From sighandlers.cc:
  156.   extern int pipe_handler_error_count;
  157.  
  158.   if (! plot_stream.is_open ())
  159.     {
  160.       open_plot_stream ();
  161.  
  162.       if (error_state)
  163.     return -1;
  164.     }
  165.  
  166.   int replot_len = strlen (GNUPLOT_COMMAND_REPLOT);
  167.   int splot_len = strlen (GNUPLOT_COMMAND_SPLOT);
  168.   int plot_len = strlen (GNUPLOT_COMMAND_PLOT);
  169.  
  170.   int is_replot = (strncmp (cmd, GNUPLOT_COMMAND_REPLOT, replot_len) == 0);
  171.   int is_splot = (strncmp (cmd, GNUPLOT_COMMAND_SPLOT, splot_len) == 0);
  172.   int is_plot = (strncmp (cmd, GNUPLOT_COMMAND_PLOT, plot_len) == 0);
  173.  
  174.   if (plot_line_count == 0 && is_replot)
  175.     error ("replot: no previous plot");
  176.   else
  177.     {
  178.       plot_stream << cmd;
  179.  
  180.       if (! (is_replot || is_splot || is_plot)
  181.       && plot_line_count > 0
  182.       && user_pref.automatic_replot)
  183.     plot_stream << GNUPLOT_COMMAND_REPLOT << "\n";
  184.  
  185.       plot_stream.flush ();
  186.       pipe_handler_error_count = 0;
  187.     }
  188.  
  189.   return 0;
  190. }
  191.  
  192. // Plotting, eh?
  193.  
  194. tree_plot_command::tree_plot_command (void) : tree_command ()
  195. {
  196.   range = 0;
  197.   plot_list = 0;
  198.   ndim = 0;
  199. }
  200.  
  201. tree_plot_command::tree_plot_command (subplot_list *plt, int nd)
  202.   : tree_command ()
  203. {
  204.   range = 0;
  205.   plot_list = plt;
  206.   ndim = nd;
  207. }
  208.  
  209. tree_plot_command::tree_plot_command (subplot_list *plt,
  210.                       plot_limits *rng, int nd)
  211.   : tree_command ()
  212. {
  213.   range = rng;
  214.   plot_list = plt;
  215.   ndim = nd;
  216. }
  217.  
  218. tree_plot_command::~tree_plot_command (void)
  219. {
  220.   delete range;
  221.   delete plot_list;
  222. }
  223.  
  224. void
  225. tree_plot_command::eval (void)
  226. {
  227.   if (error_state)
  228.     return;
  229.  
  230.   open_plot_stream ();
  231.  
  232.   ostrstream plot_buf;
  233.  
  234.   switch (ndim)
  235.     {
  236.     case 1:
  237.       if (plot_line_count == 0)
  238.     {
  239.       if (plot_list)
  240.         plot_buf << GNUPLOT_COMMAND_PLOT;
  241.       else
  242.         {
  243.           ::error ("replot: must have something to plot");
  244.           return;
  245.         }
  246.     }
  247.       else
  248.     plot_buf << GNUPLOT_COMMAND_REPLOT;
  249.       break;
  250.  
  251.     case 2:
  252.       if (clear_before_plotting || plot_line_count == 0)
  253.     {
  254.       plot_line_count = 0;
  255.       plot_buf << GNUPLOT_COMMAND_PLOT;
  256.     }
  257.       else
  258.     plot_buf << GNUPLOT_COMMAND_REPLOT;
  259.       break;
  260.  
  261.     case 3:
  262.       if (clear_before_plotting || plot_line_count == 0)
  263.     {
  264.       plot_line_count = 0;
  265.       plot_buf << GNUPLOT_COMMAND_SPLOT;
  266.     }
  267.       else
  268.     plot_buf << GNUPLOT_COMMAND_REPLOT;
  269.       break;
  270.  
  271.     default:
  272.       gripe_2_or_3_dim_plot ();
  273.       return;
  274.     }
  275.  
  276.   if (range)
  277.     {
  278.       if (plot_line_count == 0)
  279.     range->print (ndim, plot_buf);
  280.       else
  281.     warning ("can't specify new plot ranges with `replot' or while\
  282.  hold is on");
  283.     }
  284.  
  285.   if (error_state)
  286.     return;
  287.  
  288.   if (plot_list)
  289.     {
  290.       int status = plot_list->print (ndim, plot_buf);
  291.  
  292.       if (error_state || status < 0)
  293.     return;
  294.     }
  295.  
  296.   plot_buf << "\n" << ends;
  297.  
  298. // Just testing...
  299. //  char *message = plot_buf.str ();
  300. //  cout << "[*]" << message << "[*]\n";
  301.  
  302.   if (parametric_plot && ndim == 2)
  303.     {
  304.       warning ("can't make 2D parametric plot -- setting noparametric...");
  305.       send_to_plot_stream ("set noparametric\n");
  306.       char *message = plot_buf.str ();
  307.       send_to_plot_stream (message);
  308.       delete [] message;
  309.       send_to_plot_stream ("set parametric\n");
  310.     }
  311.   else
  312.     {
  313.       char *message = plot_buf.str ();
  314.       send_to_plot_stream (message);
  315.       delete [] message;
  316.     }
  317. }
  318.  
  319. void
  320. tree_plot_command::print_code (ostream& os)
  321. {
  322.   print_code_indent (os);
  323.  
  324.   switch (ndim)
  325.     {
  326.     case 1:
  327.       os << "replot";
  328.       break;
  329.  
  330.     case 2:
  331.       os << "gplot";
  332.       break;
  333.  
  334.     case 3:
  335.       os << "gsplot";
  336.       break;
  337.  
  338.     default:
  339.       os << "<unkown plot command>";
  340.       break;
  341.     }
  342.  
  343.   if (range)
  344.     range->print_code (os);
  345.  
  346.   if (plot_list)
  347.     plot_list->print_code (os);
  348. }
  349.  
  350. plot_limits::plot_limits (void)
  351. {
  352.   x_range = 0;
  353.   y_range = 0;
  354.   z_range = 0;
  355. }
  356.  
  357. plot_limits::plot_limits (plot_range *xlim)
  358. {
  359.   x_range = xlim;
  360.   y_range = 0;
  361.   z_range = 0;
  362. }
  363.  
  364. plot_limits::plot_limits (plot_range *xlim,
  365.                     plot_range *ylim)
  366. {
  367.   x_range = xlim;
  368.   y_range = ylim;
  369.   z_range = 0;
  370. }
  371.  
  372. plot_limits::plot_limits (plot_range *xlim,
  373.                     plot_range *ylim,
  374.                     plot_range *zlim)
  375. {
  376.   x_range = xlim;
  377.   y_range = ylim;
  378.   z_range = zlim;
  379. }
  380.  
  381. plot_limits::~plot_limits (void)
  382. {
  383.   delete x_range;
  384.   delete y_range;
  385.   delete z_range;
  386. }
  387.  
  388. void
  389. plot_limits::print (int ndim, ostrstream& plot_buf)
  390. {
  391.   if (ndim  == 2 || ndim == 3)
  392.     {
  393.       if (x_range)
  394.     x_range->print (plot_buf);
  395.       else
  396.     return;
  397.  
  398.       if (y_range)
  399.     y_range->print (plot_buf);
  400.       else
  401.     return;
  402.     }
  403.  
  404.   if (ndim == 3 && z_range)
  405.     z_range->print (plot_buf);
  406. }
  407.  
  408. void
  409. plot_limits::print_code (ostream& os)
  410. {
  411.   if (x_range)
  412.     x_range->print_code (os);
  413.  
  414.   if (y_range)
  415.     y_range->print_code (os);
  416.  
  417.   if (z_range)
  418.     z_range->print_code (os);
  419. }
  420.  
  421. plot_range::plot_range (void)
  422. {
  423.   lower = 0;
  424.   upper = 0;
  425. }
  426.  
  427. plot_range::plot_range (tree_expression *l, tree_expression *u)
  428. {
  429.   lower = l;
  430.   upper = u;
  431. }
  432.  
  433. plot_range::~plot_range (void)
  434. {
  435.   delete lower;
  436.   delete upper;
  437. }
  438.  
  439. void
  440. plot_range::print (ostrstream& plot_buf)
  441. {
  442.   plot_buf << " [";
  443.  
  444.   if (lower)
  445.     {
  446.       tree_constant lower_val = lower->eval (0);
  447.       if (error_state)
  448.     {
  449.       ::error ("evaluating lower bound of plot range");
  450.       return;
  451.     }
  452.       else
  453.     {
  454.       double lo = lower_val.double_value ();
  455.       plot_buf << lo;
  456.     }
  457.     }
  458.  
  459.   plot_buf << ":";
  460.  
  461.   if (upper)
  462.     {
  463.       tree_constant upper_val = upper->eval (0);
  464.       if (error_state)
  465.     {
  466.       ::error ("evaluating upper bound of plot range");
  467.       return;
  468.     }
  469.       else
  470.     {
  471.       double hi = upper_val.double_value ();
  472.       plot_buf << hi;
  473.     }
  474.     }
  475.  
  476.   plot_buf << "]";
  477. }
  478.  
  479. void
  480. plot_range::print_code (ostream& os)
  481. {
  482.   os << " [";
  483.  
  484.   if (lower)
  485.     lower->print_code (os);
  486.  
  487.   os << ":";
  488.  
  489.   if (upper)
  490.     upper->print_code (os);
  491.  
  492.   os << "]";
  493. }
  494.  
  495. subplot_using::subplot_using (void)
  496. {
  497.   qualifier_count = 0;
  498.   x[0] = x[1] = x[2] = x[3] = 0;
  499.   scanf_fmt = 0;
  500.   have_values = 0;
  501. }
  502.  
  503. subplot_using::subplot_using (tree_expression *fmt) : val (4, -1)
  504. {
  505.   qualifier_count = 0;
  506.   x[0] = x[1] = x[2] = x[3] = 0;
  507.   scanf_fmt = fmt;
  508.   have_values = 0;
  509. }
  510.  
  511. subplot_using::~subplot_using (void)
  512. {
  513.   delete scanf_fmt;
  514. }
  515.  
  516. subplot_using *
  517. subplot_using::set_format (tree_expression *fmt)
  518. {
  519.   scanf_fmt = fmt;
  520.   return this;
  521. }
  522.  
  523. subplot_using *
  524. subplot_using::add_qualifier (tree_expression *t)
  525. {
  526.   if (qualifier_count < 4)
  527.     x[qualifier_count] = t;
  528.  
  529.   qualifier_count++;
  530.  
  531.   return this;
  532. }
  533.  
  534. int
  535. subplot_using::eval (int ndim, int n_max)
  536. {
  537.   if ((ndim == 2 && qualifier_count > 4)
  538.       || (ndim == 3 && qualifier_count > 3))
  539.     return -1;
  540.  
  541.   if (have_values)
  542.     return 1;
  543.  
  544.   if (qualifier_count > 0)
  545.     val.resize (qualifier_count);
  546.  
  547.   for (int i = 0; i < qualifier_count; i++)
  548.     {
  549.       if (x[i])
  550.     {
  551.       tree_constant tmp = x[i]->eval (0);
  552.       if (error_state)
  553.         {
  554.           ::error ("evaluating plot using command");
  555.           return -1;
  556.         }
  557.  
  558.       double val_tmp;
  559.       if (tmp.is_defined ())
  560.         {
  561.           val_tmp = tmp.double_value ();
  562.  
  563.           if (error_state)
  564.         return -1;
  565.  
  566.           if (xisnan (val_tmp))
  567.         {
  568.           ::error ("NaN is invalid as a column specifier");
  569.           return -1;
  570.         }
  571.  
  572.           int n = NINT (val_tmp);
  573.  
  574.           if (n < 1 || n_max > 0 && n > n_max)
  575.         {
  576.           ::error ("using: column %d out of range", n); 
  577.           return -1;
  578.         }
  579.           else
  580.         val.elem (i) = n;
  581.         }
  582.       else
  583.         return -1;
  584.     }
  585.       else
  586.     return -1;
  587.     }
  588.  
  589.   if (scanf_fmt)
  590.     warning ("ignoring scanf format in plot command");
  591.  
  592.   have_values = 1;
  593.  
  594.   return 0;
  595. }
  596.  
  597. ColumnVector
  598. subplot_using::values (int ndim, int n_max)
  599. {
  600.   int status = eval (ndim, n_max);
  601.  
  602.   if (status < 0 || ! have_values)
  603.     return -1;
  604.  
  605.   return val;
  606. }
  607.  
  608. int
  609. subplot_using::print (int ndim, int n_max, ostrstream& plot_buf)
  610. {
  611.   int status = eval (ndim, n_max);
  612.  
  613.   if (status < 0 || ! have_values)
  614.     return -1;
  615.  
  616.   for (int i = 0; i < qualifier_count; i++)
  617.     {
  618.       if (i == 0)
  619.     plot_buf << " " << GNUPLOT_COMMAND_USING << " ";
  620.       else
  621.     plot_buf << ":";
  622.  
  623.       plot_buf << val.elem (i);
  624.     }
  625.  
  626.   return 0;
  627. }
  628.  
  629. void
  630. subplot_using::print_code (ostream& os)
  631. {
  632.   os << " using ";
  633.   for (int i = 0; i < qualifier_count; i++)
  634.     {
  635.       if (i > 0)
  636.     os << ":";
  637.  
  638.       if (x[i])
  639.     x[i]->print_code (os);
  640.     }
  641. }
  642.  
  643. subplot_style::subplot_style (void)
  644. {
  645.   style = 0;
  646.   linetype = 0;
  647.   pointtype = 0;
  648. }
  649.  
  650. subplot_style::subplot_style (char *s)
  651. {
  652.   style = strsave (s);
  653.   linetype = 0;
  654.   pointtype = 0;
  655. }
  656.  
  657. subplot_style::subplot_style (char *s, tree_expression *lt)
  658. {
  659.   style = strsave (s);
  660.   linetype = lt;
  661.   pointtype = 0;
  662. }
  663.  
  664. subplot_style::subplot_style (char *s, tree_expression *lt,
  665.                     tree_expression *pt)
  666. {
  667.   style = strsave (s);
  668.   linetype = lt;
  669.   pointtype = pt;
  670. }
  671.  
  672. subplot_style::~subplot_style (void)
  673.   delete [] style;
  674.   delete linetype;
  675.   delete pointtype;
  676. }
  677.  
  678. int
  679. subplot_style::print (ostrstream& plot_buf)
  680. {
  681.   if (style)
  682.     {
  683.       plot_buf << " " << GNUPLOT_COMMAND_WITH << " " << style;
  684.  
  685.       if (linetype)
  686.     {
  687.       tree_constant tmp = linetype->eval (0);
  688.       if (! error_state && tmp.is_defined ())
  689.         {
  690.           double val = tmp.double_value ();
  691.           if (xisnan (val))
  692.         {
  693.           ::error ("NaN is invalid a plotting line style");
  694.           return -1;
  695.         }
  696.           else
  697.         plot_buf << " " << NINT (val);
  698.         }
  699.       else
  700.         {
  701.           ::error ("evaluating plot style command");
  702.           return -1;
  703.         }
  704.     }
  705.  
  706.       if (pointtype)
  707.     {
  708.       tree_constant tmp = pointtype->eval (0);
  709.       if (! error_state && tmp.is_defined ())
  710.         {
  711.           double val = tmp.double_value ();
  712.           if (xisnan (val))
  713.         {
  714.           ::error ("NaN is invalid a plotting point style");
  715.           return -1;
  716.         }
  717.           else
  718.         plot_buf << " " << NINT (val);
  719.         }
  720.       else
  721.         {
  722.           ::error ("evaluating plot style command");
  723.           return -1;
  724.         }
  725.     }
  726.     }
  727.   else
  728.     return -1;
  729.  
  730.   return 0;
  731. }
  732.  
  733. int
  734. subplot_style::errorbars (void)
  735. {
  736.   return (style
  737.       && (almost_match ("errorbars", style, 1, 0)
  738.           || almost_match ("boxerrorbars", style, 5, 0)));
  739. }
  740.  
  741. void
  742. subplot_style::print_code (ostream& os)
  743. {
  744.   os << " with " << style;
  745.  
  746.   if (linetype)
  747.     {
  748.       os << " ";
  749.       linetype->print_code (os);
  750.     }
  751.  
  752.   if (pointtype)
  753.     {
  754.       os << " ";
  755.       pointtype->print_code (os);
  756.     }
  757. }
  758.  
  759. subplot::subplot (void)
  760. {
  761.   plot_data = 0;
  762.   using_clause = 0;
  763.   title_clause = 0;
  764.   style_clause = 0;
  765. }
  766.  
  767. subplot::subplot (tree_expression *data)
  768. {
  769.   plot_data = data;
  770.   using_clause = 0;
  771.   title_clause = 0;
  772.   style_clause = 0;
  773. }
  774.  
  775. subplot::subplot (subplot_using *u, tree_expression *t, subplot_style *s)
  776. {
  777.   plot_data = 0;
  778.   using_clause = u;
  779.   title_clause = t;
  780.   style_clause = s;
  781. }
  782.  
  783. subplot::~subplot (void)
  784. {
  785.   delete plot_data;
  786.   delete using_clause;
  787.   delete title_clause;
  788.   delete style_clause;
  789. }
  790.  
  791. void
  792. subplot::set_data (tree_expression *data)
  793. {
  794.   plot_data = data;
  795. }
  796.  
  797. tree_constant
  798. subplot::extract_plot_data (int ndim, tree_constant& data)
  799. {
  800.   tree_constant retval;
  801.  
  802.   if (using_clause)
  803.     {
  804.       ColumnVector val = using_clause->values (ndim);
  805.  
  806.       Octave_object args;
  807.       args(1) = val;
  808.       args(0) = tree_constant::magic_colon_t;
  809.  
  810.       Octave_object tmp = data.eval (0, 1, args);
  811.       retval = tmp(0);
  812.  
  813.       if (error_state)
  814.     return tree_constant ();
  815.     }
  816.   else
  817.     {
  818.       retval = data;
  819.     }
  820.  
  821.   if (ndim == 2 && style_clause && style_clause->errorbars ())
  822.     {
  823.       int nc = retval.columns ();
  824.  
  825.       if (nc < 3 || nc > 4)
  826.     {
  827.       error ("plots with errorbars require 3 or 4 columns of data");
  828.       error ("but %d were provided", nc);
  829.       return tree_constant ();
  830.     }
  831.     }
  832.  
  833.   return retval;
  834. }
  835.  
  836. int
  837. subplot::handle_plot_data (int ndim, ostrstream& plot_buf)
  838. {
  839.   if (plot_data)
  840.     {
  841.       tree_constant data = plot_data->eval (0);
  842.  
  843.       if (! error_state && data.is_defined ())
  844.     {
  845.       char *file = 0;
  846.       if (data.is_string ())
  847.         {
  848. // Should really try to look at data file to determine n_max.  Can't
  849. // do much about other arbitrary gnuplot commands though...
  850.  
  851.           int n_max = 0;
  852.  
  853.           file = tilde_expand (data.string_value ());
  854.           ifstream ftmp (file);
  855.           if (ftmp)
  856.         {
  857.           plot_buf << " \"" << file << '"';
  858.           free (file);
  859.         }
  860.           else
  861.         {
  862.           free (file);
  863.           file = 0;
  864.  
  865. // Opening as a file failed.  Let's try passing it along as a plot
  866. // command.
  867.           plot_buf << " " << data.string_value ();
  868.         }
  869.  
  870.           if (using_clause)
  871.         {
  872.           int status = using_clause->print (ndim, n_max, plot_buf);
  873.           if (status < 0)
  874.             return -1;
  875.         }
  876.         }
  877.       else
  878.         {
  879. // Eliminate the need for printing a using clause to plot_buf.
  880.  
  881.           tree_constant tmp_data = extract_plot_data (ndim, data);
  882.  
  883.           if (tmp_data.is_defined ())
  884.         {
  885.           switch (ndim)
  886.             {
  887.             case 2:
  888.               file = save_in_tmp_file (tmp_data, ndim);
  889.               break;
  890.  
  891.             case 3:
  892.               file = save_in_tmp_file (tmp_data, ndim,
  893.                            parametric_plot);
  894.               break;
  895.  
  896.             default:
  897.               gripe_2_or_3_dim_plot ();
  898.               break;
  899.             }
  900.  
  901.           if (file)
  902.             {
  903.               mark_for_deletion (file);
  904.               plot_buf << " \"" << file << '"';
  905.             }
  906.         }
  907.         }
  908.     }
  909.       else
  910.     return -1;
  911.     }
  912.   else
  913.     return -1;
  914.  
  915.   return 0;
  916. }
  917.  
  918. int
  919. subplot::print (int ndim, ostrstream& plot_buf)
  920. {
  921.   int status = handle_plot_data (ndim, plot_buf);
  922.  
  923.   if (status < 0)
  924.     return -1;
  925.  
  926.   if (title_clause)
  927.     {
  928.       tree_constant tmp = title_clause->eval (0);
  929.       if (! error_state && tmp.is_string ())
  930.     plot_buf << " " << GNUPLOT_COMMAND_TITLE << " "
  931.       << '"' << tmp.string_value () << '"';
  932.       else
  933.     {
  934.       warning ("line title must be a string");
  935.       plot_buf << " " << GNUPLOT_COMMAND_TITLE << " "
  936.         << '"' << "line " << plot_line_count << '"';
  937.     }
  938.     }
  939.   else
  940.     plot_buf << " " << GNUPLOT_COMMAND_TITLE << " "
  941.       << '"' << "line " << plot_line_count << '"';
  942.  
  943.   if (style_clause)
  944.     {
  945.       int status = style_clause->print (plot_buf);
  946.       if (status < 0)
  947.     return -1;
  948.     }
  949.  
  950.   return 0;
  951. }
  952.  
  953. void
  954. subplot::print_code (ostream& os)
  955. {
  956.   if (plot_data)
  957.     {
  958.       os << " ";
  959.       plot_data->print_code (os);
  960.     }
  961.  
  962.   if (using_clause)
  963.     using_clause->print_code (os);
  964.  
  965.   if (title_clause)
  966.     title_clause->print_code (os);
  967.  
  968.   if (style_clause)
  969.     style_clause->print_code (os);
  970. }
  971.  
  972. int
  973. subplot_list::print (int ndim, ostrstream& plot_buf)
  974. {
  975.   int status = 0;
  976.  
  977.   for (Pix p = first (); p != 0; next (p))
  978.     {
  979.       subplot *elt = this->operator () (p);
  980.  
  981.       plot_line_count++;
  982.  
  983.       if (p != first ())
  984.     plot_buf << ",\\\n  ";
  985.  
  986.       status = elt->print (ndim, plot_buf);
  987.  
  988.       if (status < 0)
  989.     break;
  990.     }
  991.  
  992.   return status;
  993. }
  994.  
  995. void
  996. subplot_list::print_code (ostream& os)
  997. {
  998.   Pix p = first ();
  999.  
  1000.   while (p)
  1001.     {
  1002.       subplot *elt = this->operator () (p);
  1003.  
  1004.       next (p);
  1005.  
  1006.       if (elt)
  1007.     {
  1008.       elt->print_code (os);
  1009.  
  1010.       if (p)
  1011.         os << ",";
  1012.     }
  1013.     }
  1014. }
  1015.  
  1016. char *
  1017. save_in_tmp_file (tree_constant& t, int ndim, int parametric)
  1018. {
  1019.   char *name = octave_tmp_file_name ();
  1020.   if (name)
  1021.     {
  1022.       ofstream file (name);
  1023.       if (file)
  1024.     {
  1025.       switch (ndim)
  1026.         {
  1027.         case 2:
  1028.           save_ascii_data (file, t, 0, 1);
  1029.           break;
  1030.  
  1031.         case 3:
  1032.           save_three_d (file, t, parametric);
  1033.           break;
  1034.  
  1035.         default:
  1036.           gripe_2_or_3_dim_plot ();
  1037.           break;
  1038.         }
  1039.     }
  1040.       else
  1041.     {
  1042.       error ("couldn't open temporary output file `%s'", name);
  1043.       name = 0;
  1044.     }
  1045.     }
  1046.   return name;
  1047. }
  1048.  
  1049. void
  1050. mark_for_deletion (const char *filename)
  1051. {
  1052.   char *tmp = strsave (filename);
  1053.   tmp_files.push (tmp);
  1054. }
  1055.  
  1056. void
  1057. cleanup_tmp_files (void)
  1058. {
  1059.   while (! tmp_files.empty ())
  1060.     {
  1061.       char *filename = tmp_files.pop ();
  1062.       unlink (filename);
  1063.       delete [] filename;
  1064.     }
  1065. }
  1066.  
  1067. void
  1068. close_plot_stream (void)
  1069. {
  1070.   if (plot_stream.is_open ())
  1071.     plot_stream.close ();
  1072.  
  1073.   plot_line_count = 0;
  1074. }
  1075.  
  1076. DEFUN ("clearplot", Fclearplot, Sclearplot, 0, 0,
  1077.   "clearplot (): clear the plot window")
  1078. {
  1079.   Octave_object retval;
  1080.   send_to_plot_stream ("clear\n");
  1081.  
  1082. // XXX FIXME XXX -- instead of just clearing these things, it would be
  1083. // nice if we could reset things to a user-specified default state.
  1084.  
  1085.   send_to_plot_stream ("set title\n");
  1086.   send_to_plot_stream ("set xlabel\n");
  1087.   send_to_plot_stream ("set ylabel\n");
  1088.   send_to_plot_stream ("set nogrid\n");
  1089.   send_to_plot_stream ("set nolabel\n");
  1090.  
  1091. // This makes a simple `replot' not work after a `clearplot' command
  1092. // has been issued.
  1093.  
  1094.   plot_line_count = 0;
  1095.  
  1096.   return retval;
  1097. }
  1098.  
  1099. DEFALIAS (clg, clearplot);
  1100.  
  1101. DEFUN ("closeplot", Fcloseplot, Scloseplot, 0, 0,
  1102.   "closeplot (): close the stream to plotter")
  1103. {
  1104.   Octave_object retval;
  1105.   close_plot_stream ();
  1106.   return retval;
  1107. }
  1108.  
  1109. DEFUN_TEXT ("hold", Fhold, Shold, 1, 0,
  1110.   "hold [on|off]\n\
  1111. \n\
  1112. determine whether the plot window is cleared before the next line is\n\
  1113. drawn.  With no argument, toggle the current state.") 
  1114. {
  1115.   Octave_object retval;
  1116.  
  1117.   DEFINE_ARGV("hold");
  1118.  
  1119.   switch (argc)
  1120.     {
  1121.     case 1:
  1122.       clear_before_plotting = ! clear_before_plotting;
  1123.       break;
  1124.  
  1125.     case 2:
  1126.       if (strcasecmp (argv[1], "on") == 0)
  1127.     clear_before_plotting = 0;
  1128.       else if (strcasecmp (argv[1], "off") == 0)
  1129.     clear_before_plotting = 1;
  1130.       else
  1131.     print_usage ("hold");
  1132.       break;
  1133.  
  1134.     default:
  1135.       print_usage ("hold");
  1136.       break;
  1137.     }
  1138.  
  1139.   DELETE_ARGV;
  1140.  
  1141.   return retval;
  1142. }
  1143.  
  1144. DEFUN ("ishold", Fishold, Sishold, 0, 1,
  1145.   "ishold\n\
  1146. \n\
  1147. Return 1 if hold is on, otherwise return 0.")
  1148. {
  1149.   return (double) (! clear_before_plotting);
  1150. }
  1151.  
  1152. DEFUN ("purge_tmp_files", Fpurge_tmp_files, Spurge_tmp_files, 0, 0,
  1153.   "delete temporary data files used for plotting")
  1154. {
  1155.   Octave_object retval;
  1156.   cleanup_tmp_files ();
  1157.   return retval;
  1158. }
  1159.  
  1160. DEFUN_TEXT ("set", Fset, Sset, -1, 0,
  1161.   "set [options]\n\
  1162. \n\
  1163. set plotting options")
  1164. {
  1165.   Octave_object retval;
  1166.  
  1167.   DEFINE_ARGV("set");
  1168.  
  1169.   ostrstream plot_buf;
  1170.  
  1171.   if (argc > 1)
  1172.     {
  1173.       if (almost_match ("parametric", argv[1], 3))
  1174.     parametric_plot = 1;
  1175.       else if (almost_match ("noparametric", argv[1], 5))
  1176.     parametric_plot = 0;
  1177.       else if (almost_match ("term", argv[1], 1))
  1178.     {
  1179.       delete [] gnuplot_terminal_type;
  1180.       ostrstream buf;
  1181.       for (int i = 2; i < argc; i++)
  1182.         buf << argv[i] << " ";
  1183.       buf << "\n" << ends;
  1184.       gnuplot_terminal_type = buf.str ();
  1185.     }
  1186.     }
  1187.  
  1188.   for (int i = 0; i < argc; i++)
  1189.     plot_buf << argv[i] << " ";
  1190.  
  1191.   plot_buf << "\n" << ends;
  1192.  
  1193.   char *plot_command = plot_buf.str ();
  1194.   send_to_plot_stream (plot_command);
  1195.  
  1196.   delete [] plot_command;
  1197.  
  1198.   DELETE_ARGV;
  1199.  
  1200.   return retval;
  1201. }
  1202.  
  1203. DEFUN_TEXT ("show", Fshow, Sshow, -1, 0,
  1204.   "show [options]\n\
  1205. \n\
  1206. show plotting options")
  1207. {
  1208.   Octave_object retval;
  1209.  
  1210.   DEFINE_ARGV("show");
  1211.  
  1212.   ostrstream plot_buf;
  1213.  
  1214.   for (int i = 0; i < argc; i++)
  1215.     plot_buf << argv[i] << " ";
  1216.  
  1217.   plot_buf << "\n" << ends;
  1218.  
  1219.   char *plot_command = plot_buf.str ();
  1220.   send_to_plot_stream (plot_command);
  1221.  
  1222.   delete [] plot_command;
  1223.  
  1224.   DELETE_ARGV;
  1225.  
  1226.   return retval;
  1227. }
  1228.  
  1229. /*
  1230. ;;; Local Variables: ***
  1231. ;;; mode: C++ ***
  1232. ;;; page-delimiter: "^/\\*" ***
  1233. ;;; End: ***
  1234. */
  1235.