import java.awt.*; import java.util.*; import java.io.*; public class Histogram { public static final int WIDTH = 2100; public static final int HEIGHT = 1100; public static final int GUTTER = 200; public static final int Y_AXIS = HEIGHT + GUTTER; public static final int X_AXIS = GUTTER; public static final int TICK_SIZE = 10; public static final Font LABEL_FONT = new Font("monospace", Font.BOLD, 24); public static void main(String[] args) throws FileNotFoundException { DrawingPanel panel = new DrawingPanel(WIDTH + 2 * GUTTER, HEIGHT + 2 * GUTTER); Graphics pen = panel.getGraphics(); drawHistogram(pen); } // Draws a histogram of the exam scores public static void drawHistogram(Graphics pen) throws FileNotFoundException { drawAxes(pen); drawXTicks(pen, 10, 5); drawYTicks(pen, 20, 5); int[] counts = getCounts(); // a different way of getting a filled counts array: // make the array here, and pass it as a parameter by reference. // int[] counts = new int[102]; // fillCounts(counts); // run through the array of counts, and draw a bar for each count System.out.println("Counts : " + Arrays.toString(counts)); for (int i = 0; i < counts.length; i++) { drawBar(pen, i, counts[i]); } } // fills in the array parameter. (this strategy isn't as good as getCounts() // for this specific situation -- it makes more sense to create the array and // return it. however, in other situations, you might have an array you want // modify, and passing it as a parameter, like in this method, is the way to go) public static void fillCounts(int[] scoreCounts) throws FileNotFoundException { Scanner input = new Scanner(new File("18wi-mid-scores.txt")); while (input.hasNextLine()) { String line = input.nextLine(); Scanner tokens = new Scanner(line); int actual = tokens.nextInt(); scoreCounts[actual] = scoreCounts[actual] + 1; } } // creates and returns a count array. the returned array will contain // a count of how many students in each index. the index represents the score public static int[] getCounts() throws FileNotFoundException { int[] counts = new int[102]; // process the data file : build up an array of counts of scores // make an array of size 102 (0 - 101 inclusive) // run through the data file // increment the count inside array for the score at the corresponding index Scanner input = new Scanner(new File("18wi-mid-scores.txt")); while (input.hasNextLine()) { String line = input.nextLine(); Scanner tokens = new Scanner(line); int actual = tokens.nextInt(); counts[actual] = counts[actual] + 1; } return counts; } // Uses the given Graphics to draws a bar at the given score // representing the given count. Assumes max count of 50 for graphing // and a max score of 100 public static void drawBar(Graphics pen, int score, int count) { int maxScore = 100; int barWidth = WIDTH / maxScore; int centering = (barWidth / 2) - 1; int xOffset = barWidth * score - centering; int maxCount = 50; // TODO should use constants to match up with y-ticks on x-axis int yHeight = (int) Math.round( (1.0 * count / maxCount) * HEIGHT + centering ); pen.setColor(Color.GREEN); pen.fillRect(X_AXIS + xOffset, Y_AXIS - yHeight, barWidth - 2, yHeight); } // Use the given Graphics to draw (marks + 1) tick marks, each mark representing // a jump of stepSize units on the x axis. public static void drawXTicks(Graphics pen, int marks, int stepSize) { int textSetback = 70; int textHeight = 18; // somehow related to Font size :( pen.setFont(LABEL_FONT); for (int i = 0; i <= marks; i++) { String label = "" + i * stepSize; int yHeight = i * (HEIGHT / marks); int y = Y_AXIS - yHeight; pen.drawString(label, X_AXIS - textSetback, y + textHeight / 2); pen.drawLine(X_AXIS, y, X_AXIS - TICK_SIZE, y); } } // Use the given Graphics to draw (marks + 1) tick marks, each mark representing // a jump of stepSize units on the y axis. public static void drawYTicks(Graphics pen, int marks, int stepSize) { int textSetback = 50; int textCharWidth = 12; // somehow related to Font size :( pen.setFont(LABEL_FONT); for (int i = 0; i <= marks; i++) { String label = "" + i * stepSize; int xOffset = i * (WIDTH / marks); int x = X_AXIS + xOffset; int labelX = x - label.length() * textCharWidth / 2; pen.drawString(label, labelX, Y_AXIS + textSetback); pen.drawLine(x, Y_AXIS, x, Y_AXIS + TICK_SIZE); } } // Use the given Graphics to draw the axes on the graph public static void drawAxes(Graphics pen) { pen.setColor(Color.BLACK); pen.drawLine(X_AXIS, Y_AXIS, X_AXIS, GUTTER); pen.drawLine(X_AXIS, Y_AXIS, WIDTH + GUTTER, Y_AXIS); } }