1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
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;
}
}
|