summaryrefslogtreecommitdiff
path: root/ws2015/eip/blaetter/05/Histogramm.java
blob: 87e6b4e4f0a5dce92b43097d91dd8b52562dbf76 (plain)
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;
    }
}