TParallelCoord.cxx

Go to the documentation of this file.
00001 // @(#)root/treeviewer:$Id: TParallelCoord.cxx 35796 2010-09-27 13:40:30Z couet $
00002 // Author: Bastien Dalla Piazza  02/08/2007
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include "TParallelCoord.h"
00013 #include "TParallelCoordVar.h"
00014 #include "TParallelCoordRange.h"
00015 
00016 #include "Riostream.h"
00017 #include "TROOT.h"
00018 #include "TVirtualX.h"
00019 #include "TPad.h"
00020 #include "TPolyLine.h"
00021 #include "TGraph.h"
00022 #include "TPaveText.h"
00023 #include "float.h"
00024 #include "TMath.h"
00025 #include "TBox.h"
00026 #include "TH1.h"
00027 #include "TStyle.h"
00028 #include "TEntryList.h"
00029 #include "TFrame.h"
00030 #include "TTree.h"
00031 #include "TTreePlayer.h"
00032 #include "TSelectorDraw.h"
00033 #include "TTreeFormula.h"
00034 #include "TView.h"
00035 #include "TRandom.h"
00036 #include "TEnv.h"
00037 #include "TCanvas.h"
00038 #include "TGaxis.h"
00039 #include "TFile.h"
00040 
00041 ClassImp(TParallelCoord)
00042 
00043 //______________________________________________________________________________
00044 /* Begin_Html
00045 <center><h2>Parallel Coordinates class</h2></center>
00046 <p>
00047 The multidimensional system of Parallel coordinates is a common way of studying high-dimensional geometry and visualizing multivariate problems. It has first been proposed by A. Inselberg in 1981.
00048 <p>
00049 To show a set of points in an n-dimensional space, a backdrop is drawn consisting of n parallel lines. A point in n-dimensional space is represented as a polyline with vertices on the parallel axes; the position of the vertex on the i-th axis corresponds to the i-th coordinate of the point.
00050 <p>
00051 This tool comes with a rather large gui in the editor. It is necessary to use this editor in order to explore a data set, as explained below.
00052 <h4>Reduce cluttering:</h4>
00053 <p>
00054 The main issue for parallel coordinates is the very high cluttering of the output when dealing with large data set. Two techniques have been implemented to bypass that so far:
00055 <ul>
00056 <li>Draw doted lines instead of plain lines with an adjustable dots spacing. A slider to adjust the dots spacing is available in the editor.</li>
00057 <li>Sort the entries to display with  a "weight cut". On each axis is drawn a histogram describing the distribution of the data on the corresponding variable. The "weight" of an entry is the sum of the bin content of each bin the entry is going through. An entry going through the histograms peaks will have a big weight wether an entry going randomly through the histograms will have a rather small weight. Setting a cut on this weight allows to draw only the most representative entries. A slider set the cut is also available in the gui.</li>
00058 </ul>
00059 <center><h2>Selections:</h2></center>
00060 <p>
00061 Selections of specific entries can be defined over the data se using parallel coordinates. With that representation, a selection is an ensemble of ranges defined on the axes. Ranges defined on the same axis are conjugated with OR (an entry must be in one or the other ranges to be selected). Ranges on different axes are are conjugated with AND (an entry must be in all the ranges to be selected). Several selections can be defined with different colors. It is possible to generate an entry list from a given selection and apply it to the tree using the editor ("Apply to tree" button).
00062 <center><h2>Axes:</h2></center>
00063 <p>
00064 Options can be defined each axis separatly using the right mouse click. These options can be applied to every axes using the editor.
00065 <ul>
00066 <li>Axis width: If set to 0, the axis is simply a line. If higher, a color histogram is drawn on the axis.</li>
00067 <li>Axis histogram height: If not 0, a usual bar histogram is drawn on the plot.</li>
00068 </ul>
00069 <p>
00070 The order in which the variables are drawn is essential to see the clusters. The axes can be dragged to change their position. A zoom is also available. The logarithm scale is also available by right clicking on the axis.
00071 <center><h2>Candle chart:</h2></center>
00072 <p>
00073 TParallelCoord can also be used to display a candle chart. In that mode, every variable is drawn in the same scale. The candle chart can be combined with the parallel coordinates mode, drawing the candle sticks over the axes.
00074 End_Html
00075 Begin_Macro(source)
00076 {
00077    TCanvas *c1 = new TCanvas("c1");
00078    TFile *f = TFile::Open("$ROOTSYS/tutorials/tree/cernstaff.root");
00079    TTree *T = (TTree*)f->Get("T");
00080    T->Draw("Age:Grade:Step:Cost:Division:Nation","","para");
00081    TParallelCoord* para = (TParallelCoord*)gPad->GetListOfPrimitives()->FindObject("ParaCoord");
00082    TParallelCoordVar* grade = (TParallelCoordVar*)para->GetVarList()->FindObject("Grade");
00083    grade->AddRange(new TParallelCoordRange(grade,11.5,14));
00084    para->AddSelection("less30");
00085    para->GetCurrentSelection()->SetLineColor(kViolet);
00086    TParallelCoordVar* age = (TParallelCoordVar*)para->GetVarList()->FindObject("Age");
00087    age->AddRange(new TParallelCoordRange(age,21,30));
00088    return c1;
00089 }
00090 End_Macro
00091 Begin_Html
00092 <p> Some references:
00093 <ul>
00094 <li> Alfred Inselberg's Homepage <http://www.math.tau.ac.il/~aiisreal>, with Visual Tutorial, History, Selected Publications and Applications.</li>
00095 <li> A small, easy introduction <http://catt.okstate.edu/jones98/parallel.html> by Christopher V. Jones. </li>
00096 <li> Almir Olivette Artero, Maria Cristina Ferreira de Oliveira, Haim Levkowitz, "Uncovering Clusters in Crowded Parallel Coordinates Visualizations," <i>infovis</i>, pp. 81-88,  IEEE Symposium on Information Visualization (INFOVIS'04),  2004. </li>
00097 </ul>
00098 End_Html
00099 */
00100 
00101 
00102 //______________________________________________________________________________
00103 TParallelCoord::TParallelCoord()
00104    :TNamed()
00105 {
00106    // Default constructor.
00107 
00108    Init();
00109 }
00110 
00111 
00112 //______________________________________________________________________________
00113 TParallelCoord::TParallelCoord(Long64_t nentries)
00114 {
00115    // Constructor without a reference to a tree,
00116    // the datas must be added afterwards with
00117    // TParallelCoord::AddVariable(Double_t*,const char*).
00118 
00119    Init();
00120    fNentries = nentries;
00121    fCurrentN = fNentries;
00122    fVarList = new TList();
00123    fSelectList = new TList();
00124    fCurrentSelection = new TParallelCoordSelect();
00125    fSelectList->Add(fCurrentSelection);
00126 }
00127 
00128 
00129 //______________________________________________________________________________
00130 TParallelCoord::TParallelCoord(TTree* tree, Long64_t nentries)
00131    :TNamed("ParaCoord","ParaCoord")
00132 {
00133    // Normal constructor, the datas must be added afterwards
00134    // with TParallelCoord::AddVariable(Double_t*,const char*).
00135 
00136    Init();
00137    Int_t estimate = tree->GetEstimate();
00138    if (nentries>estimate) {
00139       Warning("TParallelCoord","Call tree->SetEstimate(tree->GetEntries()) to display all the tree variables");
00140       fNentries = estimate;
00141    } else {
00142       fNentries = nentries;
00143    }
00144    fCurrentN = fNentries;
00145    fTree = tree;
00146    fTreeName = fTree->GetName();
00147    if (fTree->GetCurrentFile()) fTreeFileName = fTree->GetCurrentFile()->GetName();
00148    else fTreeFileName = "";
00149    fVarList = new TList();
00150    fSelectList = new TList();
00151    fCurrentSelection = new TParallelCoordSelect();
00152    fSelectList->Add(fCurrentSelection);
00153 }
00154 
00155 
00156 //______________________________________________________________________________
00157 TParallelCoord::~TParallelCoord()
00158 {
00159    // Destructor.
00160 
00161    if (fCurrentEntries) delete fCurrentEntries;
00162    if (fInitEntries != fCurrentEntries && fInitEntries != 0) delete fInitEntries;
00163    if (fVarList) {
00164       fVarList->Delete();
00165       delete fVarList;
00166    }
00167    if (fSelectList) {
00168       fSelectList->Delete();
00169       delete fSelectList;
00170    }
00171    if (fCandleAxis) delete fCandleAxis;
00172    SetDotsSpacing(0);
00173 }
00174 
00175 
00176 //______________________________________________________________________________
00177 void TParallelCoord::AddVariable(Double_t* val, const char* title)
00178 {
00179    // Add a variable.
00180 
00181    ++fNvar;
00182    fVarList->Add(new TParallelCoordVar(val,title,fVarList->GetSize(),this));
00183    SetAxesPosition();
00184 }
00185 
00186 
00187 //______________________________________________________________________________
00188 void TParallelCoord::AddVariable(const char* varexp)
00189 {
00190    // Add a variable from an expression.
00191 
00192    if(!fTree) return; // The tree from whichone one will get the data must be defined.
00193 
00194    // Select in the only the entries of this TParallelCoord.
00195    TEntryList *list = GetEntryList(kFALSE);
00196    fTree->SetEntryList(list);
00197 
00198    // ensure that there is only one variable given:
00199 
00200    TString exp = varexp;
00201 
00202    if (exp.Contains(':') || exp.Contains(">>") || exp.Contains("<<")) {
00203       Warning("AddVariable","Only a single variable can be added at a time.");
00204       return;
00205    }
00206    if (exp == ""){
00207       Warning("AddVariable","Nothing to add");
00208       return;
00209    }
00210 
00211    Long64_t en = fTree->Draw(varexp,"","goff");
00212    if (en<0) {
00213       Warning("AddVariable","%s could not be evaluated",varexp);
00214       return;
00215    }
00216 
00217    AddVariable(fTree->GetV1(),varexp);
00218    TParallelCoordVar* var = (TParallelCoordVar*)fVarList->Last();
00219    var->Draw();
00220 }
00221 
00222 
00223 //______________________________________________________________________________
00224 void TParallelCoord::AddSelection(const char* title)
00225 {
00226    // Add a selection.
00227 
00228    TParallelCoordSelect *sel = new TParallelCoordSelect(title);
00229    fSelectList->Add(sel);
00230    fCurrentSelection = sel;
00231 }
00232 
00233 
00234 //______________________________________________________________________________
00235 void  TParallelCoord::ApplySelectionToTree()
00236 {
00237    // Apply the current selection to the tree.
00238 
00239    if(!fTree) return;
00240    if(fSelectList) {
00241       if(fSelectList->GetSize() == 0) return;
00242       if(fCurrentSelection == 0) fCurrentSelection = (TParallelCoordSelect*)fSelectList->First();
00243    }
00244    fCurrentEntries = GetEntryList();
00245    fNentries = fCurrentEntries->GetN();
00246    fCurrentFirst = 0;
00247    fCurrentN = fNentries;
00248    fTree->SetEntryList(fCurrentEntries);
00249    TString varexp = "";
00250    TIter next(fVarList);
00251    TParallelCoordVar* var;
00252    while ((var = (TParallelCoordVar*)next())) varexp.Append(Form(":%s",var->GetTitle()));
00253    varexp.Remove(TString::kLeading,':');
00254    TSelectorDraw* selector = (TSelectorDraw*)((TTreePlayer*)fTree->GetPlayer())->GetSelector();
00255    fTree->Draw(varexp.Data(),"","goff para");
00256    next.Reset();
00257    Int_t i = 0;
00258    while ((var = (TParallelCoordVar*)next())) {
00259       var->SetValues(fNentries, selector->GetVal(i));
00260       ++i;
00261    }
00262    if (fSelectList) {           // FIXME It would be better to update the selections by deleting
00263       fSelectList->Delete();    // the meaningless ranges (selecting everything or nothing for example)
00264       fCurrentSelection = 0;    // after applying a new entrylist to the tree.
00265    }
00266    gPad->Modified();
00267    gPad->Update();
00268 }
00269 
00270 
00271 //______________________________________________________________________________
00272 void  TParallelCoord::BuildParallelCoord(TSelectorDraw* selector, Bool_t candle)
00273 {
00274    // Call constructor and add the variables.
00275 
00276    TParallelCoord* pc = new TParallelCoord(selector->GetTree(),selector->GetNfill());
00277    pc->SetBit(kCanDelete);
00278    selector->SetObject(pc);
00279    TString varexp = "";
00280    for(Int_t i=0;i<selector->GetDimension();++i) {
00281       pc->AddVariable(selector->GetVal(i),selector->GetVar(i)->GetTitle());
00282       varexp.Append(Form(":%s",selector->GetVar(i)->GetTitle()));
00283    }
00284    varexp.Remove(TString::kLeading,':');
00285    if (selector->GetSelect()) varexp.Append(Form("{%s}",selector->GetSelect()->GetTitle()));
00286    pc->SetTitle(varexp.Data());
00287    if (!candle) pc->Draw();
00288    else pc->Draw("candle");
00289 }
00290 
00291 //______________________________________________________________________________
00292 void TParallelCoord::CleanUpSelections(TParallelCoordRange* range)
00293 {
00294    // Clean up the selections from the ranges which could have been deleted
00295    // when a variable has been deleted.
00296 
00297    TIter next(fSelectList);
00298    TParallelCoordSelect* select;
00299    while ((select = (TParallelCoordSelect*)next())){
00300       if(select->Contains(range)) select->Remove(range);
00301    }
00302 }
00303 
00304 
00305 //______________________________________________________________________________
00306 void TParallelCoord::DeleteSelection(TParallelCoordSelect * sel)
00307 {
00308    // Delete a selection.
00309 
00310    fSelectList->Remove(sel);
00311    delete sel;
00312    if(fSelectList->GetSize() == 0) fCurrentSelection = 0;
00313    else fCurrentSelection = (TParallelCoordSelect*)fSelectList->At(0);
00314 }
00315 
00316 
00317 //______________________________________________________________________________
00318 Int_t TParallelCoord::DistancetoPrimitive(Int_t px, Int_t py)
00319 {
00320    // Compute the distance from the TParallelCoord.
00321 
00322    if(!gPad) return 9999;
00323 
00324    TFrame *frame = gPad->GetFrame();
00325 
00326    Double_t x1,x2,y1,y2,xx,yy;
00327 
00328    x1 = frame->GetX1()+0.01;
00329    x2 = frame->GetX2()-0.01;
00330    y2 = frame->GetY2()-0.01;
00331    y1 = frame->GetY1()+0.01;
00332 
00333    xx = gPad->AbsPixeltoX(px);
00334    yy = gPad->AbsPixeltoY(py);
00335 
00336    if(xx>x1 && xx<x2 && yy>y1 && yy<y2) return 0;
00337    else                                 return 9999;
00338 }
00339 
00340 
00341 //______________________________________________________________________________
00342 void TParallelCoord::Draw(Option_t* option)
00343 {
00344    // Draw the parallel coordinates graph.
00345 
00346    if (!GetTree()) return;
00347    if (!fCurrentEntries) fCurrentEntries = fInitEntries;
00348    Bool_t optcandle = kFALSE;
00349    TString opt = option;
00350    opt.ToLower();
00351    if(opt.Contains("candle")) {
00352       optcandle = kTRUE;
00353       opt.ReplaceAll("candle","");
00354    }
00355    if(optcandle) {
00356       SetBit(kPaintEntries,kFALSE);
00357       SetBit(kCandleChart,kTRUE);
00358       SetGlobalScale(kTRUE);
00359    }
00360 
00361    if (gPad) {
00362       if (!gPad->IsEditable()) gROOT->MakeDefCanvas();
00363    } else gROOT->MakeDefCanvas();
00364    TView *view = gPad->GetView();
00365    if(view){
00366       delete view;
00367       gPad->SetView(0);
00368    }
00369    gPad->Clear();
00370    if (!optcandle) {
00371       if (gPad && gPad->IsA() == TCanvas::Class()
00372          && !((TCanvas*)gPad)->GetShowEditor()) {
00373          ((TCanvas*)gPad)->ToggleEditor();
00374          ((TCanvas*)gPad)->ToggleEventStatus();
00375       }
00376    }
00377 
00378    gPad->SetBit(TGraph::kClipFrame,kTRUE);
00379 
00380    TFrame *frame = new TFrame(0.1,0.1,0.9,0.9);
00381    frame->SetBorderSize(0);
00382    frame->SetBorderMode(0);
00383    frame->SetFillStyle(0);
00384    frame->SetLineColor(gPad->GetFillColor());
00385    frame->Draw();
00386    AppendPad(option);
00387    TPaveText *title = new TPaveText(0.05,0.95,0.35,1);
00388    title->AddText(GetTitle());
00389    title->Draw();
00390    SetAxesPosition();
00391    TIter next(fVarList);
00392    TParallelCoordVar* var;
00393    while ((var = (TParallelCoordVar*)next())) {
00394       if(optcandle) {
00395          var->SetBoxPlot(kTRUE);
00396          var->SetHistogramHeight(0.5);
00397          var->SetHistogramLineWidth(0);
00398       }
00399       var->Draw();
00400    }
00401 
00402    if (optcandle) {
00403       if (TestBit(kVertDisplay)) fCandleAxis = new TGaxis(0.05,0.1,0.05,0.9,GetGlobalMin(),GetGlobalMax());
00404       else                       fCandleAxis = new TGaxis(0.1,0.05,0.9,0.05,GetGlobalMin(),GetGlobalMax());
00405       fCandleAxis->Draw();
00406    }
00407 
00408    if (gPad && gPad->IsA() == TCanvas::Class())
00409       ((TCanvas*)gPad)->Selected(gPad,this,1);
00410 }
00411 
00412 
00413 //______________________________________________________________________________
00414 void TParallelCoord::ExecuteEvent(Int_t /*entry*/, Int_t /*px*/, Int_t /*py*/)
00415 {
00416    // Execute the corresponding entry.
00417 
00418    gPad->SetCursor(kHand);
00419 }
00420 
00421 
00422 //______________________________________________________________________________
00423 TParallelCoordSelect* TParallelCoord::GetCurrentSelection()
00424 {
00425    // Return the selection currently being edited.
00426 
00427    if (!fSelectList) return 0;
00428    if (!fCurrentSelection) {
00429       fCurrentSelection = (TParallelCoordSelect*)fSelectList->First();
00430    }
00431    return fCurrentSelection;
00432 }
00433 
00434 
00435 //______________________________________________________________________________
00436 TEntryList* TParallelCoord::GetEntryList(Bool_t sel)
00437 {
00438    // Get the whole entry list or one for a selection.
00439 
00440    if(!sel || fCurrentSelection->GetSize() == 0){ // If no selection is specified, return the entry list of all the entries.
00441       return fInitEntries;
00442    } else { // return the entry list corresponding to the current selection.
00443       TEntryList *enlist = new TEntryList(fTree);
00444       TIter next(fVarList);
00445       for (Long64_t li=0;li<fNentries;++li) {
00446          next.Reset();
00447          Bool_t inrange=kTRUE;
00448          TParallelCoordVar* var;
00449          while((var = (TParallelCoordVar*)next())){
00450             if(!var->Eval(li,fCurrentSelection)) inrange = kFALSE;
00451          }
00452          if(!inrange) continue;
00453          enlist->Enter(fCurrentEntries->GetEntry(li));
00454       }
00455       return enlist;
00456    }
00457 }
00458 
00459 
00460 //______________________________________________________________________________
00461 Double_t TParallelCoord::GetGlobalMax()
00462 {
00463    // return the global maximum.
00464 
00465    Double_t gmax=-FLT_MAX;
00466    TIter next(fVarList);
00467    TParallelCoordVar* var;
00468    while ((var = (TParallelCoordVar*)next())) {
00469       if (gmax < var->GetCurrentMax()) gmax = var->GetCurrentMax();
00470    }
00471    return gmax;
00472 }
00473 
00474 
00475 //______________________________________________________________________________
00476 Double_t TParallelCoord::GetGlobalMin()
00477 {
00478    // return the global minimum.
00479 
00480    Double_t gmin=FLT_MAX;
00481    TIter next(fVarList);
00482    TParallelCoordVar* var;
00483    while ((var = (TParallelCoordVar*)next())) {
00484       if (gmin > var->GetCurrentMin()) gmin = var->GetCurrentMin();
00485    }
00486    return gmin;
00487 }
00488 
00489 
00490 //______________________________________________________________________________
00491 Int_t TParallelCoord::GetNbins()
00492 {
00493    // get the binning of the histograms.
00494 
00495    return ((TParallelCoordVar*)fVarList->First())->GetNbins();
00496 }
00497 
00498 
00499 //______________________________________________________________________________
00500 TParallelCoordSelect* TParallelCoord::GetSelection(const char* title)
00501 {
00502    // Get a selection from its title.
00503 
00504    TIter next(fSelectList);
00505    TParallelCoordSelect* sel;
00506    while ((sel = (TParallelCoordSelect*)next()) && strcmp(title,sel->GetTitle())) { }
00507    return sel;
00508 }
00509 
00510 
00511 //______________________________________________________________________________
00512 TTree* TParallelCoord::GetTree()
00513 {
00514    // return the tree if fTree is defined. If not, the method try to load the tree
00515    // from fTreeFileName.
00516 
00517    if (fTree) return fTree;
00518    if (fTreeFileName=="" || fTreeName=="") {
00519       Error("GetTree","Cannot load the tree: no tree defined!");
00520       return 0;
00521    }
00522    TFile *f = TFile::Open(fTreeFileName.Data());
00523    if (!f) {
00524       Error("GetTree","Tree file name : \"%s\" does not exsist (Are you in the correct directory?).",fTreeFileName.Data());
00525       return 0;
00526    } else if (f->IsZombie()) {
00527       Error("GetTree","while opening \"%s\".",fTreeFileName.Data());
00528       return 0;
00529    } else {
00530       fTree = (TTree*)f->Get(fTreeName.Data());
00531       if (!fTree) {
00532          Error("GetTree","\"%s\" not found in \"%s\".", fTreeName.Data(), fTreeFileName.Data());
00533          return 0;
00534       } else {
00535          fTree->SetEntryList(fCurrentEntries);
00536          TString varexp = "";
00537          TIter next(fVarList);
00538          TParallelCoordVar* var;
00539          while ((var = (TParallelCoordVar*)next())) varexp.Append(Form(":%s",var->GetTitle()));
00540          varexp.Remove(TString::kLeading,':');
00541          fTree->Draw(varexp.Data(),"","goff para");
00542          TSelectorDraw* selector = (TSelectorDraw*)((TTreePlayer*)fTree->GetPlayer())->GetSelector();
00543          next.Reset();
00544          Int_t i = 0;
00545          while ((var = (TParallelCoordVar*)next())) {
00546             var->SetValues(fNentries, selector->GetVal(i));
00547             ++i;
00548          }
00549          return fTree;
00550       }
00551    }
00552 }
00553 
00554 
00555 //______________________________________________________________________________
00556 Double_t* TParallelCoord::GetVariable(const char* vartitle)
00557 {
00558    // Get the variables values from its title.
00559 
00560    TIter next(fVarList);
00561    TParallelCoordVar* var = 0;
00562    while(((var = (TParallelCoordVar*)next()) != 0) && (var->GetTitle() != vartitle)) { }
00563    if(!var) return 0;
00564    else     return var->GetValues();
00565 }
00566 
00567 
00568 //______________________________________________________________________________
00569 Double_t* TParallelCoord::GetVariable(Int_t i)
00570 {
00571    // Get the variables values from its index.
00572 
00573    if(i<0 || (UInt_t)i>fNvar) return 0;
00574    else return ((TParallelCoordVar*)fVarList->At(i))->GetValues();
00575 }
00576 
00577 
00578 //______________________________________________________________________________
00579 void TParallelCoord::Init()
00580 {
00581    // Initialise the data members of TParallelCoord.
00582 
00583    fNentries = 0;
00584    fVarList = 0;
00585    fSelectList = 0;
00586    SetBit(kVertDisplay,kTRUE);
00587    SetBit(kCurveDisplay,kFALSE);
00588    SetBit(kPaintEntries,kTRUE);
00589    SetBit(kLiveUpdate,kFALSE);
00590    SetBit(kGlobalScale,kFALSE);
00591    SetBit(kCandleChart,kFALSE);
00592    SetBit(kGlobalLogScale,kFALSE);
00593    fTree = 0;
00594    fCurrentEntries = 0;
00595    fInitEntries = 0;
00596    fCurrentSelection = 0;
00597    fNvar = 0;
00598    fDotsSpacing = 0;
00599    fCurrentFirst = 0;
00600    fCurrentN = 0;
00601    fCandleAxis = 0;
00602    fWeightCut = 0;
00603    fLineWidth = 1;
00604    fLineColor = kGreen-8;
00605    fTreeName = "";
00606    fTreeFileName = "";
00607 }
00608 
00609 //______________________________________________________________________________
00610 void TParallelCoord::Paint(Option_t* /*option*/)
00611 {
00612    // Paint the parallel coordinates graph.
00613 
00614    if (!GetTree()) return;
00615    gPad->Range(0,0,1,1);
00616    TFrame *frame = gPad->GetFrame();
00617    frame->SetLineColor(gPad->GetFillColor());
00618    SetAxesPosition();
00619    if(TestBit(kPaintEntries)){
00620       PaintEntries(0);
00621       TIter next(fSelectList);
00622       TParallelCoordSelect* sel;
00623       while((sel = (TParallelCoordSelect*)next())) {
00624          if(sel->GetSize()>0 && sel->TestBit(TParallelCoordSelect::kActivated)) {
00625             PaintEntries(sel);
00626          }
00627       }
00628    }
00629    gPad->RangeAxis(0,0,1,1);
00630 }
00631 
00632 
00633 //______________________________________________________________________________
00634 void TParallelCoord::PaintEntries(TParallelCoordSelect* sel)
00635 {
00636    // Loop over the entries and paint them.
00637 
00638    if (fVarList->GetSize() < 2) return;
00639    Int_t i=0;
00640    Long64_t n=0;
00641 
00642    Double_t *x = new Double_t[fNvar];
00643    Double_t *y = new Double_t[fNvar];
00644 
00645    TGraph    *gr     = 0;
00646    TPolyLine *pl     = 0;
00647    TAttLine  *evline = 0;
00648 
00649    if (TestBit (kCurveDisplay)) {gr = new TGraph(fNvar); evline = (TAttLine*)gr;}
00650    else                       {pl = new TPolyLine(fNvar); evline = (TAttLine*)pl;}
00651 
00652    if (fDotsSpacing == 0) evline->SetLineStyle(1);
00653    else                   evline->SetLineStyle(11);
00654    if (!sel){
00655       evline->SetLineWidth(GetLineWidth());
00656       evline->SetLineColor(GetLineColor());
00657    } else {
00658       evline->SetLineWidth(sel->GetLineWidth());
00659       evline->SetLineColor(sel->GetLineColor());
00660    }
00661    TParallelCoordVar *var;
00662 
00663    TFrame *frame = gPad->GetFrame();
00664    Double_t lx   = ((frame->GetX2() - frame->GetX1())/(fNvar-1));
00665    Double_t ly   = ((frame->GetY2() - frame->GetY1())/(fNvar-1));
00666    Double_t a,b;
00667    TRandom r;
00668 
00669    for (n=fCurrentFirst; n<fCurrentFirst+fCurrentN; ++n) {
00670       TListIter next(fVarList);
00671       Bool_t inrange = kTRUE;
00672       // Loop to check whenever the entry must be painted.
00673       if (sel) {
00674          while ((var = (TParallelCoordVar*)next())){
00675             if (!var->Eval(n,sel)) inrange = kFALSE;
00676          }
00677       }
00678       if (fWeightCut > 0) {
00679          next.Reset();
00680          Int_t entryweight = 0;
00681          while ((var = (TParallelCoordVar*)next())) entryweight+=var->GetEntryWeight(n);
00682          if (entryweight/(Int_t)fNvar < fWeightCut) inrange = kFALSE;
00683       }
00684       if(!inrange) continue;
00685       i = 0;
00686       next.Reset();
00687       // Loop to set the polyline points.
00688       while ((var = (TParallelCoordVar*)next())) {
00689          var->GetEntryXY(n,x[i],y[i]);
00690          ++i;
00691       }
00692       // beginning to paint the first point at a random distance
00693       // to avoid artefacts when increasing the dots spacing.
00694       if (fDotsSpacing != 0) {
00695          if (TestBit(kVertDisplay)) {
00696             a    = (y[1]-y[0])/(x[1]-x[0]);
00697             b    = y[0]-a*x[0];
00698             x[0] = x[0]+lx*r.Rndm(n);
00699             y[0] = a*x[0]+b;
00700          } else {
00701             a    = (x[1]-x[0])/(y[1]-y[0]);
00702             b    = x[0]-a*y[0];
00703             y[0] = y[0]+ly*r.Rndm(n);
00704             x[0] = a*y[0]+b;
00705          }
00706       }
00707       if (pl) pl->PaintPolyLine(fNvar,x,y);
00708       else    gr->PaintGraph(fNvar,x,y,"C");
00709    }
00710 
00711    if (pl) delete pl;
00712    if (gr) delete gr;
00713    delete [] x;
00714    delete [] y;
00715 }
00716 
00717 
00718 //______________________________________________________________________________
00719 void TParallelCoord::RemoveVariable(TParallelCoordVar *var)
00720 {
00721    // Delete a variable from the graph.
00722 
00723    fVarList->Remove(var);
00724    fNvar = fVarList->GetSize();
00725    SetAxesPosition();
00726 }
00727 
00728 
00729 //______________________________________________________________________________
00730 TParallelCoordVar* TParallelCoord::RemoveVariable(const char* vartitle)
00731 {
00732    // Delete the variable "vartitle" from the graph.
00733 
00734    TIter next(fVarList);
00735    TParallelCoordVar* var=0;
00736    while((var = (TParallelCoordVar*)next())) {
00737       if (!strcmp(var->GetTitle(),vartitle)) break;
00738    }
00739    if(!var) Error("RemoveVariable","\"%s\" not a variable",vartitle);
00740    fVarList->Remove(var);
00741    fNvar = fVarList->GetSize();
00742    SetAxesPosition();
00743    var->DeleteVariable();
00744    return var;
00745 }
00746 
00747 
00748 //______________________________________________________________________________
00749 void TParallelCoord::ResetTree()
00750 {
00751    // Reset the tree entry list to the initial one..
00752 
00753    if(!fTree) return;
00754    fTree->SetEntryList(fInitEntries);
00755    fCurrentEntries = fInitEntries;
00756    fNentries = fCurrentEntries->GetN();
00757    fCurrentFirst = 0;
00758    fCurrentN = fNentries;
00759    TString varexp = "";
00760    TIter next(fVarList);
00761    TParallelCoordVar* var;
00762    while ((var = (TParallelCoordVar*)next())) varexp.Append(Form(":%s",var->GetTitle()));
00763    varexp.Remove(TString::kLeading,':');
00764    fTree->Draw(varexp.Data(),"","goff para");
00765    next.Reset();
00766    TSelectorDraw* selector = (TSelectorDraw*)((TTreePlayer*)fTree->GetPlayer())->GetSelector();
00767    Int_t i = 0;
00768    while ((var = (TParallelCoordVar*)next())) {
00769       var->SetValues(fNentries, selector->GetVal(i));
00770       ++i;
00771    }
00772    if (fSelectList) {           // FIXME It would be better to update the selections by deleting
00773       fSelectList->Delete();    // the meaningless ranges (selecting everything or nothing for example)
00774       fCurrentSelection = 0;    // after applying a new entrylist to the tree.
00775    }
00776    gPad->Modified();
00777    gPad->Update();
00778 }
00779 
00780 
00781 //______________________________________________________________________________
00782 void TParallelCoord::SaveEntryLists(const char* filename, Bool_t overwrite)
00783 {
00784    // Save the entry lists in a root file "filename.root".
00785 
00786    TString sfile = filename;
00787    if (sfile == "") sfile = Form("%s_parallelcoord_entries.root",fTree->GetName());
00788 
00789    TFile* f = TFile::Open(sfile.Data());
00790    if (f) {
00791       Warning("SaveEntryLists","%s already exists.", sfile.Data());
00792       if (!overwrite) return;
00793       else Warning("SaveEntryLists","Overwriting.");
00794       f = new TFile(sfile.Data(),"RECREATE");
00795    } else {
00796       f = new TFile(sfile.Data(),"CREATE");
00797    }
00798    gDirectory = f;
00799    fInitEntries->Write("initentries");
00800    fCurrentEntries->Write("currententries");
00801    Info("SaveEntryLists","File \"%s\" written.",sfile.Data());
00802 }
00803 
00804 
00805 //______________________________________________________________________________
00806 void TParallelCoord::SavePrimitive(ostream & out, Option_t* options)
00807 {
00808    // Save the TParallelCoord in a macro.
00809 
00810    TString opt = options;
00811    opt.ToLower();
00812    //Bool_t overwrite = opt.Contains("overwrite"); // Is there a way to specify "options" when saving ?
00813    // Save the entrylists.
00814    const char* filename = Form("%s_parallelcoord_entries.root",fTree->GetName());
00815    SaveEntryLists(filename,kTRUE); // FIXME overwriting by default.
00816    SaveTree(fTreeFileName,kTRUE);  // FIXME overwriting by default.
00817    out<<"   // Create a TParallelCoord."<<endl;
00818    out<<"   TFile *f = TFile::Open(\""<<fTreeFileName.Data()<<"\");"<<endl;
00819    out<<"   TTree* tree = (TTree*)f->Get(\""<<fTreeName.Data()<<"\");"<<endl;
00820    out<<"   TParallelCoord* para = new TParallelCoord(tree,"<<fNentries<<");"<<endl;
00821    out<<"   // Load the entrylists."<<endl;
00822    out<<"   TFile *entries = TFile::Open(\""<<filename<<"\");"<<endl;
00823    out<<"   TEntryList *currententries = (TEntryList*)entries->Get(\"currententries\");"<<endl;
00824    out<<"   tree->SetEntryList(currententries);"<<endl;
00825    out<<"   para->SetInitEntries((TEntryList*)entries->Get(\"initentries\"));"<<endl;
00826    out<<"   para->SetCurrentEntries(currententries);"<<endl;
00827    TIter next(fSelectList);
00828    TParallelCoordSelect* sel;
00829    out<<"   TParallelCoordSelect* sel;"<<endl;
00830    out<<"   para->GetSelectList()->Delete();"<<endl;
00831    while ((sel = (TParallelCoordSelect*)next())) {
00832       out<<"   para->AddSelection(\""<<sel->GetTitle()<<"\");"<<endl;
00833       out<<"   sel = (TParallelCoordSelect*)para->GetSelectList()->Last();"<<endl;
00834       out<<"   sel->SetLineColor("<<sel->GetLineColor()<<");"<<endl;
00835       out<<"   sel->SetLineWidth("<<sel->GetLineWidth()<<");"<<endl;
00836    }
00837    TIter nextbis(fVarList);
00838    TParallelCoordVar* var;
00839    TString varexp = "";
00840    while ((var = (TParallelCoordVar*)nextbis())) varexp.Append(Form(":%s",var->GetTitle()));
00841    varexp.Remove(TString::kLeading,':');
00842    out<<"   tree->Draw(\""<<varexp.Data()<<"\",\"\",\"goff para\");"<<endl;
00843    out<<"   TSelectorDraw* selector = (TSelectorDraw*)((TTreePlayer*)tree->GetPlayer())->GetSelector();"<<endl;
00844    nextbis.Reset();
00845    Int_t i=0;
00846    out<<"   TParallelCoordVar* var;"<<endl;
00847    while ((var = (TParallelCoordVar*)nextbis())) {
00848       out<<"   //***************************************"<<endl;
00849       out<<"   // Create the axis \""<<var->GetTitle()<<"\"."<<endl;
00850       out<<"   para->AddVariable(selector->GetVal("<<i<<"),\""<<var->GetTitle()<<"\");"<<endl;
00851       out<<"   var = (TParallelCoordVar*)para->GetVarList()->Last();"<<endl;
00852       var->SavePrimitive(out,"pcalled");
00853       ++i;
00854    }
00855    out<<"   //***************************************"<<endl;
00856    out<<"   // Set the TParallelCoord parameters."<<endl;
00857    out<<"   para->SetCurrentFirst("<<fCurrentFirst<<");"<<endl;
00858    out<<"   para->SetCurrentN("<<fCurrentN<<");"<<endl;
00859    out<<"   para->SetWeightCut("<<fWeightCut<<");"<<endl;
00860    out<<"   para->SetDotsSpacing("<<fDotsSpacing<<");"<<endl;
00861    out<<"   para->SetLineColor("<<GetLineColor()<<");"<<endl;
00862    out<<"   para->SetLineWidth("<<GetLineWidth()<<");"<<endl;
00863    out<<"   para->SetBit(TParallelCoord::kVertDisplay,"<<TestBit(kVertDisplay)<<");"<<endl;
00864    out<<"   para->SetBit(TParallelCoord::kCurveDisplay,"<<TestBit(kCurveDisplay)<<");"<<endl;
00865    out<<"   para->SetBit(TParallelCoord::kPaintEntries,"<<TestBit(kPaintEntries)<<");"<<endl;
00866    out<<"   para->SetBit(TParallelCoord::kLiveUpdate,"<<TestBit(kLiveUpdate)<<");"<<endl;
00867    out<<"   para->SetBit(TParallelCoord::kGlobalLogScale,"<<TestBit(kGlobalLogScale)<<");"<<endl;
00868    if (TestBit(kGlobalScale)) out<<"   para->SetGlobalScale(kTRUE);"<<endl;
00869    if (TestBit(kCandleChart)) out<<"   para->SetCandleChart(kTRUE);"<<endl;
00870    if (TestBit(kGlobalLogScale)) out<<"   para->SetGlobalLogScale(kTRUE);"<<endl;
00871    out<<endl<<"   para->Draw();"<<endl;
00872 }
00873 
00874 
00875 //______________________________________________________________________________
00876 void TParallelCoord::SaveTree(const char* filename, Bool_t overwrite)
00877 {
00878    // Save the tree in a file if fTreeFileName == "".
00879 
00880    if (!(fTreeFileName=="")) return;
00881    TString sfile = filename;
00882    if (sfile == "") sfile = Form("%s.root",fTree->GetName());
00883 
00884    TFile* f = TFile::Open(sfile.Data());
00885    if (f) {
00886       Warning("SaveTree","%s already exists.", sfile.Data());
00887       if (!overwrite) return;
00888       else Warning("SaveTree","Overwriting.");
00889       f = new TFile(sfile.Data(),"RECREATE");
00890    } else {
00891       f = new TFile(sfile.Data(),"CREATE");
00892    }
00893    gDirectory = f;
00894    fTree->Write(fTreeName.Data());
00895    fTreeFileName = sfile;
00896    Info("SaveTree","File \"%s\" written.",sfile.Data());
00897 }
00898 
00899 
00900 //______________________________________________________________________________
00901 void TParallelCoord::SetAxesPosition()
00902 {
00903    // Update the position of the axes.
00904 
00905    if(!gPad) return;
00906    Bool_t vert          = TestBit (kVertDisplay);
00907    TFrame *frame        = gPad->GetFrame();
00908    if (fVarList->GetSize() > 1) {
00909       if (vert) {
00910          frame->SetX1(1.0/((Double_t)fVarList->GetSize()+1));
00911          frame->SetX2(1-frame->GetX1());
00912          frame->SetY1(0.1);
00913          frame->SetY2(0.9);
00914          gPad->RangeAxis(1.0/((Double_t)fVarList->GetSize()+1),0.1,1-frame->GetX1(),0.9);
00915       } else {
00916          frame->SetX1(0.1);
00917          frame->SetX2(0.9);
00918          frame->SetY1(1.0/((Double_t)fVarList->GetSize()+1));
00919          frame->SetY2(1-frame->GetY1());
00920          gPad->RangeAxis(0.1,1.0/((Double_t)fVarList->GetSize()+1),0.9,1-frame->GetY1());
00921       }
00922 
00923       Double_t horSpace    = (frame->GetX2() - frame->GetX1())/(fNvar-1);
00924       Double_t verSpace   = (frame->GetY2() - frame->GetY1())/(fNvar-1);
00925       Int_t i=0;
00926       TIter next(fVarList);
00927 
00928       TParallelCoordVar* var;
00929       while((var = (TParallelCoordVar*)next())){
00930          if (vert) var->SetX(gPad->GetFrame()->GetX1() + i*horSpace,TestBit(kGlobalScale));
00931          else      var->SetY(gPad->GetFrame()->GetY1() + i*verSpace,TestBit(kGlobalScale));
00932          ++i;
00933       }
00934    } else if (fVarList->GetSize()==1) {
00935       frame->SetX1(0.1);
00936       frame->SetX2(0.9);
00937       frame->SetY1(0.1);
00938       frame->SetY2(0.9);
00939       if (vert) ((TParallelCoordVar*)fVarList->First())->SetX(0.5,TestBit(kGlobalScale));
00940       else      ((TParallelCoordVar*)fVarList->First())->SetY(0.5,TestBit(kGlobalScale));
00941    }
00942 }
00943 
00944 
00945 //______________________________________________________________________________
00946 void TParallelCoord::SetAxisHistogramBinning(Int_t n)
00947 {
00948    // Set the same histogram axis binning for all axis.
00949 
00950    TIter next(fVarList);
00951    TParallelCoordVar *var;
00952    while((var = (TParallelCoordVar*)next())) var->SetHistogramBinning(n);
00953 }
00954 
00955 
00956 //______________________________________________________________________________
00957 void TParallelCoord::SetAxisHistogramHeight(Double_t h)
00958 {
00959    // Set the same histogram axis height for all axis.
00960 
00961    TIter next(fVarList);
00962    TParallelCoordVar *var;
00963    while((var = (TParallelCoordVar*)next())) var->SetHistogramHeight(h);
00964 }
00965 
00966 
00967 //______________________________________________________________________________
00968 void TParallelCoord::SetGlobalLogScale(Bool_t lt)
00969 {
00970    // All axes in log scale.
00971 
00972    if (lt == TestBit(kGlobalLogScale)) return;
00973    SetBit(kGlobalLogScale,lt);
00974    TIter next(fVarList);
00975    TParallelCoordVar* var;
00976    while ((var = (TParallelCoordVar*)next())) var->SetLogScale(lt);
00977    if (TestBit(kGlobalScale)) SetGlobalScale(kTRUE);
00978 }
00979 
00980 
00981 //______________________________________________________________________________
00982 void TParallelCoord::SetGlobalScale(Bool_t gl)
00983 {
00984    // Constraint all axes to the same scale.
00985 
00986    SetBit(kGlobalScale,gl);
00987    if (fCandleAxis) {
00988       delete fCandleAxis;
00989       fCandleAxis = 0;
00990    }
00991    if (gl) {
00992       Double_t min,max;
00993       min = GetGlobalMin();
00994       max = GetGlobalMax();
00995       if (TestBit(kGlobalLogScale) && min<=0) min = 0.00001*max;
00996       if (TestBit(kVertDisplay)) {
00997          if (!TestBit(kGlobalLogScale)) fCandleAxis = new TGaxis(0.05,0.1,0.05,0.9,min,max);
00998          else                           fCandleAxis = new TGaxis(0.05,0.1,0.05,0.9,min,max,510,"G");
00999       } else {
01000          if (!TestBit(kGlobalLogScale)) fCandleAxis = new TGaxis(0.1,0.05,0.9,0.05,min,max);
01001          else                           fCandleAxis = new TGaxis(0.1,0.05,0.9,0.05,min,max,510,"G");
01002       }
01003       fCandleAxis->Draw();
01004       SetGlobalMin(min);
01005       SetGlobalMax(max);
01006       TIter next(fVarList);
01007       TParallelCoordVar* var;
01008       while ((var = (TParallelCoordVar*)next())) var->GetHistogram();
01009    }
01010    gPad->Modified();
01011    gPad->Update();
01012 }
01013 
01014 
01015 //______________________________________________________________________________
01016 void TParallelCoord::SetAxisHistogramLineWidth(Int_t lw)
01017 {
01018    // Set the same histogram axis line width for all axis.
01019 
01020    TIter next(fVarList);
01021    TParallelCoordVar *var;
01022    while((var = (TParallelCoordVar*)next())) var->SetHistogramLineWidth(lw);
01023 }
01024 
01025 
01026 //______________________________________________________________________________
01027 void TParallelCoord::SetCandleChart(Bool_t can)
01028 {
01029    // Set a candle chart display.
01030 
01031    SetBit(kCandleChart,can);
01032    SetGlobalScale(can);
01033    TIter next(fVarList);
01034    TParallelCoordVar* var;
01035    while ((var = (TParallelCoordVar*)next())) {
01036       var->SetBoxPlot(can);
01037       var->SetHistogramLineWidth(0);
01038    }
01039    if (fCandleAxis) delete fCandleAxis;
01040    fCandleAxis = 0;
01041    SetBit(kPaintEntries,!can);
01042    if (can) {
01043       if (TestBit(kVertDisplay)) fCandleAxis = new TGaxis(0.05,0.1,0.05,0.9,GetGlobalMin(),GetGlobalMax());
01044       else                       fCandleAxis = new TGaxis(0.1,0.05,0.9,0.05,GetGlobalMin(),GetGlobalMax());
01045       fCandleAxis->Draw();
01046    } else {
01047       if (fCandleAxis) {
01048          delete fCandleAxis;
01049          fCandleAxis = 0;
01050       }
01051    }
01052    gPad->Modified();
01053    gPad->Update();
01054 }
01055 
01056 
01057 //______________________________________________________________________________
01058 void TParallelCoord::SetCurrentFirst(Long64_t f)
01059 {
01060    // Set the first entry to be dispayed.
01061 
01062    if(f<0 || f>fNentries) return;
01063    fCurrentFirst = f;
01064    if(fCurrentFirst + fCurrentN > fNentries) fCurrentN = fNentries-fCurrentFirst;
01065    TIter next(fVarList);
01066    TParallelCoordVar* var;
01067    while ((var = (TParallelCoordVar*)next())) {
01068       var->GetMinMaxMean();
01069       var->GetHistogram();
01070       if (var->TestBit(TParallelCoordVar::kShowBox)) var->GetQuantiles();
01071    }
01072 }
01073 
01074 
01075 //______________________________________________________________________________
01076 void TParallelCoord::SetCurrentN(Long64_t n)
01077 {
01078    // Set the number of entry to be displayed.
01079 
01080    if(n<=0) return;
01081    if(fCurrentFirst+n>fNentries) fCurrentN = fNentries-fCurrentFirst;
01082    else fCurrentN = n;
01083    TIter next(fVarList);
01084    TParallelCoordVar* var;
01085    while ((var = (TParallelCoordVar*)next())) {
01086       var->GetMinMaxMean();
01087       var->GetHistogram();
01088       if (var->TestBit(TParallelCoordVar::kShowBox)) var->GetQuantiles();
01089    }
01090 }
01091 
01092 
01093 //______________________________________________________________________________
01094 TParallelCoordSelect* TParallelCoord::SetCurrentSelection(const char* title)
01095 {
01096    // Set the selection beeing edited.
01097 
01098    if (fCurrentSelection && fCurrentSelection->GetTitle() == title) return fCurrentSelection;
01099    TIter next(fSelectList);
01100    TParallelCoordSelect* sel;
01101    while((sel = (TParallelCoordSelect*)next()) && strcmp(sel->GetTitle(),title))
01102    if (sel) fCurrentSelection = sel;
01103    return sel;
01104 }
01105 
01106 
01107 //______________________________________________________________________________
01108 void TParallelCoord::SetCurrentSelection(TParallelCoordSelect* sel)
01109 {
01110    // Set the selection beeing edited.
01111 
01112    if (fCurrentSelection == sel) return;
01113    fCurrentSelection = sel;
01114 }
01115 
01116 
01117 //______________________________________________________________________________
01118 void TParallelCoord::SetDotsSpacing(Int_t s)
01119 {
01120    // Set dots spacing. Modify the line style 11.
01121 
01122    if (s == fDotsSpacing) return;
01123    fDotsSpacing = s;
01124    gStyle->SetLineStyleString(11,Form("%d %d",4,s*8));
01125 }
01126 
01127 
01128 //______________________________________________________________________________
01129 void TParallelCoord::SetEntryList(TParallelCoord* para, TEntryList* enlist)
01130 {
01131    // Set the entry lists of "para".
01132 
01133    para->SetCurrentEntries(enlist);
01134    para->SetInitEntries(enlist);
01135 }
01136 
01137 
01138 //______________________________________________________________________________
01139 void TParallelCoord::SetGlobalMax(Double_t max)
01140 {
01141    // Force all variables to adopt the same max.
01142 
01143    TIter next(fVarList);
01144    TParallelCoordVar* var;
01145    while ((var = (TParallelCoordVar*)next())) {
01146       var->SetCurrentMax(max);
01147    }
01148 }
01149 
01150 
01151 //______________________________________________________________________________
01152 void TParallelCoord::SetGlobalMin(Double_t min)
01153 {
01154    // Force all variables to adopt the same min.
01155 
01156    TIter next(fVarList);
01157    TParallelCoordVar* var;
01158    while ((var = (TParallelCoordVar*)next())) {
01159       var->SetCurrentMin(min);
01160    }
01161 }
01162 
01163 
01164 //______________________________________________________________________________
01165 void TParallelCoord::SetLiveRangesUpdate(Bool_t on)
01166 {
01167    // If true, the pad is updated while the motion of a dragged range.
01168 
01169    SetBit(kLiveUpdate,on);
01170    TIter next(fVarList);
01171    TParallelCoordVar* var;
01172    while((var = (TParallelCoordVar*)next())) var->SetLiveRangesUpdate(on);
01173 }
01174 
01175 
01176 //______________________________________________________________________________
01177 void TParallelCoord::SetVertDisplay(Bool_t vert)
01178 {
01179    // Set the vertical or horizontal display.
01180 
01181    if (vert == TestBit (kVertDisplay)) return;
01182    SetBit(kVertDisplay,vert);
01183    if (!gPad) return;
01184    UInt_t ui = 0;
01185    TFrame* frame = gPad->GetFrame();
01186    Double_t horaxisspace = (frame->GetX2() - frame->GetX1())/(fNvar-1);
01187    Double_t veraxisspace = (frame->GetY2() - frame->GetY1())/(fNvar-1);
01188    TIter next(fVarList);
01189    TParallelCoordVar* var;
01190    while ((var = (TParallelCoordVar*)next())) {
01191       if (vert) var->SetX(frame->GetX1() + ui*horaxisspace,TestBit(kGlobalScale));
01192       else      var->SetY(frame->GetY1() + ui*veraxisspace,TestBit(kGlobalScale));
01193       ++ui;
01194    }
01195    if (TestBit(kCandleChart)) {
01196       if (fCandleAxis) delete fCandleAxis;
01197       if (TestBit(kVertDisplay)) fCandleAxis = new TGaxis(0.05,0.1,0.05,0.9,GetGlobalMin(),GetGlobalMax());
01198       else                       fCandleAxis = new TGaxis(0.1,0.05,0.9,0.05,GetGlobalMin(),GetGlobalMax());
01199       fCandleAxis->Draw();
01200    }
01201    gPad->Modified();
01202    gPad->Update();
01203 }
01204 
01205 
01206 //______________________________________________________________________________
01207 void TParallelCoord::UnzoomAll()
01208 {
01209    // Unzoom all variables.
01210 
01211    TIter next(fVarList);
01212    TParallelCoordVar* var;
01213    while((var = (TParallelCoordVar*)next())) var->Unzoom();
01214 }

Generated on Tue Jul 5 15:43:44 2011 for ROOT_528-00b_version by  doxygen 1.5.1