package nmrsvd; import java.awt.*; import javax.swing.*; //for JPanel public class Graph extends JPanel{ //JPanel instead of Frame /* add(x, y) Adds a point to a list. Expects points to come in x-order. Graph() Compulsory call Graph(graphTitle, xAxisTitle, yAxisTitle) Version with labelling options. Use empty strings if not all titles applicable nextGraph() Starts a new graph on the same axes. One showGraph call can be used for all the graphs. setColor(int 0 to 3) Choice of black, magenta, blue, red (constants are available instead of numbers) setSymbol(boolean) Deduced from the colour (Convenient if colours are being set) setSymbol(int 0 to 3) circle, upside down triangle, triangle, square (Used if colours are not being set) setLine(boolean) Normally on, can be turned off (Remember to turn it on again for the next line) setTitle(String) Will appear on a key alongside the symbol and/or in the chosen colour showGraph() Plot the data curves */ private String xAxisTitle, yAxisTitle, graphTitle; private boolean keys; public void Graph() { /* the simple constructor */ initializeGraph(); graphTitle = ""; xAxisTitle = ""; yAxisTitle = ""; } public void Graph(String g, String x, String y) { /* the alternative consructor with axes abd titles */ initializeGraph(); graphTitle = g; xAxisTitle = x; yAxisTitle = y; } private class Dataset { /* Simple class for recording basic info about a set of points. Allows more than one graph to be drawn on an axis. All initialisation done in nextGraph. */ int count, plotType; String title; boolean colorRequired, symbolRequired, titleRequired, lineRequired; } private ListGentle points; private ListGentle datasets; private void initializeGraph () { datasets = new ListGentle (); nextGraph(); points = new ListGentle (); xMax = yMax = Double.MIN_VALUE; xMin = yMin = Double.MAX_VALUE; keys = false; // setSize(640, 480); // super.setTitle("Graph"); // addWindowListener(new WindowAdapter(){ // public void windowClosing(WindowEvent e){ // dispose(); // } // }); } public void nextGraph () { Dataset d = new Dataset (); d.count = 0; d.plotType = black; d.title = ""; d.symbolRequired = false; d.colorRequired = false; d.titleRequired = false; d.lineRequired = true; datasets.add (d); } public void setColor (int c) { ((Dataset) datasets.current()).colorRequired = true; ((Dataset) datasets.current()).plotType = c; } public void setSymbol (boolean b) { ((Dataset) datasets.current()).symbolRequired = b; } public void setSymbol (int c) { ((Dataset) datasets.current()).symbolRequired = true; ((Dataset) datasets.current()).plotType = c; } public void setTitle (String s) { ((Dataset) datasets.current()).titleRequired = true; ((Dataset) datasets.current()).title = s; keys = true; } public void setLine (boolean b) { ((Dataset) datasets.current()).lineRequired = b; if (b==false) ((Dataset) datasets.current()).symbolRequired = true; } public void add (double x, double y) { points.add (new Point (x,y)); ((Dataset)datasets.current()).count++; if (x > xMax) xMax = x; if (x < xMin) xMin = x; if (y > yMax) yMax = y; if (y < yMin) yMin = y; } public void showGraph () { repaint(); setVisible(true); } private class Point { /* simple class for an x,y coordinate */ double xCoord, yCoord; Point (double x, double y) { xCoord = x; yCoord = y; } } private void drawTitles (Graphics g) { Dataset d; int x = xBorder; //legende int y = getHeight()-yBorder/2; //legende datasets.reset(); boolean lastset = datasets.eol(); while (!lastset) { d = (Dataset) datasets.current(); if (d.colorRequired) changeColor(g, d.plotType); if (d.symbolRequired) { drawSymbol(g, d.plotType, x, y-cs); x += 4*cs; } g.drawString(d.title, x, y); x += g.getFontMetrics().stringWidth(d.title)+20; lastset = datasets.eol(); if (!lastset) datasets.succ(); } g.setColor(Color.black); } private void drawAxes (Graphics g) { Font plain = g.getFont(); Font small = new Font(plain.getFamily(), Font.PLAIN,10); Font bold = new Font(plain.getFamily(), Font.BOLD,14); g.drawLine(xBorder-5, yOrigin, xAxisLength+xBorder+5, yOrigin); //axe x g.drawLine(xOrigin, yBorder-5, xOrigin, yAxisLength+yBorder+5); //axe y g.drawString(xAxisTitle, getWidth()-g.getFontMetrics().stringWidth(xAxisTitle)-xBorder/2, yOrigin-5); //"x" g.drawString(yAxisTitle, xOrigin-g.getFontMetrics().stringWidth(yAxisTitle)/2, yBorder-8); //"y" g.setFont(bold); g.drawString(graphTitle, (getWidth()-g.getFontMetrics().stringWidth(graphTitle))/2, yBorder/2); //titre g.setFont(plain); if (keys) drawTitles(g); // Tick and Label the four min/max points only int scaleXMin = scaleX(xMin); int scaleXMax = scaleX(xMax); int scaleYMin = scaleY(yMin); int scaleYMax = scaleY(yMax); //tick yMax: g.drawLine(xOrigin-5, scaleYMax, xOrigin+5, scaleYMax); //tick yMin: g.drawLine(xOrigin-5, scaleYMin, xOrigin+5, scaleYMin); //tick xMax: g.drawLine(scaleXMax, yOrigin+5, scaleXMax, yOrigin); //tick xMin: g.drawLine(scaleXMin, yOrigin+5, scaleXMin, yOrigin); g.setFont(small); //xMin: g.drawString(Double.toString(xMin),scaleXMin-10,yOrigin+15); //xMax: g.drawString(Double.toString(xMax),scaleXMax-10,yOrigin+15); //yMin: g.drawString(Double.toString(Math.round(100*yMin)/100.0), xOrigin-35, scaleYMin+4); //yMax: g.drawString(Double.toString(Math.round(100*yMax)/100.0), xOrigin-35, scaleYMax+4); g.setFont(plain); } private double xSpread, ySpread, xMin, xMax, yMin, yMax; private int xAxisLength, yAxisLength, xOrigin, yOrigin; private int xBorder, yBorder; public void paint (Graphics g) { super.paint(g); // for JComponent and fitting procedure ******************** // calculate length of axes from window size minus a border of 20 xBorder = 40; yBorder = 80; xAxisLength = (int) getWidth() - 2*xBorder; yAxisLength = (int) getHeight() - 2*yBorder; // calculate value spreads from mins and maxs // which have been recorded as we go xSpread = xMax - xMin; ySpread = yMax - yMin; if (xMin > 0) xOrigin = scaleX(xMin); else xOrigin = scaleX(0); if (yMin > 0) yOrigin = scaleY(yMin); else yOrigin = scaleY(0); drawAxes(g); plotGraphs(g); } private int scaleX(double x) { return (int) ((x-xMin) / xSpread*xAxisLength) + xBorder ; } private int scaleY(double y) { return (int) (yAxisLength - ((y-yMin) / ySpread*yAxisLength)) + yBorder; } private void changeColor(Graphics g, int c) { switch (c) { case black : {g.setColor(Color.black); break;} case magenta : {g.setColor(Color.magenta); break;} case blue : {g.setColor(Color.blue); break;} case red : {g.setColor(Color.red); break;} } } private static final int cs = 3; // pixel size of a symbol private void drawSymbol (Graphics g, int sy, int x, int y) { switch (sy) { case black : {g.drawOval (x-cs, y-cs, 2*cs, 2*cs); break;} case magenta : {g.drawPolygon (trix(x),uptriy(y), 3); break;} case blue : {g.drawPolygon (trix(x),triy(y), 3); break;} case red : {g.drawRect (x-cs, y-cs, 2*cs, 2*cs); break;} } } private void plotGraphs (Graphics g) { Point p, q; int x1, y1, x2, y2; Dataset d; boolean lastset; Color c; // Loop through each dataset datasets.reset(); /* The points are in one big list, split by the counts recorded in each dataset */ points.reset(); lastset = datasets.eol(); do { d = (Dataset) datasets.current(); if (d.colorRequired) changeColor(g, d.plotType); // Start with the first point in the list for this graph p = (Point) points.current(); x1 = scaleX(p.xCoord); y1 = scaleY(p.yCoord); if (d.symbolRequired) drawSymbol(g, d.plotType, x1, y1); // Loop through the points as stored in the list for (int i=1; i