Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TFileDrawMap.cxx
Go to the documentation of this file.
1 // @(#)root/treeplayer:$Id$
2 // Author: Rene Brun 15/01/2003
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2003, 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 /** \class TFileDrawMap
13 This class is automatically called by TFile::DrawMap.
14 It draws a canvas showing the internal structure of a ROOT file.
15 Each key or basket in a file is shown with a fill area drawn
16 at the byte position of the key/basket in the file.
17 The Y axis of the canvas shows the number of Kbytes/Mbytes.
18 The X axis shows the bytes between y(i) and y(i+1).
19 A color corresponding to the class in the key/basket is automatically
20 selected using the class unique identifier.
21 
22 When moving the mouse in the canvas, the "Event Status" panels
23 shows the object corresponding to the mouse position.
24 if the object is a key, it shows the class and object name as well as
25 the file directory name if the file has sub-directories.
26 
27 if the object is a basket, it shows:
28  - the name of the Tree
29  - the name of the branch
30  - the basket number
31  - the entry number in the basket
32 
33 Special keys like the StreamerInfo record, the Keys List Record
34 and the Free Blocks Record are also shown.
35 
36 When clicking the right mouse button, a pop-up menu is shown
37 with its title identifying the picked object and with the items:
38  - DrawObject: in case of a key, the Draw function of the object is called
39  in case of a basket, the branch is drawn for all entries
40  - DumpObject: in case of a key, the Dump function of the object is called
41  in case of a basket, tree->Show(entry) is called
42  - InspectObject: the Inspect function is called for the object.
43 
44 The normal axis zoom functionality can be used to zoom or unzoom
45 One can also use the TCanvas context menu SetCanvasSize to make
46 a larger canvas and use the canvas scroll bars.
47 
48 When the class is built, it is possible to identify a subset of the
49 objects to be shown. For example, to view only the keys with
50 names starting with "abc", set the argument keys to "abc*".
51 The default is to view all the objects.
52 The argument options can also be used (only one option currently)
53 When the option "same" is given, the new picture is suprimposed.
54 The option "same" is useful, eg:
55 to draw all keys with names = "abc" in a first pass
56 then all keys with names = "uv*" in a second pass, etc.
57 */
58 
59 #include "TFileDrawMap.h"
60 #include "TROOT.h"
61 #include "TClass.h"
62 #include "TFile.h"
63 #include "TTree.h"
64 #include "TBranch.h"
65 #include "TLeaf.h"
66 #include "TMath.h"
67 #include "TVirtualPad.h"
68 #include "TStyle.h"
69 #include "TH1.h"
70 #include "TBox.h"
71 #include "TKey.h"
72 #include "TRegexp.h"
73 #include "TSystem.h"
74 
75 ClassImp(TFileDrawMap);
76 
77 ////////////////////////////////////////////////////////////////////////////////
78 /// Default TreeFileMap constructor.
79 
80 TFileDrawMap::TFileDrawMap() :TNamed()
81 {
82  fFile = 0;
83  fFrame = 0;
84  fXsize = 1000;
85  fYsize = 1000;
86 }
87 
88 ////////////////////////////////////////////////////////////////////////////////
89 /// TFileDrawMap normal constructor.
90 /// see descriptions of arguments above
91 
92 TFileDrawMap::TFileDrawMap(const TFile *file, const char *keys, Option_t *option)
93  : TNamed("TFileDrawMap","")
94 {
95  fFile = (TFile*)file;
96  fKeys = keys;
97  fOption = option;
98  fOption.ToLower();
99  SetBit(kCanDelete);
100 
101  //create histogram used to draw the map frame
102 
103  if (file->GetEND() > 1000000) {
104  fXsize = 1000000;
105  } else {
106  fXsize = 1000;
107  }
108  fFrame = new TH1D("hmapframe","",1000,0,fXsize);
109  fFrame->SetDirectory(0);
110  fFrame->SetBit(TH1::kNoStats);
111  fFrame->SetBit(kCanDelete);
112  fFrame->SetMinimum(0);
113  if (fXsize > 1000) {
114  fFrame->GetYaxis()->SetTitle("MBytes");
115  } else {
116  fFrame->GetYaxis()->SetTitle("KBytes");
117  }
118  fFrame->GetXaxis()->SetTitle("Bytes");
119  fYsize = 1 + Int_t(file->GetEND()/fXsize);
120  fFrame->SetMaximum(fYsize);
121  fFrame->GetYaxis()->SetLimits(0,fYsize);
122 
123  //Bool_t show = kFALSE;
124  if (gPad) {
125  gPad->Clear();
126  //show = gPad->GetCanvas()->GetShowEventStatus();
127  }
128  Draw();
129  if (gPad) {
130  //if (!show) gPad->GetCanvas()->ToggleEventStatus();
131  gPad->Update();
132  }
133 }
134 
135 ////////////////////////////////////////////////////////////////////////////////
136 /// Tree destructor.
137 
138 TFileDrawMap::~TFileDrawMap()
139 {
140  //delete fFrame; //should not be deleted (kCanDelete set)
141 }
142 
143 ////////////////////////////////////////////////////////////////////////////////
144 /// Show sequence of baskets reads for the list of baskets involved
145 /// in the list of branches (separated by ",")
146 /// - if branches="", the branch pointed by the mouse is taken.
147 /// - if branches="*", all branches are taken
148 /// Example:
149 ///
150 /// AnimateTree("x,y,u");
151 
152 void TFileDrawMap::AnimateTree(const char *branches)
153 {
154  TString ourbranches( GetName() );
155  Ssiz_t pos = ourbranches.Index(", basket=");
156  if (pos == kNPOS) return;
157  ourbranches.Remove(pos);
158  pos = ourbranches.Index(", branch=");
159  if (pos == kNPOS) return;
160  ourbranches[pos] = 0;
161 
162  TTree *tree = (TTree*)fFile->Get(ourbranches.Data());
163  if (!tree) return;
164  TString info;
165  if (strlen(branches) > 0) info = branches;
166  else info = ourbranches.Data()+pos+9;
167  printf("Animating tree, branches=%s\n",info.Data());
168 
169  // create list of branches
170  Int_t nzip = 0;
171  TBranch *branch;
172  TObjArray list;
173  char *comma;
174  while((comma = strrchr((char*)info.Data(),','))) {
175  *comma = 0;
176  comma++;
177  while (*comma == ' ') comma++;
178  branch = tree->GetBranch(comma);
179  if (branch) {
180  nzip += (Int_t)branch->GetZipBytes();
181  branch->SetUniqueID(0);
182  list.Add(branch);
183  }
184  }
185  comma = (char*)info.Data();
186  while (*comma == ' ') comma++;
187  branch = tree->GetBranch(comma);
188  if (branch) {
189  nzip += (Int_t)branch->GetZipBytes();
190  branch->SetUniqueID(0);
191  list.Add(branch);
192  }
193  Double_t fractionRead = Double_t(nzip)/Double_t(fFile->GetEND());
194  Int_t nbranches = list.GetEntries();
195 
196  // loop on all tree entries
197  Int_t nentries = (Int_t)tree->GetEntries();
198  Int_t sleep = 1;
199  Int_t stime = (Int_t)(100./(nentries*fractionRead));
200  if (stime < 10) {stime=1; sleep = nentries/400;}
201  gPad->SetDoubleBuffer(0); // turn off double buffer mode
202  gVirtualX->SetDrawMode(TVirtualX::kInvert); // set the drawing mode to XOR mode
203  for (Int_t entry=0;entry<nentries;entry++) {
204  for (Int_t ib=0;ib<nbranches;ib++) {
205  branch = (TBranch*)list.At(ib);
206  Int_t nbaskets = branch->GetListOfBaskets()->GetSize();
207  Int_t basket = TMath::BinarySearch(nbaskets,branch->GetBasketEntry(), (Long64_t) entry);
208  Int_t nbytes = branch->GetBasketBytes()[basket];
209  Int_t bseek = branch->GetBasketSeek(basket);
210  Int_t entry0 = branch->GetBasketEntry()[basket];
211  Int_t entryn = branch->GetBasketEntry()[basket+1];
212  Int_t eseek = (Int_t)(bseek + nbytes*Double_t(entry-entry0)/Double_t(entryn-entry0));
213  DrawMarker(ib,branch->GetUniqueID());
214  DrawMarker(ib,eseek);
215  branch->SetUniqueID(eseek);
216  gSystem->ProcessEvents();
217  if (entry%sleep == 0) gSystem->Sleep(stime);
218  }
219  }
220 }
221 
222 ////////////////////////////////////////////////////////////////////////////////
223 /// Compute distance from point px,py to this TreeFileMap.
224 /// Find the closest object to the mouse, save its path in the TFileDrawMap name.
225 
226 Int_t TFileDrawMap::DistancetoPrimitive(Int_t px, Int_t py)
227 {
228  Int_t pxmin = gPad->XtoAbsPixel(gPad->GetUxmin());
229  Int_t pxmax = gPad->XtoAbsPixel(gPad->GetUxmax());
230  Int_t pymin = gPad->YtoAbsPixel(gPad->GetUymin());
231  Int_t pymax = gPad->YtoAbsPixel(gPad->GetUymax());
232  if (px > pxmin && px < pxmax && py > pymax && py < pymin) {
233  SetName(GetObjectInfo(px,py));
234  return 0;
235  }
236  return fFrame->DistancetoPrimitive(px,py);
237 }
238 
239 ////////////////////////////////////////////////////////////////////////////////
240 /// Draw marker.
241 
242 void TFileDrawMap::DrawMarker(Int_t marker, Long64_t eseek)
243 {
244  Int_t iy = gPad->YtoAbsPixel(eseek/fXsize);
245  Int_t ix = gPad->XtoAbsPixel(eseek%fXsize);
246  Int_t d;
247  Int_t mark = marker%4;
248  switch (mark) {
249  case 0 :
250  d = 6; //arrow
251  gVirtualX->DrawLine(ix-3*d,iy,ix,iy);
252  gVirtualX->DrawLine(ix-d,iy+d,ix,iy);
253  gVirtualX->DrawLine(ix-d,iy-d,ix,iy);
254  gVirtualX->DrawLine(ix-d,iy-d,ix-d,iy+d);
255  break;
256  case 1 :
257  d = 5; //up triangle
258  gVirtualX->DrawLine(ix-d,iy-d,ix+d,iy-d);
259  gVirtualX->DrawLine(ix+d,iy-d,ix,iy+d);
260  gVirtualX->DrawLine(ix,iy+d,ix-d,iy-d);
261  break;
262  case 2 :
263  d = 5; //open square
264  gVirtualX->DrawLine(ix-d,iy-d,ix+d,iy-d);
265  gVirtualX->DrawLine(ix+d,iy-d,ix+d,iy+d);
266  gVirtualX->DrawLine(ix+d,iy+d,ix-d,iy+d);
267  gVirtualX->DrawLine(ix-d,iy+d,ix-d,iy-d);
268  break;
269  case 3 :
270  d = 8; //cross
271  gVirtualX->DrawLine(ix-d,iy,ix+d,iy);
272  gVirtualX->DrawLine(ix,iy-d,ix,iy+d);
273  break;
274  }
275 }
276 
277 ////////////////////////////////////////////////////////////////////////////////
278 /// Draw object at the mouse position.
279 
280 void TFileDrawMap::DrawObject()
281 {
282  TVirtualPad *padsave = gROOT->GetSelectedPad();
283  if (padsave == gPad) {
284  //must create a new canvas
285  gROOT->MakeDefCanvas();
286  } else {
287  padsave->cd();
288  }
289 
290  // case of a TTree
291  char *info = new char[fName.Length()+1];
292  strlcpy(info,fName.Data(),fName.Length()+1);
293  char *cbasket = (char*)strstr(info,", basket=");
294  if (cbasket) {
295  *cbasket = 0;
296  char *cbranch = (char*)strstr(info,", branch=");
297  if (!cbranch) return;
298  *cbranch = 0;
299  cbranch += 9;
300  TTree *tree = (TTree*)fFile->Get(info);
301  if (tree) tree->Draw(cbranch);
302  return;
303  }
304 
305  // other objects
306  TObject *obj = GetObject();
307  if (obj) obj->Draw();
308 }
309 
310 
311 ////////////////////////////////////////////////////////////////////////////////
312 /// Dump object at the mouse position.
313 
314 void TFileDrawMap::DumpObject()
315 {
316  TObject *obj = GetObject();
317  if (obj) {
318  obj->Dump();
319  return;
320  }
321  char *centry = (char*)strstr(GetName(),"entry=");
322  if (!centry) return;
323  Int_t entry = 0;
324  sscanf(centry+6,"%d",&entry);
325  TString info(GetName());
326  char *colon = (char*)strstr((char*)info.Data(),"::");
327  if (!colon) return;
328  colon--;
329  *colon = 0;
330  TTree *tree; fFile->GetObject(info.Data(),tree);
331  if (tree) tree->Show(entry);
332 }
333 
334 ////////////////////////////////////////////////////////////////////////////////
335 /// Execute action corresponding to one event.
336 
337 void TFileDrawMap::ExecuteEvent(Int_t event, Int_t px, Int_t py)
338 {
339  fFrame->ExecuteEvent(event,px,py);
340 }
341 
342 ////////////////////////////////////////////////////////////////////////////////
343 /// Retrieve object at the mouse position in memory.
344 
345 TObject *TFileDrawMap::GetObject()
346 {
347  if (strstr(GetName(),"entry=")) return 0;
348  char *info = new char[fName.Length()+1];
349  strlcpy(info,fName.Data(),fName.Length()+1);
350  char *colon = strstr(info,"::");
351  if (!colon) return 0;
352  colon--;
353  *colon = 0;
354  return fFile->Get(info);
355 }
356 
357 ////////////////////////////////////////////////////////////////////////////////
358 /// Redefines TObject::GetObjectInfo.
359 /// Displays the keys info in the file corresponding to cursor position px,py
360 /// in the canvas status bar info panel
361 
362 char *TFileDrawMap::GetObjectInfo(Int_t px, Int_t py) const
363 {
364  // Thread safety: this solution is not elegant, but given the action performed
365  // by the method, this construct can be considered nonproblematic.
366  static TString info;
367  GetObjectInfoDir(fFile, px, py, info);
368  return (char*)info.Data();
369 }
370 
371 ////////////////////////////////////////////////////////////////////////////////
372 /// Redefines TObject::GetObjectInfo.
373 /// Displays the keys info in the directory
374 /// corresponding to cursor position px,py
375 
376 Bool_t TFileDrawMap::GetObjectInfoDir(TDirectory *dir, Int_t px, Int_t py, TString &info) const
377 {
378  Double_t x = gPad->AbsPixeltoX(px);
379  Double_t y = gPad->AbsPixeltoY(py);
380  Int_t iy = (Int_t)y;
381  Long64_t pbyte = (Long64_t)(fXsize*iy+x);
382  Int_t nbytes;
383  Long64_t bseek;
384  TDirectory *dirsav = gDirectory;
385  dir->cd();
386 
387  TIter next(dir->GetListOfKeys());
388  TKey *key;
389  while ((key = (TKey*)next())) {
390  TDirectory *curdir = gDirectory;
391  TClass *cl = TClass::GetClass(key->GetClassName());
392  // a TDirectory ?
393  if (cl && cl == TDirectoryFile::Class()) {
394  curdir->cd(key->GetName());
395  TDirectory *subdir = gDirectory;
396  Bool_t gotInfo = GetObjectInfoDir(subdir, px, py, info);
397  if (gotInfo) {
398  dirsav->cd();
399  return kTRUE;
400  }
401  curdir->cd();
402  continue;
403  }
404  // a TTree ?
405  if (cl && cl->InheritsFrom(TTree::Class())) {
406  TTree *tree = (TTree*)gDirectory->Get(key->GetName());
407  TIter nextb(tree->GetListOfLeaves());
408  TLeaf *leaf;
409  while ((leaf = (TLeaf*)nextb())) {
410  TBranch *branch = leaf->GetBranch();
411  Int_t nbaskets = branch->GetMaxBaskets();
412  Int_t offsets = branch->GetEntryOffsetLen();
413  Int_t len = leaf->GetLen();
414  for (Int_t i=0;i<nbaskets;i++) {
415  bseek = branch->GetBasketSeek(i);
416  if (!bseek) break;
417  nbytes = branch->GetBasketBytes()[i];
418  if (pbyte >= bseek && pbyte < bseek+nbytes) {
419  Int_t entry = branch->GetBasketEntry()[i];
420  if (!offsets) entry += (pbyte-bseek)/len;
421  if (curdir == (TDirectory*)fFile) {
422  info.Form("%s%s, branch=%s, basket=%d, entry=%d",curdir->GetPath(),key->GetName(),branch->GetName(),i,entry);
423  } else {
424  info.Form("%s/%s, branch=%s, basket=%d, entry=%d",curdir->GetPath(),key->GetName(),branch->GetName(),i,entry);
425  }
426  return kTRUE;
427  }
428  }
429  }
430  }
431  nbytes = key->GetNbytes();
432  bseek = key->GetSeekKey();
433  if (pbyte >= bseek && pbyte < bseek+nbytes) {
434  if (curdir == (TDirectory*)fFile) {
435  info.Form("%s%s ::%s, nbytes=%d",curdir->GetPath(),key->GetName(),key->GetClassName(),nbytes);
436  } else {
437  info.Form("%s/%s ::%s, nbytes=%d",curdir->GetPath(),key->GetName(),key->GetClassName(),nbytes);
438  }
439  dirsav->cd();
440  return kTRUE;
441  }
442  }
443  // Are we in the Keys list
444  if (pbyte >= dir->GetSeekKeys() && pbyte < dir->GetSeekKeys()+dir->GetNbytesKeys()) {
445  info.Form("%sKeys List, nbytes=%d",dir->GetPath(),dir->GetNbytesKeys());
446  dirsav->cd();
447  return kTRUE;
448  }
449  if (dir == (TDirectory*)fFile) {
450  // Are we in the TStreamerInfo
451  if (pbyte >= fFile->GetSeekInfo() && pbyte < fFile->GetSeekInfo()+fFile->GetNbytesInfo()) {
452  info.Form("%sStreamerInfo List, nbytes=%d",dir->GetPath(),fFile->GetNbytesInfo());
453  dirsav->cd();
454  return kTRUE;
455  }
456  // Are we in the Free Segments
457  if (pbyte >= fFile->GetSeekFree() && pbyte < fFile->GetSeekFree()+fFile->GetNbytesFree()) {
458  info.Form("%sFree List, nbytes=%d",dir->GetPath(),fFile->GetNbytesFree());
459  dirsav->cd();
460  return kTRUE;
461  }
462  }
463  info.Form("(byte=%lld)",pbyte);
464  dirsav->cd();
465  return kFALSE;
466 }
467 
468 ////////////////////////////////////////////////////////////////////////////////
469 /// Inspect object at the mouse position.
470 
471 void TFileDrawMap::InspectObject()
472 {
473  TObject *obj = GetObject();
474  if (obj) obj->Inspect();
475 }
476 
477 ////////////////////////////////////////////////////////////////////////////////
478 /// Paint this TFileDrawMap.
479 
480 void TFileDrawMap::Paint(Option_t *)
481 {
482  // draw map frame
483  if (!fOption.Contains("same")) {
484  gPad->Clear();
485  //just in case axis Y has been unzoomed
486  if (fFrame->GetMaximumStored() < -1000) {
487  fFrame->SetMaximum(fYsize+1);
488  fFrame->SetMinimum(0);
489  fFrame->GetYaxis()->SetLimits(0,fYsize+1);
490  }
491  fFrame->Paint("a");
492  }
493 
494  //draw keys
495  PaintDir(fFile, fKeys.Data());
496 
497  fFrame->Draw("sameaxis");
498 }
499 
500 ////////////////////////////////////////////////////////////////////////////////
501 /// Paint the object at bseek with nbytes using the box object.
502 
503 void TFileDrawMap::PaintBox(TBox &box, Long64_t bseek, Int_t nbytes)
504 {
505  Int_t iy = bseek/fXsize;
506  Int_t ix = bseek%fXsize;
507  Int_t ny = 1+(nbytes+ix)/fXsize;
508  Double_t xmin,ymin,xmax,ymax;
509  for (Int_t j=0;j<ny;j++) {
510  if (j == 0) xmin = (Double_t)ix;
511  else xmin = 0;
512  xmax = xmin + nbytes;
513  if (xmax > fXsize) xmax = fXsize;
514  ymin = iy+j;
515  ymax = ymin+1;
516  nbytes -= (Int_t)(xmax-xmin);
517  if (xmax < gPad->GetUxmin()) continue;
518  if (xmin > gPad->GetUxmax()) continue;
519  if (xmin < gPad->GetUxmin()) xmin = gPad->GetUxmin();
520  if (xmax > gPad->GetUxmax()) xmax = gPad->GetUxmax();
521  if (ymax < gPad->GetUymin()) continue;
522  if (ymin > gPad->GetUymax()) continue;
523  if (ymin < gPad->GetUymin()) ymin = gPad->GetUymin();
524  if (ymax > gPad->GetUymax()) ymax = gPad->GetUymax();
525  //box.TAttFill::Modify();
526  box.PaintBox(xmin,ymin,xmax,ymax);
527  }
528 }
529 
530 ////////////////////////////////////////////////////////////////////////////////
531 /// Paint keys in a directory.
532 
533 void TFileDrawMap::PaintDir(TDirectory *dir, const char *keys)
534 {
535  TDirectory *dirsav = gDirectory;
536  TIter next(dir->GetListOfKeys());
537  TKey *key;
538  Int_t color = 0;
539  TBox box;
540  TRegexp re(keys,kTRUE);
541  while ((key = (TKey*)next())) {
542  Int_t nbytes = key->GetNbytes();
543  Long64_t bseek = key->GetSeekKey();
544  TClass *cl = TClass::GetClass(key->GetClassName());
545  if (cl) {
546  color = (Int_t)(cl->GetUniqueID()%20);
547  } else {
548  color = 1;
549  }
550  box.SetFillColor(color);
551  box.SetFillStyle(1001);
552  TString s = key->GetName();
553  if (strcmp(fKeys.Data(),key->GetName()) && s.Index(re) == kNPOS) continue;
554  // a TDirectory ?
555  if (cl && cl == TDirectoryFile::Class()) {
556  TDirectory *curdir = gDirectory;
557  gDirectory->cd(key->GetName());
558  TDirectory *subdir = gDirectory;
559  PaintDir(subdir,"*");
560  curdir->cd();
561  }
562  PaintBox(box,bseek,nbytes);
563  // a TTree ?
564  if (cl && cl->InheritsFrom(TTree::Class())) {
565  TTree *tree = (TTree*)gDirectory->Get(key->GetName());
566  TIter nextb(tree->GetListOfLeaves());
567  TLeaf *leaf;
568  while ((leaf = (TLeaf*)nextb())) {
569  TBranch *branch = leaf->GetBranch();
570  color = branch->GetFillColor();
571  if (color == 0) color = 1;
572  box.SetFillColor(color);
573  Int_t nbaskets = branch->GetMaxBaskets();
574  for (Int_t i=0;i<nbaskets;i++) {
575  bseek = branch->GetBasketSeek(i);
576  if (!bseek) break;
577  nbytes = branch->GetBasketBytes()[i];
578  PaintBox(box,bseek,nbytes);
579  }
580  }
581  }
582  }
583  // draw the box for Keys list
584  box.SetFillColor(50);
585  box.SetFillStyle(1001);
586  PaintBox(box,dir->GetSeekKeys(),dir->GetNbytesKeys());
587  if (dir == (TDirectory*)fFile) {
588  // draw the box for TStreamerInfo
589  box.SetFillColor(6);
590  box.SetFillStyle(3008);
591  PaintBox(box,fFile->GetSeekInfo(),fFile->GetNbytesInfo());
592  // draw the box for Free Segments
593  box.SetFillColor(1);
594  box.SetFillStyle(1001);
595  PaintBox(box,fFile->GetSeekFree(),fFile->GetNbytesFree());
596  }
597  dirsav->cd();
598 }