package org.freehep.math.minuit; import java.util.List; /** MnPlot produces a text-screen graphical output of (x,y) points. E.g. * from Scan or Contours. * @version $Id: MnPlot.java 8584 2006-08-10 23:06:37Z duns $ */ public class MnPlot { public MnPlot() { this(80,30); } public MnPlot(int width, int length) { thePageWidth = width; thePageLength = length; if(thePageWidth > 120) thePageWidth = 120; if(thePageLength > 56) thePageLength = 56; } public void plot(List<Point> points) { double[] x = new double[points.size()]; double[] y = new double[points.size()]; StringBuffer chpt = new StringBuffer(points.size()); int i = 0; for(Point ipoint : points) { x[i] = ipoint.first; y[i] = ipoint.second; chpt.append('*'); i++; } mnplot(x, y, chpt, points.size(), width(), length()); } public void plot(double xmin, double ymin, List<Point> points) { double[] x = new double[points.size()+2]; x[0] = xmin; x[1] = xmin; double[] y = new double[points.size()+2]; y[0] = ymin; y[1] = ymin; StringBuffer chpt = new StringBuffer(points.size()+2); chpt.append(' '); chpt.append('X'); int i = 2; for(Point ipoint : points) { x[i] = ipoint.first; y[i] = ipoint.second; chpt.append('*'); i++; } mnplot(x, y, chpt, points.size()+2, width(), length()); } int width() { return thePageWidth; } int length() { return thePageLength; } private int thePageWidth; private int thePageLength; private void mnplot(double[] xpt, double[] ypt, StringBuffer chpt, int nxypt, int npagwd, int npagln) { //*-*-*-*Plots points in array xypt onto one page with labelled axes*-*-*-*-* //*-* =========================================================== //*-* NXYPT is the number of points to be plotted //*-* XPT(I) = x-coord. of ith point //*-* YPT(I) = y-coord. of ith point //*-* CHPT(I) = character to be plotted at this position //*-* the input point arrays XPT, YPT, CHPT are destroyed. //*-* //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* /* Local variables */ double xmin, ymin, xmax, ymax, savx, savy, yprt; double bwidx, bwidy, xbest, ybest, ax, ay, bx, by; double[] xvalus = new double[12]; double any, dxx, dyy; int iten, i, j, k, maxnx, maxny, iquit, ni, linodd; int nxbest, nybest, km1, ibk, isp1, nx, ny, ks, ix; boolean overpr; StringBuffer cline = new StringBuffer(npagwd); for (int ii=0; ii<npagwd; ii++) cline.append(' '); char chsav, chbest; /* Function Body */ //*-* Computing MIN maxnx = npagwd-20 < 100 ? npagwd-20 : 100; if (maxnx < 10) maxnx = 10; maxny = npagln; if (maxny < 10) maxny = 10; if (nxypt <= 1) return; xbest = xpt[0]; ybest = ypt[0]; chbest = chpt.charAt(0); //*-*- order the points by decreasing y km1 = nxypt - 1; for (i = 1; i <= km1; ++i) { iquit = 0; ni = nxypt - i; for (j = 1; j <= ni; ++j) { if (ypt[j-1] > ypt[j]) continue; savx = xpt[j-1]; xpt[j-1] = xpt[j]; xpt[j] = savx; savy = ypt[j-1]; ypt[j-1] = ypt[j]; ypt[j] = savy; chsav = chpt.charAt(j-1); chpt.setCharAt(j-1,chpt.charAt(j)); chpt.setCharAt(j,chsav); iquit = 1; } if (iquit == 0) break; } //*-*- find extreme values xmax = xpt[0]; xmin = xmax; for (i = 1; i <= nxypt; ++i) { if (xpt[i-1] > xmax) xmax = xpt[i-1]; if (xpt[i-1] < xmin) xmin = xpt[i-1]; } dxx = (xmax - xmin)*.001; xmax += dxx; xmin -= dxx; mnbins(xmin, xmax, maxnx); xmin = this.bl; xmax = this.bh; nx = this.nb; bwidx = this.bwid; ymax = ypt[0]; ymin = ypt[nxypt-1]; if (ymax == ymin) ymax = ymin + 1; dyy = (ymax - ymin)*.001; ymax += dyy; ymin -= dyy; mnbins(ymin, ymax, maxny); ymin = this.bl; ymax = this.bh; ny = this.nb; bwidy = this.bwid; any = (double) ny; //*-*- if first point is blank, it is an 'origin' if (chbest != ' ') { xbest = (xmax + xmin)*.5; ybest = (ymax + ymin)*.5; } //*-*- find scale constants ax = 1 / bwidx; ay = 1 / bwidy; bx = -ax*xmin + 2; by = -ay*ymin - 2; //*-*- convert points to grid positions for (i = 1; i <= nxypt; ++i) { xpt[i-1] = ax*xpt[i-1] + bx; ypt[i-1] = any - ay*ypt[i-1] - by; } nxbest = (int) (ax*xbest + bx); nybest = (int) (any - ay*ybest - by); //*-*- print the points ny += 2; nx += 2; isp1 = 1; linodd = 1; overpr = false; for (i = 1; i <= ny; ++i) { for (ibk = 1; ibk <= nx; ++ibk) { cline.setCharAt(ibk-1,' '); } // cline.setCharAt(nx,'\0'); // cline.setCharAt(nx+1,'\0'); cline.setCharAt(0,'.'); cline.setCharAt(nx-1,'.'); cline.setCharAt(nxbest-1,'.'); if (i == 1 || i == nybest || i == ny) { for (j = 1; j <= nx; ++j) { cline.setCharAt(j-1,'.'); } } yprt = ymax - (i-1.)*bwidy; boolean isplset = false; if (isp1 <= nxypt) { //*-*- find the points to be plotted on this line for (k = isp1; k <= nxypt; ++k) { ks = (int) ypt[k-1]; if (ks > i) { isp1 = k; isplset = true; break; } ix = (int) xpt[k-1]; if (cline.charAt(ix-1) != '.' && cline.charAt(ix-1) != ' ') { if (cline.charAt(ix-1) == chpt.charAt(k-1)) continue; overpr = true; //*-*- OVERPR is true if one or more positions contains more than //*-*- one point cline.setCharAt(ix-1,'&'); continue; } cline.setCharAt(ix-1,chpt.charAt(k-1)); } if (!isplset) isp1 = nxypt + 1; } if (linodd != 1 && i != ny) { linodd = 1; System.out.printf(" %s",cline.substring(0,60)); } else { System.out.printf(" %14.7g ..%s",yprt,cline.substring(0,60)); linodd = 0; } System.out.println(); } //*-*- print labels on x-axis every ten columns for (ibk = 1; ibk <= nx; ++ibk) { cline.setCharAt(ibk-1,' '); if (ibk % 10 == 1) cline.setCharAt(ibk-1,'/'); } System.out.printf(" %s",cline); System.out.printf("\n"); for (ibk = 1; ibk <= 12; ++ibk) { xvalus[ibk-1] = xmin + (ibk-1.)*10*bwidx; } System.out.printf(" "); iten = (nx + 9) / 10; for (ibk = 1; ibk <= iten; ++ibk) { System.out.printf(" %9.4g", xvalus[ibk-1]); } System.out.printf("\n"); if (overpr) { String chmess = " Overprint character is &"; System.out.printf(" ONE COLUMN=%13.7g%s",bwidx,chmess); } else { String chmess = " "; System.out.printf(" ONE COLUMN=%13.7g%s",bwidx,chmess); } System.out.println(); } private void mnbins(double a1, double a2, int naa) { //*-*-*-*-*-*-*-*-*-*-*Compute reasonable histogram intervals*-*-*-*-*-*-*-*-* //*-* ====================================== //*-* Function TO DETERMINE REASONABLE HISTOGRAM INTERVALS //*-* GIVEN ABSOLUTE UPPER AND LOWER BOUNDS A1 AND A2 //*-* AND DESIRED MAXIMUM NUMBER OF BINS NAA //*-* PROGRAM MAKES REASONABLE BINNING FROM BL TO BH OF WIDTH BWID //*-* F. JAMES, AUGUST, 1974 , stolen for Minuit, 1988 //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* /* Local variables */ double awid,ah, al, sigfig, sigrnd, alb; int kwid, lwid, na=0, log_; al = a1 < a2 ? a1 : a2; ah = a1 > a2 ? a1 : a2; if (al == ah) ah = al + 1; //*-*- IF NAA .EQ. -1 , PROGRAM USES BWID INPUT FROM CALLING ROUTINE boolean skip = (naa == -1 && bwid > 0); if (!skip) { na = naa - 1; if (na < 1) na = 1; } for (;;) { if (!skip) { //*-*- GET NOMINAL BIN WIDTH IN EXPON FORM awid = (ah-al) / ((double) na); log_ = (int) (Math.log10(awid)); if (awid <= 1) --log_; sigfig = awid*Math.pow(10, -log_); //*-*- ROUND MANTISSA UP TO 2, 2.5, 5, OR 10 if (sigfig <= 2) { sigrnd = 2; } else if (sigfig <= 2.5) { sigrnd = 2.5; } else if (sigfig <= 5) { sigrnd = 5; } else { sigrnd = 1; ++log_; } bwid = sigrnd*Math.pow(10, log_); } alb = al / bwid; lwid = (int) alb; if (alb < 0) --lwid; bl = bwid*((double)lwid); alb = ah / bwid + 1; kwid = (int) alb; if (alb < 0) --kwid; bh = bwid*((double) kwid); nb = kwid - lwid; if (naa <= 5) { if (naa == -1) return; //*-*- REQUEST FOR ONE BIN IS DIFFICULT CASE if (naa > 1 || nb == 1) return; bwid *= 2; nb = 1; return; } if (nb << 1 != naa) return; ++na; skip = false; continue; } } private double bl; private double bh; private int nb; private double bwid; }