import java.awt.Rectangle; import java.awt.Color; import java.awt.Point; class Histogramm { public static final int SPACING = 1; public static final int MIN_BAR_WIDTH = 2; public static final int HEIGHT = 480; public static final int LABEL_HEIGHT = 12; public static final int MIN_WIDTH = 640; public static final Color COLD = Color.blue; public static final Color HOT = Color.red; public static void main(String[] args) { if (args.length < 2) { System.err.println("Need at least two arguments"); System.exit(2); } String input = ""; for (int i = 1; i < args.length; i++) input += args[i]; char[] alphabet = args[0].toCharArray(); // We convert to char[] instead of byte[] in order to be unicode aware graph(alphabet, makeRelative(countOccurences(alphabet, input))); // Why can’t we have nice things? Like function composition? } public static double[] makeRelative (int[] counts) { double[] relativeCounts = new double[counts.length]; int max = 0; // I'm sure there's a library function for this but I was too lazy to look for (int c : counts) if (c > max) max = c; for (int i = 0; i < counts.length; i++) relativeCounts[i] = ((double) counts[i]) / max; return relativeCounts; } public static void graph(char[] alphabet, double[] counts) { int minWidth = MIN_BAR_WIDTH * (counts.length) + SPACING * (counts.length - 1); int width = Math.max(minWidth, MIN_WIDTH); int barWidth = (width - SPACING * (counts.length - 1)) / counts.length; GraphicsWindow gw = new GraphicsWindow(width, HEIGHT); gw.setText("Histogramm"); int x = 0; for (int i = 0; i < counts.length; i++) { int height = (int) (counts[i] * HEIGHT); Point corner = new Point(x, HEIGHT - height); Rectangle bar = new Rectangle(corner.x, corner.y, barWidth, height); boolean labelAbove = height <= LABEL_HEIGHT; gw.setColor(color(counts[i])); gw.fill(bar); gw.setColor(labelAbove ? Color.black : Color.white); gw.drawStringAt(String.format("%c", alphabet[i]), new Point(corner.x, corner.y + (labelAbove ? -5 : LABEL_HEIGHT))); x += SPACING + barWidth; } gw.mouseClick(); System.exit(0); } public static Color color(double c) { double r, g, b; r = HOT.getRed() * c + COLD.getRed() * (1 - c); g = HOT.getGreen() * c + COLD.getGreen() * (1 - c); b = HOT.getBlue() * c + COLD.getBlue() * (1 - c); return new Color((int) r, (int) g, (int) b); } public static int[] countOccurences(char[] alphabet, String input) { int[] count = new int[alphabet.length]; for (int i = 0; i < alphabet.length; i++) count[i] = 0; for (char c : input.toCharArray()) for (int i = 0; i < alphabet.length; i++) if (alphabet[i] == c) count[i]++; /* We could skip right to the next input character as soon as we * find a match but this implementation supports multiple occurences * of a char in the alphabet (inefficiently) */ return count; } }