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 | |
package org.jfree.chart.plot; |
27 | |
|
28 | |
import java.awt.Graphics2D; |
29 | |
import java.awt.Shape; |
30 | |
import java.awt.geom.Rectangle2D; |
31 | |
import java.awt.geom.Point2D; |
32 | |
import java.awt.Point; |
33 | |
import java.awt.Color; |
34 | |
import java.awt.Rectangle; |
35 | |
import java.awt.event.MouseEvent; |
36 | |
import java.lang.IllegalArgumentException; |
37 | |
import java.lang.Integer; |
38 | |
import java.lang.Math; |
39 | |
import java.util.ResourceBundle; |
40 | |
import java.util.TreeSet; |
41 | |
|
42 | |
import javax.swing.JPanel; |
43 | |
import javax.swing.event.ChangeListener; |
44 | |
import javax.swing.event.ChangeEvent; |
45 | |
|
46 | |
import org.jfree.ui.RectangleEdge; |
47 | |
|
48 | |
import org.jfree.chart.ChartMouseEvent; |
49 | |
import org.jfree.chart.ChartMouseListener; |
50 | |
import org.jfree.chart.axis.HeatMapAxis; |
51 | |
import org.jfree.chart.axis.CategoryLabelPositions; |
52 | |
import org.jfree.chart.entity.HCTreeNodeEntity; |
53 | |
import org.jfree.chart.entity.HeatMapBlockEntity; |
54 | |
import org.jfree.chart.entity.EntityCollection; |
55 | |
import org.jfree.chart.event.ClusteringTreeChangeEvent; |
56 | |
import org.jfree.chart.event.PlotChangeEvent; |
57 | |
import org.jfree.chart.event.SelectionChangeEvent; |
58 | |
import org.jfree.chart.labels.HCToolTipGenerator; |
59 | |
import org.jfree.chart.plot.HCMediator; |
60 | |
import org.jfree.chart.plot.AbstractHCClusteringInfo; |
61 | |
import org.jfree.chart.plot.DummyHCClusteringInfo; |
62 | |
import org.jfree.chart.plot.StandardHCClusteringInfo; |
63 | |
import org.jfree.chart.plot.HCTreeNodeInfo; |
64 | |
import org.jfree.chart.plot.Plot; |
65 | |
import org.jfree.data.hc.HCDataset; |
66 | |
import org.jfree.data.hc.HeatMap; |
67 | |
import org.jfree.data.hc.DataRange; |
68 | |
import org.jfree.data.hc.HCTreeNode; |
69 | |
import org.jfree.chart.editor.GradientColorPaletteEditor; |
70 | |
import org.jfree.chart.editor.HCOptionsEditor; |
71 | |
|
72 | |
|
73 | |
|
74 | |
|
75 | |
|
76 | |
|
77 | |
|
78 | |
|
79 | |
|
80 | |
public class HCPlot |
81 | |
extends Plot |
82 | |
implements |
83 | |
ChartMouseListener, |
84 | |
ChangeListener { |
85 | |
|
86 | |
private HCDataset dataset; |
87 | |
private HeatMapAxis rowNames; |
88 | |
private HeatMapAxis columnNames; |
89 | |
private AbstractHCClusteringInfo rowClusteringInfo; |
90 | |
private AbstractHCClusteringInfo columnClusteringInfo; |
91 | |
private boolean columnNamesVisibility; |
92 | |
private boolean rowNamesVisibility; |
93 | |
private boolean columnTreeVisibility; |
94 | |
private boolean rowTreeVisibility; |
95 | |
|
96 | |
private double columnTreeSize; |
97 | |
private double rowTreeSize; |
98 | |
private double columnNamesSize; |
99 | |
private double rowNamesSize; |
100 | |
private double topMarginSize; |
101 | |
private double bottomMarginSize; |
102 | |
private double leftMarginSize; |
103 | |
private double rightMarginSize; |
104 | |
|
105 | |
private GradientColorPalette palette; |
106 | |
private GradientColorPaletteEditor paletteEditor; |
107 | |
private HCOptionsEditor optionsEditor; |
108 | |
|
109 | |
private Rectangle selection; |
110 | |
|
111 | |
public static final int LEFT = 0; |
112 | |
public static final int TOP = 1; |
113 | |
|
114 | |
private HCToolTipGenerator toolTipGenerator; |
115 | |
private boolean mouseOverHighlight; |
116 | |
private int columnTreeHighlight; |
117 | |
private int rowTreeHighlight; |
118 | |
private boolean selectionHighlight; |
119 | |
private boolean averageHighlight; |
120 | |
|
121 | |
private TreeSet closedRows; |
122 | |
private TreeSet closedColumns; |
123 | |
|
124 | |
private boolean drawFromLeftToRight; |
125 | |
private boolean drawFromTopToBottom; |
126 | |
|
127 | |
|
128 | |
|
129 | |
|
130 | |
|
131 | |
|
132 | |
|
133 | 20 | public HCPlot(HCDataset dataset) { |
134 | |
|
135 | |
HCMediator rowHCMediator; |
136 | |
HCMediator columnHCMediator; |
137 | |
|
138 | 20 | this.dataset=dataset; |
139 | 20 | this.columnNamesVisibility = true; |
140 | 20 | this.rowNamesVisibility = true; |
141 | |
|
142 | 20 | if (this.dataset.getColumnClusteringTree() != null) { |
143 | |
|
144 | 11 | this.columnClusteringInfo = new StandardHCClusteringInfo( |
145 | |
this.dataset.getColumnClusteringTree(), |
146 | |
this.dataset.getHeatMap().getColumnNames(), |
147 | |
this.TOP |
148 | |
); |
149 | 11 | this.columnTreeVisibility = true; |
150 | |
|
151 | 11 | } else { |
152 | |
|
153 | 8 | this.columnClusteringInfo = new DummyHCClusteringInfo( |
154 | |
this.dataset.getHeatMap().getColumnNames(), |
155 | |
this.TOP |
156 | |
); |
157 | 8 | this.columnTreeVisibility = false; |
158 | |
|
159 | |
} |
160 | |
|
161 | 19 | if (this.dataset.getRowClusteringTree() != null) { |
162 | |
|
163 | 11 | this.rowClusteringInfo = new StandardHCClusteringInfo( |
164 | |
this.dataset.getRowClusteringTree(), |
165 | |
this.dataset.getHeatMap().getRowNames(), |
166 | |
this.LEFT |
167 | |
); |
168 | 11 | this.rowTreeVisibility = true; |
169 | |
|
170 | 11 | } else { |
171 | |
|
172 | 8 | this.rowClusteringInfo = new DummyHCClusteringInfo( |
173 | |
this.dataset.getHeatMap().getRowNames(), |
174 | |
this.LEFT |
175 | |
); |
176 | 8 | this.rowTreeVisibility = false; |
177 | |
|
178 | |
} |
179 | |
|
180 | 19 | columnHCMediator = new HCMediator(this.columnClusteringInfo); |
181 | 19 | this.columnClusteringInfo.addChangeListener(this); |
182 | 19 | rowHCMediator = new HCMediator(this.rowClusteringInfo); |
183 | 19 | this.rowClusteringInfo.addChangeListener(this); |
184 | |
|
185 | 19 | this.rowNames = new HeatMapAxis(); |
186 | 19 | this.rowNames.setPlot(rowHCMediator); |
187 | 19 | this.rowNames.setLowerMargin(0); |
188 | 19 | this.rowNames.setUpperMargin(0); |
189 | 19 | this.rowNames.setMaximumCategoryLabelWidthRatio( |
190 | |
(float)0.95); |
191 | |
|
192 | |
|
193 | 19 | this.columnNames = new HeatMapAxis(); |
194 | 19 | this.columnNames.setPlot(columnHCMediator); |
195 | 19 | this.columnNames.setLowerMargin(0); |
196 | 19 | this.columnNames.setUpperMargin(0); |
197 | 19 | this.columnNames.setCategoryLabelPositions( |
198 | |
|
199 | |
CategoryLabelPositions.UP_90 |
200 | |
); |
201 | 19 | this.columnNames.setMaximumCategoryLabelWidthRatio( |
202 | |
(float)0.95); |
203 | |
|
204 | |
|
205 | |
|
206 | |
|
207 | |
|
208 | |
|
209 | |
|
210 | 19 | this.optionsEditor = new HCOptionsEditor(this); |
211 | 19 | this.paletteEditor = new GradientColorPaletteEditor(); |
212 | 19 | this.palette = null; |
213 | 19 | this.setColoring(createDefaultColorMap()); |
214 | 19 | this.selection = null; |
215 | |
|
216 | 19 | this.closedColumns = new TreeSet(); |
217 | 19 | this.closedRows = new TreeSet(); |
218 | |
|
219 | |
|
220 | 19 | double ratio = (double)(this.dataset.getHeatMap().getRowCount()) |
221 | |
/ this.dataset.getHeatMap().getColumnsCount(); |
222 | 19 | if ( ratio < 1 ) { |
223 | |
|
224 | |
|
225 | 18 | this.columnTreeSize = 0.2; |
226 | 18 | this.rowTreeSize = 0.2*ratio; |
227 | 18 | this.columnNamesSize = 0.12; |
228 | 18 | this.rowNamesSize = 0.12*ratio; |
229 | 18 | this.topMarginSize = 1.0/64.0; |
230 | 18 | this.leftMarginSize = 1.0/64.0*ratio; |
231 | |
|
232 | 18 | } else { |
233 | |
|
234 | |
|
235 | 1 | this.rowTreeSize = 0.2; |
236 | 1 | this.columnTreeSize = 0.2/ratio; |
237 | 1 | this.rowNamesSize = 0.12; |
238 | 1 | this.columnNamesSize = 0.12/ratio; |
239 | 1 | this.leftMarginSize = 1.0/64.0; |
240 | 1 | this.topMarginSize = 1.0/64.0/ratio; |
241 | |
|
242 | |
} |
243 | 19 | this.bottomMarginSize = this.topMarginSize; |
244 | 19 | this.rightMarginSize = this.leftMarginSize; |
245 | |
|
246 | 19 | this.mouseOverHighlight = true; |
247 | 19 | this.selectionHighlight = true; |
248 | 19 | this.averageHighlight = true; |
249 | 19 | this.columnTreeHighlight = -1; |
250 | 19 | this.rowTreeHighlight = -1; |
251 | |
|
252 | 19 | this.drawFromLeftToRight = true; |
253 | 19 | this.drawFromTopToBottom = true; |
254 | |
|
255 | 19 | } |
256 | |
|
257 | |
|
258 | |
|
259 | |
|
260 | |
|
261 | |
|
262 | |
|
263 | |
private GradientColorPalette createDefaultColorMap() { |
264 | |
|
265 | |
GradientColorPalette palette; |
266 | |
|
267 | 19 | double min=0; |
268 | 19 | double max=0; |
269 | |
int i; |
270 | |
|
271 | 286 | for (i = 0; i<this.dataset.getHeatMap().getItemCount(); i++) { |
272 | |
|
273 | 267 | double value = this.dataset.getHeatMap().getItem(i).doubleValue(); |
274 | 267 | if (value < min) min = value; |
275 | 267 | if (value > max) max = value; |
276 | |
|
277 | |
} |
278 | |
|
279 | 19 | return new GradientColorPalette(min,max); |
280 | |
|
281 | |
} |
282 | |
|
283 | |
|
284 | |
|
285 | |
|
286 | |
|
287 | |
|
288 | |
public AbstractHCClusteringInfo getColumnClusteringInfo() { |
289 | |
|
290 | 3 | return this.columnClusteringInfo; |
291 | |
|
292 | |
} |
293 | |
|
294 | |
|
295 | |
|
296 | |
|
297 | |
|
298 | |
|
299 | |
public AbstractHCClusteringInfo getRowClusteringInfo() { |
300 | |
|
301 | 4 | return this.rowClusteringInfo; |
302 | |
|
303 | |
} |
304 | |
|
305 | |
|
306 | |
|
307 | |
|
308 | |
|
309 | |
|
310 | |
public HCDataset getDataset() { |
311 | |
|
312 | 2 | return this.dataset; |
313 | |
|
314 | |
} |
315 | |
|
316 | |
|
317 | |
|
318 | |
|
319 | |
|
320 | |
|
321 | |
public String getPlotType() { |
322 | |
|
323 | 1 | return "Hierarchical Clustering and Heatmap"; |
324 | |
|
325 | |
} |
326 | |
|
327 | |
|
328 | |
|
329 | |
|
330 | |
public void showRowTree() { |
331 | |
|
332 | 5 | if (this.dataset.getRowClusteringTree() == null) |
333 | 1 | throw new NullPointerException("Cannot show a null tree."); |
334 | 4 | this.rowTreeVisibility = true; |
335 | 4 | notifyListeners(new PlotChangeEvent(this)); |
336 | |
|
337 | 4 | } |
338 | |
|
339 | |
|
340 | |
|
341 | |
|
342 | |
public void showColumnTree() { |
343 | |
|
344 | 5 | if (this.dataset.getColumnClusteringTree() == null) |
345 | 1 | throw new NullPointerException("Cannot show a null tree."); |
346 | 4 | this.columnTreeVisibility = true; |
347 | 4 | notifyListeners(new PlotChangeEvent(this)); |
348 | |
|
349 | 4 | } |
350 | |
|
351 | |
|
352 | |
|
353 | |
|
354 | |
public void hideRowTree() { |
355 | |
|
356 | 5 | if (this.dataset.getRowClusteringTree() == null) |
357 | 1 | throw new NullPointerException("Cannot hide a null tree."); |
358 | 4 | this.rowTreeVisibility = false; |
359 | 4 | notifyListeners(new PlotChangeEvent(this)); |
360 | |
|
361 | 4 | } |
362 | |
|
363 | |
|
364 | |
|
365 | |
|
366 | |
public void hideColumnTree() { |
367 | |
|
368 | 5 | if (this.dataset.getColumnClusteringTree() == null) |
369 | 1 | throw new NullPointerException("Cannot hide a null tree."); |
370 | 4 | this.columnTreeVisibility = false; |
371 | 4 | notifyListeners(new PlotChangeEvent(this)); |
372 | |
|
373 | 4 | } |
374 | |
|
375 | |
|
376 | |
|
377 | |
|
378 | |
|
379 | |
|
380 | |
public boolean getRowTreeVisibility() { |
381 | |
|
382 | 18 | if (this.dataset.getRowClusteringTree() == null) |
383 | 3 | return false; |
384 | 15 | return this.rowTreeVisibility; |
385 | |
|
386 | |
} |
387 | |
|
388 | |
|
389 | |
|
390 | |
|
391 | |
|
392 | |
|
393 | |
public boolean getColumnTreeVisibility() { |
394 | |
|
395 | 17 | if (this.dataset.getColumnClusteringTree() == null) |
396 | 2 | return false; |
397 | 15 | return this.columnTreeVisibility; |
398 | |
|
399 | |
} |
400 | |
|
401 | |
|
402 | |
|
403 | |
|
404 | |
public void showColumnNames() { |
405 | |
|
406 | 2 | this.columnNamesVisibility = true; |
407 | 2 | notifyListeners(new PlotChangeEvent(this)); |
408 | |
|
409 | 2 | } |
410 | |
|
411 | |
|
412 | |
|
413 | |
|
414 | |
public void showRowNames() { |
415 | |
|
416 | 2 | this.rowNamesVisibility = true; |
417 | 2 | notifyListeners(new PlotChangeEvent(this)); |
418 | |
|
419 | 2 | } |
420 | |
|
421 | |
|
422 | |
|
423 | |
|
424 | |
public void hideColumnNames() { |
425 | |
|
426 | 2 | this.columnNamesVisibility = false; |
427 | 2 | notifyListeners(new PlotChangeEvent(this)); |
428 | |
|
429 | 2 | } |
430 | |
|
431 | |
|
432 | |
|
433 | |
|
434 | |
public void hideRowNames() { |
435 | |
|
436 | 2 | this.rowNamesVisibility = false; |
437 | 2 | notifyListeners(new PlotChangeEvent(this)); |
438 | |
|
439 | 2 | } |
440 | |
|
441 | |
|
442 | |
|
443 | |
|
444 | |
|
445 | |
|
446 | |
public boolean getColumnNamesVisibility() { |
447 | |
|
448 | 12 | return this.columnNamesVisibility; |
449 | |
|
450 | |
} |
451 | |
|
452 | |
|
453 | |
|
454 | |
|
455 | |
|
456 | |
|
457 | |
public boolean getRowNamesVisibility() { |
458 | |
|
459 | 12 | return this.rowNamesVisibility; |
460 | |
|
461 | |
} |
462 | |
|
463 | |
|
464 | |
|
465 | |
|
466 | |
|
467 | |
|
468 | |
public void setColoring(GradientColorPalette color) { |
469 | |
|
470 | 21 | if (this.palette != null) this.palette.removeChangeListener(this); |
471 | 21 | this.palette = color; |
472 | 21 | this.palette.addChangeListener(this); |
473 | 20 | this.paletteEditor.setColoring (color); |
474 | 20 | notifyListeners(new PlotChangeEvent(this)); |
475 | |
|
476 | 20 | } |
477 | |
|
478 | |
|
479 | |
|
480 | |
|
481 | |
|
482 | |
|
483 | |
public GradientColorPalette getColoring() { |
484 | |
|
485 | 1 | return this.palette; |
486 | |
|
487 | |
} |
488 | |
|
489 | |
|
490 | |
|
491 | |
|
492 | |
|
493 | |
|
494 | |
|
495 | |
public void setRowNamesSize(double size) { |
496 | |
|
497 | 3 | if (size < 0) throw new IllegalArgumentException( |
498 | |
"Size of names cannot be negative."); |
499 | 2 | if (size > 1) throw new IllegalArgumentException( |
500 | |
"Size of names cannot be more than 1."); |
501 | 1 | this.rowNamesSize = size; |
502 | 1 | notifyListeners(new PlotChangeEvent(this)); |
503 | |
|
504 | 1 | } |
505 | |
|
506 | |
|
507 | |
|
508 | |
|
509 | |
|
510 | |
|
511 | |
|
512 | |
public void setColumnNamesSize(double size) { |
513 | |
|
514 | 3 | if (size < 0) throw new IllegalArgumentException( |
515 | |
"Size of names cannot be negative."); |
516 | 2 | if (size > 1) throw new IllegalArgumentException( |
517 | |
"Size of names cannot be more than 1."); |
518 | 1 | this.columnNamesSize = size; |
519 | 1 | notifyListeners(new PlotChangeEvent(this)); |
520 | |
|
521 | 1 | } |
522 | |
|
523 | |
|
524 | |
|
525 | |
|
526 | |
|
527 | |
|
528 | |
public double getRowNamesSize() { |
529 | |
|
530 | 3 | return this.rowNamesSize; |
531 | |
|
532 | |
} |
533 | |
|
534 | |
|
535 | |
|
536 | |
|
537 | |
|
538 | |
|
539 | |
public double getColumnNamesSize() { |
540 | |
|
541 | 3 | return this.columnNamesSize; |
542 | |
|
543 | |
} |
544 | |
|
545 | |
|
546 | |
|
547 | |
|
548 | |
|
549 | |
|
550 | |
|
551 | |
public void setRowTreeSize(double size) { |
552 | |
|
553 | 8 | if (size < 0) throw new IllegalArgumentException( |
554 | |
"Size of a tree cannot be negative."); |
555 | 5 | if (size > 1) throw new IllegalArgumentException( |
556 | |
"Size of a tree cannot be more than 1."); |
557 | 3 | this.rowTreeSize = size; |
558 | 3 | notifyListeners(new PlotChangeEvent(this)); |
559 | |
|
560 | 3 | } |
561 | |
|
562 | |
|
563 | |
|
564 | |
|
565 | |
|
566 | |
|
567 | |
|
568 | |
public void setColumnTreeSize(double size) { |
569 | |
|
570 | 8 | if (size < 0) throw new IllegalArgumentException( |
571 | |
"Size of a tree cannot be negative."); |
572 | 5 | if (size > 1) throw new IllegalArgumentException( |
573 | |
"Size of a tree cannot be more than 1."); |
574 | 3 | this.columnTreeSize = size; |
575 | 3 | notifyListeners(new PlotChangeEvent(this)); |
576 | |
|
577 | 3 | } |
578 | |
|
579 | |
|
580 | |
|
581 | |
|
582 | |
|
583 | |
|
584 | |
public double getRowTreeSize() { |
585 | |
|
586 | 6 | return this.rowTreeSize; |
587 | |
|
588 | |
} |
589 | |
|
590 | |
|
591 | |
|
592 | |
|
593 | |
|
594 | |
|
595 | |
public double getColumnTreeSize() { |
596 | |
|
597 | 6 | return this.columnTreeSize; |
598 | |
|
599 | |
} |
600 | |
|
601 | |
|
602 | |
|
603 | |
|
604 | |
|
605 | |
|
606 | |
|
607 | |
|
608 | |
public void setSelection(Rectangle selection) |
609 | |
throws IndexOutOfBoundsException { |
610 | |
|
611 | 11 | if (selection.getMinX() < 0) throw new IndexOutOfBoundsException(); |
612 | 9 | if (selection.getMinY() < 0) throw new IndexOutOfBoundsException(); |
613 | 8 | if (selection.getMaxX() > this.dataset.getHeatMap().getColumnsCount()) |
614 | 1 | throw new IndexOutOfBoundsException(); |
615 | 7 | if (selection.getMaxY() > this.dataset.getHeatMap().getRowCount()) |
616 | 1 | throw new IndexOutOfBoundsException(); |
617 | |
|
618 | 6 | Rectangle oldSelection = this.selection; |
619 | 6 | this.selection = selection; |
620 | 6 | notifyListeners(new SelectionChangeEvent(this,oldSelection)); |
621 | |
|
622 | 6 | } |
623 | |
|
624 | |
|
625 | |
|
626 | |
|
627 | |
|
628 | |
|
629 | |
|
630 | |
public Rectangle getSelection() { |
631 | |
|
632 | 4 | return this.selection; |
633 | |
} |
634 | |
|
635 | |
|
636 | |
|
637 | |
|
638 | |
|
639 | |
|
640 | |
|
641 | |
|
642 | |
public void setMouseOverHighlight(boolean highlight) { |
643 | |
|
644 | 2 | this.mouseOverHighlight = highlight; |
645 | 2 | notifyListeners(new PlotChangeEvent(this)); |
646 | |
|
647 | 2 | } |
648 | |
|
649 | |
|
650 | |
|
651 | |
|
652 | |
|
653 | |
|
654 | |
|
655 | |
|
656 | |
|
657 | |
public boolean getMouseOverHighlight() { |
658 | |
|
659 | 2 | return this.mouseOverHighlight; |
660 | |
|
661 | |
} |
662 | |
|
663 | |
|
664 | |
|
665 | |
|
666 | |
|
667 | |
|
668 | |
|
669 | |
|
670 | |
public void setSelectionHighlight(boolean highlight) { |
671 | |
|
672 | 2 | this.selectionHighlight = highlight; |
673 | 2 | notifyListeners(new PlotChangeEvent(this)); |
674 | |
|
675 | 2 | } |
676 | |
|
677 | |
|
678 | |
|
679 | |
|
680 | |
|
681 | |
|
682 | |
|
683 | |
|
684 | |
|
685 | |
public boolean getSelectionHighlight() { |
686 | |
|
687 | 8 | return this.selectionHighlight; |
688 | |
|
689 | |
} |
690 | |
|
691 | |
|
692 | |
|
693 | |
|
694 | |
|
695 | |
|
696 | |
|
697 | |
|
698 | |
public void setAverageHighlight(boolean highlight) { |
699 | |
|
700 | 3 | this.averageHighlight = highlight; |
701 | 3 | notifyListeners(new PlotChangeEvent(this)); |
702 | |
|
703 | 3 | } |
704 | |
|
705 | |
|
706 | |
|
707 | |
|
708 | |
|
709 | |
|
710 | |
|
711 | |
|
712 | |
|
713 | |
|
714 | |
public boolean getAverageHighlight() { |
715 | |
|
716 | 16 | return this.averageHighlight; |
717 | |
|
718 | |
} |
719 | |
|
720 | |
|
721 | |
|
722 | |
|
723 | |
|
724 | |
|
725 | |
|
726 | |
|
727 | |
public void setRowTreeHighlight(int index) { |
728 | |
|
729 | 3 | this.rowTreeHighlight = index; |
730 | 3 | notifyListeners(new PlotChangeEvent(this)); |
731 | |
|
732 | 3 | } |
733 | |
|
734 | |
|
735 | |
|
736 | |
|
737 | |
|
738 | |
|
739 | |
|
740 | |
|
741 | |
public void setColumnTreeHighlight(int index) { |
742 | |
|
743 | 3 | this.columnTreeHighlight = index; |
744 | 3 | notifyListeners(new PlotChangeEvent(this)); |
745 | |
|
746 | 3 | } |
747 | |
|
748 | |
|
749 | |
|
750 | |
|
751 | |
|
752 | |
|
753 | |
|
754 | |
public int getRowTreeHighlight() { |
755 | |
|
756 | 3 | return this.rowTreeHighlight; |
757 | |
|
758 | |
} |
759 | |
|
760 | |
|
761 | |
|
762 | |
|
763 | |
|
764 | |
|
765 | |
|
766 | |
public int getColumnTreeHighlight() { |
767 | |
|
768 | 3 | return this.columnTreeHighlight; |
769 | |
|
770 | |
} |
771 | |
|
772 | |
|
773 | |
|
774 | |
|
775 | |
|
776 | |
|
777 | |
public int getHeatMapRowCount() { |
778 | |
|
779 | 14 | return this.rowClusteringInfo.getNumberOfVisibleItems(); |
780 | |
|
781 | |
} |
782 | |
|
783 | |
|
784 | |
|
785 | |
|
786 | |
|
787 | |
|
788 | |
public int getHeatMapColumnsCount() { |
789 | |
|
790 | 14 | return this.columnClusteringInfo.getNumberOfVisibleItems(); |
791 | |
|
792 | |
} |
793 | |
|
794 | |
|
795 | |
|
796 | |
|
797 | |
|
798 | |
|
799 | |
|
800 | |
|
801 | |
|
802 | |
public DataRange getDatasetRowsAtHeatMapRow(int row) { |
803 | |
|
804 | 4 | return this.rowClusteringInfo.getDataRangeForVisibleIndex(row); |
805 | |
|
806 | |
} |
807 | |
|
808 | |
|
809 | |
|
810 | |
|
811 | |
|
812 | |
|
813 | |
|
814 | |
|
815 | |
|
816 | |
public DataRange getDatasetColumnsAtHeatMapColumn(int column) { |
817 | |
|
818 | 4 | return this.columnClusteringInfo.getDataRangeForVisibleIndex(column); |
819 | |
|
820 | |
} |
821 | |
|
822 | |
|
823 | |
|
824 | |
|
825 | |
|
826 | |
|
827 | |
|
828 | |
|
829 | |
|
830 | |
|
831 | |
|
832 | |
|
833 | |
private HCTreeNodeEntity drawSubTree( |
834 | |
Graphics2D g2, |
835 | |
HCPlotState state, |
836 | |
HCTreeNodeInfo node, |
837 | |
Rectangle2D area, |
838 | |
RectangleEdge edge) { |
839 | |
|
840 | |
HCTreeNodeEntity leftEntity; |
841 | |
HCTreeNodeEntity rightEntity; |
842 | |
HCTreeNodeEntity thisEntity; |
843 | |
Rectangle thisArea; |
844 | |
Rectangle2D areaForRightSubTree; |
845 | |
Point center; |
846 | |
EntityCollection entities; |
847 | |
String tip; |
848 | |
|
849 | |
|
850 | |
|
851 | 70 | if (!node.isNodeOpen()) { |
852 | |
|
853 | |
|
854 | 42 | thisArea = state.calculateClosedNodeArea( |
855 | |
area, |
856 | |
node, |
857 | |
edge |
858 | |
); |
859 | 42 | center = state.calculateClosedNodeCenter( |
860 | |
thisArea, |
861 | |
node.getNode().getHeight(), |
862 | |
edge |
863 | |
); |
864 | |
|
865 | |
|
866 | 42 | } else if ( |
867 | |
(node.getLeftChild() == null) || |
868 | |
(node.getRightChild() == null) |
869 | |
) { |
870 | |
|
871 | |
|
872 | |
|
873 | 0 | thisArea = state.calculateLeafNodeArea(area,node,edge); |
874 | 0 | center = state.calculateLeafNodeCenter(thisArea,edge); |
875 | |
|
876 | 0 | } else { |
877 | |
|
878 | |
|
879 | 28 | leftEntity = drawSubTree ( |
880 | |
g2, |
881 | |
state, |
882 | |
node.getLeftChild(), |
883 | |
area, |
884 | |
edge |
885 | |
); |
886 | |
|
887 | 28 | areaForRightSubTree = state.calculateSubTreeArea( |
888 | |
area, |
889 | |
leftEntity.getSubTreeArea(), |
890 | |
edge |
891 | |
); |
892 | |
|
893 | 28 | rightEntity = drawSubTree ( |
894 | |
g2, |
895 | |
state, |
896 | |
node.getRightChild(), |
897 | |
areaForRightSubTree, |
898 | |
edge |
899 | |
); |
900 | 28 | thisArea = state.calculateBranchNodeArea( |
901 | |
node.getNode().getHeight(), |
902 | |
leftEntity, |
903 | |
rightEntity, |
904 | |
area, |
905 | |
edge |
906 | |
); |
907 | 28 | center = state.calculateBranchNodeCenter( |
908 | |
node.getNode().getHeight(), |
909 | |
leftEntity, |
910 | |
rightEntity, |
911 | |
area, |
912 | |
edge |
913 | |
); |
914 | |
|
915 | |
} |
916 | |
|
917 | |
|
918 | |
|
919 | 70 | if (this.toolTipGenerator != null) { |
920 | |
|
921 | 65 | tip = this.toolTipGenerator.generateToolTip(node); |
922 | |
|
923 | 65 | } else tip = null; |
924 | 70 | thisEntity = new HCTreeNodeEntity( |
925 | |
new Rectangle( |
926 | |
(int)center.getX()-5, |
927 | |
(int)center.getY()-5, |
928 | |
11, |
929 | |
11 |
930 | |
), |
931 | |
tip, |
932 | |
null, |
933 | |
center, |
934 | |
thisArea, |
935 | |
node |
936 | |
); |
937 | 70 | entities = state.getEntityCollection(); |
938 | 70 | if (entities != null) { |
939 | |
|
940 | 70 | entities.add(thisEntity); |
941 | |
|
942 | |
} |
943 | 70 | redrawNode(g2, state, thisEntity, edge); |
944 | |
|
945 | 70 | return thisEntity; |
946 | |
|
947 | |
} |
948 | |
|
949 | |
|
950 | |
|
951 | |
|
952 | |
|
953 | |
|
954 | |
|
955 | |
|
956 | |
|
957 | |
|
958 | |
|
959 | |
private void redrawNode( |
960 | |
Graphics2D g2, |
961 | |
HCPlotState state, |
962 | |
HCTreeNodeEntity entity, |
963 | |
RectangleEdge edge) { |
964 | |
|
965 | 70 | int centerX = (int)entity.getCenter().getX(); |
966 | 70 | int centerY = (int)entity.getCenter().getY(); |
967 | 70 | Rectangle subTreeArea = entity.getSubTreeArea(); |
968 | 70 | int width = (int)(subTreeArea.getWidth()); |
969 | 70 | int height = (int)(subTreeArea.getHeight()); |
970 | 70 | int minX = (int)(subTreeArea.getMinX()); |
971 | 70 | int minY = (int)(subTreeArea.getMinY()); |
972 | 70 | int maxX = (int)(subTreeArea.getMinX()+width); |
973 | 70 | int maxY = (int)(subTreeArea.getMinY()+height); |
974 | 70 | HCTreeNode node = entity.getHCTreeNodeInfo().getNode(); |
975 | |
double height1; |
976 | |
double height2; |
977 | |
|
978 | 70 | g2.setPaint(getOutlinePaint()); |
979 | |
|
980 | 70 | if (entity.getHCTreeNodeInfo().isNodeOpen()) { |
981 | |
|
982 | |
|
983 | 28 | if ((node.getLeftChild() != null) && |
984 | |
(node.getRightChild() != null) |
985 | |
) { |
986 | |
|
987 | |
|
988 | 28 | height1 = node.getLeftChild().getHeight(); |
989 | 28 | height2 = node.getRightChild().getHeight(); |
990 | 28 | if (edge == RectangleEdge.TOP) { |
991 | |
|
992 | 16 | g2.drawLine( |
993 | |
minX, |
994 | |
centerY, |
995 | |
minX, |
996 | |
maxY-(int)( |
997 | |
height1*state.getColumnTreeHeightUnitInPixels() |
998 | |
+state.getSizeOfNodeSymbol()/2 |
999 | |
)); |
1000 | 16 | g2.drawLine( |
1001 | |
maxX, |
1002 | |
centerY, |
1003 | |
maxX, |
1004 | |
maxY-(int)( |
1005 | |
height2*state.getColumnTreeHeightUnitInPixels() |
1006 | |
+state.getSizeOfNodeSymbol()/2 |
1007 | |
)); |
1008 | 16 | g2.drawLine( |
1009 | |
minX, |
1010 | |
centerY, |
1011 | |
maxX, |
1012 | |
centerY); |
1013 | |
|
1014 | 16 | } else if (edge == RectangleEdge.BOTTOM) { |
1015 | |
|
1016 | |
|
1017 | |
|
1018 | 0 | g2.drawLine( |
1019 | |
minX, |
1020 | |
centerY, |
1021 | |
minX, |
1022 | |
minY+(int)( |
1023 | |
height1*state.getColumnTreeHeightUnitInPixels() |
1024 | |
+state.getSizeOfNodeSymbol()/2 |
1025 | |
)); |
1026 | 0 | g2.drawLine( |
1027 | |
maxX, |
1028 | |
centerY, |
1029 | |
maxX, |
1030 | |
minY+(int)( |
1031 | |
height2*state.getColumnTreeHeightUnitInPixels() |
1032 | |
+state.getSizeOfNodeSymbol()/2 |
1033 | |
)); |
1034 | 0 | g2.drawLine( |
1035 | |
minX, |
1036 | |
centerY, |
1037 | |
maxX, |
1038 | |
centerY); |
1039 | |
|
1040 | 0 | } else if(edge == RectangleEdge.LEFT) { |
1041 | |
|
1042 | 12 | g2.drawLine( |
1043 | |
centerX, |
1044 | |
minY, |
1045 | |
maxX-(int)( |
1046 | |
height1*state.getRowTreeHeightUnitInPixels() |
1047 | |
+state.getSizeOfNodeSymbol()/2 |
1048 | |
), |
1049 | |
minY); |
1050 | 12 | g2.drawLine( |
1051 | |
centerX, |
1052 | |
maxY, |
1053 | |
maxX-(int)( |
1054 | |
height2*state.getRowTreeHeightUnitInPixels() |
1055 | |
+state.getSizeOfNodeSymbol()/2 |
1056 | |
), |
1057 | |
maxY); |
1058 | 12 | g2.drawLine( |
1059 | |
centerX, |
1060 | |
minY, |
1061 | |
centerX, |
1062 | |
maxY); |
1063 | |
|
1064 | 12 | } else if(edge == RectangleEdge.RIGHT) { |
1065 | |
|
1066 | |
|
1067 | |
|
1068 | 0 | g2.drawLine( |
1069 | |
centerX, |
1070 | |
minY, |
1071 | |
minX+(int)( |
1072 | |
height1*state.getRowTreeHeightUnitInPixels() |
1073 | |
+state.getSizeOfNodeSymbol()/2 |
1074 | |
), |
1075 | |
minY); |
1076 | 0 | g2.drawLine( |
1077 | |
centerX, |
1078 | |
maxY, |
1079 | |
minX+(int)( |
1080 | |
height2*state.getRowTreeHeightUnitInPixels() |
1081 | |
+state.getSizeOfNodeSymbol()/2 |
1082 | |
), |
1083 | |
maxY); |
1084 | 0 | g2.drawLine( |
1085 | |
centerX, |
1086 | |
minY, |
1087 | |
centerX, |
1088 | |
maxY); |
1089 | |
|
1090 | 0 | } else throw new IllegalArgumentException("Invalid edge."); |
1091 | |
|
1092 | |
} else { |
1093 | |
|
1094 | |
; |
1095 | |
|
1096 | |
} |
1097 | 28 | Rectangle r = new Rectangle( |
1098 | |
centerX-state.getSizeOfNodeSymbol()/2, |
1099 | |
centerY-state.getSizeOfNodeSymbol()/2, |
1100 | |
state.getSizeOfNodeSymbol(), |
1101 | |
state.getSizeOfNodeSymbol()); |
1102 | 28 | g2.fill(r); |
1103 | |
|
1104 | 28 | } else { |
1105 | |
|
1106 | |
|
1107 | |
Rectangle r; |
1108 | |
|
1109 | 42 | if ((node.getLeftChild() == null) || |
1110 | |
(node.getRightChild() == null) |
1111 | |
) { |
1112 | |
|
1113 | |
|
1114 | 38 | if (edge == RectangleEdge.TOP) { |
1115 | |
|
1116 | 20 | r = new Rectangle( |
1117 | |
centerX-state.getSizeOfNodeSymbol()/2, |
1118 | |
centerY-state.getSizeOfNodeSymbol()/2, |
1119 | |
state.getSizeOfNodeSymbol(), |
1120 | |
state.getSizeOfNodeSymbol()/2); |
1121 | |
|
1122 | 20 | } else if (edge == RectangleEdge.BOTTOM) { |
1123 | |
|
1124 | |
|
1125 | 0 | r = new Rectangle( |
1126 | |
centerX-state.getSizeOfNodeSymbol()/2, |
1127 | |
centerY, |
1128 | |
state.getSizeOfNodeSymbol(), |
1129 | |
state.getSizeOfNodeSymbol()/2); |
1130 | |
|
1131 | 0 | } else if (edge == RectangleEdge.LEFT) { |
1132 | |
|
1133 | 18 | r = new Rectangle( |
1134 | |
centerX-state.getSizeOfNodeSymbol()/2, |
1135 | |
centerY-state.getSizeOfNodeSymbol()/2, |
1136 | |
state.getSizeOfNodeSymbol()/2, |
1137 | |
state.getSizeOfNodeSymbol()); |
1138 | |
|
1139 | 18 | } else if (edge == RectangleEdge.RIGHT) { |
1140 | |
|
1141 | |
|
1142 | 0 | r = new Rectangle( |
1143 | |
centerX, |
1144 | |
centerY-state.getSizeOfNodeSymbol()/2, |
1145 | |
state.getSizeOfNodeSymbol()/2, |
1146 | |
state.getSizeOfNodeSymbol()); |
1147 | |
|
1148 | 0 | } else throw new IllegalArgumentException("Invalid edge."); |
1149 | |
|
1150 | |
} else { |
1151 | |
|
1152 | |
|
1153 | 4 | r = new Rectangle( |
1154 | |
centerX-(state.getSizeOfNodeSymbol())/2, |
1155 | |
centerY-(state.getSizeOfNodeSymbol())/2, |
1156 | |
state.getSizeOfNodeSymbol(), |
1157 | |
state.getSizeOfNodeSymbol()); |
1158 | |
|
1159 | |
} |
1160 | 42 | if (edge == RectangleEdge.TOP) { |
1161 | |
|
1162 | 23 | g2.drawLine( centerX, (int)r.getMaxY(), centerX, maxY ); |
1163 | |
|
1164 | 23 | } else if (edge == RectangleEdge.BOTTOM) { |
1165 | |
|
1166 | |
|
1167 | 0 | g2.drawLine( centerX, (int)r.getMinY(), centerX, minY ); |
1168 | |
|
1169 | 0 | } else if(edge == RectangleEdge.LEFT) { |
1170 | |
|
1171 | 19 | g2.drawLine( (int)r.getMaxX(),centerY,maxX,centerY); |
1172 | |
|
1173 | 19 | } else if(edge == RectangleEdge.RIGHT) { |
1174 | |
|
1175 | |
|
1176 | 0 | g2.drawLine( (int)r.getMinX(),centerY,minX,centerY); |
1177 | |
|
1178 | 0 | } else throw new IllegalArgumentException("Invalid edge."); |
1179 | |
|
1180 | 42 | g2.draw(r); |
1181 | |
} |
1182 | |
|
1183 | 70 | } |
1184 | |
|
1185 | |
|
1186 | |
|
1187 | |
|
1188 | |
|
1189 | |
|
1190 | |
|
1191 | |
|
1192 | |
|
1193 | |
|
1194 | |
|
1195 | |
|
1196 | |
private void drawBlock ( |
1197 | |
Graphics2D g2, |
1198 | |
Rectangle2D area, |
1199 | |
HCPlotState state, |
1200 | |
int row, |
1201 | |
int column) { |
1202 | |
DataRange columns; |
1203 | |
DataRange rows; |
1204 | |
HeatMapBlockEntity entity; |
1205 | |
EntityCollection entities; |
1206 | |
Rectangle r; |
1207 | |
int minRow; |
1208 | |
int maxRow; |
1209 | |
int minColumn; |
1210 | |
int maxColumn; |
1211 | |
int rowCounter; |
1212 | |
int columnCounter; |
1213 | |
int blockCount; |
1214 | |
double averageValue; |
1215 | |
String tip; |
1216 | |
|
1217 | |
|
1218 | 74 | columns = this.columnClusteringInfo.getDataRangeForVisibleIndex(column); |
1219 | 74 | rows = this.rowClusteringInfo.getDataRangeForVisibleIndex(row); |
1220 | |
|
1221 | |
try { |
1222 | 74 | minColumn = columns.getLeftBound(); |
1223 | 74 | maxColumn = columns.getRightBound(); |
1224 | 74 | minRow = rows.getLeftBound(); |
1225 | 74 | maxRow = rows.getRightBound(); |
1226 | 0 | } catch (Exception e) { |
1227 | 0 | return; |
1228 | 74 | } |
1229 | |
|
1230 | |
for ( |
1231 | 74 | averageValue = 0, blockCount = 0, rowCounter = minRow; |
1232 | 158 | rowCounter <= maxRow; |
1233 | 84 | rowCounter++ |
1234 | |
) { |
1235 | |
for ( |
1236 | 84 | columnCounter = minColumn; |
1237 | 204 | columnCounter <= maxColumn; |
1238 | 120 | columnCounter++, blockCount++ |
1239 | |
) { |
1240 | 120 | averageValue += this.dataset.getHeatMap() |
1241 | |
.get(rowCounter,columnCounter); |
1242 | |
} |
1243 | |
} |
1244 | 74 | averageValue = averageValue/blockCount; |
1245 | |
|
1246 | 74 | g2.setColor(this.palette.getColor(averageValue)); |
1247 | |
|
1248 | |
|
1249 | |
|
1250 | 74 | r = new Rectangle( |
1251 | |
state.getHeatMapXCoordinate(column), |
1252 | |
state.getHeatMapYCoordinate(row), |
1253 | |
state.getHeatMapXCoordinate(column+1) - |
1254 | |
state.getHeatMapXCoordinate(column), |
1255 | |
state.getHeatMapYCoordinate(row+1) - |
1256 | |
state.getHeatMapYCoordinate(row) |
1257 | |
); |
1258 | |
|
1259 | 74 | g2.fill(r); |
1260 | |
|
1261 | 74 | if (blockCount>1 && getAverageHighlight()) { |
1262 | |
|
1263 | 14 | if ( rows.getWidth() > 1) { |
1264 | 5 | Integer introw = new Integer(row); |
1265 | 5 | closedRows.add(introw); |
1266 | |
} |
1267 | 14 | if ( columns.getWidth() > 1) { |
1268 | 9 | Integer intcolumn = new Integer(column); |
1269 | 9 | closedColumns.add(intcolumn); |
1270 | |
} |
1271 | |
|
1272 | |
} |
1273 | |
|
1274 | 74 | if (this.toolTipGenerator != null) { |
1275 | 59 | tip = this.toolTipGenerator.generateToolTip( |
1276 | |
this.dataset.getHeatMap(), |
1277 | |
rows, |
1278 | |
columns |
1279 | |
); |
1280 | 59 | } |
1281 | 15 | else tip = null; |
1282 | 74 | entity = new HeatMapBlockEntity( |
1283 | |
r, |
1284 | |
tip, |
1285 | |
null, |
1286 | |
row, |
1287 | |
column |
1288 | |
); |
1289 | 74 | entities = state.getEntityCollection(); |
1290 | 74 | if (entities != null) { |
1291 | 74 | entities.add(entity); |
1292 | |
} |
1293 | |
|
1294 | 74 | } |
1295 | |
|
1296 | |
|
1297 | |
|
1298 | |
|
1299 | |
|
1300 | |
|
1301 | |
|
1302 | |
|
1303 | |
|
1304 | |
|
1305 | |
|
1306 | |
private void drawSelection(Graphics2D g2, HCPlotState state, Color color, Rectangle r) { |
1307 | |
|
1308 | 7 | g2.setColor(color); |
1309 | |
|
1310 | 7 | int column = (int)r.getX(); |
1311 | 7 | int row = (int)r.getY(); |
1312 | 7 | int lastrow = row + (int)r.getHeight()-1; |
1313 | 7 | int lastcolumn = column + (int)r.getWidth()-1; |
1314 | |
|
1315 | 7 | g2.draw(new Rectangle( |
1316 | |
state.getHeatMapXCoordinate(column), |
1317 | |
state.getHeatMapYCoordinate(row), |
1318 | |
state.getHeatMapXCoordinate(lastcolumn+1) |
1319 | |
-state.getHeatMapXCoordinate(column)-1, |
1320 | |
state.getHeatMapYCoordinate(lastrow+1) |
1321 | |
-state.getHeatMapYCoordinate(row)-1 |
1322 | |
)); |
1323 | 7 | } |
1324 | |
|
1325 | |
|
1326 | |
|
1327 | |
|
1328 | |
|
1329 | |
|
1330 | |
|
1331 | |
private void drawHeatMap( |
1332 | |
Graphics2D g2, |
1333 | |
HCPlotState state, |
1334 | |
Rectangle2D area, |
1335 | |
int visibleColumns, |
1336 | |
int visibleRows |
1337 | |
) { |
1338 | |
|
1339 | |
int height; |
1340 | |
int width; |
1341 | |
int row; |
1342 | |
int column; |
1343 | |
int minRow; |
1344 | |
int minColumn; |
1345 | |
int maxRow; |
1346 | |
int maxColumn; |
1347 | 11 | int count = 0; |
1348 | |
|
1349 | 11 | Rectangle clip = g2.getClip().getBounds(); |
1350 | |
|
1351 | |
|
1352 | 8 | minColumn = (int)Math.floor( |
1353 | |
(clip.getMinX() - area.getMinX()) / state.getBlockWidth() |
1354 | |
); |
1355 | 8 | if (minColumn < 0) minColumn = 0; |
1356 | |
|
1357 | 8 | minRow = (int)Math.floor( |
1358 | |
(clip.getMinY() - area.getMinY()) / state.getBlockHeight() |
1359 | |
); |
1360 | 8 | if (minRow < 0) minRow = 0; |
1361 | |
|
1362 | 8 | maxColumn = (int)Math.ceil( |
1363 | |
(clip.getMaxX() - area.getMinX()) / state.getBlockWidth() |
1364 | |
); |
1365 | 8 | if (maxColumn > visibleColumns) maxColumn = visibleColumns; |
1366 | |
|
1367 | 8 | maxRow = (int)Math.ceil( |
1368 | |
(clip.getMaxY() - area.getMinY()) / state.getBlockHeight() |
1369 | |
); |
1370 | 8 | if (maxRow > visibleRows) maxRow = visibleRows; |
1371 | |
|
1372 | 30 | for (row=minRow; row < maxRow; row ++) { |
1373 | |
|
1374 | 96 | for (column=minColumn; column < maxColumn; column ++) { |
1375 | |
|
1376 | 74 | drawBlock (g2,area,state,row,column); |
1377 | 74 | count++; |
1378 | |
|
1379 | |
} |
1380 | |
|
1381 | |
} |
1382 | |
|
1383 | 8 | } |
1384 | |
|
1385 | |
|
1386 | |
|
1387 | |
|
1388 | |
|
1389 | |
|
1390 | |
|
1391 | |
|
1392 | |
|
1393 | |
|
1394 | |
public void draw( |
1395 | |
Graphics2D g2, |
1396 | |
Rectangle2D area, |
1397 | |
Point2D anchor, |
1398 | |
PlotState parentState, |
1399 | |
PlotRenderingInfo info) { |
1400 | |
|
1401 | |
|
1402 | |
|
1403 | |
|
1404 | 13 | int visibleColumns = this.getHeatMapColumnsCount(); |
1405 | 13 | int visibleRows = this.getHeatMapRowCount(); |
1406 | 13 | int totalColumns = this.dataset.getHeatMap().getColumnsCount(); |
1407 | 13 | int totalRows = this.dataset.getHeatMap().getRowCount(); |
1408 | |
|
1409 | 13 | int topMargin = (int)(area.getHeight() * this.topMarginSize); |
1410 | 12 | int bottomMargin = (int)(area.getHeight() * this.bottomMarginSize); |
1411 | 12 | int leftMargin = (int)(area.getWidth() * this.leftMarginSize); |
1412 | 12 | int rightMargin = (int)(area.getWidth() * this.rightMarginSize); |
1413 | 12 | int minX = (int)area.getMinX()+leftMargin; |
1414 | 12 | int minY = (int)area.getMinY()+topMargin; |
1415 | 12 | int width = (int)area.getWidth()-leftMargin-rightMargin; |
1416 | 12 | int height = (int)area.getHeight()-bottomMargin-topMargin; |
1417 | 12 | int columnTreeHeight = (int)(height *this.columnTreeSize); |
1418 | 12 | int rowTreeWidth = (int)(width *this.rowTreeSize); |
1419 | 12 | if (!this.rowTreeVisibility) rowTreeWidth = 0; |
1420 | 12 | if (!this.columnTreeVisibility) columnTreeHeight = 0; |
1421 | 12 | int columnNamesInitialHeight = (int)(height * this.columnNamesSize); |
1422 | 12 | int rowNamesInitialWidth = (int)(width * this.rowNamesSize); |
1423 | 12 | int heatMapWidth = (int)((double) |
1424 | |
( area.getWidth() - rowTreeWidth - rowNamesInitialWidth) |
1425 | |
* visibleColumns / totalColumns); |
1426 | 12 | int heatMapHeight = (int)((double) |
1427 | |
( area.getHeight() - columnTreeHeight - columnNamesInitialHeight) |
1428 | |
* visibleRows / totalRows); |
1429 | 12 | int columnNamesHeight = height - heatMapHeight - columnTreeHeight; |
1430 | 12 | int rowNamesWidth = width - heatMapWidth - rowTreeWidth; |
1431 | 12 | if (!this.rowNamesVisibility) rowNamesWidth = 0; |
1432 | 12 | if (!this.columnNamesVisibility) columnNamesHeight = 0; |
1433 | 12 | int maxX = minX+width; |
1434 | 12 | int maxY = minY+height; |
1435 | |
int heatMapMinX; |
1436 | |
int heatMapMinY; |
1437 | |
int heatMapMaxX; |
1438 | |
int heatMapMaxY; |
1439 | |
RectangleEdge columnNamesLocation; |
1440 | |
RectangleEdge rowNamesLocation; |
1441 | |
RectangleEdge columnTreeLocation; |
1442 | |
RectangleEdge rowTreeLocation; |
1443 | |
|
1444 | |
Rectangle columnTreeArea; |
1445 | |
Rectangle rowTreeArea; |
1446 | |
Rectangle columnNamesArea; |
1447 | |
Rectangle rowNamesArea; |
1448 | |
Rectangle heatMapArea; |
1449 | |
|
1450 | 12 | if (drawFromLeftToRight) { |
1451 | |
|
1452 | 12 | heatMapMinX = minX+rowTreeWidth; |
1453 | 12 | rowTreeLocation = RectangleEdge.LEFT; |
1454 | 12 | rowNamesLocation = RectangleEdge.RIGHT; |
1455 | |
|
1456 | 12 | } else { |
1457 | |
|
1458 | |
|
1459 | 0 | heatMapMinX = minX+rowNamesWidth; |
1460 | 0 | rowTreeLocation = RectangleEdge.RIGHT; |
1461 | 0 | rowNamesLocation = RectangleEdge.LEFT; |
1462 | |
|
1463 | |
} |
1464 | |
|
1465 | 12 | if (drawFromTopToBottom) { |
1466 | |
|
1467 | 12 | heatMapMinY = minY+columnTreeHeight; |
1468 | 12 | columnTreeLocation = RectangleEdge.TOP; |
1469 | 12 | columnNamesLocation = RectangleEdge.BOTTOM; |
1470 | |
|
1471 | 12 | } else { |
1472 | |
|
1473 | |
|
1474 | 0 | heatMapMinY = minY+columnNamesHeight; |
1475 | 0 | columnTreeLocation = RectangleEdge.BOTTOM; |
1476 | 0 | columnNamesLocation = RectangleEdge.TOP; |
1477 | |
|
1478 | |
} |
1479 | |
|
1480 | 12 | heatMapMaxX = heatMapMinX + heatMapWidth; |
1481 | 12 | heatMapMaxY = heatMapMinY + heatMapHeight; |
1482 | |
|
1483 | 12 | if (drawFromTopToBottom) { |
1484 | |
|
1485 | 12 | columnTreeArea = new Rectangle( |
1486 | |
heatMapMinX, minY, heatMapWidth, columnTreeHeight |
1487 | |
); |
1488 | 12 | columnNamesArea = new Rectangle( |
1489 | |
heatMapMinX, heatMapMaxY, heatMapWidth, maxY-heatMapMaxY |
1490 | |
); |
1491 | |
|
1492 | 12 | } else { |
1493 | |
|
1494 | |
|
1495 | 0 | columnTreeArea = new Rectangle( |
1496 | |
heatMapMinX, heatMapMaxY, heatMapWidth, columnTreeHeight |
1497 | |
); |
1498 | 0 | columnNamesArea = new Rectangle( |
1499 | |
heatMapMinX, minY, heatMapWidth, maxY-heatMapMaxY |
1500 | |
); |
1501 | |
|
1502 | |
} |
1503 | |
|
1504 | 12 | if (drawFromLeftToRight) { |
1505 | |
|
1506 | 12 | rowTreeArea = new Rectangle( |
1507 | |
minX, heatMapMinY, rowTreeWidth, heatMapHeight |
1508 | |
); |
1509 | 12 | rowNamesArea = new Rectangle( |
1510 | |
heatMapMaxX, heatMapMinY, maxX-heatMapMaxX, heatMapHeight |
1511 | |
); |
1512 | |
|
1513 | 12 | } else { |
1514 | |
|
1515 | |
|
1516 | 0 | rowTreeArea = new Rectangle( |
1517 | |
heatMapMaxX, heatMapMinY, rowTreeWidth, heatMapHeight |
1518 | |
); |
1519 | 0 | rowNamesArea = new Rectangle( |
1520 | |
minX, heatMapMinY, maxX-heatMapMaxX, heatMapHeight |
1521 | |
); |
1522 | |
|
1523 | |
} |
1524 | |
|
1525 | 12 | heatMapArea = new Rectangle( |
1526 | |
heatMapMinX, heatMapMinY, heatMapWidth, heatMapHeight |
1527 | |
); |
1528 | |
|
1529 | |
int sizeOfNodeSymbol; |
1530 | |
double getColumnTreeHeightUnitInPixels; |
1531 | |
double getRowTreeHeightUnitInPixels; |
1532 | 12 | double blockWidth = columnTreeArea.getWidth()/visibleColumns; |
1533 | 12 | double blockHeight = rowTreeArea.getHeight()/visibleRows; |
1534 | |
|
1535 | 12 | if (blockWidth < blockHeight) |
1536 | 11 | sizeOfNodeSymbol = (int)(3 + blockWidth/5); |
1537 | |
else |
1538 | 1 | sizeOfNodeSymbol = (int)(3 + blockHeight/5); |
1539 | |
|
1540 | 12 | if (this.dataset.getColumnClusteringTree() != null) |
1541 | 11 | getColumnTreeHeightUnitInPixels = columnTreeArea.getHeight() / |
1542 | |
this.dataset.getColumnClusteringTree().getHeight(); |
1543 | |
else |
1544 | 1 | getColumnTreeHeightUnitInPixels = 0; |
1545 | |
|
1546 | 12 | if (this.dataset.getRowClusteringTree() != null) |
1547 | 11 | getRowTreeHeightUnitInPixels = rowTreeArea.getWidth() / |
1548 | |
this.dataset.getRowClusteringTree().getHeight(); |
1549 | |
else |
1550 | 1 | getRowTreeHeightUnitInPixels = 0; |
1551 | |
|
1552 | 12 | HCPlotState state = new HCPlotState( |
1553 | |
info, |
1554 | |
(int)(heatMapArea.getMinX()), |
1555 | |
(int)(heatMapArea.getMinY()), |
1556 | |
sizeOfNodeSymbol, |
1557 | |
blockWidth, |
1558 | |
blockHeight, |
1559 | |
getColumnTreeHeightUnitInPixels, |
1560 | |
getRowTreeHeightUnitInPixels); |
1561 | |
|
1562 | 12 | if (info != null) { |
1563 | |
|
1564 | 11 | info.setPlotArea(area); |
1565 | 11 | info.setDataArea(heatMapArea); |
1566 | |
|
1567 | |
} |
1568 | |
|
1569 | |
|
1570 | |
|
1571 | |
|
1572 | 12 | drawBackground(g2,area); |
1573 | |
|
1574 | 11 | drawHeatMap(g2,state,heatMapArea,visibleColumns,visibleRows); |
1575 | |
|
1576 | 8 | if ( (getColumnTreeVisibility ()) && |
1577 | |
(g2.getClip().intersects(columnTreeArea))) { |
1578 | |
|
1579 | 7 | drawSubTree( |
1580 | |
g2, |
1581 | |
state, |
1582 | |
this.columnClusteringInfo.getRootNode(), |
1583 | |
columnTreeArea, |
1584 | |
columnTreeLocation |
1585 | |
); |
1586 | |
|
1587 | |
} |
1588 | 8 | if ( (getRowTreeVisibility ()) && |
1589 | |
(g2.getClip().intersects(rowTreeArea))) { |
1590 | |
|
1591 | 7 | drawSubTree( |
1592 | |
g2, |
1593 | |
state, |
1594 | |
this.rowClusteringInfo.getRootNode(), |
1595 | |
rowTreeArea, |
1596 | |
rowTreeLocation |
1597 | |
); |
1598 | |
|
1599 | |
} |
1600 | 8 | if (getRowNamesVisibility ()) { |
1601 | |
|
1602 | 8 | this.rowNames.draw( |
1603 | |
g2, |
1604 | |
RectangleEdge.coordinate(heatMapArea,rowNamesLocation), |
1605 | |
area, |
1606 | |
rowNamesArea, |
1607 | |
rowNamesLocation, |
1608 | |
info |
1609 | |
|
1610 | |
); |
1611 | |
|
1612 | |
} |
1613 | 8 | if (getColumnNamesVisibility ()) { |
1614 | |
|
1615 | 8 | this.columnNames.draw( |
1616 | |
g2, |
1617 | |
RectangleEdge.coordinate(heatMapArea,columnNamesLocation), |
1618 | |
area, |
1619 | |
columnNamesArea, |
1620 | |
columnNamesLocation, |
1621 | |
info |
1622 | |
); |
1623 | |
} |
1624 | |
|
1625 | 8 | if ( !closedRows.isEmpty() ) { |
1626 | |
|
1627 | 1 | int rowcount = closedRows.size(); |
1628 | 1 | Integer item = null; |
1629 | 1 | Color color = new Color(0,0,0); |
1630 | |
|
1631 | 1 | int i=0; |
1632 | 2 | while (i < rowcount) { |
1633 | 1 | i++; |
1634 | 1 | item = (Integer)closedRows.first(); |
1635 | 1 | closedRows.remove(item); |
1636 | 1 | Rectangle r = new Rectangle( |
1637 | |
0, |
1638 | |
item.intValue(), |
1639 | |
visibleColumns, |
1640 | |
1 |
1641 | |
); |
1642 | 1 | drawSelection(g2, state, color, r); |
1643 | 1 | } |
1644 | |
} |
1645 | |
|
1646 | 8 | if ( !closedColumns.isEmpty() ) { |
1647 | |
|
1648 | 3 | int columncount = closedColumns.size(); |
1649 | 3 | Integer item = null; |
1650 | 3 | Color color = new Color(0,0,0); |
1651 | |
|
1652 | 3 | int i=0; |
1653 | 6 | while (i < columncount) { |
1654 | 3 | i++; |
1655 | 3 | item = (Integer)closedColumns.first(); |
1656 | 3 | closedColumns.remove(item); |
1657 | 3 | Rectangle r = new Rectangle( |
1658 | |
item.intValue(), |
1659 | |
0, |
1660 | |
1, |
1661 | |
visibleRows |
1662 | |
); |
1663 | 3 | drawSelection(g2, state, color, r); |
1664 | 3 | } |
1665 | |
} |
1666 | |
|
1667 | 8 | if ( this.selection != null && getSelectionHighlight()) { |
1668 | 3 | Color color = new Color(255,255,255); |
1669 | 3 | drawSelection(g2, state, color, this.selection); |
1670 | |
} |
1671 | |
|
1672 | 8 | } |
1673 | |
|
1674 | |
|
1675 | |
|
1676 | |
|
1677 | |
|
1678 | |
|
1679 | |
public void chartMouseMoved(ChartMouseEvent event) { |
1680 | |
|
1681 | 3 | if ((this.mouseOverHighlight) && (event.getEntity() != null)) { |
1682 | |
|
1683 | 2 | if (event.getEntity() instanceof HeatMapBlockEntity) { |
1684 | |
|
1685 | 1 | HeatMapBlockEntity entity = |
1686 | |
(HeatMapBlockEntity)event.getEntity(); |
1687 | 1 | int oldRow = getRowTreeHighlight (); |
1688 | 1 | int oldColumn = getColumnTreeHighlight (); |
1689 | |
|
1690 | 1 | if ((oldRow != entity.getRow()) |
1691 | |
|| (oldColumn != entity.getColumn())) { |
1692 | |
|
1693 | 1 | setRowTreeHighlight (entity.getRow()); |
1694 | 1 | setColumnTreeHighlight (entity.getColumn()); |
1695 | |
|
1696 | |
|
1697 | |
|
1698 | |
} |
1699 | |
|
1700 | 1 | } else if (event.getEntity() instanceof HCTreeNodeEntity) { |
1701 | |
|
1702 | |
; |
1703 | |
|
1704 | |
} |
1705 | |
|
1706 | |
} |
1707 | |
|
1708 | 3 | } |
1709 | |
|
1710 | |
|
1711 | |
|
1712 | |
|
1713 | |
|
1714 | |
|
1715 | |
public void chartMouseClicked(ChartMouseEvent event) { |
1716 | |
|
1717 | 13 | MouseEvent e = event.getTrigger(); |
1718 | 13 | if (event.getEntity() != null) { |
1719 | |
|
1720 | 10 | if (event.getEntity() instanceof HeatMapBlockEntity && |
1721 | |
|
1722 | |
getSelectionHighlight()) { |
1723 | |
|
1724 | 3 | HeatMapBlockEntity entity = |
1725 | |
(HeatMapBlockEntity)event.getEntity(); |
1726 | |
|
1727 | 3 | Rectangle selectionCandidate = new Rectangle ( |
1728 | |
entity.getColumn(), |
1729 | |
entity.getRow(), |
1730 | |
1, |
1731 | |
1 |
1732 | |
); |
1733 | 3 | if (selectionCandidate.equals(this.selection)) { |
1734 | |
|
1735 | 1 | this.selection=null; |
1736 | |
|
1737 | 1 | } else { |
1738 | |
|
1739 | 2 | setSelection ( selectionCandidate ); |
1740 | |
|
1741 | |
} |
1742 | |
|
1743 | 3 | } else if (event.getEntity() instanceof HCTreeNodeEntity) { |
1744 | |
|
1745 | 7 | HCTreeNodeEntity entity = |
1746 | |
(HCTreeNodeEntity)event.getEntity(); |
1747 | 7 | HCTreeNodeInfo node = entity.getHCTreeNodeInfo(); |
1748 | 7 | boolean alt = event.getTrigger().isAltDown(); |
1749 | 7 | boolean shift = event.getTrigger().isShiftDown(); |
1750 | 7 | boolean control = event.getTrigger().isControlDown(); |
1751 | 7 | if (shift) { |
1752 | |
|
1753 | 2 | node.setSubTreeOpen(!node.isNodeOpen()); |
1754 | |
|
1755 | 2 | } else if (!control) { |
1756 | |
|
1757 | 3 | this.selection = null; |
1758 | 3 | node.setNodeOpen(!node.isNodeOpen()); |
1759 | |
|
1760 | 3 | } else if (control) { |
1761 | |
|
1762 | 2 | handleClick(node); |
1763 | |
|
1764 | |
} |
1765 | |
|
1766 | |
} |
1767 | |
|
1768 | |
|
1769 | |
} |
1770 | |
|
1771 | 13 | } |
1772 | |
|
1773 | |
|
1774 | |
|
1775 | |
|
1776 | |
|
1777 | |
|
1778 | |
|
1779 | |
private void handleClick(HCTreeNodeInfo node) { |
1780 | |
|
1781 | 2 | int treelocation = node.getClusteringInfo().getLocation(); |
1782 | 2 | int leftbound=0; |
1783 | 2 | int rightbound=0; |
1784 | |
Rectangle r; |
1785 | |
|
1786 | |
try { |
1787 | 2 | leftbound = node.getVisibleDataRange().getLeftBound(); |
1788 | 2 | rightbound = node.getVisibleDataRange().getRightBound(); |
1789 | 0 | } catch (Exception e){ |
1790 | 0 | return; |
1791 | 2 | } |
1792 | |
|
1793 | 2 | if (treelocation == this.LEFT) { |
1794 | 1 | r = new Rectangle( |
1795 | |
0, |
1796 | |
leftbound, |
1797 | |
this.getHeatMapColumnsCount(), |
1798 | |
rightbound-leftbound+1 |
1799 | |
); |
1800 | 1 | } |
1801 | 1 | else if (treelocation == this.TOP) { |
1802 | 1 | r = new Rectangle( |
1803 | |
leftbound, |
1804 | |
0, |
1805 | |
rightbound-leftbound+1, |
1806 | |
this.getHeatMapRowCount() |
1807 | |
|
1808 | |
|
1809 | |
); |
1810 | |
|
1811 | 1 | } |
1812 | 0 | else r=null; |
1813 | |
|
1814 | 2 | if (this.selection != null && this.selection.equals(r)) |
1815 | 1 | this.selection = null; |
1816 | |
else |
1817 | 1 | this.setSelection(r); |
1818 | |
|
1819 | |
|
1820 | 2 | } |
1821 | |
|
1822 | |
|
1823 | |
|
1824 | |
|
1825 | |
|
1826 | |
|
1827 | |
|
1828 | |
public void stateChanged(ChangeEvent event) { |
1829 | |
|
1830 | 8 | Object source = event.getSource(); |
1831 | 7 | if (source instanceof HCTreeNodeInfo) { |
1832 | |
|
1833 | |
|
1834 | |
|
1835 | 7 | HCTreeNodeInfo info = (HCTreeNodeInfo)(event.getSource()); |
1836 | 7 | this.notifyListeners(new ClusteringTreeChangeEvent (this, info)); |
1837 | |
|
1838 | |
} |
1839 | |
|
1840 | 7 | } |
1841 | |
|
1842 | |
|
1843 | |
|
1844 | |
|
1845 | |
|
1846 | |
|
1847 | |
public HCToolTipGenerator getToolTipGenerator() { |
1848 | |
|
1849 | 2 | return this.toolTipGenerator; |
1850 | |
|
1851 | |
} |
1852 | |
|
1853 | |
|
1854 | |
|
1855 | |
|
1856 | |
|
1857 | |
|
1858 | |
public void setToolTipGenerator(HCToolTipGenerator toolTipGenerator) { |
1859 | |
|
1860 | 4 | this.toolTipGenerator = toolTipGenerator; |
1861 | |
|
1862 | 4 | } |
1863 | |
|
1864 | |
|
1865 | |
|
1866 | |
|
1867 | |
|
1868 | |
|
1869 | |
public JPanel getOptionsPanel() { |
1870 | |
|
1871 | 1 | return this.optionsEditor.getPanel(); |
1872 | |
|
1873 | |
} |
1874 | |
|
1875 | |
|
1876 | |
|
1877 | |
|
1878 | |
|
1879 | |
|
1880 | |
public JPanel getPalettePanel() { |
1881 | |
|
1882 | 1 | return this.paletteEditor.getPanel(); |
1883 | |
|
1884 | |
} |
1885 | |
|
1886 | |
|
1887 | |
|
1888 | |
|
1889 | |
|
1890 | |
|
1891 | |
public String getOptionsPanelName() { |
1892 | |
|
1893 | 1 | ResourceBundle lr = ResourceBundle.getBundle("org.jfree.chart.editor.LocalizationBundle"); |
1894 | 1 | return lr.getString("HC_options_panel"); |
1895 | |
|
1896 | |
} |
1897 | |
|
1898 | |
|
1899 | |
|
1900 | |
|
1901 | |
|
1902 | |
|
1903 | |
public String getPalettePanelName() { |
1904 | |
|
1905 | 1 | ResourceBundle lr = ResourceBundle.getBundle("org.jfree.chart.editor.LocalizationBundle"); |
1906 | 1 | return lr.getString("HC_palette_panel"); |
1907 | |
|
1908 | |
} |
1909 | |
|
1910 | |
} |
1911 | |
|