1 package edu.psu.geovista.category;
2
3 /***
4 * <p>Title: Studio applications</p>
5 * <p>Description: </p>
6 * <p>Copyright: Copyright (c) 2002</p>
7 * <p>Company: GeoVSITA Center</p>
8 * @author Xiping Dai
9 * @version 1.0
10 */
11
12 import java.lang.*;
13 import java.awt.*;
14 import javax.swing.*;
15 import java.awt.event.*;
16 import java.util.Vector;
17 import edu.psu.geovista.app.scatterplot.*;
18 import edu.psu.geovista.data.ArraySort2D;
19 import edu.psu.geovista.data.StatisticsVectors;
20 import javax.swing.border.*;
21 import javax.swing.BorderFactory;
22
23 public class MultiClassDistributions extends JPanel implements MouseListener, ComponentListener
24 {
25 private static double AXISSPACEPORTION = 1.0/6.0;
26 private static int DEFAULT_HIST_NUM = 20;
27 private static double DELTA = 1;
28 private Color background;
29 private Color foreground;
30 private boolean axisOn = true;
31 private int plotOriginX;
32 private int plotOriginY;
33 private int plotEndX;
34 private int plotEndY;
35 private Vector[] dataVector;
36 private int classNumber;
37 private Vector oneVarData = new Vector();
38 private Vector dataXVector = new Vector();
39 private int displayVarIdx;
40 private double xAxisMin;
41 private double xAxisMax;
42 private double yAxisMin;
43 private double yAxisMax;
44 private double delta;
45 private Vector dataDistributions = new Vector();
46 private Vector exsIntVector = new Vector();
47 private Vector whyIntVector = new Vector();
48 private int nonsamplenum=100;
49 private double[] continuousData;
50 private boolean gauss;
51 private Vector dataGaussians = new Vector();
52 private Vector dataGaussiansInt = new Vector();
53 private JPopupMenu popup;
54 private JCheckBoxMenuItem[] classCheckBox;
55 private int currentCheckBox;
56 //private EventListenerList listenerListAction = new EventListenerList();
57
58 public MultiClassDistributions(){
59 this.setBorder(BorderFactory.createLineBorder(Color.gray));
60 popup = new JPopupMenu();
61 }
62
63 public void setDisplayVariableIndex(int index){
64 this.displayVarIdx = index;
65 this.initialize();
66 this.repaint();
67 }
68
69 public int getDisplayVariableIndex(){
70 return this.displayVarIdx;
71 }
72
73 public void setDataVector(Vector[] dataVector){
74 this.dataVector = dataVector;
75 this.classNumber = this.dataVector.length;
76
77 this.exsIntVector.setSize(this.classNumber);
78
79 this.classCheckBox = new JCheckBoxMenuItem[this.classNumber];
80 for(int i = 0; i < this.classNumber; i ++){
81 this.classCheckBox[i] = new JCheckBoxMenuItem("class" + new Integer(i).toString());
82 this.classCheckBox[i].setName(new Integer(i).toString());
83 this.classCheckBox[i].setSelected(true);
84 this.popup.add(this.classCheckBox[i], i);
85 this.currentCheckBox = i;
86 classCheckBox[i].addActionListener(new ActionListener() {
87
88 /***
89 * put your documentation comment here
90 * @param e
91 */
92 public void actionPerformed (ActionEvent e) {
93 boolean isSelected = classCheckBox[currentCheckBox].isSelected();
94 classCheckBox[currentCheckBox].setSelected(!isSelected);
95 repaint();
96 }
97 });
98 }
99 addMouseListener(this);
100
101 initialize();
102
103 }
104
105 public Vector[] getDataVector(){
106 return this.dataVector;
107 }
108
109 public void setAxisOn (boolean axisOn){
110 this.axisOn = axisOn;
111 }
112
113 public boolean getAxisOn (){
114 return this.axisOn;
115 }
116
117 public void setGaussOn (boolean gauss){
118 this.gauss = gauss;
119 }
120
121 public boolean getGaussOn (){
122 return this.gauss;
123 }
124
125 /***
126 * put your documentation comment here
127 * @param c
128 */
129 public void setBackground (Color c) {
130 if (c == null)
131 return;
132 this.background = c;
133 int colorTotal = c.getRed() + c.getGreen() + c.getBlue();
134 int greyColor = 128 * 3;
135 if (colorTotal < greyColor)
136 this.foreground = Color.white;
137 else
138 this.foreground = Color.black;
139 this.repaint();
140 }
141
142 /*private double[] calculatePDF(double[] data){
143 double[] pdfArray;
144 double[][] dataWithIndex = new double[data.length][2];
145 int len = data.length;
146 pdfArray = new double[len];
147
148 for (int i = 0; i < len; i++) {
149 dataWithIndex[i][0] = data[i];
150 dataWithIndex[i][1] = i;
151 }
152 //now sort
153 ArraySort2D.sortDouble(dataWithIndex,0);
154 //this.pdfArray[0] = dataWithIndex[0][0];
155 //this.pdfArray[len-1] = dataWithIndex[len-1][0];
156 for (int i = 0; i < len; i ++){
157 int numberInDelta = 1;
158 int j = 1;
159 double mean = dataWithIndex[i][0];
160 while ((i != 0)&&(dataWithIndex[i-j][0] > dataWithIndex[i][0] - this.delta)){
161 mean += dataWithIndex[i-j][0];
162 j ++;
163 if (j > i){
164 break;
165 }
166 }
167 numberInDelta += j-1;
168 j = 1;
169 while ((i != len-1)&&(dataWithIndex[i+j][0] < dataWithIndex[i][0] + this.delta)){
170 mean += dataWithIndex[i+j][0];
171 j ++;
172 if ((i+j) == len){
173 break;
174 }
175 }
176 numberInDelta += j-1;
177 if (numberInDelta ==0){
178 pdfArray[i] = 0;
179 }else{
180 mean /= numberInDelta;
181 pdfArray[i] = numberInDelta/this.delta/2/len;
182 }
183 }
184
185 DataArray pdfDataArray = new DataArray(pdfArray);
186 double yMin = ((double[])pdfDataArray.getExtent().clone())[0];
187 double yMax = ((double[])pdfDataArray.getExtent().clone())[1];
188 this.yAxisMin = (this.yAxisMin <= yMin) ? yAxisMin : yMin;
189 this.yAxisMax = (this.yAxisMax >= yMax) ? yAxisMax : yMax;
190 return pdfArray;
191 }*/
192
193 private double[] nonsamplepdf(double[] data, int cl) {
194 int len = data.length;
195 double[][] dataWithIndex = new double[len][2];
196 double[] pdfArray;
197
198 //add index
199 if (dataWithIndex == null || dataWithIndex.length != data.length || dataWithIndex[0].length != 2) {
200 dataWithIndex = new double[data.length][2];
201 }
202 for (int i = 0; i < len; i++) {
203 dataWithIndex[i][0] = data[i];
204 dataWithIndex[i][1] = i;
205 }
206 //now sort
207 ArraySort2D.sortDouble(dataWithIndex,0);
208 //this.pdfArray[0] = dataWithIndex[0][0];
209 //this.pdfArray[len-1] = dataWithIndex[len-1][0];
210
211 double xMin;
212 double xMax;
213 DataArray dataArray;
214
215 dataArray = new DataArray(data);
216 xMin = ((double[])dataArray.getExtent().clone())[0];
217 xMax = ((double[])dataArray.getExtent().clone())[1];
218 this.delta = (xMax - xMin)/20.0;
219
220 int minindex, maxindex;
221 minindex=maxindex=0;
222 double interval=(xMax-xMin)/nonsamplenum;
223 pdfArray=new double[nonsamplenum]; // y
224 double[] continuousData = new double[nonsamplenum]; // x
225 for (int i = 0; i < nonsamplenum; i ++){
226 continuousData[i]=(i+0.5)*interval+xMin;
227 // find minimum
228 while ((dataWithIndex[minindex][0]<continuousData[i]-this.delta)&&minindex<len-1) {
229 minindex+=1;
230 }
231 // find maximum
232 while ((dataWithIndex[maxindex][0]<continuousData[i]+this.delta)&&maxindex<len-1) {
233 maxindex+=1;
234 }
235 if (this.delta != 0){
236 pdfArray[i]=(maxindex-minindex)/(len*this.delta*2.0);
237 }else{
238 pdfArray[i] = 0;
239 }
240 }
241
242 this.dataXVector.add(cl, continuousData.clone());
243
244 DataArray pdfDataArray = new DataArray(pdfArray);
245 double yMin = ((double[])pdfDataArray.getExtent().clone())[0];
246 double yMax = ((double[])pdfDataArray.getExtent().clone())[1];
247 this.yAxisMin = (this.yAxisMin <= yMin) ? yAxisMin : yMin;
248 this.yAxisMax = (this.yAxisMax >= yMax) ? yAxisMax : yMax;
249
250 this.xAxisMin = (this.xAxisMin <= xMin) ? xAxisMin : xMin;
251 this.xAxisMax = (this.xAxisMax >= xMax) ? xAxisMax : xMax;
252
253 if (this.gauss == true){
254
255 double[] dataGaussian = new double[len];
256 double mean = StatisticsVectors.mean(data);
257 //System.out.println("mean " + mean);
258 double variance = 0;
259 if(this.delta != 0){
260 variance = StatisticsVectors.variance(data);
261 }
262 //System.out.println("variance " + variance);
263 for(int i = 0; i < continuousData.length; i ++){
264 if (this.delta != 0){
265 dataGaussian[i] = 1/Math.sqrt(2*Math.PI*variance) * Math.exp(-Math.pow(continuousData[i]-mean, 2)/2/variance);
266 }else{
267 dataGaussian[i] = 0;
268 }
269 }
270 this.dataGaussians.add(cl, dataGaussian.clone());
271 }
272
273 return pdfArray;
274 }
275
276 private void initialize(){
277 this.oneVarData.clear();
278 this.dataDistributions.clear();
279 this.dataXVector.clear();
280
281 for(int i = 0; i < this.classNumber; i ++){
282 int len = this.dataVector[i].size();
283 double[] oneClassData = new double[len];
284 for(int j = 0; j < len; j ++){
285 if (((double[])(this.dataVector[i].get(j))).length <= this.displayVarIdx){
286 return;
287 }
288 oneClassData[j] = ((double[])(this.dataVector[i].get(j)))[this.displayVarIdx];
289 }
290 this.oneVarData.add(oneClassData.clone());
291 }
292
293 this.xAxisMin = 0;
294 this.xAxisMax = 0;
295
296 this.addComponentListener(this);
297
298 this.setBackground(Color.white);
299
300 this.yAxisMin = 0;
301 this.yAxisMax = 0;
302 for (int i = 0; i < this.classNumber; i ++){
303 dataDistributions.add(i, this.nonsamplepdf((double[])this.oneVarData.get(i), i).clone());
304 }
305
306 setupDataforDisplay();
307 this.validate();
308 }
309
310 private void setupDataforDisplay(){
311
312 if (axisOn){
313 plotOriginX = (int)(this.getWidth()*AXISSPACEPORTION);
314 plotOriginY = (int)(this.getHeight()*(1 - AXISSPACEPORTION));
315 plotEndX = (int)(this.getWidth()) - (int)(this.getWidth()*AXISSPACEPORTION/2);
316 plotEndY = (int)(this.getHeight()*AXISSPACEPORTION/2);
317 }else {
318 plotOriginX = 0;
319 plotOriginY = (int)(this.getSize().getHeight() - 2);
320 plotEndX = (int)(this.getSize().getWidth()) - 3;
321 plotEndY = 3;
322 }
323
324 //get positions on screen
325 double scaleX, scaleY;
326 scaleX = getScale(plotOriginX, plotEndX, xAxisMin, xAxisMax);
327 scaleY = getScale(plotOriginY, plotEndY, yAxisMin, yAxisMax);
328
329 this.exsIntVector.clear();
330 this.whyIntVector.clear();
331 this.dataGaussiansInt.clear();
332 //double[] dataX = new double[nonsamplenum];
333 for(int cl = 0; cl < this.classNumber; cl ++){
334 int[] exsInt = new int[nonsamplenum];
335 int[] whyInt = new int[nonsamplenum];
336 exsInt = getValueScreen((double[])dataXVector.get(cl), scaleX, plotOriginX, xAxisMin);
337 whyInt = getValueScreen((double[])this.dataDistributions.get(cl), scaleY, plotOriginY, yAxisMin);
338 this.exsIntVector.add(cl, exsInt.clone());
339 this.whyIntVector.add(cl, whyInt.clone());
340 }
341
342 if (gauss == true){
343 for(int cl = 0; cl < this.classNumber; cl ++){
344 int[] gaussianInt = new int[nonsamplenum];
345 gaussianInt = getValueScreen((double[])this.dataGaussians.get(cl), scaleY, plotOriginY, yAxisMin);
346 this.dataGaussiansInt.add(cl, gaussianInt.clone());
347 }
348 }
349 }
350
351 public void paintComponent (Graphics g) {
352 g.setColor(background);
353 g.fillRect(0, 0, getSize().width, getSize().height);
354 g.setColor(foreground);
355 if (this.axisOn == true){
356 drawAxis(g);
357 }
358 drawPlot(g);
359 }
360
361 private void drawPlot (Graphics g) {
362 for(int cl = 0; cl < this.classNumber; cl ++){
363 //int[] exsInt = (int[])this.exsIntVector.get(cl);
364 //int[] whyInt = (int[])this.whyIntVector.get(cl);
365 if(cl == 0){
366 g.setColor(Color.red);
367 }else if(cl == 1){
368 g.setColor(Color.BLUE);
369 }else if(cl == 2){
370 g.setColor(Color.green);
371 }else if(cl == 3){
372 g.setColor(Color.orange);
373 }else if(cl == 4){
374 g.setColor(Color.darkGray);
375 }
376 if (this.classCheckBox[cl].isSelected() == true){
377 for (int i = 0; i < nonsamplenum; i ++){
378 g.drawOval(((int[])this.exsIntVector.get(cl))[i], ((int[])this.whyIntVector.get(cl))[i], 2, 2);
379 }
380
381 if(gauss == true){
382 int[] gy = (int[])this.dataGaussiansInt.get(cl);
383 for (int i = 0; i < nonsamplenum; i ++){
384 //g.drawOval(((int[])this.exsIntVector.get(cl))[i], gy[i], 2, 2);
385 g.drawPolyline(((int[])this.exsIntVector.get(cl)), gy, this.nonsamplenum);
386 }
387 }
388 g.setColor(foreground);
389 }
390 }
391 }
392
393
394 private void drawAxis (Graphics g) {
395 int plotWidth, plotHeight;
396 plotWidth = (int)this.getSize().getWidth();
397 plotHeight = (int)this.getSize().getHeight();
398 g.setColor(foreground);
399 g.drawLine(plotOriginX, plotEndY, plotOriginX, plotOriginY);
400 g.drawLine(plotOriginX, plotOriginY, plotEndX, plotOriginY);
401 // draw tick bars for scales on Y coordinate
402 int fontSize;
403 if (plotWidth < plotHeight){
404 if (plotWidth < 300){
405 fontSize = 9;
406 } else {
407 fontSize = (int)(plotWidth/32);
408 }
409 }else {
410 if (plotHeight < 300){
411 fontSize = 9;
412 } else {
413 fontSize = (int)(plotHeight/32);
414 }
415 }
416 Font font = new Font("", Font.PLAIN, fontSize);
417 g.setFont(font);
418 //draw the labels on y axis (frequency).
419 /*String scaleStringY;
420 double barNumber = this.pdfDataArray.getTickNumber();
421 double yBarDistance = ((plotOriginY - plotEndY)/barNumber);
422 //System.out.println("drawaxis: "+plotOriginY+" "+plotEndY+" "+yBarDistance+" "+barNumber);
423 for (int i = 0; i <= barNumber; i++) {
424 g.drawLine(plotOriginX - 3, plotEndY + (int)(i*yBarDistance), plotOriginX,
425 plotEndY + (int)(i*yBarDistance));
426 if (Math.abs(this.pdfDataArray.getMajorTick()) <= 1) {
427 scaleStringY = Float.toString((float)(yAxisMax - i*this.pdfDataArray.getMajorTick()));
428 }
429 else {
430 scaleStringY = Integer.toString((int)(yAxisMax - i*this.pdfDataArray.getMajorTick()));
431 }
432 g.drawString(scaleStringY, plotOriginX - (int)(plotWidth*AXISSPACEPORTION/2),
433 plotEndY + (int)(i*yBarDistance + yBarDistance*1/6));
434 }*/
435 //draw the labels on x axis.
436 //First tick.
437 String scaleStringX;
438 g.drawLine(plotOriginX, plotOriginY, plotOriginX, plotOriginY + 3);
439 if (Math.abs(xAxisMin) <= 1) {
440 scaleStringX = Float.toString((float)xAxisMin);
441 } else {
442 scaleStringX = Integer.toString((int)xAxisMin);
443 }
444 g.drawString(scaleStringX, plotOriginX - 3, plotOriginY + (int)(plotHeight*AXISSPACEPORTION/4));
445 //Last tick.
446 g.drawLine(plotEndX, plotOriginY, plotEndX, plotOriginY + 3);
447 if (Math.abs(xAxisMax) <= 1) {
448 scaleStringX = Float.toString((float)xAxisMax);
449 } else {
450 scaleStringX = Integer.toString((int)xAxisMax);
451 }
452 g.drawString(scaleStringX, plotEndX - 8, plotOriginY + (int)(plotHeight*AXISSPACEPORTION/4));
453 font = new Font("", Font.PLAIN, fontSize + 3);
454 g.setFont(font);
455 //draw X axis attribute string
456 //g.drawString(this.variableName, plotOriginX + (plotEndX - plotOriginX)/2 - plotWidth/12,
457 // plotOriginY + plotHeight/6 - 5);
458 //draw Y axis attribute string. Need rotation for drawing the string vertically.
459 Graphics2D g2d = (Graphics2D)g;
460 g2d.rotate(-Math.PI/2, plotOriginX - plotWidth/9, plotOriginY - (plotOriginY
461 - plotEndY)/3);
462 g2d.drawString("Density", plotOriginX - plotWidth/9, plotOriginY - (plotOriginY
463 - plotEndY)/3);
464 g2d.rotate(+Math.PI/2, plotOriginX - plotWidth/9, plotOriginY - (plotOriginY
465 - plotEndY)/3);
466 }
467
468 /***
469 * Calculate scale between real data and integer data for showing up on screen.
470 * @param min
471 * @param max
472 * @param dataMin
473 * @param dataMax
474 * @return scale
475 */
476 private double getScale (int min, int max, double dataMin, double dataMax) {
477 double scale;
478 scale = (max - min)/(dataMax - dataMin);
479 return scale;
480 }
481 /***
482 * Convert the single value to integer value worked on screen.
483 * @param data
484 * @param scale
485 * @param min
486 * @param dataMin
487 * @return valueScreen
488 */
489 private int getValueScreen (double data, double scale, int min, double dataMin) {
490 int valueScreen;
491 if (Double.isNaN(data)) {
492 valueScreen = Integer.MIN_VALUE;
493 }
494 else {
495 valueScreen = (int)((data - dataMin)*scale + min);
496 }
497 return valueScreen;
498 }
499 /***
500 * Convert the numeric values of observations to integer value worked on screen.
501 * @param dataArray
502 * @param scale
503 * @param min
504 * @param dataMin
505 * @return valueScreen
506 */
507 private int[] getValueScreen (double[] dataArray, double scale, int min, double dataMin) {
508 int[] valueScreen = new int[dataArray.length];
509 for (int i = 0; i < dataArray.length; i++) {
510 if (Double.isNaN(dataArray[i])) {
511 valueScreen[i] = Integer.MIN_VALUE;
512 }
513 else {
514 valueScreen[i] = (int)((dataArray[i] - dataMin)*scale + min);
515 }
516 }
517 return valueScreen;
518 }
519
520 public void componentHidden(ComponentEvent e) {
521
522 }
523
524 public void componentMoved(ComponentEvent e) {
525
526 }
527
528 public void componentResized(ComponentEvent e) {
529 this.setupDataforDisplay();
530 this.repaint();
531 }
532
533 public void componentShown(ComponentEvent e) {
534 }
535
536 /***
537 * put your documentation comment here
538 * @param e
539 */
540 private void maybeShowPopup (MouseEvent e) {
541 if (e.isPopupTrigger()) {
542 popup.show(e.getComponent(), e.getX(), e.getY());
543 }
544 }
545
546 public void mouseClicked(MouseEvent e){
547 int count = e.getClickCount();
548 //double click, pop up a detail scatter plot.
549 if (count == 2){ // This is a double-click or triple...
550 MultiClassDistributions detailSP = new MultiClassDistributions();
551 detailSP.setAxisOn(true);
552 detailSP.setBackground(background);
553 detailSP.setGaussOn(true);
554 detailSP.setDisplayVariableIndex(this.displayVarIdx);
555 detailSP.setDataVector(this.dataVector);
556 //detailSP.setElementPosition(dataIndices);
557 //detailSP.setColorArrayForObs(this.colorArrayForObs);
558 //detailSP.setSelectedObservations(selRecords);
559 //detailSP.setSelections(this.selections);
560 JFrame dlgSP = new JFrame("Detailed Distributions");
561 //JDialog dlgSP = new JDialog(dummyFrame, "Detailed Distributions", true);
562 dlgSP.setLocation(300, 300);
563 dlgSP.setSize(300, 300);
564 dlgSP.getContentPane().setLayout(new BorderLayout());
565 dlgSP.getContentPane().add(detailSP, BorderLayout.CENTER);
566 /*detailSP.addActionListener(new ActionListener() {
567
568 /**
569 * put your documentation comment here
570 * @param e
571 */
572 /*public void actionPerformed (ActionEvent e) {
573 //System.out.println("something came from detailed one.");
574 ScatterPlot detailSP = (ScatterPlot)e.getSource();
575 String command = e.getActionCommand();
576 if (command.compareTo(ScatterPlot.COMMAND_POINT_SELECTED) == 0) {
577 //System.out.println("SPMC.plotUnitPanel.actionPerformed(), point selected");
578 //Vector selRecords = detailSP.getSelectedObservations();
579 int[] selections = detailSP.getSelections();
580 // Don't recall the scatterplot which generated the original event
581 //ScatterPlot.this.setSelectedObservations(selRecords);
582 ScatterPlot.this.setSelections(selections);
583 ScatterPlot.this.fireActionPerformed(COMMAND_POINT_SELECTED);
584 }
585 else if(command.compareTo(ScatterPlot.COMMAND_DATARANGE_SET)==0){
586 double[] dataArrayX = detailSP.getXAxisExtents();
587 double[] dataArrayY = detailSP.getYAxisExtents();
588 ScatterPlot.this.setXAxisExtents(dataArrayX);
589 ScatterPlot.this.setYAxisExtents(dataArrayY);
590 fireActionPerformed(COMMAND_DATARANGE_SET);
591 }
592 //System.err.println("Unknown command! = " + command);
593 }
594 });*/
595 dlgSP.show();
596 }
597 }
598
599 public void mousePressed(MouseEvent e){
600 if (e.isPopupTrigger())
601 maybeShowPopup(e);
602 }
603
604 public void mouseReleased(MouseEvent e){
605 if (e.isPopupTrigger()){
606 maybeShowPopup(e);
607 }
608 }
609
610 public void mouseEntered(MouseEvent e){
611 }
612
613 public void mouseExited(MouseEvent e){
614 }
615
616 }
This page was automatically generated by Maven