/* * PyramidCanvas.java * * --Copyright notice-- * * Copyright (c) Andy Evans. * http://www.geog.leeds.ac.uk/people/a.evans/ * This software is licensed under 'The Artistic License' which can be found at * the Open Source Initiative website at... * http://www.opensource.org/licenses/artistic-license.php * Please note that the optional Clause 8 does not apply to this code. * * The Standard Version source code, and associated documentation can be found at... * Evans, A.J. (2001) 'PyramidGraph' Centre for Computational Geography * [online] http://www.ccg.leeds.ac.uk/software/pyramidgraph/ * If you happen to use this code on a project and fancy referencing it, * that would be great. * * --End of Copyright notice-- * */ import java.awt.*; /** * This class implements a pryramid graph.

* To use one of these objects, call its constructor (with or without a * background colour), then call its setUp method. The two are separated * so you can put something on the screen without waiting to read in the * data. * @version 1.2 * @author Andrew Evans **/ public class PyramidCanvas extends Canvas { private double[][][] values = null; // Holds values. private String[][] columnText = null; // Holds bar labels. Only use first set at present. private String[][] rowText = null; // Holds scrollbar labels. Only use first set at present. private int barHeight; // Holds the vertical size of the bars. private int width; // Total width to draw in. private int height; // Total height to draw in. private int value; // Number of dataset (row) in files to draw. private int heightIncrement; // Vertical distance between bars. private int widthIncrement; // Horizontal distance between center of graphs. private double scale; // Scale factor for drawing axes and rescaling values. private int numberOfFiles; // Number of files / graphs to display. private int numberOfBars; // Number of bars in each dataset. private double max; // Max value for the data, used for drawing scales and rescaling. private double min; // Min value for the data, used for drawing scales and rescaling. private int widthStart = 0; // Point at which we can start drawing without going over bar labels. private int maxWidth = 0; // Width of max value, used for spacing axis values. private int zeroWidth = 0; // Width of zero figure, used for spacing axis values. private int labelWidth = 0; // Width of last label, used for spacing scrollbar labels. private String prefix = null; // Prefix for the current label. private int prefixAndLabelWidth = 0; // Width of prefix plus first label, used for spacing scrollbar labels. private Color[] colours = null; // Holds the colours for each dataset. private Color foreground = null; // Holds the colours for the text and lines. private Color background = null; // Holds the background colour. /** * Default constructor.

* Does nothing. **/ public PyramidCanvas() { } /** * Constructor taking in a background colour.

* Just sets up a blank square with the background colour. **/ public PyramidCanvas(Color bg) { setBackground(bg); } /** * This method sets up the graph with data.

* @param vals - the values to print [file][rows][columns]. * @param clabels - the labels for the bars (columns) in a file. * @param rlabels - the labels for each dataset (row) in a file. * @param px - the prefix for the current label. * @param co - array of Colors, one for each file / set of boxes. * @param fg - foreground Color. * @param bg - background Color. * @param bheight - height of bars. * @param mx - max value for the data, used for drawing scales and rescaling. Should not be less than the largest number shown. * @param mn - min value for the data, used for drawing scales and rescaling. Should not be less than the smallest number shown. * @param ws - width of largest bar label, used for spacing left side. * @param mw - width of max value, used for spacing axis values. * @param zw - width of zero figure, used for spacing axis values. * @param lw - width of last label, used for spacing scrollbar labels. * @param pw - width of prefix plus first label, used for spacing scrollbar labels. **/ public void setUp(double[][][] vals, String[][] clabels, String[][] rlabels, String px, Color[] co, Color fg, Color bg, int bheight, double mx, double mn, int ws, int mw, int zw, int lw, int pw) { values = vals; // Holds values. columnText = clabels; // Holds bar labels. Only use first set at present. rowText = rlabels; // Holds scrollbar labels. Only use first set at present. barHeight = bheight; // Holds the vertical size of the bars. colours = co; // Holds the colours for each dataset. foreground = fg; // Holds the colours for the text and lines. background = bg; // Holds the background colour. labelWidth = lw; // Width of last label, used for spacing scrollbar labels. max = mx; // Max value for the data, used for drawing scales and rescaling. min = mn; // Min value for the data, used for drawing scales and rescaling. maxWidth = mw; // Width of max value, used for spacing axis values. zeroWidth = zw; // Width of zero figure, used for spacing axis values. prefix = px; // Prefix for the current label. prefixAndLabelWidth = pw; // Width of prefix plus first label, used for spacing scrollbar labels. numberOfBars = vals[0][0].length; // Number of bars to display. numberOfFiles = vals.length; // Number of files to display. widthStart = ws + 5; // Point at which we can start drawing without going over bar labels. width = this.getSize().width - widthStart - 20; // Width available to draw bars. height = this.getSize().height - barHeight - 50; // Height available to draw bars. heightIncrement = (height / numberOfBars); // Distance between bars. widthIncrement = (width - ((numberOfFiles) * 10)) / numberOfFiles; // Distance between centers of graphs. scale = widthIncrement / max - min; // Scaling factor given width to work with. value = 0; // Starting value (display first dataset in files). setBackground(background); repaint(); } /** * This method sets the dataset to draw.

* It should be called with a row number from the files to draw. **/ public void setValue(int i) { value = i; } /** * This method calls paint with a Graphics object.

* It's been overridden to prevent repaint flicker. **/ public void update() { paint(this.getGraphics()); } /** * This method paints the graphs.

* For each file it draws the boxes and an axis, using the max value * taken from all the files. **/ public void paint(Graphics g) { // Set the colour, just incase. g.setColor(foreground); // Draw the bar labels using the first file's first row. for (int i = 1; i < numberOfBars + 1; i++) { g.drawString(columnText[0][i], 2, height - ((i - 1) * heightIncrement) - heightIncrement + (barHeight / 2)); } // Draw the labels for the scrollbar. In order these are the minimum (first data row // label from first file), the maximum (last data row label from first file), and the // current dataset label with any prefix set by the developer. g.drawString(rowText[0][0], 2, getSize().height); g.drawString(rowText[0][rowText[0].length - 1], getSize().width - labelWidth, getSize().height); g.drawString(prefix + rowText[0][value], (getSize().width / 2) - (prefixAndLabelWidth / 2), getSize().height); // Run through the files and draw the graphs. for (int i = 0; i < numberOfFiles; i++) { // Calculate the centerpoint for each graph. Note that pairs of // graphs need to come out with the same center, so odd and even numbered // graphs are handled differently to give this behaviour. int center = (i%2 == 0) ? ((i + 1) * widthIncrement) + widthStart + (i * 10) : (i * widthIncrement) + widthStart + ((i - 1) * 10); // Run through the bars we want to draw. for (int j = 0; j < numberOfBars; j++) { // Draw a filled rectangle of the appropriate colour, then a foreground // colour border. Note that we want even rectangles to go left of // the center, and odd ones to the right. if (i%2 == 0) { g.setColor(colours[i]); g.fillRect(center - (int)((values[i][value][j] - min)*scale), height - (j * heightIncrement) - heightIncrement, (int)((values[i][value][j] - min)*scale), barHeight); g.setColor(foreground); g.drawRect(center - (int)((values[i][value][j] - min)*scale), height - (j * heightIncrement) - heightIncrement, (int)((values[i][value][j] - min)*scale), barHeight); } else { g.setColor(colours[i]); g.fillRect(center , height - (j * heightIncrement) - heightIncrement, (int)((values[i][value][j] - min)*scale), barHeight); g.setColor(foreground); g.drawRect(center , height - (j * heightIncrement) - heightIncrement, (int)((values[i][value][j] - min)*scale), barHeight); } } // End running through bars. // Now draw the axis for the graph. First the axis itself, then the tick mark, // then the axis label. Again, left and right graphs are handled separately. if (i%2 == 0) { g.drawLine(center, height , center - (int)((max - min) * scale), height ); g.drawLine(center - (int)((max - min) * scale), height , center - (int)((max - min) * scale), height - 2); g.drawString(Double.toString(max), center - (int)((max - min) * scale), height + 13); } else { g.drawLine(center, height, center + (int)((max - min) * scale), height); g.drawLine(center + (int)((max - min) * scale), height, center + (int)((max - min) * scale), height - 2); g.drawString(Double.toString(max), center + (int)((max - min) * scale) - maxWidth, height + 13); } // Finally draw the central tickmark, and, if an odd numbered file, // the central label. g.drawLine(center, height, center, height - 2); if (i%2 == 0) g.drawString(Double.toString(min), center - (zeroWidth / 2), height + 13); } // End running through files. } // End of paint(Graphics g). // End of PyramidCanvas. }