View Javadoc

1   /*
2   * The contents of this file are subject to the BT "ZEUS" Open Source 
3   * Licence (L77741), Version 1.0 (the "Licence"); you may not use this file 
4   * except in compliance with the Licence. You may obtain a copy of the Licence
5   * from $ZEUS_INSTALL/licence.html or alternatively from
6   * http://www.labs.bt.com/projects/agents/zeus/licence.htm
7   * 
8   * Except as stated in Clause 7 of the Licence, software distributed under the
9   * Licence is distributed WITHOUT WARRANTY OF ANY KIND, either express or 
10  * implied. See the Licence for the specific language governing rights and 
11  * limitations under the Licence.
12  * 
13  * The Original Code is within the package zeus.*.
14  * The Initial Developer of the Original Code is British Telecommunications
15  * public limited company, whose registered office is at 81 Newgate Street, 
16  * London, EC1A 7AJ, England. Portions created by British Telecommunications 
17  * public limited company are Copyright 1996-9. All Rights Reserved.
18  * 
19  * THIS NOTICE MUST BE INCLUDED ON ANY COPY OF THIS FILE
20  */
21  
22  
23  
24  package zeus.visualiser.statistics.charts;
25  
26  import java.util.*;
27  import java.awt.*;
28  import zeus.util.*;
29  import zeus.gui.ColorManager;
30  
31  
32  public class Histogram implements DrawObject {
33     protected static final int    TYPE1 = 0;
34     protected static final int    TYPE2 = 1;
35     protected static final double TINY = 1E-6;
36     protected static final int    LEFT = 100;
37     protected static final int    STEP = 5;
38     protected static final int    TICK_SIZE = 10;
39     protected static final int    KEY_DEPTH = 20;
40  
41     protected String title;
42     protected Vector bars = new Vector();
43     protected int x, y = 0;
44     protected FontMetrics fm;
45     protected Font font;
46     protected int    gap = 10;
47     protected double max = 0.0, min = 0.0, sum = 0.0;
48     protected int type = -1;
49     protected boolean[] is_valid;
50     protected String[] keys;
51  
52     class Bar { double value; String label; Color color; double[] values; }
53  
54     public Histogram() {
55     }
56     public Histogram(double[] values, String[] labels, String title) {
57        setData(values,labels,title);
58     }
59  
60     public Histogram(double[][] values, String[] labels, String[] keys,
61                      String title) {
62        setData(values,labels,keys,title);
63     }
64     public void setData(double[] values, String[] labels, String title) {
65        type = TYPE1;
66        this.title = title;
67  
68        int pos = 0;
69        bars.removeAllElements();
70        max = min = sum = 0.0;
71        for(int j=0;j<values.length;j++) {
72           if (Math.abs(values[j]-0.0) > TINY) {
73               max = Math.max(max,values[j]);
74               min = Math.min(min,values[j]);
75               Bar bar = new Bar();
76               bar.value = values[j];
77               bar.label = labels[j];
78               bar.color = ColorManager.getColor(pos++);
79               bars.addElement(bar);
80           }
81        }
82     }
83     public void setData(double[][] values, String[] labels,
84                         String[] keys, String title) {
85        type = TYPE2;
86        this.title = title;
87  
88        bars.removeAllElements();
89        max = min = sum = 0.0;
90        is_valid = new boolean[keys.length];
91        this.keys = new String[keys.length];
92        for( int i = 0; i < keys.length; i++ ) {
93           this.keys[i] = keys[i];
94           is_valid[i] = false;
95        }
96        double s;
97        for( int i = 0; i < values.length; i++ ) {
98           s = 0.0;
99           for( int j = 0; j < values[i].length; j++ ) {
100              if (Math.abs(values[i][j]-0.0) > TINY) {
101                 is_valid[j] = true;
102                 s += values[i][j];
103              }
104          }
105          max = Math.max(max,s);
106          min = Math.min(min,s);
107          if ( Math.abs(s-0.0) > TINY ) {
108             Bar bar = new Bar();
109             bar.values = new double[values[i].length];
110             for( int k = 0; k < bar.values.length; k++ )
111                bar.values[k] = values[i][k];
112             bar.label = labels[i];
113             bars.addElement(bar);
114          }
115       }
116    }
117 
118 
119    public void drawYourSelf(Graphics g) {
120       font = new Font("Arial", Font.BOLD, 14);
121       fm = g.getFontMetrics(font);
122       g.setFont(font);
123       int w  = fm.stringWidth(title);
124       int h  = fm.getHeight();
125       g.drawString(title,(x-w)/2,h);
126 
127       if ( bars.isEmpty() ) return;
128 
129       int mw = 0;
130       Bar bar;
131       font = new Font("Arial", Font.PLAIN, 12);
132       fm = g.getFontMetrics(font);
133       g.setFont(font);
134       for( int i = 0; i < bars.size(); i++ ) {
135          bar = (Bar) bars.elementAt(i);
136          mw = Math.max(mw,fm.stringWidth(bar.label));
137       }
138       mw += 10;
139       int length = (mw+gap)*bars.size();
140 
141       double max_h = min > 0.0 ? max : Math.abs(max-min);
142 
143       int x0 = 0, y0 = 0, x1, y1, x2, y2, xp, yp;
144       switch( type ) {
145          case TYPE1:
146             g.drawLine(LEFT,3*h,LEFT,y-2*h);
147             x0 = LEFT;
148             y0 = (int)(3.0*h + (max/max_h)*(y-5.0*h));
149             x1 = x0 + length;
150             y1 = y0;
151             g.drawLine(x0,y0,x1,y1);
152             y1 = y0;
153             for( int i = 0; i < bars.size(); i++ ) {
154                bar = (Bar) bars.elementAt(i);
155                x1 = x0 + (mw+gap)*i + gap/2;
156                x2 = x1 + (mw+gap) - gap/2;
157                y2 = (int)(y0 - (bar.value/max)*(y0-3.0*h));
158                g.setColor(bar.color);
159                g.fillRect(Math.min(x1,x2),Math.min(y1,y2),
160                           Math.abs(x2-x1),Math.abs(y2-y1));
161 
162                w = fm.stringWidth(bar.label);
163                yp = bar.value > 0.0 ? y1 + h : y1 - h;
164                g.setColor(Color.black);
165                g.drawString(bar.label,x1+(mw+gap-w)/2,yp);
166             }
167             break;
168          case TYPE2:
169             g.drawLine(LEFT,3*h,LEFT,y-2*h);
170             x0 = LEFT;
171             y0 = (int)(3.0*h + (max/max_h)*(y-5.0*h));
172             x1 = x0 + length;
173             y1 = y0;
174             g.drawLine(x0,y0,x1,y1);
175             for( int i = 0; i < bars.size(); i++ ) {
176                bar = (Bar) bars.elementAt(i);
177                x1 = x0 + (mw+gap)*i + gap/2;
178                x2 = x1 + (mw+gap) - gap/2;
179                double yval = 0;
180                y2 = y1 = y0;
181                for( int j = 0; j < bar.values.length; j++ ) {
182                   yval += bar.values[j];
183                   y1 = y2;
184                   y2 = (int)(y0 - (yval/max)*(y0-3.0*h));
185                   g.setColor(ColorManager.getColor(j));
186                   g.fillRect(Math.min(x1,x2),Math.min(y1,y2),
187                              Math.abs(x2-x1),Math.abs(y2-y1));
188                }
189                w = fm.stringWidth(bar.label);
190                yp = yval > 0.0 ? y0 + h : y0 - h;
191                g.setColor(Color.black);
192                g.drawString(bar.label,x1+(mw+gap-w)/2,yp);
193             }
194             break;
195          default:
196             return;
197       }
198       // draw y-scale
199       double v, dv;
200       dv = (max/STEP);
201       dv = ((int)(dv+0.51) == 0) ? dv : (double)((int)(dv+0.51));
202       int step = (int)((y0-3.0*h)*dv/max);
203       g.setColor(Color.black);
204       v = 0.0;
205       xp = x0; yp = y0;
206       while( v-TINY <= max ) {
207          String yval = Double.toString(v);
208          yval = Misc.decimalPlaces(yval,2);
209          g.drawLine(xp,yp,xp-TICK_SIZE,yp);
210          w = fm.stringWidth(yval);
211          g.drawString(yval,xp-TICK_SIZE-w-5,yp);
212          v += dv;
213          yp -= step;
214       }
215       if ( min < 0.0 ) {
216          v = -dv;
217          xp = x0; yp = y0 + step;
218          while( v > min ) {
219             String yval = Double.toString(v);
220             yval = Misc.decimalPlaces(yval,2);
221             g.drawLine(xp,yp,xp-TICK_SIZE,yp);
222             w = fm.stringWidth(yval);
223             g.drawString(yval,xp-TICK_SIZE-w-5,yp);
224             v -= dv;
225             yp += step;
226          }
227       }
228       // add key
229       if ( type == TYPE2 ) {
230          x1 = x0 + length + LEFT; y1 = 3*h;
231          h = fm.getHeight();
232          int dh = Math.max(h+10,KEY_DEPTH);
233          g.setColor(Color.black);
234          g.drawString("Key",x1,y1);
235          for( int i = 0; i < keys.length; i++ ) {
236             if ( is_valid[i] ) {
237                y1 += dh;
238                g.setColor(ColorManager.getColor(i));
239                g.fillRect(x1,y1,dh-3,dh-3);
240                g.setColor(Color.black);
241                g.drawString(keys[i],x1+dh,y1+(dh-3)/2);
242             }
243          }
244       }
245    }
246 
247    public void setXY(int xc, int yc) {
248       x = xc; y = yc;
249    }
250 }