home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / RLaB 1.15c / rlib / plplot.r < prev    next >
Encoding:
Text File  |  1994-11-06  |  54.6 KB  |  2,483 lines  |  [TEXT/RLAB]

  1. #
  2. # New plot.r for use with PLPLOT library.
  3. # The help files for these functions are in
  4. # misc/plhelp
  5. #
  6.  
  7. # plplot.r
  8.  
  9. # This file is a part of RLaB ("Our"-LaB)
  10. # Copyright (C) 1994  Ian R. Searle
  11.  
  12. # This program is free software; you can redistribute it and/or modify
  13. # it under the terms of the GNU General Public License as published by
  14. # the Free Software Foundation; either version 2 of the License, or
  15. # (at your option) any later version.
  16.  
  17. # This program is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. # GNU General Public License for more details.
  21.  
  22. # You should have received a copy of the GNU General Public License
  23. # along with this program; if not, write to the Free Software
  24. # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26. # See the file ../COPYING
  27.  
  28. #
  29. # If your system does not deal with Infs and NaNs well, then
  30. # uncomment the following lines.
  31. #
  32.  
  33. # static (isinf, isnan)
  34. #
  35. # isinf = function ( A ) { return (0); };
  36. # isnan = function ( A ) { return (0); };
  37.  
  38. static (WIN)        # The static plot window structure
  39. static (P)        # The active/current plot window
  40.  
  41. #
  42. # Static (private) functions. For use from within
  43. # this file only.
  44. #
  45.  
  46. static (create_plot_object)
  47. static (check_plot_object)
  48. static (xy_scales)
  49. static (x_scales)
  50. static (y_scales)
  51. static (z_scales)
  52. static (XYZ_scales)
  53. static (list_scales)
  54. static (list_sort)
  55. static (hist_scales)
  56. static (plot_matrix)
  57. static (plot_list)
  58. static (check_3d_list)
  59. static (find_char)
  60. static (get_style)
  61. static (make_legend)
  62. static (plhold_first)
  63.  
  64. #
  65. # Defaults
  66. #
  67.  
  68. static (grid_x_default, grid_y_default)
  69. static (grid_3x_default, grid_3y_default, grid_3z_default)
  70.  
  71. grid_x_default = "bcnst";
  72. grid_y_default = "bcnstv";
  73. grid_3x_default = "bnstu";
  74. grid_3y_default = "bnstu";
  75. grid_3z_default = "bcdmnstuv";
  76.  
  77. static (subplot_f)
  78. subplot_f = 0;
  79.  
  80. #
  81. # Create the default plot-object.
  82. # Initialize to all the default values
  83. #
  84.  
  85. if (!exist (WIN)) 
  86. {
  87.   # Create the plot-object list
  88.   WIN = <<>>;
  89. }
  90.  
  91. create_plot_object = function ( N, nx, ny )
  92. {
  93.   if (!exist (N)) { N = 0; }
  94.   
  95.   pobj = <<>>;
  96.   pobj.subplot = 0;        # The current subplot no.
  97.   pobj.nplot = nx*ny;        # Total no. of plots on window
  98.   
  99.   pobj.fontld = 0;        # Loaded extended fonts?
  100.   
  101.   for (i in 1:(nx*ny))
  102.   {
  103.     pobj.style.[i] = "line";    # The type/style of plot to draw
  104.     pobj.pstyle[i] = 1;            # The point-style
  105.     pobj.nbin[i] = 1j;          # The number of bins for a histogram
  106.     pobj.width[i] = 1;        # The pen width for current plot
  107.     pobj.font[i] = 1;        # The current font
  108.     pobj.xlabel[i] = "";
  109.     pobj.ylabel[i] = "";
  110.     pobj.zlabel[i] = "";
  111.     pobj.title[i] = "";
  112.     pobj.orientation[i] = "portrait";
  113.     pobj.desc.[i] = "default";        # The legend description
  114.     pobj.gridx[i] =  grid_x_default;    # Plot axes style, 2D-X
  115.     pobj.gridy[i] =  grid_y_default;    # Plot axes style, 2D-Y
  116.     pobj.grid3x[i] = grid_3x_default;    # Plot axes style, 3D-X
  117.     pobj.grid3y[i] = grid_3y_default;    # Plot axes style, 3D-Y
  118.     pobj.grid3z[i] = grid_3z_default;    # Plot axes style, 3D-Z
  119.     pobj.aspect[i] = 0;                # Plot aspect style
  120.     pobj.alt[i] = 60;
  121.     pobj.az[i] = 45;
  122.     
  123.     pobj.xmin[i] = 1j;
  124.     pobj.xmax[i] = 1j;
  125.     pobj.ymin[i] = 1j;
  126.     pobj.ymax[i] = 1j;
  127.     pobj.zmin[i] = 1j;
  128.     pobj.zmax[i] = 1j;
  129.     
  130.     pobj.page.xp = 0;
  131.     pobj.page.yp = 0;
  132.     pobj.xleng = 400;
  133.     pobj.yleng = 300;
  134.     pobj.xoff = 200;
  135.     pobj.yoff = 200;
  136.  
  137.     for (j in 1:14) { pobj.color[i;j] = j; }       
  138.     for (j in 1:8)  { pobj.lstyle[i;j] = j; }
  139.   }
  140.   
  141.   #
  142.   # Save the newly generated plot-object
  143.   # in a list of plot-objects.
  144.   
  145.   WIN.[N] = pobj;
  146. };
  147.  
  148. ##############################################################################
  149. #
  150. # Check to make sure a plot-object exists. If one
  151. # does not exist, create it.
  152. #
  153.  
  154. check_plot_object = function ()
  155. {
  156.   if (length (WIN) == 0)
  157.   {
  158.     pstart();
  159.     return 0;
  160.   }
  161.   return 1;
  162. };
  163.  
  164. ##############################################################################
  165. #
  166. # Set the current plot window
  167. # Default value = 0
  168. #
  169.  
  170. pwin = function ( N )
  171. {
  172.   check_plot_object ();
  173.   if (!exist (N)) { N = 0; }
  174.   
  175.   # Check to make sure N is valid
  176.   
  177.   for (i in members (WIN))
  178.   {
  179.     if (N == strtod (i))
  180.     {
  181.       _plsstrm (N);
  182.       return P = N;
  183.     }
  184.   }
  185.   printf ("pwin: invalid argument, N = %i\n", N);
  186.   printf ("      valid values are:\n");
  187.   WIN?
  188. };
  189.  
  190. ##############################################################################
  191. #
  192. # Show the current plot-window, and the possibilities
  193. #
  194.  
  195. showpwin = function ( all )
  196. {
  197.   if (length (WIN) == 0)
  198.   {
  199.     printf ("No plot objects\n");
  200.     return 0;
  201.   }
  202.   
  203.   printf ("Current plot-window is:\t\t%i\n", P);
  204.   printf ("Available plot windows are:\t");
  205.   for (i in members (WIN))
  206.   {
  207.     printf ("%s   ", i);
  208.   }
  209.   printf ("\n");
  210.  
  211.   if (exist (all))
  212.   {
  213.     for (i in members (WIN.[P]))
  214.     {
  215.       WIN.[P].[i]
  216.     }
  217.   }
  218. };
  219.  
  220. ##############################################################################
  221. #
  222. # Set/start/select the plot device
  223. #
  224.  
  225. pstart = function ( nx, ny, dev )
  226. {
  227.   if (!exist (nx)) { nx = 1; }
  228.   if (!exist (ny)) { ny = 1; }
  229.   if (!exist (dev)) { dev = "?"; }
  230.   
  231.   # Create the plot-object
  232.   # First, figure out the index
  233.   if (!exist (P))
  234.   {
  235.     P = 0;
  236.   else
  237.     P = P + 1;
  238.   }
  239.   
  240.   create_plot_object (P, nx, ny);
  241.   _plsstrm (P);
  242.   
  243.   #_plscolbg (255,255,255); # white
  244.   # Default window size for X
  245.   _plspage (0, 0, 400, 300, 200, 200);
  246.   
  247.   # Start up the plot-window
  248.   _plstart (dev, nx, ny);
  249.   
  250.   _plwid (8);
  251.   
  252.   # Turn between plot pause off
  253.   _plspause (0);
  254.   _pltext ();
  255.   
  256.   return P;
  257. };
  258.  
  259. ##############################################################################
  260. #
  261. # Close a plot device. We must destroy the current plot-object
  262. # And switch the output stream back to the default.
  263. #
  264.  
  265. pclose = function ()
  266. {
  267.   if (size (WIN) > 1)
  268.   {   
  269.     #
  270.     # Clear WIN.[P] and reset P to 1st plot-window
  271.     #
  272.  
  273.     clear (WIN.[P]);
  274.     _plend1 ();
  275.     _plsstrm (strtod (members (WIN)[1]));
  276.     P = strtod (members (WIN)[1]);
  277.   else
  278.     if (exist (WIN.[P])) 
  279.     { 
  280.       clear (WIN.[P]); 
  281.       clear (P);
  282.     }
  283.     _plend1 ();
  284.   }
  285. };
  286.  
  287. ##############################################################################
  288. #
  289. # Close ALL the plot-windows
  290. #
  291.  
  292. pend = function ()
  293. {
  294.   _plend ();
  295.   if (exist (WIN)) { clear (WIN); }
  296.   if (exist (P)) { clear (P); }
  297.   WIN = <<>>;
  298. };
  299.  
  300. ##############################################################################
  301. #
  302. # Change plot aspect ratio
  303. #
  304.  
  305. plaspect = function ( aspect )
  306. {
  307.   check_plot_object ();
  308.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  309.   if (!exist (aspect))
  310.   {
  311.     WIN.[P].aspect[i] = 0;
  312.   else
  313.     WIN.[P].aspect[i] = aspect;
  314.   }
  315. };
  316.  
  317. ##############################################################################
  318. #
  319. # Change plot line style
  320. #
  321.  
  322. plstyle = function ( style )
  323. {
  324.   check_plot_object ();
  325.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  326.  
  327.   if (exist (style)) 
  328.   {
  329.     if (class (style) == "string") 
  330.     {
  331.       WIN.[P].style.[i] = style;
  332.     }
  333.     return 1;
  334.   }
  335.   WIN.[P].style.[i] = "line";  
  336. };
  337.  
  338. ##############################################################################
  339. #
  340. # Get the right value of line-style
  341. #
  342.  
  343. get_style = function ( STY, K )
  344. {
  345.   local (sty);
  346.   sty = mod(K, STY.n);
  347.   if(sty == 0) 
  348.   { 
  349.     sty = STY.n; 
  350.   }
  351.   return STY[sty];
  352. };
  353.  
  354. ##############################################################################
  355. #
  356. # Change fonts
  357. #
  358.  
  359. plfont = function ( font )
  360. {
  361.   check_plot_object ();
  362.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  363.   
  364.   if (!exist (font)) { font = 1; }
  365.   
  366.   if (WIN.[P].fontld == 0)
  367.   {
  368.     _plfontld (1);
  369.     WIN.[P].fontld = 1;
  370.   }
  371.   
  372.   WIN.[P].font[i] = font;
  373.   return P;
  374. };
  375.  
  376. ##############################################################################
  377. #
  378. # Change pen width
  379. #
  380.  
  381. plwid = function ( width )
  382. {
  383.   check_plot_object ();
  384.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  385.   
  386.   if (!exist (width)) { width = 1; }
  387.   WIN.[P].width[i] = width;
  388.   return P;
  389. };
  390.  
  391. ##############################################################################
  392. #
  393. # Place some text on the plot
  394. #
  395.  
  396. plptex = function ( text, x , y , dx , dy , just )
  397. {
  398.   if (!check_plot_object ()) 
  399.   {
  400.     printf ("Must use plot() before plptex()\n");
  401.     return 0;
  402.   }
  403.   
  404.   if (!exist (x)) { x = 0; }
  405.   if (!exist (y)) { y = 0; }
  406.   if (!exist (dx)) { dx = abs(x)+1; }
  407.   if (!exist (dy)) { dy = 0; }
  408.   if (!exist (just)) { just = 0; }
  409.   
  410.   _plptex (x, y, dx, dy, just, text);
  411. };
  412.  
  413. ##############################################################################
  414. #
  415. # Set up the viewing altitude for 3-D plots
  416. #
  417.  
  418. plalt = function ( ALT )
  419. {
  420.   check_plot_object ();
  421.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  422.  
  423.   if (exist (ALT)) 
  424.   { 
  425.     WIN.[P].alt[i] = ALT; 
  426.   else
  427.     WIN.[P].alt[i] = 60;
  428.   }
  429.   return P;
  430. };
  431.  
  432. ##############################################################################
  433. #
  434. # Set the viewing azimuth for 3-D plots
  435. #
  436.  
  437. plaz = function ( AZ )
  438. {
  439.   check_plot_object ();
  440.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  441.  
  442.   if (exist (AZ)) 
  443.   { 
  444.     WIN.[P].az[i] = AZ; 
  445.   else
  446.     WIN.[P].az[i] = 45;
  447.   }
  448.   return P;
  449. };
  450.  
  451. ##############################################################################
  452. #
  453. # Find a character in a string
  454. #
  455.  
  456. find_char = function ( str , char )
  457. {  
  458.   tmp = strsplt (str);
  459.   for (i in 1:tmp.n)
  460.   {
  461.     if (tmp[i] == char) 
  462.     {
  463.       return i;
  464.     }
  465.   }
  466.   return 0;
  467. };
  468.  
  469. ##############################################################################
  470. #
  471. # Sort list element names/labels by numeric order, then string order.
  472. #
  473.  
  474. list_sort = function ( L )
  475. {
  476.   tl = <<>>;
  477.   j = k = 1;
  478.  
  479.   for (i in members (L))
  480.   {
  481.     if (!isnan (strtod (i)))
  482.     {
  483.       num[j] = i;
  484.       j++;
  485.       else
  486.       char[k] = i;
  487.       k++;
  488.     }
  489.   }
  490.   
  491.   # Sort the numeric labels
  492.   
  493.   if (exist (num))
  494.   {
  495.     num = sort (strtod (num)).val;
  496.     tl.num = num;
  497.   }
  498.  
  499.   if (exist (char))
  500.   {
  501.     tl.char = char;
  502.   }
  503.  
  504.   return tl;
  505. };
  506.  
  507. ##############################################################################
  508. #
  509. # Set the subplot, this overides the action in plot().
  510. #
  511.  
  512. subplot = function ( sub )
  513. {
  514.   check_plot_object ();
  515.   
  516.   if (!exist (sub)) 
  517.   { 
  518.     sub = 0;
  519.     #WIN.[P].subplot = WIN.[P].subplot + 1;
  520.     subplot_f = 0;
  521.     _pladv (0);
  522.   else
  523.     if (sub > WIN.[P].nplot) 
  524.     { 
  525.       error ("Current window does not have this many subplots");
  526.     }
  527.     WIN.[P].subplot = sub - 1;
  528.     subplot_f = 1;
  529.     _pladv (sub);
  530.   }
  531. };
  532.  
  533. ##############################################################################
  534. #
  535. # Plot the columns of a matrix (X-Y plot).
  536. #
  537. ##############################################################################
  538.  
  539. plot = function ( data, key )
  540. {
  541.   check_plot_object ();
  542.   
  543.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  544.   if (!exist (key)) { key = 1; }
  545.  
  546.   #
  547.   # Draw the graph
  548.   # Step through the matrix plotting
  549.   # each column versus the 1st
  550.   #
  551.   
  552.   if (class (data) == "num")
  553.   {
  554.     #
  555.     # Set up the plot basics
  556.     #
  557.  
  558.     if (abs (key) > data.nc)
  559.     {
  560.       error_1 ("plot: KEY argument > M.nc");
  561.     }
  562.     
  563.     _plgra ();
  564.     _plcol (1);
  565.     _pllsty (1);
  566.     _plfont (WIN.[P].font[p]);
  567.     _plwid (WIN.[P].width[p]);
  568.  
  569.     if (!subplot_f) 
  570.     {
  571.       _pladv (0);        # Advance 1 subplot
  572.     else
  573.       subplot_f = 0;     # The user has set the subplot
  574.     }
  575.  
  576.     if (WIN.[P].aspect[p] != 0)
  577.     {
  578.       _plvasp (WIN.[P].aspect[p]);
  579.     else
  580.       _plvsta ();
  581.     }
  582.     
  583.     #
  584.     # Compute scale limits
  585.     #
  586.  
  587.     k = find ((1:data.nc) != abs (key));
  588.     if (key > 0)
  589.     {
  590.       if (data.nc != 1)
  591.       {
  592.     x_scales ( real(data)[;key], p, xmin, xmax );
  593.     y_scales ( real(data)[;k],   p, ymin, ymax );
  594.       else
  595.     x_scales ( (1:data.nr)', p, xmin, xmax );
  596.     y_scales ( real(data),   p, ymin, ymax );
  597.       }
  598.     else if (key < 0) {
  599.       x_scales ( real(data)[;k],   p, xmin, xmax );
  600.       y_scales ( real(data)[;abs(key)], p, ymin, ymax );
  601.     else
  602.       x_scales ( (1:data.nr)', p, xmin, xmax );
  603.       y_scales ( real(data),   p, ymin, ymax );
  604.     } }
  605.  
  606.     _plwind (xmin, xmax, ymin, ymax);
  607.     _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  608.     if (plot_matrix ( data, key, p, 0, xmin, xmax, ymin, ymax, ymax-ymin ) < 0) 
  609.     {
  610.       return -1;
  611.     }
  612.     
  613.     else if (class (data) == "list") {
  614.       
  615.       _plgra ();
  616.       _plcol (1);
  617.       _pllsty (1);
  618.       _plfont (WIN.[P].font[p]);
  619.       _plwid (WIN.[P].width[p]);
  620.  
  621.       list_scales ( data, key, p, xmin, xmax, ymin, ymax );
  622.  
  623.       if (!subplot_f) 
  624.       {
  625.     _pladv (0);        # Advance 1 subplot
  626.       else
  627.     subplot_f = 0;     # The user has set the subplot
  628.       }
  629.  
  630.       if (WIN.[P].aspect[p] != 0)
  631.       {
  632.     _plvasp (WIN.[P].aspect[p]);
  633.       else
  634.        _plvsta ();
  635.       }
  636.       
  637.       _plwind (xmin, xmax, ymin, ymax);
  638.       _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  639.       if (plot_list ( data, key, p, xmin, xmax, ymin, ymax ) < 0) 
  640.       { 
  641.     return -1;
  642.       }
  643.  
  644.     else
  645.       error ("plot: un-acceptable argument");
  646.   } }
  647.  
  648.   _pllsty (1);
  649.   _plcol (1);
  650.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  651.   _plflush ();
  652.   _pltext ();
  653.   
  654.   #
  655.   # Increment the plot no. so that next time
  656.   # we use the correct settings.
  657.   #
  658.   
  659.   WIN.[P].subplot = WIN.[P].subplot + 1;
  660.   return P;
  661. };
  662.  
  663. #
  664. # plhold:
  665. # Plot some data, and "hold" on for more.
  666. # Plot the data, setting up the plot as usual the first time.
  667. # On subsequent plots do not do any setup, just plot some
  668. # more. plhold_off must be called to finish up.
  669. #
  670.  
  671. plhold_first = 1;    # True (1) if plhold() has NOT been used.
  672.                         # Or if plhold_off() has been used.
  673.             # False (0) if plhold is in use
  674.  
  675. static (hxmin, hxmax, hymin, hymax)
  676.  
  677. plhold = function ( data, key )
  678. {
  679.   check_plot_object ();
  680.   
  681.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  682.   if (!exist (key)) { key = 1; }
  683.   if (abs (key) > data.nc)
  684.   {
  685.     error_1 ("plot: KEY argument > M.nc");
  686.   }
  687.   
  688.   if (plhold_first)
  689.   {
  690.     if (class (data) == "num")
  691.     {
  692.       #
  693.       # Do the setup ONCE
  694.       #
  695.       hxmin = hxmax = hymin = hymax = 0;
  696.       _plgra ();
  697.       _plcol (1);
  698.       _pllsty (1);
  699.       _plfont (WIN.[P].font[p]);
  700.       _plwid (WIN.[P].width[p]);
  701.  
  702.       if (!subplot_f) 
  703.       {
  704.     _pladv (0);        # Advance 1 subplot
  705.       else
  706.     subplot_f = 0;     # The user has set the subplot
  707.       }
  708.  
  709.       if (WIN.[P].aspect[p] != 0)
  710.       {
  711.     _plvasp (WIN.[P].aspect[p]);
  712.       else
  713.     _plvsta ();
  714.       }
  715.  
  716.       xy_scales ( real(data), p, hxmin, hxmax, hymin, hymax );
  717.       
  718.       k = find ((1:data.nc) != abs (key));
  719.       if (key > 0)
  720.       {
  721.     x_scales ( real(data)[;key], p, xmin, xmax );
  722.     if (data.nc != 1)
  723.     {
  724.       y_scales ( real(data)[;k],   p, ymin, ymax );
  725.         else
  726.       y_scales ( (1:data.nr)',   p, ymin, ymax );
  727.     }
  728.       else if (key < 0) {
  729.     x_scales ( real(data)[;k],   p, xmin, xmax );
  730.     y_scales ( real(data)[;abs(key)], p, ymin, ymax );
  731.       else
  732.     x_scales ( (1:data.nr)', p, xmin, xmax );
  733.     y_scales ( real(data),   p, ymin, ymax );
  734.       } }
  735.  
  736.       _plwind (hxmin, hxmax, hymin, hymax);
  737.       _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  738.       _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);
  739.     else
  740.       error ("plot: un-acceptable argument");
  741.     }
  742.     plhold_first = 0;
  743.   }
  744.   
  745.   if (plot_matrix ( data, key, p, 0, hxmin, hxmax, hymin, hymax, hymax-hymin ) < 0) 
  746.   { 
  747.     return -1; 
  748.   }
  749.  
  750.   _plcol (1);
  751.   _plflush ();
  752.   _pltext ();
  753.  
  754.   return P;
  755. };
  756.  
  757. ##############################################################################
  758. #
  759. # Clean up the plotting environment and get ready
  760. # for normal interactive usage.
  761. #
  762.  
  763. plhold_off = function ( )
  764. {
  765.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  766.   plhold_first = 1;  
  767.   _plcol (1);
  768.   _plflush ();
  769.   _pltext ();
  770.   WIN.[P].subplot = WIN.[P].subplot + 1;
  771.   return P;
  772. };
  773.  
  774. ##############################################################################
  775. #
  776. # Plot a 3-Dimensional graph. The data is composed in a list, with
  777. # elements `x', `y', and `z'. x and y are single-dimension arrays
  778. # (row or column matrices), and z is a two-dimensional array. The
  779. # array z, is a function of x and y: z = f(x,y). Thus, the values in
  780. # the array x can be thought of a "row-labels", and the values of y
  781. # can be thought of as "column-lables" for the 2-dimensioal array z.
  782. #
  783. # At present plot3 can plot 3 distinct lists. Each list may have
  784. # different X, Y, and Z scales.
  785. #
  786. ##############################################################################
  787.  
  788. plot3 = function ( L31, L32, L33 )
  789. {
  790.   check_plot_object ();
  791.  
  792.   #
  793.   # 1st check list contents
  794.   #
  795.   
  796.   if (exist (L31)) { check_3d_list (L31); }
  797.   if (exist (L32)) { check_3d_list (L32); }
  798.   if (exist (L33)) { check_3d_list (L33); }
  799.   
  800.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  801.  
  802.   #
  803.   # Figure out the scale limits. 
  804.   # Needs improvement!
  805.   #
  806.   
  807.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  808.   if (exist (L31)) 
  809.   {
  810.     XYZ_scales (L31.x, L31.y, L31.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  811.     xmin = Xmin; xmax = Xmax;
  812.     ymin = Ymin; ymax = Ymax;
  813.     zmin = Zmin; zmax = Zmax;
  814.   }
  815.   if (exist (L32)) 
  816.   {
  817.     XYZ_scales (L32.x, L32.y, L32.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  818.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  819.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  820.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  821.   }   
  822.   if (exist (L33)) 
  823.   {
  824.     XYZ_scales (L33.x, L33.y, L33.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  825.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  826.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  827.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  828.   }
  829.   
  830.   _plgra ();
  831.   _plcol (1);
  832.   _pllsty (1);
  833.   _plfont (WIN.[P].font[p]);
  834.   _plwid (WIN.[P].width[p]);
  835.   
  836.   basex = 2; basey = 2; height = 4;
  837.   xmin2d = -2.0; xmax2d = 2.0;
  838.   ymin2d = -3.0; ymax2d = 5.0;
  839.   
  840.   _plenv (xmin2d, xmax2d, ymin2d, ymax2d, 0, -2);
  841.   _plw3d (basex, basey, height, xmin, xmax, ymin, ymax, ...
  842.           zmin, zmax, WIN.[P].alt[p], WIN.[P].az[p]);
  843.   _plbox3 (WIN.[P].grid3x[p], WIN.[P].xlabel[p], 0, 0, ...
  844.            WIN.[P].grid3y[p], WIN.[P].ylabel[p], 0, 0, ...
  845.            WIN.[P].grid3z[p], WIN.[P].zlabel[p], 0, 0);
  846.   _plmtex ("t", 1.0, 0.5, 0.5, WIN.[P].title[p]);
  847.  
  848.   if (exist (L31))
  849.   {
  850.     if (find_char (WIN.[P].grid3x[p], "l"))
  851.     { x = log10 (real (L31.x)); else x = real (L31.x); }
  852.     if (find_char (WIN.[P].grid3y[p], "l"))
  853.     { y = log10 (real (L31.y)); else y = real (L31.y); }
  854.     if (find_char (WIN.[P].grid3z[p], "l"))
  855.     { z = log10 (real (L31.z)); else z = real (L31.z); }
  856.     
  857.     _plcol (2);
  858.     _plot3d (x, y, z, L31.x.n, L31.y.n, 3, 0);
  859.   }
  860.   if (exist (L32))
  861.   {
  862.     if (find_char (WIN.[P].grid3x[p], "l"))
  863.     { x = log10 (real (L32.x)); else x = real (L32.x); }
  864.     if (find_char (WIN.[P].grid3y[p], "l"))
  865.     { y = log10 (real (L32.y)); else y = real (L32.y); }
  866.     if (find_char (WIN.[P].grid3z[p], "l"))
  867.     { z = log10 (real (L32.z)); else z = real (L32.z); }
  868.     
  869.     _plcol (3);
  870.     _pllsty (2);
  871.     _plot3d (x, y, z, L32.x.n, L32.y.n, 3, 0);
  872.   }
  873.   if (exist (L33)) 
  874.   {
  875.     if (find_char (WIN.[P].grid3x[p], "l"))
  876.     { x = log10 (real (L33.x)); else x = real (L33.x); }
  877.     if (find_char (WIN.[P].grid3y[p], "l"))
  878.     { y = log10 (real (L33.y)); else y = real (L33.y); }
  879.     if (find_char (WIN.[P].grid3z[p], "l"))
  880.     { z = log10 (real (L33.z)); else z = real (L33.z); }
  881.     
  882.     _plcol (4);
  883.     _pllsty (3);
  884.     _plot3d (x, y, z, L33.x.n, L33.y.n, 3, 0);
  885.   }
  886.   
  887.   _plflush ();
  888.   _pltext ();
  889.   
  890.   #
  891.   # Increment the plot no. so that next time
  892.   # we use the correct settings.
  893.   #
  894.   
  895.   WIN.[P].subplot = WIN.[P].subplot + 1;
  896.   
  897.   return P;
  898. };
  899.  
  900. ##############################################################################
  901. #
  902. # Plot a 3-Dimensional graph. The data is composed in a list, with
  903. # elements `x', `y', and `z'. x and y are single-dimension arrays
  904. # (row or column matrices), and z is a two-dimensional array. The
  905. # array z, is a function of x and y: z = f(x,y). Thus, the values in
  906. # the array x can be thought of a "row-labels", and the values of y
  907. # can be thought of as "column-lables" for the 2-dimensioal array z.
  908. #
  909. # At present plmesh can plot 3 distinct lists. Each list may have
  910. # different X, Y, and Z scales.
  911. #
  912. ##############################################################################
  913.  
  914. plmesh = function ( L31, L32, L33 )
  915. {
  916.   check_plot_object ();
  917.   
  918.   #
  919.   # 1st check list contents
  920.   #
  921.   
  922.   if (exist (L31)) { check_3d_list (L31); }
  923.   if (exist (L32)) { check_3d_list (L32); }
  924.   if (exist (L33)) { check_3d_list (L33); }
  925.   
  926.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  927.  
  928.   #
  929.   # Figure out the scale limits. 
  930.   # Needs improvement!
  931.   #
  932.   
  933.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  934.   if (exist (L31)) 
  935.   {
  936.     XYZ_scales (L31.x, L31.y, L31.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  937.     xmin = Xmin; xmax = Xmax;
  938.     ymin = Ymin; ymax = Ymax;
  939.     zmin = Zmin; zmax = Zmax;
  940.   }
  941.   if (exist (L32)) 
  942.   {
  943.     XYZ_scales (L32.x, L32.y, L32.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  944.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  945.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  946.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  947.   }   
  948.   if (exist (L33)) 
  949.   {
  950.     XYZ_scales (L33.x, L33.y, L33.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  951.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  952.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  953.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  954.   }
  955.  
  956.   _plgra ();
  957.   _plcol (1);
  958.   _pllsty (1);
  959.   _plfont (WIN.[P].font[p]);
  960.   _plwid (WIN.[P].width[p]);
  961.   
  962.   basex = 2; basey = 2; height = 4;
  963.   xmin2d = -2.0; xmax2d = 2.0;
  964.   ymin2d = -3.0; ymax2d = 5.0;
  965.   
  966.   _plenv (xmin2d, xmax2d, ymin2d, ymax2d, 0, -2);
  967.   _plw3d (basex, basey, height, xmin, xmax, ymin, ymax, ...
  968.           zmin, zmax, WIN.[P].alt[p], WIN.[P].az[p]);
  969.   _plbox3 (WIN.[P].grid3x[p], WIN.[P].xlabel[p], 0, 0, ...
  970.            WIN.[P].grid3y[p], WIN.[P].ylabel[p], 0, 0, ...
  971.            WIN.[P].grid3z[p], WIN.[P].zlabel[p], 0, 0);
  972.   _plmtex ("t", 1.0, 0.5, 0.5, WIN.[P].title[p]);
  973.  
  974.   if (exist (L31))
  975.   {
  976.     if (find_char (WIN.[P].grid3x[p], "l"))
  977.     { x = log10 (real (L31.x)); else x = real (L31.x); }
  978.     if (find_char (WIN.[P].grid3y[p], "l"))
  979.     { y = log10 (real (L31.y)); else y = real (L31.y); }
  980.     if (find_char (WIN.[P].grid3z[p], "l"))
  981.     { z = log10 (real (L31.z)); else z = real (L31.z); }
  982.     
  983.     _plcol (2);
  984.     _plmesh (x, y, z, L31.x.n, L31.y.n, 3);
  985.   }
  986.   if (exist (L32))
  987.   {
  988.     if (find_char (WIN.[P].grid3x[p], "l"))
  989.     { x = log10 (real (L32.x)); else x = real (L32.x); }
  990.     if (find_char (WIN.[P].grid3y[p], "l"))
  991.     { y = log10 (real (L32.y)); else y = real (L32.y); }
  992.     if (find_char (WIN.[P].grid3z[p], "l"))
  993.     { z = log10 (real (L32.z)); else z = real (L32.z); }
  994.     
  995.     _plcol (3);
  996.     _pllsty (2);
  997.     _plmesh (x, y, z, L32.x.n, L32.y.n, 3);
  998.   }
  999.   if (exist (L33)) 
  1000.   {
  1001.     if (find_char (WIN.[P].grid3x[p], "l"))
  1002.     { x = log10 (real (L33.x)); else x = real (L33.x); }
  1003.     if (find_char (WIN.[P].grid3y[p], "l"))
  1004.     { y = log10 (real (L33.y)); else y = real (L33.y); }
  1005.     if (find_char (WIN.[P].grid3z[p], "l"))
  1006.     { z = log10 (real (L33.z)); else z = real (L33.z); }
  1007.     
  1008.     _plcol (4);
  1009.     _pllsty (3);
  1010.     _plmesh (x, y, z, L33.x.n, L33.y.n, 3);
  1011.   }
  1012.  
  1013.   _plflush ();
  1014.   _pltext ();
  1015.   
  1016.   #
  1017.   # Increment the plot no. so that next time
  1018.   # we use the correct settings.
  1019.   #
  1020.   
  1021.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1022.   
  1023.   return P;
  1024. };
  1025.  
  1026. ##############################################################################
  1027. #
  1028. # Plot contours. The data is composed in a list, with
  1029. # elements `x', `y', and `z'. x and y are single-dimension arrays
  1030. # (row or column matrices), and z is a two-dimensional array. The
  1031. # array z, is a function of x and y: z = f(x,y). Thus, the values in
  1032. # the array x can be thought of a "row-labels", and the values of y
  1033. # can be thought of as "column-lables" for the 2-dimensioal array z.
  1034. #
  1035. ##############################################################################
  1036.  
  1037. plcont = function ( CL )
  1038. {
  1039.   check_plot_object ();
  1040.   
  1041.   #
  1042.   # 1st check list contents
  1043.   #
  1044.   
  1045.   if (exist (CL)) { check_3d_list (CL); }
  1046.  
  1047.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1048.   
  1049.   #
  1050.   # Figure out the scale limits. 
  1051.   # Needs improvement!
  1052.   #
  1053.  
  1054.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  1055.   if (exist (CL)) 
  1056.   {
  1057.     XYZ_scales (CL.x, CL.y, CL.z, p, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax);
  1058.     if (Xmin < xmin) { xmin = Xmin; } if (Xmax > xmax) { xmax = Xmax; }
  1059.     if (Ymin < ymin) { ymin = Ymin; } if (Ymax > ymax) { ymax = Ymax; }
  1060.     if (Zmin < zmin) { zmin = Zmin; } if (Zmax > zmax) { zmax = Zmax; }
  1061.   }
  1062.  
  1063.   _plgra ();
  1064.   _plcol (1);
  1065.   _pllsty (1);
  1066.   _plfont (WIN.[P].font[p]);
  1067.   _plwid (WIN.[P].width[p]);
  1068.  
  1069.   #
  1070.   # Set up the 1st viewport for drawing the plot.
  1071.   #
  1072.  
  1073.   if (!subplot_f) 
  1074.   {
  1075.     _pladv (0);        # Advance 1 subplot
  1076.   else
  1077.     subplot_f = 0;     # The user has set the subplot
  1078.   }
  1079.  
  1080.   _plvpas (0.15, 0.75, 0.15, 0.85, WIN.[P].aspect[p]);
  1081.   # _plvpor (0.15, 0.75, 0.15, 0.85);
  1082.   _plwind (xmin, xmax, ymin, ymax);
  1083.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  1084.  
  1085.   # Convert the data to log data if necessary.
  1086.   if (find_char (WIN.[P].gridx[p], "l"))
  1087.   { x = log10 (real (CL.x)); else x = real (CL.x); }
  1088.   if (find_char (WIN.[P].gridy[p], "l"))
  1089.   { y = log10 (real (CL.y)); else y = real (CL.y); }
  1090.   z = real (CL.z);
  1091.   
  1092.   if (exist (CL.clevel))
  1093.   {
  1094.     clevel = CL.clevel;
  1095.   else
  1096.     clevel = linspace(zmin, zmax, 10);
  1097.   }
  1098.  
  1099.   #
  1100.   # Draw the contours
  1101.   #
  1102.  
  1103.   l = 1;
  1104.   for (i in 1:clevel.n)
  1105.   {
  1106.     k = mod (i-1, 14) + 1;
  1107.     j = mod (i-1, 8) + 1;
  1108.     _pllsty(j);
  1109.     _plcol (1+k);
  1110.     if (_plcont (x, y, z, 1, CL.x.n, 1, CL.y.n, clevel[i]))
  1111.     {
  1112.       llevel[l] = clevel[i];
  1113.       l = l + 1;
  1114.     }
  1115.   }
  1116.  
  1117.   #
  1118.   # Reset color and draw the labels.
  1119.   #
  1120.  
  1121.   _plcol (1);
  1122.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  1123.  
  1124.   #
  1125.   # Draw the contour legend. Use a new viewport to the right
  1126.   # of the contour plot.
  1127.   #
  1128.  
  1129.   #_plvpas (0.75, 1.0, 0.15, 0.85, WIN.[P].aspect[p]);
  1130.   _plvpor (0.75, 1.0, 0.15, 0.85);
  1131.   _plwind (0, 1, 0, 1);
  1132.  
  1133.   v = 1 - 1/(2*llevel.n);
  1134.  
  1135.   for (i in 1:llevel.n)
  1136.   {
  1137.     xl = [0.1, 0.2, 0.3]';
  1138.     yl = [v, v, v]';
  1139.     v = v - 1/llevel.n;
  1140.  
  1141.     k = mod (i-1, 14) + 1;
  1142.     j = mod (i-1, 8) + 1;
  1143.  
  1144.     _plcol (1+k);
  1145.     _pllsty (j);
  1146.  
  1147.     _plline (3, xl, yl);
  1148.     sprintf (stmp, "%.2g", llevel[i]);
  1149.     plptex (stmp, xl[3]+.1, yl[3], , , 0);
  1150.   }
  1151.  
  1152.   # Flush  and go back to text mode.
  1153.   _plflush ();
  1154.   _pltext ();
  1155.   
  1156.   #
  1157.   # Increment the plot no. so that next time
  1158.   # we use the correct settings.
  1159.   #
  1160.   
  1161.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1162.   
  1163.   return P;
  1164. };
  1165.  
  1166. ##############################################################################
  1167. #
  1168. # Plot 3-D lines, etc...
  1169. #
  1170.  
  1171. pl3d = function ( X, Y, Z, BR )
  1172. {
  1173.   local (X, Y, Z, BR)
  1174.   check_plot_object ();
  1175.   
  1176.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1177.  
  1178.   #
  1179.   # Some basic checks
  1180.   #
  1181.  
  1182.   if ((N = X.n) != Y.n) { error ("pl3d: X and Y must have same length"); }
  1183.   if (N != Z.n) { error ("pl3d: X and Z must have same length"); }
  1184.  
  1185.   if (!exist (BR)) { BR = N; }
  1186.   if (mod (N, BR) != 0) { error ("pl3d: X.n must be divisible by BR"); }
  1187.   iBR = int (N / BR);
  1188.   if (iBR == 1) { k = N; else k = BR; }
  1189.  
  1190.   #
  1191.   # Figure out the scale limits. 
  1192.   # Needs improvement!
  1193.   #
  1194.   
  1195.   xmin = xmax = ymin = ymax = zmin = zmax = 0;
  1196.   XYZ_scales (X, Y, Z, p, xmin, xmax, ymin, ymax, zmin, zmax);
  1197.  
  1198.   _plgra ();
  1199.   _plcol (1);
  1200.   _pllsty (1);
  1201.   _plfont (WIN.[P].font[p]);
  1202.   _plwid (WIN.[P].width[p]);
  1203.   
  1204.   if (!subplot_f) 
  1205.   {
  1206.     _pladv (0);        # Advance 1 subplot
  1207.     else
  1208.     subplot_f = 0;     # The user has set the subplot
  1209.   }
  1210.  
  1211.   if (find_char (WIN.[P].grid3x[p], "l"))
  1212.   { X = log10 (real (X)); else X = real (X); }
  1213.   if (find_char (WIN.[P].grid3y[p], "l"))
  1214.   { Y = log10 (real (Y)); else Y = real (Y); }
  1215.   if (find_char (WIN.[P].grid3z[p], "l"))
  1216.   { Z = log10 (real (Z)); else Z = real (Z); }
  1217.     
  1218.   basex = 2; basey = 2; height = 4;
  1219.   xmin2d = -2.0; xmax2d = 2.0;
  1220.   ymin2d = -3.0; ymax2d = 5.0;
  1221.   
  1222.   _plvpas (0.15, 0.85, 0.15, 0.85, WIN.[P].aspect[p]);
  1223.   _plwind (xmin2d, xmax2d, ymin2d, ymax2d);
  1224.   _plw3d (basex, basey, height, xmin, xmax, ymin, ymax, ...
  1225.           zmin, zmax, WIN.[P].alt[p], WIN.[P].az[p]);
  1226.   _plbox3 (WIN.[P].grid3x[p], WIN.[P].xlabel[p], 0, 0, ...
  1227.            WIN.[P].grid3y[p], WIN.[P].ylabel[p], 0, 0, ...
  1228.            WIN.[P].grid3z[p], WIN.[P].zlabel[p], 0, 0);
  1229.   _plmtex ("t", 1.0, 0.5, 0.5, WIN.[P].title[p]);
  1230.  
  1231.   _plcol (2);
  1232.   for (i in 1:iBR)
  1233.   {
  1234.     j = [(i-1)*k+1:i*k];
  1235.     _plline3 (k, X[j], Y[j], Z[j]);
  1236.   }
  1237.   _plflush ();
  1238.   _pltext ();
  1239.   
  1240.   #
  1241.   # Increment the plot no. so that next time
  1242.   # we use the correct settings.
  1243.   #
  1244.   
  1245.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1246.   
  1247.   return P;
  1248. };
  1249.  
  1250. ##############################################################################
  1251. #
  1252. # error bar plot
  1253. #
  1254.  
  1255. plerry = function (x, y, y_low, y_high)
  1256. {
  1257.   check_plot_object ();
  1258.   
  1259.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1260.   WIN.[P].desc.[p] = 1j;    // use own legend
  1261.   
  1262.   if (x.nr != y.nr || x.nr != y_low.nr || x.nr != y_high.nr) 
  1263.   {
  1264.     error(" Size inconsistent in plerry.");
  1265.   }
  1266.   _plgra ();
  1267.   _plcol (1);
  1268.   _pllsty (1);
  1269.   _plfont (WIN.[P].font[p]);
  1270.   _plwid (WIN.[P].width[p]);
  1271.   xy_scales ( real([x,y,y_low,y_high]), p, xmin, xmax, ymin, ymax );
  1272.   
  1273.   if (!subplot_f) 
  1274.   {
  1275.     _pladv (0);        # Advance 1 subplot
  1276.   else
  1277.     subplot_f = 0;     # The user has set the subplot
  1278.   }
  1279.  
  1280.   if (WIN.[P].aspect[p] != 0)
  1281.   {
  1282.     _plvasp (WIN.[P].aspect[p]);
  1283.   else
  1284.     _plvsta ();
  1285.   }
  1286.  
  1287.   _plwind (xmin, xmax, ymin, ymax);
  1288.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  1289.  
  1290.   if (plot_matrix ( [x,y], p, 0, xmin, xmax, ymin, ymax, ymax-ymin ) < 0) 
  1291.   { 
  1292.     return -1; 
  1293.   }
  1294.  
  1295.   _plcol (3);
  1296.   _plerry(x.nr, x, y_low, y_high);
  1297.   _plcol (1);
  1298.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  1299.   _plflush ();
  1300.   _pltext ();
  1301.   
  1302.   #
  1303.   # Increment the plot no. so that next time
  1304.   # we use the correct settings.
  1305.   #
  1306.   
  1307.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1308.   return P;      
  1309. };
  1310.  
  1311. ##############################################################################
  1312. #
  1313. # Plot a Histogram(s), from the columns of a matrix.
  1314. #
  1315. ##############################################################################
  1316.  
  1317. plhist = function ( M , nbin )
  1318. {
  1319.   check_plot_object ();
  1320.   
  1321.   if (!exist (nbin)) { nbin = 10; }
  1322.   
  1323.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1324.   np = M.nr;
  1325.   
  1326.   # Compute max/min values of data
  1327.   
  1328.   ymin = min (min (real (M)));
  1329.   ymax = max (max (real (M)));
  1330.   
  1331.   #
  1332.   # Check computed scale limits against user's
  1333.   #
  1334.   
  1335.   if (WIN.[P].ymin[p] != 1j) { ymin = WIN.[P].ymin[p]; }
  1336.   if (WIN.[P].ymax[p] != 1j) { ymax = WIN.[P].ymax[p]; }
  1337.  
  1338.   _plgra ();
  1339.   _plcol (1);
  1340.   _plfont (WIN.[P].font[p]);
  1341.   _plwid (WIN.[P].width[p]);
  1342.   
  1343.   for (i in 1:M.nc) 
  1344.   { 
  1345.     hscale[i] = hist_scales (M[;i], nbin);
  1346.   }  
  1347.  
  1348.   if (!subplot_f) {
  1349.     _pladv (0);        # Advance 1 subplot
  1350.   else
  1351.     subplot_f = 0;     # The user has set the subplot
  1352.   }
  1353.  
  1354.   if (WIN.[P].aspect[p] != 0)
  1355.   {
  1356.     _plvasp (WIN.[P].aspect[p]);
  1357.   else
  1358.     _plvsta ();
  1359.   }
  1360.  
  1361.   _plwind (ymin, ymax, 0, max (hscale));
  1362.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  1363.  
  1364.   v = max (hscale);
  1365.   xmax = ymax;
  1366.   for (i in 1:M.nc)
  1367.   {
  1368.     k = mod (i, 14) + 1;
  1369.     _plcol (WIN.[P].color[p;k]);
  1370.     _plhist (np, real(M[;i]), ymin, ymax, nbin, 1);
  1371.     
  1372.     if (!any (any (WIN.[P].desc.[p] == 1j)))
  1373.     {
  1374.       # Use the default if necessary
  1375.       if (WIN.[P].desc.[p][1] == "default") 
  1376.       {
  1377.     desc = "c"+num2str(i);
  1378.       else if (WIN.[P].desc.[p].n >= i) {
  1379.     desc = WIN.[P].desc.[p][i];
  1380.       else
  1381.     # Not sure what to do, user has messed up.
  1382.     desc = "";
  1383.       } }
  1384.  
  1385.       v = v - max(hscale)/11;
  1386.       xl = (ymax-ymin)*[10.5/12, 11/12, 11.5/12]' + ymin;
  1387.       yl = [v, v, v]';
  1388.  
  1389.       _plline (3, xl, yl);
  1390.       plptex(desc, xl[1]-(ymax-ymin)/25, yl[3], , , 1);
  1391.     }
  1392.   }
  1393.  
  1394.   _plcol (1);
  1395.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  1396.   _plflush ();
  1397.   _pltext ();
  1398.  
  1399.   #
  1400.   # Increment the plot no. so that next time
  1401.   # we use the correct settings.
  1402.   #
  1403.   
  1404.   WIN.[P].subplot = WIN.[P].subplot + 1;
  1405.  
  1406.   return 1;
  1407. };
  1408.  
  1409. ##############################################################################
  1410. #
  1411. # Various support functions for the WIN list
  1412. #
  1413. ##############################################################################
  1414.  
  1415. #
  1416. # Replot
  1417. #
  1418.  
  1419. replot = function ( )
  1420. {
  1421.   check_plot_object ();
  1422.   _replot ();
  1423. };
  1424.  
  1425. ##############################################################################
  1426. #
  1427. # Set the X-axis label
  1428. #
  1429.  
  1430. xlabel = function ( xstr )
  1431. {
  1432.   check_plot_object ();
  1433.   if (!exist (xstr)) { xstr = ""; }
  1434.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1435.   WIN.[P].xlabel[i] = xstr;
  1436. };
  1437.  
  1438. ##############################################################################
  1439. #
  1440. # Set the Y-axis label
  1441. #
  1442.  
  1443. ylabel = function ( xstr )
  1444. {
  1445.   check_plot_object ();
  1446.   if (!exist (xstr)) { xstr = ""; }
  1447.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1448.   WIN.[P].ylabel[i] = xstr;
  1449. };
  1450.  
  1451. ##############################################################################
  1452. #
  1453. # Set the Z-axis label
  1454. #
  1455.  
  1456. zlabel = function ( xstr )
  1457. {
  1458.   check_plot_object ();
  1459.   if (!exist (xstr)) { xstr = ""; }
  1460.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1461.   WIN.[P].zlabel[i] = xstr;
  1462. };
  1463.  
  1464. ##############################################################################
  1465. #
  1466. # Set the plot-title
  1467. #
  1468.  
  1469. ptitle = function ( xstr )
  1470. {
  1471.   check_plot_object ();
  1472.   if (!exist (xstr)) { xstr = ""; }
  1473.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  1474.   WIN.[P].title[p] = xstr;
  1475. };
  1476.  
  1477. ##############################################################################
  1478. #
  1479. # Set the scale limits.
  1480. #
  1481.  
  1482. plimits = function ( xmin, xmax, ymin, ymax, zmin, zmax )
  1483. {
  1484.   check_plot_object ();
  1485.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1486.  
  1487.   if (exist (xmin)) 
  1488.   {
  1489.     WIN.[P].xmin[i] = xmin;
  1490.   else
  1491.     WIN.[P].xmin[i] = 1j;
  1492.   }
  1493.   if (exist (xmax)) 
  1494.   { 
  1495.     WIN.[P].xmax[i] = xmax;
  1496.   else
  1497.     WIN.[P].xmax[i] = 1j;
  1498.   }
  1499.  
  1500.   if (exist (ymin)) 
  1501.   {
  1502.     WIN.[P].ymin[i] = ymin;
  1503.   else
  1504.     WIN.[P].ymin[i] = 1j;
  1505.   }
  1506.   if (exist (ymax)) 
  1507.   {
  1508.     WIN.[P].ymax[i] = ymax;
  1509.   else
  1510.     WIN.[P].ymax[i] = 1j;
  1511.   }
  1512.  
  1513.   if (exist (zmin)) 
  1514.   {
  1515.     WIN.[P].zmin[i] = zmin;
  1516.   else
  1517.     WIN.[P].zmin[i] = 1j;
  1518.   }
  1519.   if (exist (zmax)) 
  1520.   {
  1521.     WIN.[P].zmax[i] = zmax;
  1522.   else
  1523.     WIN.[P].zmax[i] = 1j;
  1524.   }
  1525. };
  1526.  
  1527. ##############################################################################
  1528. #
  1529. # Set 2-D grid styles. A not-so-friendly interface.
  1530. #
  1531.  
  1532. plgrid = function ( sty_x, sty_y )
  1533. {
  1534.   check_plot_object ();
  1535.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1536.  
  1537.   if (exist (sty_x)) 
  1538.   { 
  1539.     if (class (sty_x) == "string")
  1540.     {
  1541.       WIN.[P].gridx[i] = sty_x;
  1542.     else
  1543.       error ("plgrid: requires string argument GRID_STY_X");
  1544.     }
  1545.   else
  1546.     WIN.[P].gridx[i] = grid_x_default;
  1547.   }
  1548.   if (exist (sty_y)) 
  1549.   { 
  1550.     if (class (sty_y) == "string")
  1551.     {
  1552.       WIN.[P].gridy[i] = sty_y;
  1553.     else
  1554.       error ("plgrid: requires string argument GRID_STY_Y");
  1555.     }
  1556.   else
  1557.     WIN.[P].gridy[i] = grid_y_default;
  1558.   }
  1559. };
  1560.  
  1561. ##############################################################################
  1562. #
  1563. # Set 3-D grid (axis) styles
  1564. #
  1565.  
  1566. plgrid3 = function ( sty_x, sty_y, sty_z )
  1567. {  
  1568.   check_plot_object ();
  1569.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1570.   if (exist (sty_x)) 
  1571.   { 
  1572.     if (class (sty_x) == "string")
  1573.     {
  1574.       WIN.[P].grid3x[i] = sty_x;
  1575.     else
  1576.       error ("plgrid3: requires string argument GRID_STY_X");
  1577.     }
  1578.   else
  1579.     WIN.[P].grid3x[i] = grid_3x_default;
  1580.   }
  1581.   if (exist (sty_y)) 
  1582.   { 
  1583.     if (class (sty_y) == "string")
  1584.     {
  1585.       WIN.[P].grid3y[i] = sty_y;
  1586.     else
  1587.       error ("plgrid3: requires string argument GRID_STY_Y");
  1588.     }
  1589.   else
  1590.     WIN.[P].grid3y[i] = grid_3y_default;
  1591.   }
  1592.   if (exist (sty_z)) 
  1593.   { 
  1594.     if (class (sty_z) == "string")
  1595.     {
  1596.       WIN.[P].grid3z[i] = sty_z;
  1597.     else
  1598.       error ("plgrid3: requires string argument GRID_STY_Z");
  1599.     }
  1600.   else
  1601.     WIN.[P].grid3z[i] = grid_3z_default;
  1602.   }
  1603. };
  1604.  
  1605. ##############################################################################
  1606. #
  1607. # A friendlier interface to changing 2-D grid/axis
  1608. # styles.
  1609. #
  1610.  
  1611. plaxis = function ( X_STR, Y_STR )
  1612. {
  1613.   check_plot_object ();
  1614.   i = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;
  1615.   
  1616.   if (exist (X_STR))
  1617.   {
  1618.     if (X_STR == "log") { WIN.[P].gridx[i] = "bcngstl"; }
  1619.   else
  1620.     WIN.[P].gridx[i] = grid_x_default;
  1621.   }
  1622.   
  1623.   if (exist (Y_STR))
  1624.   {
  1625.     if (Y_STR == "log") { WIN.[P].gridy[i] = "bcngstlv"; }
  1626.   else
  1627.     WIN.[P].gridy[i] = grid_y_default;
  1628.   }
  1629.   return P;
  1630. };
  1631.  
  1632. ##############################################################################
  1633. #
  1634. # Various internal support functions. Eventually these will be static.
  1635. #
  1636. ##############################################################################
  1637.  
  1638. #
  1639. # Find the X or Y scale limits .
  1640. # M can be a multi-column matrix, all columns
  1641. # will be used.
  1642. #
  1643.  
  1644. x_scales = function ( M, p, xmin, xmax )
  1645. {  
  1646.   #
  1647.   # 1st check for un-plottable data
  1648.   #
  1649.   
  1650.   if (any (any (isinf (M))))
  1651.   { error ("plot: cannot plot Infs"); }
  1652.   if (any (any (isnan (M))))
  1653.   { error ("plot: cannot plot NaNs"); }
  1654.   
  1655.   xmin = min (min (M));
  1656.   xmax = max (max (M));
  1657.   
  1658.   #
  1659.   # Check computed scale limits against user's
  1660.   #
  1661.   
  1662.   if (WIN.[P].xmin[p] != 1j) { xmin = WIN.[P].xmin[p]; }
  1663.   if (WIN.[P].xmax[p] != 1j) { xmax = WIN.[P].xmax[p]; }
  1664.  
  1665.   #
  1666.   # Check for potential errors
  1667.   #
  1668.   
  1669.   if (xmin == xmax) 
  1670.   { 
  1671.     # As good a guess as any
  1672.     xmin = xmin - 1;
  1673.     xmax = xmax + 1;
  1674.   }
  1675.   
  1676.   #
  1677.   # Finally, adjust if log-scales
  1678.   #
  1679.   
  1680.   if (find_char (WIN.[P].gridx[p], "l"))
  1681.   {
  1682.     if (xmin <= 0 || xmax <= 0) { error ("cannot plot log(x<=0)"); }
  1683.     xmin = log10 (xmin);
  1684.     xmax = log10 (xmax);
  1685.   }
  1686.   
  1687.   return 1;
  1688. };
  1689.  
  1690. y_scales = function ( M, p, xmin, xmax )
  1691. {
  1692.   
  1693.   #
  1694.   # 1st check for un-plottable data
  1695.   #
  1696.   
  1697.   if (any (any (isinf (M))))
  1698.   { error ("plot: cannot plot Infs"); }
  1699.   if (any (any (isnan (M))))
  1700.   { error ("plot: cannot plot NaNs"); }
  1701.   
  1702.   xmin = min (min (M));
  1703.   xmax = max (max (M));
  1704.   
  1705.   #
  1706.   # Check computed scale limits against user's
  1707.   #
  1708.   
  1709.   if (WIN.[P].ymin[p] != 1j) { xmin = WIN.[P].ymin[p]; }
  1710.   if (WIN.[P].ymax[p] != 1j) { xmax = WIN.[P].ymax[p]; }
  1711.  
  1712.   #
  1713.   # Check for potential errors
  1714.   #
  1715.   
  1716.   if (xmin == xmax) 
  1717.   { 
  1718.     # As good a guess as any
  1719.     xmin = xmin - 1;
  1720.     xmax = xmax + 1;
  1721.   }
  1722.   
  1723.   #
  1724.   # Finally, adjust if log-scales
  1725.   #
  1726.   
  1727.   if (find_char (WIN.[P].gridy[p], "l"))
  1728.   {
  1729.     if (xmin <= 0 || xmax <= 0) { error ("cannot plot log(y<=0)"); }
  1730.     xmin = log10 (xmin);
  1731.     xmax = log10 (xmax);
  1732.   }
  1733.   
  1734.   return 1;
  1735. };
  1736.  
  1737. z_scales = function ( M, p, xmin, xmax )
  1738. {
  1739.   
  1740.   #
  1741.   # 1st check for un-plottable data
  1742.   #
  1743.   
  1744.   if (any (any (isinf (M))))
  1745.   { error ("plot: cannot plot Infs"); }
  1746.   if (any (any (isnan (M))))
  1747.   { error ("plot: cannot plot NaNs"); }
  1748.   
  1749.   xmin = min (min (M));
  1750.   xmax = max (max (M));
  1751.   
  1752.   #
  1753.   # Check computed scale limits against user's
  1754.   #
  1755.   
  1756.   if (WIN.[P].zmin[p] != 1j) { xmin = WIN.[P].zmin[p]; }
  1757.   if (WIN.[P].zmax[p] != 1j) { xmax = WIN.[P].zmax[p]; }
  1758.  
  1759.   #
  1760.   # Check for potential errors
  1761.   #
  1762.   
  1763.   if (xmin == xmax) 
  1764.   { 
  1765.     # As good a guess as any
  1766.     xmin = xmin - 1;
  1767.     xmax = xmax + 1;
  1768.   }
  1769.   
  1770.   #
  1771.   # Finally, adjust if log-scales
  1772.   #
  1773.   
  1774.   if (find_char (WIN.[P].gridz[p], "l"))
  1775.   {
  1776.     if (xmin <= 0 || xmax <= 0) { error ("plot: cannot plot log(z<=0)"); }
  1777.     xmin = log10 (xmin);
  1778.     xmax = log10 (xmax);
  1779.   }
  1780.   
  1781.   return 1;
  1782. };
  1783.  
  1784. ##############################################################################
  1785. #
  1786. # Find the X and Y scales for a single matrix. (OLD)
  1787. #
  1788.  
  1789. xy_scales = function ( M, p, xmin, xmax, ymin, ymax )
  1790. {  
  1791.   #
  1792.   # 1st check for un-plottable data
  1793.   #
  1794.   
  1795.   if (any (any (isinf (M))))
  1796.   { error ("plot: cannot plot infs"); }
  1797.   if (any (any (isnan (M))))
  1798.   { error ("plot: cannot plot NaNs"); }
  1799.   
  1800.   if (M.nc == 1)
  1801.   {
  1802.     xmin = 1;
  1803.     xmax = M.nr;
  1804.     ymin = min (M);
  1805.     ymax = max (M);
  1806.   else
  1807.     xmin = min (M[;1]);
  1808.     xmax = max (M[;1]);
  1809.     ymin = min (min (M[;2:M.nc]));
  1810.     ymax = max (max (M[;2:M.nc]));
  1811.   }
  1812.   
  1813.   #
  1814.   # Check computed scale limits against user's
  1815.   #
  1816.   
  1817.   if (WIN.[P].xmin[p] != 1j) { xmin = WIN.[P].xmin[p]; }
  1818.   if (WIN.[P].xmax[p] != 1j) { xmax = WIN.[P].xmax[p]; }
  1819.   if (WIN.[P].ymin[p] != 1j) { ymin = WIN.[P].ymin[p]; }
  1820.   if (WIN.[P].ymax[p] != 1j) { ymax = WIN.[P].ymax[p]; }
  1821.   
  1822.   #
  1823.   # Check for potential errors
  1824.   #
  1825.   
  1826.   if (xmin == xmax) 
  1827.   { 
  1828.     xmin = xmin - 1;
  1829.     xmax = xmax + 1;
  1830.   }
  1831.   
  1832.   if (ymin == ymax)
  1833.   {
  1834.     ymin = ymin - 1;
  1835.     ymax = ymax + 1;
  1836.   }
  1837.   
  1838.   #
  1839.   # Finally, adjust if log-scales
  1840.   #
  1841.   
  1842.   if (find_char (WIN.[P].gridx[p], "l"))
  1843.   {
  1844.     if (xmin <= 0 || xmax <= 0) { error ("plot: cannot plot log <= 0"); }
  1845.     xmin = log10 (xmin);
  1846.     xmax = log10 (xmax);
  1847.   }
  1848.   if (find_char (WIN.[P].gridy[p], "l"))
  1849.   {
  1850.     if (ymin <= 0 || ymax <= 0) { error ("plot: cannot plot log <= 0"); }
  1851.     ymin = log10 (ymin);
  1852.     ymax = log10 (ymax);
  1853.   }
  1854.   
  1855.   return 1;
  1856. };
  1857.  
  1858. ##############################################################################
  1859. #
  1860. # Find the X, Y and Z scales for a single matrix.
  1861. #
  1862.  
  1863. XYZ_scales = function ( X, Y, Z, p, xmin, xmax, ymin, ymax, zmin, zmax )
  1864. {
  1865.   # X - scale
  1866.   if (any (any (isinf (X))))
  1867.   { error ("cannot plot infs"); }
  1868.   if (any (any (isnan (X))))
  1869.   { error ("cannot plot NaNs"); }
  1870.   
  1871.   xmin = min (real (X));
  1872.   xmax = max (real (X));
  1873.   
  1874.   # Y - scale
  1875.   if (any (any (isinf (Y))))
  1876.   { error ("cannot plot infs"); }
  1877.   if (any (any (isnan (Y))))
  1878.   { error ("cannot plot NaNs"); }
  1879.   
  1880.   ymin = min (real (Y));
  1881.   ymax = max (real (Y));
  1882.   
  1883.   # Z - scale
  1884.   if (any (any (isinf (Y))))
  1885.   { error ("cannot plot infs"); }
  1886.   if (any (any (isnan (Y))))
  1887.   { error ("cannot plot NaNs"); }
  1888.   
  1889.   zmin = min (min (real (Z)));
  1890.   zmax = max (max (real (Z)));
  1891.   
  1892.   #
  1893.   # Check computed scale limits against user's
  1894.   #
  1895.   
  1896.   if (WIN.[P].xmin[p] != 1j) { xmin = WIN.[P].xmin[p]; }
  1897.   if (WIN.[P].xmax[p] != 1j) { xmax = WIN.[P].xmax[p]; }
  1898.   if (WIN.[P].ymin[p] != 1j) { ymin = WIN.[P].ymin[p]; }
  1899.   if (WIN.[P].ymax[p] != 1j) { ymax = WIN.[P].ymax[p]; }
  1900.   if (WIN.[P].zmin[p] != 1j) { zmin = WIN.[P].zmin[p]; }
  1901.   if (WIN.[P].zmax[p] != 1j) { zmax = WIN.[P].zmax[p]; }
  1902.   
  1903.   #
  1904.   # Check for potential errors
  1905.   #
  1906.   
  1907.   if (xmin == xmax) 
  1908.   { 
  1909.     # As good a guess as any
  1910.     xmin = xmin - 1;
  1911.     xmax = xmax + 1;
  1912.   }
  1913.   
  1914.   if (ymin == ymax) 
  1915.   { 
  1916.     # As good a guess as any
  1917.     ymin = ymin - 1;
  1918.     ymax = ymax + 1;
  1919.   }
  1920.   
  1921.   if (zmin == zmax) 
  1922.   { 
  1923.     # As good a guess as any
  1924.     zmin = zmin - 1;
  1925.     zmax = zmax + 1;
  1926.   }
  1927.   
  1928.   #
  1929.   # Finally, adjust if log-scales
  1930.   #
  1931.   
  1932.   if (find_char (WIN.[P].grid3x[p], "l"))
  1933.   {
  1934.     if (xmin <= 0 || xmax <= 0) { error ("plot: cannot plot log(x<=0)"); }
  1935.     xmin = log10 (xmin);
  1936.     xmax = log10 (xmax);
  1937.   }
  1938.   
  1939.   if (find_char (WIN.[P].grid3y[p], "l"))
  1940.   {
  1941.     if (ymin <= 0 || ymax <= 0) { error ("plot: cannot plot log(y<=0)"); }
  1942.     ymin = log10 (ymin);
  1943.     ymax = log10 (ymax);
  1944.   }
  1945.   
  1946.   if (find_char (WIN.[P].grid3z[p], "l"))
  1947.   {
  1948.     if (zmin <= 0 || zmax <= 0) { error ("plot: cannot plot log(z<=0)"); }
  1949.     zmin = log10 (zmin);
  1950.     zmax = log10 (zmax);
  1951.   }
  1952.   
  1953.   return 1;
  1954. };
  1955.  
  1956. ##############################################################################
  1957. #
  1958. # Find the X and Y scales for a list of matrices
  1959. #
  1960.  
  1961. list_scales = function ( data, key, p, Xmin, Xmax, Ymin, Ymax )
  1962. {
  1963.   once = 1;
  1964.   
  1965.   for (i in members (data))
  1966.   {
  1967.     M = real (data.[i]);
  1968.     if (class (M) != "num") { continue; }
  1969.     
  1970.     if (abs (key) > M.nc)
  1971.     {
  1972.       error_1 ("plot: KEY argument > M.nc");
  1973.     }
  1974.     
  1975.     #
  1976.     # 1st check for un-plottable data
  1977.     #
  1978.     
  1979.     if (any (any (isinf (M))))
  1980.     { error ("plot: cannot plot infs"); }
  1981.     if (any (any (isnan (M))))
  1982.     { error ("plot: cannot plot NaNs"); }
  1983.     
  1984.     k = find ((1:M.nc) != abs (key));
  1985.     if (key > 0)
  1986.     {
  1987.       if (M.nc != 1)
  1988.       {
  1989.     x_scales ( real(M)[;key], p, xmin, xmax );
  1990.     y_scales ( real(M)[;k],   p, ymin, ymax );
  1991.       else
  1992.     x_scales ( (1:M.nr)', p, xmin, xmax );
  1993.     y_scales ( real(M),   p, ymin, ymax );
  1994.       }
  1995.     else if (key < 0) {
  1996.       x_scales ( real(M)[;k],        p, xmin, xmax );
  1997.       y_scales ( real(M)[;abs(key)], p, ymin, ymax );
  1998.     else
  1999.       x_scales ( (1:M.nr)', p, xmin, xmax );
  2000.       y_scales ( real(M),   p, ymin, ymax );
  2001.     } }
  2002.  
  2003.     if (once) 
  2004.     { 
  2005.       Xmin = xmin; Xmax = xmax; Ymin = ymin; Ymax = ymax; 
  2006.       once = 0; 
  2007.     }
  2008.     if (xmin < Xmin) { Xmin = xmin; }
  2009.     if (xmax > Xmax) { Xmax = xmax; }
  2010.     if (ymin < Ymin) { Ymin = ymin; }
  2011.     if (ymax > Ymax) { Ymax = ymax; }
  2012.   }
  2013.   
  2014.   return 1;
  2015. };
  2016.  
  2017. ##############################################################################
  2018. #
  2019. # Find the maximum number of elements in a bin for a single 
  2020. # column matrix.
  2021. #
  2022.  
  2023. hist_scales = function ( data, nbin )
  2024. {
  2025.   dmin = min (real (data));
  2026.   dmax = max (real (data));
  2027.   dbin = linspace (dmin, dmax, nbin+1);
  2028.   binval = zeros (nbin, 1);
  2029.   
  2030.   for (i in 1:nbin)
  2031.   {
  2032.     binval[i] = length (find (data >= dbin[i] && data < dbin[i+1]));
  2033.   }
  2034.   
  2035.   return max (binval);
  2036. };
  2037.  
  2038. ##############################################################################
  2039. #
  2040. # Plot the columns of a matrix (core function)
  2041. #
  2042. # Notes: This is the core function for plotting a matrix. If the
  2043. # matrix is a single column, then the matrix elements are plotted
  2044. # versus the row numbers. If it is a multi-column matrix, then
  2045. # columns 2:N are plotted versus column 1.
  2046. #
  2047. # p, K, k and l are indices for plot features.
  2048. # p: the current plot index (the plot #)
  2049. # K: usually 0. This index is used to start of the line style and
  2050. # color index (k = color index, l = line-style index). This is mostly
  2051. # used by plot_list, which may call plot_matrix repeatedly.
  2052. # k: the line color index. This value determines the line color used
  2053. # for each column of data. If K = 0, then k goes like 2:14, then
  2054. # flops back to 1:14.
  2055. # l: the line style inex. This value determines the line style used
  2056. # for each column of data - not the line-type (points, or lines). If
  2057. # K = 0, then l goes like 2:8, then flops back to 1:8.
  2058. #
  2059. ##############################################################################
  2060.  
  2061. plot_matrix = function ( M, key, p, K, xmin, xmax, ymin, ymax, v )
  2062. {
  2063.   np = M.nr;
  2064.   
  2065.   if (M.nc == 1)
  2066.   {
  2067.     x = 1:M.nr;
  2068.     y = real (M);
  2069.     k = mod (1+K, 14) + 1;
  2070.     l = mod (1+K, 8);
  2071.     
  2072.     if (find_char (WIN.[P].gridx[p], "l"))
  2073.     { x = log10 (x); }
  2074.     if (find_char (WIN.[P].gridy[p], "l"))
  2075.     { y = log10 (y); }
  2076.     
  2077.     _plcol (WIN.[P].color[p;k]);
  2078.     _pllsty (WIN.[P].lstyle[p;l]);
  2079.     
  2080.     if (get_style (WIN.[P].style.[p], k-1) == "line") 
  2081.     {
  2082.       _plline (M.nr, x, y);
  2083.     else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2084.       _plpoin (M.nr, x, y, WIN.[P].pstyle[p]+k);
  2085.     else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2086.       _plline (M.nr, x, y);
  2087.       _plpoin (M.nr, x, y, WIN.[P].pstyle[p]+k);
  2088.     else {
  2089.       _plline (M.nr, x, y);
  2090.     }}}}
  2091.  
  2092.     #
  2093.     # Now do the legend 
  2094.     #
  2095.     
  2096.     if (!any (any (WIN.[P].desc.[p] == 1j)))
  2097.     {
  2098.       # Use the default if necessary
  2099.       if (WIN.[P].desc.[p][1] == "default") 
  2100.       {
  2101.     desc = "c1";
  2102.       else if (WIN.[P].desc.[p].n >= k-1) {
  2103.     desc = WIN.[P].desc.[p][k-1];
  2104.       else
  2105.     # Not sure what to do, user has messed up.
  2106.     desc = "";
  2107.       } }
  2108.              
  2109.       v = v - (ymax-ymin)/11;
  2110.       xl = (xmax-xmin)*[10.5/12, 11/12, 11.5/12]' + xmin;
  2111.       yl = [v, v, v]' + ymin;
  2112.       
  2113.       if (get_style (WIN.[P].style.[p], k-1) == "line") 
  2114.       {
  2115.     _plline (3, xl, yl);
  2116.       else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2117.     _plpoin (3, xl, yl, WIN.[P].pstyle[p]+k);
  2118.       else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2119.     _plline (3, xl, yl);
  2120.     _plpoin (3, xl, yl, WIN.[P].pstyle[p]+k);
  2121.       } } }
  2122.  
  2123.       plptex(desc, xl[1]-(xmax-xmin)/25, yl[3], , , 1);
  2124.       
  2125.     }
  2126.  
  2127.   else
  2128.  
  2129.     #
  2130.     # Check for large column dimension
  2131.     #
  2132.     
  2133.     if (M.nc > 3*M.nr)
  2134.     {
  2135.       printf (" Plot %i columns and %i rows, are you sure (y/n) ? "...
  2136.                , M.nc, M.nr);
  2137.       ans = getline ("stdin");
  2138.       if (ans.[1] != "y") { return -1; }
  2139.     }
  2140.     
  2141.     ki = find ((1:M.nc) != abs (key));
  2142.     for (i in ki)
  2143.     {
  2144.       if (key > 0)
  2145.       {
  2146.     x = real (M[;key]);
  2147.     y = real (M[;i]);
  2148.       else if (key < 0) {
  2149.     x = real (M[;i]);
  2150.     y = real (M[;abs(key)]);
  2151.       else
  2152.     x = (1:M.nr)';
  2153.     y = real (M[;i]);
  2154.       } }
  2155.  
  2156.       # Check for log scales, adjust if necessary
  2157.       if (find_char (WIN.[P].gridx[p], "l"))
  2158.       { x = log10 (x); }
  2159.       if (find_char (WIN.[P].gridy[p], "l"))
  2160.       { y = log10 (y); }
  2161.       
  2162.       k = mod (i-1 + K, 14) + 1;
  2163.       l = mod (8 + i-2 + K, 8) + 1;
  2164.       
  2165.       _plcol (WIN.[P].color[p;k]);
  2166.       _pllsty (WIN.[P].lstyle[p;l]);
  2167.       
  2168.       if (get_style (WIN.[P].style.[p], k-1) == "line") 
  2169.       {
  2170.     _plline (np, x, y);
  2171.       else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2172.     _plpoin (np, x, y, WIN.[P].pstyle[p]+k);
  2173.       else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2174.     _plline (np, x, y);
  2175.     _plpoin (np, x, y, WIN.[P].pstyle[p]+k);
  2176.       else {
  2177.     _plline (np, x, y);
  2178.       }}}}
  2179.  
  2180.       #
  2181.       # Now do the legend 
  2182.       #
  2183.       
  2184.       if (!any (any (WIN.[P].desc.[p] == 1j)))
  2185.       {
  2186.     # Use the default if necessary
  2187.     if (WIN.[P].desc.[p][1] == "default") 
  2188.     {
  2189.       desc = "c" + num2str (i);
  2190.         else if (WIN.[P].desc.[p].n >= k-1) {
  2191.       desc = WIN.[P].desc.[p][k-1];
  2192.         else
  2193.       # Not sure what to do, user has messed up.
  2194.       desc = "";
  2195.         }}
  2196.              
  2197.     v = v - (ymax-ymin)/11;
  2198.     xl = (xmax-xmin)*[10.5/12, 11/12, 11.5/12]' + xmin;
  2199.     yl = [v, v, v]' + ymin;
  2200.     
  2201.     if (get_style (WIN.[P].style.[p], k-1) == "line") 
  2202.     {
  2203.       _plline (3, xl, yl);
  2204.         else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2205.       _plpoin (3, xl, yl, WIN.[P].pstyle[p]+k);
  2206.         else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2207.       _plline (3, xl, yl);
  2208.       _plpoin (3, xl, yl, WIN.[P].pstyle[p]+k);
  2209.         }}}
  2210.     
  2211.     plptex(desc, xl[1]-(xmax-xmin)/25, yl[3], , , 1);
  2212.     
  2213.       }
  2214.     }
  2215.   }
  2216.   
  2217.   return k-1;
  2218. };
  2219.  
  2220. ##############################################################################
  2221. #
  2222. # Plot all of the matrices in a list on the same plot
  2223. #
  2224.  
  2225. plot_list = function ( L, key, p, xmin, xmax, ymin, ymax )
  2226. {
  2227.   k = 0;
  2228.   v = ymax - ymin;
  2229.   
  2230.   #
  2231.   # Sort out the list members
  2232.   #
  2233.  
  2234.   sl = list_sort (L);
  2235.  
  2236.   # Plot the list members with numeric labels 1st.
  2237.   if (exist (sl.num))
  2238.   {
  2239.     for (i in sl.num)
  2240.     {
  2241.       M = L.[i];
  2242.       if (class (M) != "num") { continue; }
  2243.       if ((k = plot_matrix (M, key, p, k, xmin, xmax, ymin, ymax, v)) < 0) 
  2244.       { 
  2245.     return k; 
  2246.       }
  2247.     }
  2248.   }
  2249.  
  2250.   # Now plot the list members with string labels.
  2251.   if (exist (sl.char))
  2252.   {
  2253.     for (i in sl.char)
  2254.     {
  2255.       M = L.[i];
  2256.       if (class (M) != "num") { continue; }
  2257.       if ((k = plot_matrix (M, key, p, k, xmin, xmax, ymin, ymax, v)) < 0) 
  2258.       { 
  2259.     return k; 
  2260.       }
  2261.     }
  2262.   }
  2263.   return 1;
  2264. };
  2265.  
  2266. ##############################################################################
  2267. #
  2268. # Check the elements of LIST.
  2269. # LIST must contain elements `x', `y',
  2270. # and `z'
  2271. #
  2272.  
  2273. check_3d_list = function ( LIST )
  2274. {
  2275.   #
  2276.   # Check existence and types
  2277.   #
  2278.   
  2279.   if (class (LIST) != "list") {
  2280.     error ("plot3: argument must be a list");
  2281.   }
  2282.   if (!exist (LIST.x)) {
  2283.     error ("plot3: arg must contain `x' member");
  2284.   else if (class (LIST.x) != "num") {
  2285.     error ("plot3: x must be numeric");
  2286.   } }
  2287.   if (!exist (LIST.y)) {
  2288.     error ("plot3: arg must contain `y' member");
  2289.   else if (class (LIST.y) != "num") {
  2290.     error ("plot3: y must be numeric"); 
  2291.   } }
  2292.   if (!exist (LIST.z)) {
  2293.     error ("plot3: arg must contain `z' member");
  2294.   else if (class (LIST.z) != "num") {
  2295.     error ("plot3: z must be numeric");
  2296.   } }
  2297.  
  2298.   #
  2299.   # Check sizes
  2300.   #
  2301.   
  2302.   if (LIST.x.n != LIST.z.nr) 
  2303.   {
  2304.     error ("plot3: x.n != z.nr");
  2305.   }
  2306.   
  2307.   if (LIST.y.n != LIST.z.nc) 
  2308.   {
  2309.     error ("plot3: y.n != z.nc");
  2310.   }
  2311.   
  2312. };
  2313.  
  2314. ##############################################################################
  2315. #
  2316. # A special type of histogram plot.
  2317. #
  2318.  
  2319. plhistx = function ( M , nbin )
  2320. {
  2321.   check_plot_object ();
  2322.   
  2323.   if (!exist (nbin)) { nbin = 10; }
  2324.   
  2325.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  2326.   np = M.nr;
  2327.   
  2328.   # Compute max/min values of data
  2329.   
  2330.   ymin = min (min(real (M)));
  2331.   ymax = max (max(real (M)));
  2332.   
  2333.   #
  2334.   # Check computed scale limits against user's
  2335.   #
  2336.   
  2337.   if (WIN.[P].ymin[p] != 1j) { ymin = WIN.[P].ymin[p]; }
  2338.   if (WIN.[P].ymax[p] != 1j) { ymax = WIN.[P].ymax[p]; }
  2339.   
  2340.   _plgra ();
  2341.   _plcol (15);
  2342.   _plfont (WIN.[P].font[p]);
  2343.   _plwid (WIN.[P].width[p]);
  2344.   
  2345.   dbin = (linspace (ymin, ymax, nbin+1))';
  2346.   for (j in 1:M.nc) 
  2347.   {
  2348.     // counting
  2349.     for (i in 1:nbin) 
  2350.     {
  2351.       binval[i;j] = length (find (M[;j] >= dbin[i] && M[;j] < dbin[i+1]));
  2352.     }
  2353.   }
  2354.   
  2355.   if (!subplot_f) {
  2356.     _pladv (0);        # Advance 1 subplot
  2357.   else
  2358.     subplot_f = 0;     # The user has set the subplot
  2359.   }
  2360.  
  2361.   if (WIN.[P].aspect[p] != 0)
  2362.   {
  2363.     _plvasp (WIN.[P].aspect[p]);
  2364.   else
  2365.     _plvsta ();
  2366.   }
  2367.  
  2368.   xmin = 0;
  2369.   xmax =  max(max(binval));
  2370.   _plwind (ymin, ymax, xmin, xmax);
  2371.   _plbox (WIN.[P].gridx[p], 0, 0, WIN.[P].gridy[p], 0, 0);
  2372.  
  2373.   #
  2374.   # Now reorganize dbin and binval so we plot points in
  2375.   # the middle of the bins.
  2376.   #
  2377.  
  2378.   delbin = abs(dbin[2] - dbin[1]);
  2379.   dbin = (linspace (ymin+delbin/2, ymax-delbin/2, nbin))';
  2380.   dbin = [ymin ; dbin ; ymax];
  2381.   binval = [zeros(1,binval.nc); binval; zeros(1,binval.nc)];
  2382.  
  2383.   v = xmax;
  2384.   for (i in 1:M.nc)
  2385.   {
  2386.     k = mod (i, 14) + 1;
  2387.     l = mod (i,  8) + 1;
  2388.     _plcol (WIN.[P].color[p;k]);
  2389.     _pllsty (WIN.[P].lstyle[p;l]);
  2390.     
  2391.     if      (get_style (WIN.[P].style.[p], k-1) == "line") 
  2392.     {
  2393.       _plline (nbin+2, dbin, binval[;i]);
  2394.     else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2395.       _plpoin (nbin+2, dbin, binval[;i], WIN.[P].pstyle[p]+k);
  2396.     else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2397.       _plline (nbin+2, dbin, binval[;i]);
  2398.       _plpoin (nbin+2, dbin, binval[;i], WIN.[P].pstyle[p]+k);     
  2399.     } } }
  2400.  
  2401.     // write legend around upper-right corner.
  2402.     // it is better to have user to choose location for legend.
  2403.     
  2404.     if (!any (any (WIN.[P].desc.[p] == 1j)))
  2405.     {
  2406.       # Use the default if necessary
  2407.       if (WIN.[P].desc.[p][1] == "default") 
  2408.       {
  2409.     desc = "c"+num2str(i);
  2410.       else if (WIN.[P].desc.[p].n >= i) {
  2411.       desc = WIN.[P].desc.[p][i];
  2412.       else
  2413.     # Not sure what to do, user has messed up.
  2414.     desc = "";
  2415.       } }
  2416.  
  2417.       v = v - (xmax)/11;
  2418.       xt = (ymax-ymin)*[10.5/12, 11/12, 11.5/12]' + ymin;
  2419.       yt = [v, v, v]';
  2420.       
  2421.       if      (get_style (WIN.[P].style.[p], k-1) == "line") 
  2422.       {
  2423.     _plline (3, xt, yt);
  2424.       else if (get_style (WIN.[P].style.[p], k-1) == "point") {
  2425.     _plpoin (3, xt, yt, WIN.[P].pstyle[p]+k);
  2426.       else if (get_style (WIN.[P].style.[p], k-1) == "line-point") {
  2427.     _plline (3, xt, yt);
  2428.     _plpoin (3, xt, yt, WIN.[P].pstyle[p]+k);
  2429.       } } }
  2430.  
  2431.       plptex(desc, xt[1]-(ymax-ymin)/25, yt[3], , , 1);
  2432.     }
  2433.   }
  2434.   
  2435.   _plcol (15);
  2436.   _pllab (WIN.[P].xlabel[p], WIN.[P].ylabel[p], WIN.[P].title[p]);  
  2437.   _plflush ();
  2438.   _pltext ();
  2439.   
  2440.   #
  2441.   # Increment the plot no. so that next time
  2442.   # we use the correct settings.
  2443.   #
  2444.   
  2445.   WIN.[P].subplot = WIN.[P].subplot + 1;
  2446.   
  2447.   return 1;
  2448. };
  2449.  
  2450.  
  2451. ##############################################################################
  2452. #
  2453. # Create a legend in the current plot window
  2454. #
  2455. # if pobj.desc.[p] = inf()        no legend
  2456. # if pobj.desc.[p] = "default"        default ("c1", "c2", ...)
  2457. # if pobj.desc.[p] = "string"        use "string" as description
  2458. #
  2459.  
  2460. #
  2461. # Set the current plot legend string
  2462. #
  2463.  
  2464. plegend = function ( LEGEND )
  2465. {
  2466.   check_plot_object ();
  2467.   
  2468.   p = mod (WIN.[P].subplot, WIN.[P].nplot) + 1;    # The current index
  2469.   
  2470.   if (!exist (LEGEND)) 
  2471.   {
  2472.     WIN.[P].desc.[p] = 1j;
  2473.     return P;
  2474.   }
  2475.   
  2476.   if (class (LEGEND) == "string")
  2477.   {
  2478.     WIN.[P].desc.[p] = LEGEND;
  2479.   }
  2480.   
  2481.   return P;
  2482. };
  2483.