Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TParallelCoordRange.cxx
Go to the documentation of this file.
1 // @(#)root/treeviewer:$Id$
2 // Author: Bastien Dalla Piazza 02/08/2007
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TParallelCoordRange.h"
13 #include "TParallelCoord.h"
14 #include "TParallelCoordVar.h"
15 
16 #include "TBox.h"
17 #include "TPolyLine.h"
18 #include "TList.h"
19 #include "TVirtualPad.h"
20 #include "TVirtualX.h"
21 #include "TPoint.h"
22 #include "TFrame.h"
23 #include "Riostream.h"
24 #include "TCanvas.h"
25 #include "TString.h"
26 
27 ClassImp(TParallelCoordRange);
28 
29 /** \class TParallelCoordRange
30 A TParallelCoordRange is a range used for parallel coordinates plots.
31 */
32 
33 ////////////////////////////////////////////////////////////////////////////////
34 /// Default constructor.
35 
36 TParallelCoordRange::TParallelCoordRange()
37  :TNamed("Range","Range"), TAttLine(), fSize(0.01)
38 {
39  fMin = 0;
40  fMax = 0;
41  fVar = NULL;
42  fSelect = NULL;
43  SetBit(kShowOnPad,kTRUE);
44  SetBit(kLiveUpdate,kFALSE);
45 }
46 
47 ////////////////////////////////////////////////////////////////////////////////
48 /// Destructor.
49 
50 TParallelCoordRange::~TParallelCoordRange()
51 {
52 }
53 
54 ////////////////////////////////////////////////////////////////////////////////
55 /// Normal constructor.
56 
57 TParallelCoordRange::TParallelCoordRange(TParallelCoordVar *var, Double_t min, Double_t max, TParallelCoordSelect *sel)
58  :TNamed("Range","Range"), TAttLine(1,1,1), fSize(0.01)
59 {
60  if(min == max) {
61  min = var->GetCurrentMin();
62  max = var->GetCurrentMax();
63  }
64  fMin = min;
65  fMax = max;
66 
67  fVar = var;
68  fSelect = NULL;
69 
70  if (!sel) {
71  TParallelCoordSelect* s = var->GetParallel()->GetCurrentSelection();
72  if (s) fSelect = s;
73  else return;
74  } else {
75  fSelect = sel;
76  }
77 
78  SetLineColor(fSelect->GetLineColor());
79 
80  SetBit(kShowOnPad,kTRUE);
81  SetBit(kLiveUpdate,var->GetParallel()->TestBit(TParallelCoord::kLiveUpdate));
82 }
83 
84 ////////////////////////////////////////////////////////////////////////////////
85 /// Make the selection which owns the range to be drawn on top of the others.
86 
87 void TParallelCoordRange::BringOnTop()
88 {
89  TList *list = fVar->GetParallel()->GetSelectList();
90  list->Remove(fSelect);
91  list->AddLast(fSelect);
92  gPad->Update();
93 }
94 
95 ////////////////////////////////////////////////////////////////////////////////
96 /// Delete the range.
97 
98 void TParallelCoordRange::Delete(const Option_t* /*options*/)
99 {
100  fVar->GetRanges()->Remove(this);
101  fVar->GetParallel()->CleanUpSelections(this);
102  delete this;
103 }
104 
105 ////////////////////////////////////////////////////////////////////////////////
106 /// Compute the distance to the primitive.
107 
108 Int_t TParallelCoordRange::DistancetoPrimitive(Int_t px, Int_t py)
109 {
110  if(TestBit(kShowOnPad)){
111  Double_t xx,yy,thisx=0,thisy=0;
112  xx = gPad->AbsPixeltoX(px);
113  yy = gPad->AbsPixeltoY(py);
114  fVar->GetXYfromValue(fMin,thisx,thisy);
115  Int_t dist = 9999;
116  if(fVar->GetVert()){
117  if(xx > thisx-2*fSize && xx < thisx && yy > thisy-fSize && yy<thisy+fSize) dist = 0;
118  fVar->GetXYfromValue(fMax,thisx,thisy);
119  if(xx > thisx-2*fSize && xx < thisx && yy > thisy-fSize && yy<thisy+fSize) dist = 0;
120  } else {
121  if(yy > thisy-2*fSize && yy < thisy && xx > thisx-fSize && xx<thisx+fSize) dist = 0;
122  fVar->GetXYfromValue(fMax,thisx,thisy);
123  if(yy > thisy-2*fSize && yy < thisy && xx > thisx-fSize && xx<thisx+fSize) dist = 0;
124  }
125  return dist;
126  } else return 9999;
127 }
128 
129 ////////////////////////////////////////////////////////////////////////////////
130 /// Draw a TParallelCoordRange.
131 
132 void TParallelCoordRange::Draw(Option_t* options)
133 {
134  AppendPad(options);
135 }
136 
137 ////////////////////////////////////////////////////////////////////////////////
138 /// Execute the entry.
139 
140 void TParallelCoordRange::ExecuteEvent(Int_t entry, Int_t px, Int_t py)
141 {
142  if (!gPad) return;
143  if (!gPad->IsEditable() && entry!=kMouseEnter) return;
144 
145  Bool_t vert = fVar->GetVert();
146  static Int_t pxold, pyold;
147  static Int_t mindragged = -1; //-1:nothing dragged, 0:max dragged, 1:mindragged, 2:both dragged;
148  Int_t plx1,plx2,ply1,ply2;
149 
150  Double_t xx,yy,txxmin=0,txxmax=0,tyymin=0,tyymax=0;
151  TFrame *frame = gPad->GetFrame();
152  xx = gPad->AbsPixeltoX(px);
153  yy = gPad->AbsPixeltoY(py);
154  fVar->GetXYfromValue(fMin,txxmin,tyymin);
155  fVar->GetXYfromValue(fMax,txxmax,tyymax);
156  if (vert) {
157  plx1 = gPad->XtoAbsPixel(txxmin-2*fSize);
158  plx2 = gPad->XtoAbsPixel(txxmax-2*fSize);
159  ply1 = gPad->YtoAbsPixel(tyymin+fSize);
160  ply2 = gPad->YtoAbsPixel(tyymax-fSize);
161  } else {
162  plx1 = gPad->XtoAbsPixel(txxmin+fSize);
163  plx2 = gPad->XtoAbsPixel(txxmax-fSize);
164  ply1 = gPad->YtoAbsPixel(tyymin-2*fSize);
165  ply2 = gPad->YtoAbsPixel(tyymax-2*fSize);
166  }
167 
168  gPad->SetCursor(kPointer);
169  gVirtualX->SetLineColor(-1);
170  gVirtualX->SetLineWidth(1);
171  TPoint *p = NULL;
172  switch (entry) {
173  case kButton1Down:
174  fVar->GetParallel()->SetCurrentSelection(fSelect);
175  ((TCanvas*)gPad)->Selected(gPad,fVar->GetParallel(),1);
176  if ((vert && yy<tyymax-fSize) || (!vert && xx < txxmax-fSize)) { //checks if the min slider is clicked.
177  mindragged = 1;
178  p = GetSliderPoints(fMin);
179  gVirtualX->DrawPolyLine(5,p);
180  delete [] p;
181  } else {
182  mindragged = 0;
183  p = GetSliderPoints(fMax);
184  gVirtualX->DrawPolyLine(5,p);
185  delete [] p;
186  }
187  gVirtualX->DrawLine(plx1,ply1,plx2,ply2);
188  break;
189  case kButton1Up: {
190  Double_t min = fMin, max= fMax;
191  if (mindragged == 1) min = fVar->GetValuefromXY(xx,yy);
192  if (mindragged == 0) max = fVar->GetValuefromXY(xx,yy);
193  if(fMin!=min || fMax != max) {
194  if (min>max) {
195  Double_t mem = min;
196  min = max;
197  max = mem;
198  }
199  fMin = min;
200  fMax = max;
201  gPad->Modified();
202  }
203  mindragged = -1;
204  break;
205  }
206  case kMouseMotion:
207  pxold = px;
208  pyold = py;
209  break;
210  case kButton1Motion:
211  if((vert && yy > frame->GetY1() && yy < frame->GetY2()) ||
212  (!vert && xx > frame->GetX1() && xx < frame->GetX2())){
213  if (vert) p = GetSliderPoints(pyold);
214  else p = GetSliderPoints(pxold);
215  gVirtualX->DrawPolyLine(5,p);
216  delete [] p;
217  if (vert) p = GetBindingLinePoints(pyold,mindragged);
218  else p = GetBindingLinePoints(pxold,mindragged);
219  gVirtualX->DrawPolyLine(2,p);
220  delete [] p;
221  if (vert) p = GetSliderPoints(py);
222  else p = GetSliderPoints(px);
223  gVirtualX->DrawPolyLine(5,p);
224  delete [] p;
225  if (vert) p = GetBindingLinePoints(py,mindragged);
226  else p = GetBindingLinePoints(px,mindragged);
227  gVirtualX->DrawPolyLine(2,p);
228  delete [] p;
229  if (TestBit(kLiveUpdate)){
230  Double_t min = fMin, max= fMax;
231  if (mindragged == 1) min = fVar->GetValuefromXY(xx,yy);
232  if (mindragged == 0) max = fVar->GetValuefromXY(xx,yy);
233  if(fMin!=min || fMax != max) {
234  if (min>max) {
235  Double_t mem = min;
236  min = max;
237  max = mem;
238  }
239  fMin = min;
240  fMax = max;
241  gPad->Modified();
242  gPad->Update();
243  }
244  }
245  }
246  pxold = px;
247  pyold = py;
248  break;
249  default:
250  //std::cout<<"entry: "<<entry<<std::endl;
251  break;
252  }
253 }
254 
255 ////////////////////////////////////////////////////////////////////////////////
256 /// Return the points of the line binding the two needles of the range.
257 
258 TPoint* TParallelCoordRange::GetBindingLinePoints(Int_t pos,Int_t mindragged)
259 {
260  Double_t txx,tyy,txxo,tyyo=0;
261  if (fVar->GetVert()){
262  txx = fVar->GetX();
263  tyy = gPad->AbsPixeltoY(pos);
264  } else {
265  tyy = fVar->GetY();
266  txx = gPad->AbsPixeltoX(pos);
267  }
268  if (mindragged==1) fVar->GetXYfromValue(fMax,txxo,tyyo);
269  else fVar->GetXYfromValue(fMin,txxo,tyyo);
270 
271  TPoint *bindline = new TPoint[2];
272  if (fVar->GetVert()) {
273  if (mindragged==1) {
274  bindline[0] = TPoint(gPad->XtoAbsPixel(txx-2*fSize),gPad->YtoAbsPixel(tyy+fSize));
275  bindline[1] = TPoint(gPad->XtoAbsPixel(txx-2*fSize),gPad->YtoAbsPixel(tyyo-fSize));
276  } else {
277  bindline[0] = TPoint(gPad->XtoAbsPixel(txx-2*fSize),gPad->YtoAbsPixel(tyyo+fSize));
278  bindline[1] = TPoint(gPad->XtoAbsPixel(txx-2*fSize),gPad->YtoAbsPixel(tyy-fSize));
279  }
280  } else {
281  if (mindragged==1) {
282  bindline[0] = TPoint(gPad->XtoAbsPixel(txx+fSize),gPad->YtoAbsPixel(tyy-2*fSize));
283  bindline[1] = TPoint(gPad->XtoAbsPixel(txxo-fSize),gPad->YtoAbsPixel(tyy-2*fSize));
284  } else {
285  bindline[0] = TPoint(gPad->XtoAbsPixel(txxo+fSize),gPad->YtoAbsPixel(tyy-2*fSize));
286  bindline[1] = TPoint(gPad->XtoAbsPixel(txx-fSize),gPad->YtoAbsPixel(tyy-2*fSize));
287  }
288  }
289  return bindline;
290 }
291 
292 ////////////////////////////////////////////////////////////////////////////////
293 /// Return the points to paint the needles at "value".
294 
295 TPoint* TParallelCoordRange::GetSliderPoints(Double_t value)
296 {
297  Double_t txx=0,tyy=0;
298  fVar->GetXYfromValue(value,txx,tyy);
299  Int_t tx[5];
300  Int_t ty[5];
301  if (fVar->GetVert()) {
302  tx[0]=gPad->XtoAbsPixel(txx);
303  tx[1]=tx[4]=gPad->XtoAbsPixel(txx-fSize);
304  ty[0]=ty[1]=ty[4]=gPad->YtoAbsPixel(tyy);
305  tx[2]=tx[3]=gPad->XtoAbsPixel(txx-2*fSize);
306  ty[2]=gPad->YtoAbsPixel(tyy+fSize);
307  ty[3]=gPad->YtoAbsPixel(tyy-fSize);
308  } else {
309  ty[0]=gPad->YtoAbsPixel(tyy);
310  ty[1]=ty[4]=gPad->YtoAbsPixel(tyy-fSize);
311  tx[0]=tx[1]=tx[4]=gPad->XtoAbsPixel(txx);
312  ty[2]=ty[3]=gPad->YtoAbsPixel(tyy-2*fSize);
313  tx[2]=gPad->XtoAbsPixel(txx-fSize);
314  tx[3]=gPad->XtoAbsPixel(txx+fSize);
315  }
316  TPoint *slider = new TPoint[5];
317  for(UInt_t ui=0;ui<5;++ui) slider[ui] = TPoint(tx[ui],ty[ui]);
318  return slider;
319 }
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// Return the points to paint the needle at "pos".
323 
324 TPoint* TParallelCoordRange::GetSliderPoints(Int_t pos)
325 {
326  Double_t txx,tyy;
327  if (fVar->GetVert()){
328  txx = fVar->GetX();
329  tyy = gPad->AbsPixeltoY(pos);
330  } else {
331  tyy = fVar->GetY();
332  txx = gPad->AbsPixeltoX(pos);
333  }
334 
335  Int_t tx[5];
336  Int_t ty[5];
337  if (fVar->GetVert()) {
338  tx[0]=gPad->XtoAbsPixel(txx);
339  tx[1]=tx[4]=gPad->XtoAbsPixel(txx-fSize);
340  ty[0]=ty[1]=ty[4]=gPad->YtoAbsPixel(tyy);
341  tx[2]=tx[3]=gPad->XtoAbsPixel(txx-2*fSize);
342  ty[2]=gPad->YtoAbsPixel(tyy+fSize);
343  ty[3]=gPad->YtoAbsPixel(tyy-fSize);
344  } else {
345  ty[0]=gPad->YtoAbsPixel(tyy);
346  ty[1]=ty[4]=gPad->YtoAbsPixel(tyy-fSize);
347  tx[0]=tx[1]=tx[4]=gPad->XtoAbsPixel(txx);
348  ty[2]=ty[3]=gPad->YtoAbsPixel(tyy-2*fSize);
349  tx[2]=gPad->XtoAbsPixel(txx-fSize);
350  tx[3]=gPad->XtoAbsPixel(txx+fSize);
351  }
352  TPoint *slider = new TPoint[5];
353  for(UInt_t ui=0;ui<5;++ui) slider[ui] = TPoint(tx[ui],ty[ui]);
354  return slider;
355 }
356 
357 ////////////////////////////////////////////////////////////////////////////////
358 /// Evaluate if the given value is within the range or not.
359 
360 Bool_t TParallelCoordRange::IsIn(Double_t evtval)
361 {
362  return evtval>=fMin && evtval<=fMax;
363 }
364 
365 ////////////////////////////////////////////////////////////////////////////////
366 /// Paint a TParallelCoordRange.
367 
368 void TParallelCoordRange::Paint(Option_t* /*options*/)
369 {
370  if(TestBit(kShowOnPad)){
371  PaintSlider(fMin,kTRUE);
372  PaintSlider(fMax,kTRUE);
373  }
374 }
375 
376 ////////////////////////////////////////////////////////////////////////////////
377 /// Paint a slider.
378 
379 void TParallelCoordRange::PaintSlider(Double_t value, Bool_t fill)
380 {
381  SetLineColor(fSelect->GetLineColor());
382 
383  TPolyLine *p= new TPolyLine();
384  p->SetLineStyle(1);
385  p->SetLineColor(1);
386  p->SetLineWidth(1);
387 
388  Double_t *x = new Double_t[5];
389  Double_t *y = new Double_t[5];
390 
391  Double_t xx,yy;
392 
393  fVar->GetXYfromValue(value,xx,yy);
394  if(fVar->GetVert()){
395  x[0] = xx; x[1]=x[4]=xx-fSize; x[2]=x[3]=xx-2*fSize;
396  y[0]=y[1]=y[4]=yy; y[2] = yy+fSize; y[3] = yy-fSize;
397  } else {
398  y[0] = yy; y[1]=y[4]=yy-fSize; y[2]=y[3]= yy-2*fSize;
399  x[0]=x[1]=x[4]=xx; x[2]=xx-fSize; x[3] = xx+fSize;
400  }
401  if (fill) {
402  p->SetFillStyle(1001);
403  p->SetFillColor(0);
404  p->PaintPolyLine(4,&x[1],&y[1],"f");
405  p->SetFillColor(GetLineColor());
406  p->SetFillStyle(3001);
407  p->PaintPolyLine(4,&x[1],&y[1],"f");
408  }
409  p->PaintPolyLine(5,x,y);
410 
411  delete p;
412  delete [] x;
413  delete [] y;
414 }
415 
416 ////////////////////////////////////////////////////////////////////////////////
417 /// Print info about the range.
418 
419 void TParallelCoordRange::Print(Option_t* /*options*/) const
420 {
421  printf("On \"%s\" : min = %f, max = %f\n", fVar->GetTitle(), fMin, fMax);
422 }
423 
424 ////////////////////////////////////////////////////////////////////////////////
425 /// Make the selection which owns the range to be drawn under all the others.
426 
427 void TParallelCoordRange::SendToBack()
428 {
429  TList *list = fVar->GetParallel()->GetSelectList();
430  list->Remove(fSelect);
431  list->AddFirst(fSelect);
432  gPad->Update();
433 }
434 
435 ////////////////////////////////////////////////////////////////////////////////
436 /// Set the selection line color.
437 
438 void TParallelCoordRange::SetLineColor(Color_t col)
439 {
440  fSelect->SetLineColor(col);
441  TAttLine::SetLineColor(col);
442 }
443 
444 ////////////////////////////////////////////////////////////////////////////////
445 /// Set the selection line width.
446 
447 void TParallelCoordRange::SetLineWidth(Width_t wid)
448 {
449  fSelect->SetLineWidth(wid);
450 }
451 
452 
453 ClassImp(TParallelCoordSelect);
454 
455 /** \class TParallelCoordSelect
456 A TParallelCoordSelect is a specialised TList to hold TParallelCoordRanges used
457 by TParallelCoord.
458 
459 Selections of specific entries can be defined over the data se using parallel
460 coordinates. With that representation, a selection is an ensemble of ranges
461 defined on the axes. Ranges defined on the same axis are conjugated with OR
462 (an entry must be in one or the other ranges to be selected). Ranges on
463 different axes are are conjugated with AND (an entry must be in all the ranges
464 to be selected). Several selections can be defined with different colors. It is
465 possible to generate an entry list from a given selection and apply it to the
466 tree using the editor ("Apply to tree" button).
467 */
468 
469 ////////////////////////////////////////////////////////////////////////////////
470 /// Default constructor.
471 
472 TParallelCoordSelect::TParallelCoordSelect()
473  : TList(), TAttLine(kBlue,1,1)
474 {
475  fTitle = "Selection";
476  SetBit(kActivated,kTRUE);
477  SetBit(kShowRanges,kTRUE);
478 }
479 
480 ////////////////////////////////////////////////////////////////////////////////
481 /// Normal constructor.
482 
483 TParallelCoordSelect::TParallelCoordSelect(const char* title)
484  : TList(), TAttLine(kBlue,1,1)
485 {
486  fTitle = title;
487  SetBit(kActivated,kTRUE);
488  SetBit(kShowRanges,kTRUE);
489 }
490 
491 ////////////////////////////////////////////////////////////////////////////////
492 /// Destructor.
493 
494 TParallelCoordSelect::~TParallelCoordSelect()
495 {
496  TIter next(this);
497  TParallelCoordRange* range;
498  while ((range = (TParallelCoordRange*)next())) range->GetVar()->GetRanges()->Remove(range);
499  TList::Delete();
500 }
501 
502 ////////////////////////////////////////////////////////////////////////////////
503 /// Activate the selection.
504 
505 void TParallelCoordSelect::SetActivated(Bool_t on)
506 {
507  TIter next(this);
508  TParallelCoordRange* range;
509  while ((range = (TParallelCoordRange*)next())) range->SetBit(TParallelCoordRange::kShowOnPad,on);
510  SetBit(kActivated,on);
511 }
512 
513 ////////////////////////////////////////////////////////////////////////////////
514 /// Show the ranges needles.
515 
516 void TParallelCoordSelect::SetShowRanges(Bool_t s)
517 {
518  TIter next(this);
519  TParallelCoordRange* range;
520  while ((range = (TParallelCoordRange*)next())) range->SetBit(TParallelCoordRange::kShowOnPad,s);
521  SetBit(kShowRanges,s);
522 }