home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Guide / c-cplusplus-interactive-guide.iso / c_ref / csource3 / 126_01 / facsplot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1985-03-11  |  23.4 KB  |  854 lines

  1. /*********************************************************************\
  2. ** .---------------------------------------------------------------. **
  3. ** |                                                               | **
  4. ** |                                                               | **
  5. ** |         Copyright (c) 1981, 1982, 1983 by Eric Martz.         | **
  6. ** |                                                               | **
  7. ** |                                                               | **
  8. ** |       Permission is hereby granted to use this source         | **
  9. ** |       code only for non-profit purposes. Publication of       | **
  10. ** |       all or any part of this source code, as well as         | **
  11. ** |       use for business purposes is forbidden without          | **
  12. ** |       written permission of the author and copyright          | **
  13. ** |       holder:                                                 | **
  14. ** |                                                               | **
  15. ** |                          Eric Martz                           | **
  16. ** |                         POWER  TOOLS                          | **
  17. ** |                    48 Hunter's Hill Circle                    | **
  18. ** |                      Amherst MA 01002 USA                     | **
  19. ** |                                                               | **
  20. ** |                                                               | **
  21. ** `---------------------------------------------------------------' **
  22. \*********************************************************************/
  23.  
  24. /*------------------------------------------------------------------*/
  25. /* This source provides an example of how HIPLOT.C has been used
  26. in producing actual plots. The application concerns distributions
  27. of 256 integers, each representing a count in a channel, from an
  28. instrument called a flow cytofluorometer, or
  29. fluorescence-activated cell sorter. Since use of the facsplot
  30. program as it stands is hardware dependent, you will not be able
  31. to run this program (or even compile and link it in its present
  32. form). However, it provides some functions which may serve as
  33. useful models for anyone wishing to write a more general purpose
  34. plotting package. In particular, see
  35.  
  36.     axis() which draws an axis
  37.     axis_scale() which puts tick marks and numbers on it
  38.         tick()
  39.     vlabel() and hlabel() which write labels next to the vertical
  40.         and horizontal axes
  41.     
  42.     scalepoint()
  43. */
  44. /*------------------------------------------------------------------*/
  45. #include "bdscio.h"
  46.  
  47. #define NIOBUFS 1
  48. #include "fio1.h"
  49.  
  50. /* FACS */
  51. #define STDERR 1
  52. #define NDISTS 5 /* NUMBER OF DISTRIBUTION BUFFERS IN MEMORY */
  53. #define DISTLEN 255
  54. char Buf[MAXLINE], **Pp[32];
  55. char Memdist[NDISTS+1][(DISTLEN+1)*5]; /* BDSC LACKS 3-DIMENSIONAL ARRAYS */
  56. char Dfinmem[NDISTS+1][16]; /* NAMES OF DISTRIBUTION FILES IN MEMORY */
  57. char Tot[NDISTS+1][5], Av[NDISTS+1][5], Max[NDISTS+1][5],
  58.     Condist[NDISTS+1][15+1], Pos[NDISTS+1][5];
  59. int Location; /* INDEX LOCATION OF CURRENT DISTRIBUTION IN MEMORY */
  60. int Nexttogo;    /* NEXT MEMORY ARRAY TO BE REFILLED BY NEEDED DISTRIBUTION */
  61. int Verbose;
  62. char *Arr;    /* POINTER TO CURRENT DISTRIBUTION IN MEMORY */
  63.  
  64. char Fpone[5], Fpzero[5], Fpmone[5],
  65.     Fphundred[5], Fpthousand[5]; /* FLOAT */
  66. char F1[5], F2[5], F3[5], F4[5]; /* FLOAT */
  67. FILE *Fpin, *Fpout;
  68.  
  69. /* MOSC */
  70. int Begregn, Endregn;
  71.  
  72. */
  73. /*------------------------------------------------------------------*/
  74. /* FACS PLOT */
  75. #define LABEL 2
  76. #define SCALE 2
  77. #define REBUF 4000
  78. #define VHALF 755
  79. #define HHALF 1015
  80. char Hmin_f[5], Vmin_f[5], Hfact_f[5], Vfact_f[5];
  81. char Xmin_f[5], Ymin_f[5];
  82. char Buf_repeat[REBUF], *At_repeat;
  83. int Lsize, Nsize; /* SIZES OF CHARACTERS FOR LABEL, SCALE */
  84. int Fill_repeat;
  85. /*------------------------------------------------------------------*/
  86.  
  87. #define FACSPLOT 1
  88.  
  89. /*------------------------------------------------------------------*/
  90. main(argc, argv)
  91.     int argc;
  92.     char **argv;
  93.     {
  94.     int option;
  95. #include "fio2.h"
  96.     if (0) putchar('a');
  97.     if (0) getchar();
  98.     if (0) fopen("x",'r');
  99.     if (0) fclose(Fpin);
  100.     if (argc >1) Verbose = YES;
  101.     else Verbose = NO;
  102.     init_facs();
  103.  
  104.     option = '1';
  105.     FOREVER {
  106. /*        fprintf(STDERR,
  107.            "\n\t1. MOSC\n%s%s%s%s%s",
  108.             "\t2. Regions\n",
  109.             "\t3. Display statistics\n",
  110.             "\t4. List distribution\n",
  111.             "\t5. Normalize\n",
  112.             "\t6. Quit\n\n");
  113.         option = charq("Option","123456");
  114. */
  115.  
  116.         switch(option) {
  117.             case '1':
  118.                 fplot();
  119.                 break;
  120.             case '2':
  121.                 break;
  122.             case '3':
  123.                 break;
  124.             case '4':
  125.                 exit(0);
  126.         }
  127.         if (!ynq("Another plot")) exit(0);
  128.     }
  129. }
  130. /*------------------------------------------------------------------*/
  131. init_facs() {
  132.     int i;
  133.     for (i=1; i <=NDISTS; i++)
  134.         Dfinmem[i][0] = NULL;
  135.     itof(Fpone,1);
  136.     itof(Fpzero,0);
  137.     itof(Fpmone,-1);
  138.     itof(Fphundred,100);
  139.     itof(Fpthousand,1000);
  140.     Nexttogo = 1;
  141. }
  142. /*------------------------------------------------------------------*/
  143.  
  144. #include "fio3.h"
  145.  
  146. /*------------------------------------------------------------------*/
  147. /* END OF FACS.C */
  148. /*------------------------------------------------------------------*/
  149. /*------------------------------------------------------------------*/
  150. fplot() {
  151.     int i, qmax, max, h, v, more, check, nofile, dstyle, atdist,
  152.         left_margin, bottom_margin, distcnt, logplot;
  153.     char dnames[128];
  154.     int line_type[10];
  155.     int curve_thickness[10];
  156.     set4baud(1, 300);
  157.     while(!ynq("Is paper ready in plotter (1200 BAUD)"));
  158.     init_plot();
  159.  
  160.     /* SELECT PLOT SIZE */
  161.     Pp[1] = "\t-------------\n";
  162.     fprintf(STDERR,"\n%s\t|  1  |  2  |\n%s\t|  3  |  4  |\n%s\n",
  163.         Pp[1],Pp[1],Pp[1]);
  164.     checkint("\nQuarter page position 1-4 (Default is full page)? ",
  165.         &i, Buf, 0, 4, 0);
  166.     init_quarter();
  167.     switch(i) {
  168.         case 0:
  169.             init_full();
  170.             break;
  171.         case 1:
  172.             Vmin = VHALF;
  173.             break;
  174.         case 2:
  175.             Hmin = HHALF;
  176.             Vmin = VHALF;
  177.             break;
  178.         case 3:
  179.             break;
  180.         case 4:
  181.             Hmin = HHALF;
  182.             break;
  183.     }
  184.     fix_origin();
  185.     
  186.     /* DEFAULT STYLE? */
  187.     dstyle = ynq("\nDefault style");
  188.  
  189.     /* CHANGE LINE THICKNESS OR CHARACTER SIZE? */
  190.     if (!dstyle AND !ynq("Use default character sizes and line thickness")) {
  191.         checkint("Curve thickness (default %d)? ",&Plot_thickness,
  192.             Buf, 1, 10, 1);
  193.         checkint("Offset (default %d)? ",&Offset,
  194.             Buf, 1, 3, 2);
  195.         checkint("Character size:\n\tfor axis labels (default %d)? ",&Lsize,
  196.             Buf, 1, 5, Lsize);
  197.         checkint("\tfor scale numbers (default %d)? ",&Nsize,
  198.             Buf, 1, 5, Nsize);
  199.         if (Lsize EQ Nsize) {
  200.             checkint("Character thickness (default %d)? ",
  201.                 &Cthick[Lsize], Buf, 1, 10, Cthick[Lsize]);
  202.         }
  203.         else {
  204.             checkint(
  205.             "Character thickness:\n\tfor axis labels (default %d)? ",
  206.                 &Cthick[Lsize], Buf, 1, 10, Cthick[Lsize]);
  207.             checkint("\tfor scale numbers (default %d)? ",
  208.                 &Cthick[Nsize], Buf, 1, 10, Cthick[Nsize]);
  209.         }
  210.     }
  211.     
  212.     /* ALLOW SPACE FOR LABELS, SCALES, AND AXES */
  213.  
  214.     /* RAISE BOTTOM TO ALLOW FOR 1 LINE OF LABEL, 1 BLANK LINE,
  215.         1 LINE OF SCALE, AND ONE BETLIN BELOW AXIS */
  216.     bottom_margin = (2 * Cheight[Lsize]) + Cheight[Nsize] + Cbetlin[Nsize];
  217.     Vmin += bottom_margin;
  218.  
  219.     /* SHIFT TO RIGHT TO ALLOW FOR:
  220.         1 HEIGHT FOR LABEL,
  221.         1 BLANK HEIGHT BETWEEN LABEL AND SCALE,
  222.         4 WIDTHS FOR SCALE,
  223.         0.5 BLANK WIDTHS BETWEEN SCALE AND AXIS. */
  224.     left_margin = (2 * Cheight[Lsize]) +
  225.         (4 * Cwidth[Lsize]) + (Cwidth[Lsize]/2);
  226.     Hmin += left_margin;
  227.  
  228.     /* GET LIST OF DISTRIBUTIONS TO BE PLOTTED */
  229.     distcnt = 0;
  230.     while (!distcnt)
  231.         distcnt = getwrds(
  232. "List on one line distributions to be plotted, separated by commas.\n",
  233.             dnames, Pp);
  234.  
  235.     /* GET CURVE THICKNESS AND LINE TYPES */
  236.     for (i=1; i <= distcnt; i++) {
  237.         line_type[i] = 0;
  238.         curve_thickness[i] = Plot_thickness;
  239.     }
  240.     if (ynq("Vary line type or curve thickness")) {
  241.         fprintf(STDERR,
  242. "Line types:\n\t0  Solid\n\t2  Broken, fine\n\t4  Broken, medium\n%s",
  243.             "\t6  Broken, coarse\n");
  244.         for (i=1; i <= distcnt; i++) {
  245.             fprintf(STDERR,"\nCurve %s:\n",Pp[i]);
  246.             checkint("\tLine type (default %d)? ",
  247.                 &line_type[i], Buf, 0, 8, 0);
  248.             checkint("\tThickness (default %d)? ",
  249.                 &curve_thickness[i], Buf, 1, 10, 1);
  250.         }
  251.     }
  252.  
  253.     /* PRINT TABLE SHOWING MAXIMA */
  254.     fprintf(STDERR,"\nFile\tTotal\tMax\nName\tCells\tCells\n\n");
  255.     max = 0;
  256.     for (i = 1; i <= distcnt; i++) {
  257.         nofile = fgetdist(Pp[i]);
  258.         if (nofile) fprintf(STDERR, "%s\t <NOT FOUND>\n",Pp[i]);
  259.         else fprintf(STDERR, "%s\t%1.0f\t%1.0f\n",
  260.             Pp[i], Tot[Location], Max[Location]);
  261.         qmax = ftoir(Max[Location]);
  262.         max = (qmax > max)? qmax: max;
  263.     }
  264.  
  265.     if (!dstyle) {
  266.  
  267.         /* SCALE ORDINATE */
  268.         logplot = ynq("\nPlot log of cell number");
  269.         if (!logplot) {
  270.             fprintf(STDERR,
  271. "Maximum cell count for this group of distributions is %d\n",
  272.                 max);
  273.             Ymax = 0;
  274.             while (Ymax < 1) {
  275.                 fprintf(STDERR,
  276. "Maximum cells on ordinate (return nothing for %d)? ",max);
  277.                 gets(Buf);
  278.                 check = ati(&Ymax,Buf);
  279.                 if (check EQ -1) Ymax = max;
  280.                 if (check EQ 1 OR Ymax < 1) {
  281.                     fprintf(STDERR,"Invalid maximum.\n");
  282.                     Ymax = 0;
  283.                 }
  284.             }
  285.             fprintf(STDERR,"Max cells = %d.\n",Ymax);
  286.         }
  287.         else {
  288.             Ymin = 1000; /* 1000 x Log(10) */
  289.             Ymax = 4000; /* 1000 x Log(10000) */
  290.         }
  291.     
  292.         /* SELECT REGION OF DISTRIBUTION FOR PLOTTING */
  293. retry:
  294.         checkint(
  295. "\nMinimum channel to plot (default: entire distribution)? ",
  296.             &Xmin, Buf, 0, 254, 0);
  297.  
  298.         checkint(
  299. "Maximum channel to plot (default: entire distribution)? ",
  300.             &Xmax, Buf, 2, 255, 255);
  301.  
  302.         if ((Xmax - Xmin) < 30) {
  303.             fprintf(STDERR,
  304. "Minimum plotting range is 30 channels.\nSpecified range is %d.\n%s",
  305.                 Xmax - Xmin, "Please try again.\n\n");
  306.             goto retry;
  307.         }
  308.     }
  309.     else {    /* DEFAULT STYLE */
  310.         logplot = NO;
  311.         Ymax = max;
  312.         Xmin = 0;
  313.         Xmax = 255;
  314.     }
  315.  
  316.     init_calcs();
  317.  
  318.     /* LABELS */
  319.     Csize = Lsize;
  320.     if (dstyle OR ynq("\nLabel axes")) {
  321.         if (logplot) vlabel("LOG CELLS/CHANNEL", left_margin);
  322.         else vlabel("CELLS/CHANNEL", left_margin);
  323.         if ('f' EQ (charq(
  324.             "Abcissa: scatter or fluorescence? (s/f)","sf")))
  325.             hlabel("CHANNEL NUMBER (FLUORESCENCE INTENSITY)",
  326.                 bottom_margin);
  327.         else
  328.             hlabel("CHANNEL NUMBER (SCATTER INTENSITY)", bottom_margin);
  329.     }
  330.  
  331.     /* AXES AND SCALES */
  332.     Csize = Nsize;
  333.     if (dstyle OR ynq("Draw and scale axes")) { 
  334.         box(Plot_thickness);
  335.         if (logplot) axis(VERTICAL, 1, 4, 3);
  336.         else axis(VERTICAL, 0, Ymax, 0);
  337.         axis(HORIZONTAL, Xmin, Xmax, 0);
  338.     }
  339.  
  340.     /* ADJUST PLOTTING AREA TO AVOID AXES, WHETHER DRAWN OR NOT */
  341.     i = (Plot_thickness * Offset) + 4;
  342.     Hmin += i;
  343.     Hmax -= i;
  344.     Vmin += i;
  345.     Vmax -= i;
  346.     init_calcs();
  347.  
  348.  
  349.     /* DATA CURVES */
  350.     for (atdist=1; atdist<=distcnt; atdist++) {
  351.         if (fgetdist(Pp[atdist])) continue;
  352.         At_repeat = Buf_repeat;
  353.         Fill_repeat = YES;
  354.         i = (Xmin > 0)? Xmin: 1;
  355.         gethv(i, &h, &v, logplot);
  356.         setlinetype(line_type[atdist]);
  357.         pen_up();
  358.         pen_to(h, v);
  359.         pen_down();
  360.         for(i++; i<=Xmax; i++) {
  361.             if (fpcomp(Arr+(i*5),Fpmone) EQ 0) break;
  362.             gethv(i, &h, &v, logplot);
  363.             pen_to(h, v);
  364.         }
  365.         pen_up();
  366.         repeat(curve_thickness[atdist]-1);
  367.         setlinetype(0);
  368.     }
  369.     home();
  370. }
  371. /*------------------------------------------------------------------*/
  372. /* GETS HORIZONTAL AND VERTICAL INTEGERS FOR FACS DISTRIBUTION PLOT:
  373.     HORIZ IS A SCALED CHANNEL NUMBER (i);
  374.     VERT IS SCALED FROM Arr+(i*5).
  375. */
  376. gethv(i, h, v, vlog)
  377.     int i, *h, *v, vlog;
  378.     {
  379.     int sign;
  380.     char y[5], x[5]; /*FLOAT*/
  381.  
  382.     /* GET h */
  383.     scalepoint(HORIZONTAL,itof(x,i),h);
  384.  
  385.     /* GET v */
  386.     fpass(y, Arr+(i*5));
  387.     if (vlog) {
  388.         log10(F1, &sign, y);
  389.         fpmult(y, F1, Fpthousand);
  390.     }
  391.     scalepoint(VERTICAL,y,v);
  392.  
  393.     /* KEEP RESULTS WITHIN PLOT BOUNDARIES */
  394.     if (*h < Hmin) *h = Hmin;
  395.     if (*h > Hmax) *h = Hmax;
  396.     if (*v < Vmin) *v = Vmin;
  397.     if (*v > Vmax) *v = Vmax;
  398. }
  399.  
  400. /*------------------------------------------------------------------*/
  401. init_full() {
  402.  
  403.     /* RANGES OF PLOTTING AREA ON PAPER */
  404.  
  405.     Hmin = 0;
  406.     Hmax = 2000;    /* 200/INCH: 10 INCHES */
  407.  
  408.     Vmin = 0;
  409.     Vmax = 1480;    /* 7.5 INCHES LESS 3-HOLE PUNCH MARGIN */
  410.  
  411.     /* RANGES OF VARIABLES TO BE PLOTTED: X IS CHANNEL, Y IS CELL COUNT */
  412.  
  413.     Ymin = 0;
  414.  
  415.     /* SIZES OF CHARACTERS FOR LABELS AND NUMERIC SCALING */
  416.     
  417.     Lsize = LABEL;
  418.     Nsize = SCALE;
  419. }
  420. /*------------------------------------------------------------------*/
  421. init_quarter() {
  422.  
  423.     /* HALF SIZE PLOT: 2000/2 = 1000; 1480/2 = 740.
  424.     ALLOWING A 30 UNIT MARGIN BETWEEN QUARTERS SUBTRACTS 15 FROM EACH.
  425.     ORIGIN MUST BE SET PROPERLY ELSEWHERE. */
  426.  
  427.     Hmin = 0;
  428.     Hmax = 985;
  429.     Vmin = 0;
  430.     Vmax = 725;
  431.  
  432.     Ymin = 0;
  433.     Lsize = Nsize = 1;
  434. }
  435. /*------------------------------------------------------------------*/
  436. init_calcs() {
  437.  
  438.     itof(Hmin_f,Hmin);
  439.     if (Verbose) fprintf(STDERR,"\nHmin_f: %f\n",Hmin_f);
  440.     Hdel = Hmax - Hmin;
  441.  
  442.     itof(Vmin_f,Vmin);
  443.     if (Verbose) fprintf(STDERR,"Vmin_f: %f\n",Vmin_f);
  444.     Vdel = Vmax - Vmin;
  445.  
  446.     itof(Xmin_f,Xmin);
  447.     if (Verbose) fprintf(STDERR,"Xmin_f: %f\n",Xmin_f);
  448.     Xdel = Xmax - Xmin;
  449.  
  450.     itof(Ymin_f,Ymin);
  451.     if (Verbose) fprintf(STDERR,"Ymin_f: %f\n",Ymin_f);
  452.     Ydel = Ymax - Ymin;
  453.  
  454.     fpdiv(Hfact_f,itof(F2,Hdel),itof(F3,Xdel));
  455.     if (Verbose) fprintf(STDERR,"Hfact_f: %f\n",Hfact_f);
  456.     fpdiv(Vfact_f,itof(F2,Vdel),itof(F3,Ydel));
  457.     if (Verbose) fprintf(STDERR,"Vfact_f: %f\n",Vfact_f);
  458.  
  459. }
  460. /*------------------------------------------------------------------*/
  461. vlabel(label,left_margin)
  462.     char *label;
  463.     int left_margin;
  464.     {
  465.     int h, v;
  466.     v = Vmin;
  467.     h = Hmin - left_margin + Cheight[Lsize];
  468.     pen_up();
  469.     pen_to(h, v);
  470.     Cvect = VERTICAL;
  471.     center(label, Vmax);
  472. }
  473. /*------------------------------------------------------------------*/
  474. hlabel(label, bottom_margin)
  475.     char *label;
  476.     int bottom_margin;
  477.     {
  478.     int h, v, new_hmin;
  479.     h = Hmin;
  480.     v = Vmin - bottom_margin;
  481.     pen_up();
  482.     pen_to(h, v);
  483.     Cvect = HORIZONTAL;
  484.     center(label, Hmax);
  485. }
  486. /*------------------------------------------------------------------*/
  487. /* LEAVES PEN AT PRE-LEAD STARTING POSITION PLUS TOP->BOTTOM THICKNESS */
  488. center(s,max)
  489.     char *s;
  490.     int max;
  491.     {
  492.     int h, v;
  493.     int width, lead;
  494.     if (Cvect EQ VERTICAL)
  495.         width = max - Vat;
  496.     else width = max - Hat;
  497.     lead = (width - (strlen(s) * Cwidth[Csize]))/2;
  498.     if (Cvect EQ VERTICAL) {
  499.         h = Hat;
  500.         v = Vat + lead;
  501.     }
  502.     else {
  503.         h = Hat + lead;
  504.         v = Vat;
  505.     }
  506.     pen_up();
  507.     pen_to(h, v);
  508.     textplot(s);
  509.     if (Cvect EQ VERTICAL) Vat -= lead;
  510.     else Hat -= lead;
  511.     pen_up();
  512.     pen_to(Hat, Vat);
  513. }
  514. /*------------------------------------------------------------------*/
  515. /* THE RANGE (max - min) WILL BE SPREAD TO FIT (Vmax - Vmin).
  516. divcnt SPECIFIES THE NUMBER OF SCALED AND TICKMARKED INTERVALS.
  517. IF divcnt IS 0, IT WILL BE SET TO A VALUE BETWEEN 3 AND 5 WITH
  518. ROUND INTERVALS.
  519.  
  520. vector IS THE DIRECTION OF THE AXIS.
  521.  
  522. min AND max ARE IN UNITS OF Y (ORDINATE VARIABLE, NOT PLOTTER INCREMENTS).
  523. */
  524. axis(vector, min, max, divcnt)
  525.     int vector, min, max, divcnt;
  526.     {
  527.     int i, h, v, tickdiv, ticklen, val, valdiv, autodiv;
  528.     char fraw[5];
  529.     if (divcnt) autodiv = NO;
  530.     else autodiv = YES;
  531.     if (autodiv) div_axis(min, max, &valdiv, &divcnt);
  532.     else valdiv = (max - min)/divcnt;
  533.     if (Verbose) fprintf(STDERR,"\ndiv_axis: valdiv = %d, divcnt = %d\n",
  534.         valdiv,divcnt);
  535.  
  536.     if (vector EQ HORIZONTAL) {
  537.         if (autodiv) {
  538.             tickdiv = ftoir(fpmult(F1,itof(F2,valdiv),Hfact_f));
  539.         }
  540.         else tickdiv = Hdel/divcnt;
  541.         ticklen = Vdel/40;
  542.     }
  543.     if (vector EQ VERTICAL) {
  544.         if (autodiv) {
  545.             tickdiv = ftoir(fpmult(F1,itof(F2,valdiv),Vfact_f));
  546.         }
  547.         else tickdiv = Vdel/divcnt;
  548.         ticklen = Hdel/60;
  549.     }
  550.     if (Verbose) fprintf(STDERR,"Tickdiv = %d\n",tickdiv);
  551.     val = min;
  552.     h = Hmin;
  553.     v = Vmin;
  554.     for (i=0; i<= divcnt; i++, val += valdiv) {
  555.         pen_to(h, v);
  556.         axis_scale(vector, val);
  557.         if (val > min AND val < max) tick(vector, ticklen);
  558.         if (vector EQ HORIZONTAL) h += tickdiv;
  559.         else v += tickdiv;
  560.     }
  561. }
  562. /*------------------------------------------------------------------*/
  563. tick(vector, len)
  564.     int vector, len;
  565.     {
  566.     saveat();
  567.     if (vector EQ VERTICAL) line(Plot_thickness,
  568.         'd', Hat + len, Vat);
  569.     else    line(Plot_thickness, 'r', Hat, Vat + len);
  570.     restore();
  571. }
  572. /*------------------------------------------------------------------*/
  573. axis_scale(vector,val)
  574.     int val, vector;
  575.     {
  576.     char sval[11];
  577.     int width;
  578.     saveat();
  579.     sprintf(sval,"%d",val);
  580.     if (vector EQ VERTICAL) pad(sval,'L',4);
  581.     width = Cwidth[Nsize] * strlen(sval);
  582.     pen_up();
  583.     Cvect = HORIZONTAL;
  584.     if (vector EQ HORIZONTAL)
  585.         pen_to(Hat - (width/2), Vat - (Cheight[Nsize] + Cbetlin[Nsize]));
  586.     else pen_to(Hat - ((Cwidth[Nsize]/2) + (strlen(sval) * Cwidth[Nsize])),
  587.         Vat - (Cheight[Nsize]/2) );
  588.     textplot(sval);
  589.     restore();
  590. }
  591. /*------------------------------------------------------------------*/
  592. /*
  593.         *h = Hmin_f + (Hfact_f * (x_f - Xmin_f))
  594.         *v = Vmin_f + (Vfact_f * (y_f - Ymin_f))
  595. */
  596. scalepoint(vector,raw,scaled)
  597.     int vector, *scaled;
  598.     char *raw; /* FLOAT */
  599.     {
  600.     char intercept[5], slope[5], plotmin[5];
  601.     if (vector EQ VERTICAL) {
  602.         fpass(intercept,Vmin_f);
  603.         fpass(slope,Vfact_f);
  604.         fpass(plotmin,Ymin_f);
  605.     }
  606.     else {
  607.         fpass(intercept,Hmin_f);
  608.         fpass(slope,Hfact_f);
  609.         fpass(plotmin,Xmin_f);
  610.     }
  611.     *scaled = ftoir(
  612.         fpadd(
  613.             F1,
  614.             fpmult(
  615.                 F2,
  616.                 fpsub(
  617.                     F3,
  618.                     raw,
  619.                     plotmin),
  620.                 slope),
  621.             intercept)
  622.         );
  623. }
  624. /*------------------------------------------------------------------*/
  625. /* END OF FACSPLOT */
  626. /*------------------------------------------------------------------*/
  627. /*------------------------------------------------------------------*/
  628. /*
  629.     FACSLIB.C:    (source length approx. 6K)
  630.  
  631.         fgetdist(fn)
  632.         read_fp_file()
  633.         readfp(fpcount,point,filep)
  634.         write_fp_file(suffix)
  635.         writefp(fpcount,point,filep)
  636. */
  637. /*------------------------------------------------------------------*/
  638. /* FLOATING POINT (FP) SCHEME FOR BDSC:
  639.  
  640. ORIGINAL (ASCII) DISTRIBUTIONS WILL BE NAMED WITH AN INTEGER.
  641.  
  642. fgetdist() PERFORMS THE FOLLOWING FUNCTIONS ON NEW DISTRIBUTIONS:
  643.  
  644. 1. READS ASCII FILE, CONVERTING IT TO FP IN MEMORY (Memdist[]).
  645.  
  646. 2. CALCULATES DESCRIPTIVE STATISTICS Tot, Av, Max.
  647.  
  648. 3. WRITES DESCRIPTIVE STATISTICS AND FP DISTRIBUTION INTO A FILE
  649. WHOSE NAME IS THE DISTRIBUTION INTEGER PREFIXED WITH "FP" (E. G.
  650. FP07 IF THE ASCII FILE WAS 07).
  651.  
  652. 4. RETURNS INDEX LOCATION (Location) AND POINTER TO ARRAY (Arr)
  653. IN MEMORY.
  654. */
  655. /*------------------------------------------------------------------*/
  656. /* MEMORY STORAGE SCHEME FOR DISTRIBUTIONS:
  657.  
  658. UP TO NDISTS DISTRIBUTIONS OF 255 COUNTS CAN BE STORED IN MEMORY
  659. SIMULTANEOUSLY IN Memdist[][] IN FLOATING POINT REPRESENTATION.
  660.  
  661. WHEN A NEW DISTRIBUTION IS TO BE PUT INTO MEMORY, IT IS PUT INTO
  662. THE FIRST EMPTY SLOT (FOR WHICH THE ARRAY OF DISTRIBUTION NAMES
  663. Dfinmem[][0] EQ NULL).
  664.  
  665. IF ALL SLOTS ARE FULL, IT IS PUT INTO Nexttogo (INITIALIZED TO 1)
  666. AND Nexttogo IS INCREMENTED. THUS, THE OLDEST IS THE NEXT TO GO.
  667. */
  668. /*------------------------------------------------------------------*/
  669. fgetdist(fn)
  670.     char fn[];
  671.     {
  672.     char prod[5], channel[5]; /* FLOAT */
  673.     int i, max, length;
  674.     char *avg, *sum;
  675.  
  676.     /* UPPER fn */
  677.     for (i=0; fn[i]; i++) fn[i] = toupper(fn[i]);
  678.  
  679.     /* SEE IF DISTR IS ALREADY IN MEMORY */
  680.     for (i=1; i<=NDISTS; i++) {
  681.         if ((strcmp(fn,Dfinmem[i])) == 0) {    /* SUCCESS */
  682.             Location = i;
  683.             Arr = Memdist[i];
  684.             if (Verbose) fprintf(STDERR,
  685.                 "%s found in memory location %d.\n",fn,i);
  686.             return(0);
  687.         }
  688.         if (Dfinmem[i][0] == NULL) break;
  689.     }
  690.     if (i > NDISTS) {
  691.         i = Nexttogo++;
  692.         if (Verbose) fprintf(STDERR,
  693.             "Memory full; %s in location %d will be replaced with %s.\n",
  694.             Dfinmem[Location],i,fn);
  695.         if (Nexttogo EQ (NDISTS + 1)) Nexttogo = 1;
  696.     }
  697.     else if(Verbose) fprintf(STDERR,
  698.         "%s will be put in empty memory slot %d.\n",    fn,i);
  699.  
  700.     /* DISTRIBUTION NOT FOUND IN MEMORY; ASSIGN NEW LOCATION */
  701.     Location = i;
  702.     Arr = Memdist[i];
  703.     strcpy(Dfinmem[i],fn);
  704.  
  705.     /* LOOK FOR FP-CONVERTED FILE */
  706.     if (!read_fp_file()) { /* RETURNS ZERO ON SUCCESS */
  707.         return (0);
  708.     }
  709.     /* ATTEMPT TO OPEN ASCII FILE */
  710.     Fpin = fopen(fn,"r-");
  711.     if (Fpin == 0) {
  712.         fprintf(STDERR,"File %s does not exist.\n",fn);
  713.         Dfinmem[Location][0] = NULL;
  714.         return(1);
  715.     }
  716.  
  717.     /* READ ASCII FILE AND GET STATISTICS */ 
  718.     if (Verbose) fprintf(STDERR,
  719.         "Reading %s and converting to floating point.\n",
  720.         fn);
  721.     avg = Av[Location];
  722.     sum = Tot[Location];
  723.     itof(avg,0);
  724.     itof(sum,0);
  725.     max = 0;
  726.     length = 0;
  727.     while((fnnlgets(Buf,Fpin)) NE NULL) {
  728.         length++;
  729.         if (length > DISTLEN) continue;
  730.         ati(&i, Buf);
  731.         max = (i > max)? i: max;
  732.         atof(F1,Buf);
  733.         fpass(Arr+(length*5),F1);
  734.         fpadd(sum,sum,F1);
  735.         fpadd(avg,
  736.             avg,
  737.             fpmult(prod,
  738.                 F1,
  739.                 itof(channel,length))
  740.         );
  741.         if (Verbose AND (length - (50*(length/50)) EQ 0))
  742.             fprintf(STDERR,"%d ",length);
  743.     }
  744.     if (Verbose) fprintf(STDERR,"\nTotal counts read = %d.\n",length);
  745.     else if (length NE DISTLEN) fprintf(STDERR,
  746.         "WARNING: Total counts read = %d.\n",length);
  747.     length = ((length>DISTLEN)? DISTLEN:length);
  748.     if (length < DISTLEN) itof(Arr+((length+1)*5),-1);
  749.     fclose(Fpin);
  750.     fpdiv(avg,avg,sum);
  751.     Condist[Location][0] = NULL;
  752.     fpass(Pos[Location],Fpzero);
  753.     itof(Max[Location], max);
  754.     if (!write_fp_file("")) return(0);
  755.     else {
  756.         fprintf(STDERR,
  757. "Fatal write error in 'write_fp_file()' called from fgetdist()\n");
  758.         exit (0);
  759.     }
  760. }
  761. /*------------------------------------------------------------------*/
  762. /* LOOK FOR FP-CONVERTED FILE; RETURN 0 ON SUCCESS, 1 0N FAILURE */
  763. read_fp_file() {
  764.     char fname[20];
  765.     strcpy(fname,Dfinmem[Location]);
  766.     strcat(fname,".FP");
  767.     Fpin = fopen(fname,"r-");
  768.     if(Fpin EQ NULL) {
  769.         if (Verbose) fprintf(STDERR,"%s does not exist.\n",fname);
  770.         return(1);
  771.     }
  772.     if (Verbose) fprintf(STDERR,"Reading %s.\n",fname);
  773.     readfp(1,Tot[Location],Fpin);
  774.     readfp(1,Av[Location],Fpin);
  775.     readfp(1,Max[Location],Fpin);
  776.     readfp(10,Buf,Fpin); /* FOR FUTURE EXPANSION */
  777.     readfp(3,Condist[Location],Fpin);
  778.     readfp(1,Pos[Location],Fpin);
  779.     readfp(255,Arr+5,Fpin);
  780.     fclose(Fpin);
  781.     return(0);
  782. }
  783. /*------------------------------------------------------------------*/
  784. readfp(fpcount,point,filep)
  785.     char *point;
  786.     int fpcount;
  787.     FILE *filep;
  788.     {
  789.     int i, check;
  790.     while (fpcount--) {
  791.         for (i=1; i<=5; i++) {
  792.             check = rawgetc(filep);
  793.             if (check EQ EOF) {
  794.                 fprintf(STDERR,
  795.                     "Unexpected EOF in readfp() while reading %s\n",
  796.                     Dfinmem[Location]);
  797.                 exit(0);
  798.             }
  799.             *(point++) = check;
  800.         }
  801.     }
  802. }
  803. /*------------------------------------------------------------------*/
  804. write_fp_file(suffix)
  805.     char *suffix;
  806.     {
  807.     char fname[20];
  808.     Arr = Memdist[Location];
  809.     strcpy(fname,Dfinmem[Location]);
  810.     strcat(fname,suffix);
  811.     strcat(fname,".FP");
  812.     if (Verbose) fprintf(STDERR,"Writing %s.\n",fname);
  813.     Fpout = fopen(fname,"w");
  814.     if(Fpout EQ NULL) return(1);
  815.     writefp(1,Tot[Location],Fpout);
  816.     writefp(1,Av[Location],Fpout);
  817.     writefp(1,Max[Location],Fpout);
  818.     writefp(10,Buf,Fpout); /* FOR FUTURE EXPANSION */
  819.     writefp(3,Condist[Location],Fpout);
  820.     writefp(1,Pos[Location],Fpout);
  821.     if (Verbose) fprintf(STDERR,"Written: 4");
  822.     writefp(255,Arr+5,Fpout);
  823.     if (Verbose) fprintf(STDERR," + 255.");
  824.     fclose(Fpout);
  825.     if (Verbose) fprintf(STDERR," Closed.\n");
  826.     return(0);
  827. }
  828.     
  829. /*------------------------------------------------------------------*/
  830. writefp(fpcount,point,filep)
  831.     char *point;
  832.     int fpcount;
  833.     FILE *filep;
  834.     {
  835.     int i, check;
  836.     while (fpcount--) {
  837.         for (i=1; i<=5; i++) {
  838.             check = putc(*(point++),filep);
  839.             if (check EQ EOF) {
  840.                 fprintf(STDERR,
  841. "Write error (disk full?) in writefp() while writing %s\n",
  842.                     Dfinmem[Location]);
  843.                 exit(0);
  844.             }
  845.         }
  846.     }
  847. }
  848. /*------------------------------------------------------------------*/
  849. /* END OF FACSLIB.C */
  850. /*------------------------------------------------------------------*/
  851.  NULL) return(1);
  852.     writefp(1,Tot[Location],Fpout);
  853.     writefp(1,Av[Location],Fpout);
  854.     writefp(1,Max[Location