Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RTreeViewer.cxx
Go to the documentation of this file.
1// Author: Sergey Linev, 7.10.2022
2
3/*************************************************************************
4 * Copyright (C) 1995-2022, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11#include <ROOT/RTreeViewer.hxx>
12
13// #include <ROOT/RLogger.hxx>
14#include <ROOT/RWebWindow.hxx>
15
16#include "TTree.h"
17#include "TVirtualPad.h"
18#include "TBranch.h"
19#include "TBranchElement.h"
20#include "TStreamerInfo.h"
21#include "TVirtualMonitoring.h"
22#include "TLeaf.h"
23#include "TH1.h"
24#include "TAxis.h"
25#include "TSystem.h"
26
27#include "TBufferJSON.h"
28
29namespace ROOT {
30
32
33private:
34
37
39 long long fLastProgressSendTm{0};
41
42public:
44 : TVirtualMonitoringWriter(), fPeriod(period), fViewer(viewer)
45 {
46 }
47
48 // TFile related info. In general they are gathered and sent only sometimes as summaries
49 bool SendFileCloseEvent(TFile * /*file*/) override { return false; }
50 bool SendFileReadProgress(TFile * /*file*/) override { return false; }
51 bool SendFileWriteProgress(TFile * /*file*/) override { return false; }
52
53 bool SendParameters(TList * /*valuelist*/, const char * /*identifier*/ = nullptr) override { return false; }
54 bool SendInfoTime() override { return false; }
55 bool SendInfoUser(const char * /*user*/ = nullptr) override { return false; }
56 bool SendInfoDescription(const char * /*jobtag*/) override { return false; }
57 bool SendInfoStatus(const char * /*status*/) override { return false; }
58
59 bool SendFileOpenProgress(TFile * /*file*/, TList * /*openphases*/, const char * /*openphasename*/,
60 bool /*forcesend*/ = false) override
61 {
62 return false;
63 }
64
65 bool SendProcessingStatus(const char * /*status*/, bool /*restarttimer*/ = false) override { return false; }
66 bool SendProcessingProgress(Double_t nevent, Double_t /*nbytes*/, bool /*force*/ = false) override
67 {
68 long long millisec = gSystem->Now();
69
71 return true;
72
73 fLastProgressSendTm = millisec;
74
76
77 fViewer.SendProgress(nevent);
78
79 return true;
80 }
81 void SetLogLevel(const char * /*loglevel*/ = "WARNING") override {}
82 void Verbose(bool /*onoff*/) override {}
83};
84
85
87public:
89
90 /// constructor
91 RTreeDrawInvokeTimer(Long_t milliSec, bool mode, RTreeViewer &viewer) : TTimer(milliSec, mode), fViewer(viewer) {}
92
93 /// timeout handler
94 /// used to process postponed requests in main ROOT thread
95 void Timeout() override { fViewer.InvokeTreeDraw(); }
96};
97
98
99} // namespace ROOT
100
101using namespace ROOT;
102using namespace std::string_literals;
103
104
105//////////////////////////////////////////////////////////////////////////////////////////////
106/// constructor
107
109{
111 fWebWindow->SetDefaultPage("file:rootui5sys/tree/index.html");
112
113 // this is call-back, invoked when message received via websocket
114 fWebWindow->SetConnectCallBack([this](unsigned connid) { WebWindowConnect(connid); });
115 fWebWindow->SetDataCallBack([this](unsigned connid, const std::string &arg) { WebWindowCallback(connid, arg); });
116 fWebWindow->SetGeometry(900, 700); // configure predefined window geometry
117 fWebWindow->SetConnLimit(1); // allow the only connection
118 fWebWindow->SetMaxQueueLength(30); // number of allowed entries in the window queue
119
120 if (tree) SetTree(tree);
121
122 fTimer = std::make_unique<RTreeDrawInvokeTimer>(10, true, *this);
123}
124
125//////////////////////////////////////////////////////////////////////////////////////////////
126/// destructor
127
129{
130
131}
132
133//////////////////////////////////////////////////////////////////////////////////////////////
134/// assign new TTree to the viewer
135
137{
138 fTree = tree;
139
140 // reset expression when new tree is assigned
141 fCfg.fExprX.clear();
142 fCfg.fExprY.clear();
143 fCfg.fExprZ.clear();
144 fCfg.fExprCut.clear();
145 fCfg.fNumber = 0;
146 fCfg.fFirst = 0;
147
148 UpdateConfig();
149
150 Update();
151}
152
153//////////////////////////////////////////////////////////////////////////////////////////////
154/// Suggest to use leaf in the gui
155/// Normally just assign as last edited expression
156
158{
159 const TBranch *branch = leaf ? leaf->GetBranch() : nullptr;
160
161 const TTree *tree = branch ? branch->GetTree() : nullptr;
162
163 if (!tree || (fTree != tree))
164 return false;
165
166 if ((const_cast<TBranch *>(branch)->GetListOfBranches()->GetLast() < 0) && (branch->GetNleaves() == 1)) {
167 std::string brname = branch->GetName();
168 if (brname == leaf->GetName())
169 return SuggestBranch(branch);
170 }
171
172 fWebWindow->Send(0, "SUGGEST:"s + FormatItemName(leaf->GetFullName().Data()));
173
174 return true;
175}
176
177//////////////////////////////////////////////////////////////////////////////////////////////
178/// Suggest to use branch in the gui
179/// Normally just assign as last edited expression
180
182{
183 const TTree *tree = branch ? branch->GetTree() : nullptr;
184
185 if (!tree || (fTree != tree))
186 return false;
187
188 fWebWindow->Send(0, "SUGGEST:"s + FormatItemName(branch->GetFullName().Data()));
189
190 return true;
191}
192
193//////////////////////////////////////////////////////////////////////////////////////////////
194/// Suggest to use expression in the gui
195/// Normally just assign as last edited expression
196
197bool RTreeViewer::SuggestExpression(const std::string &expr)
198{
199 if (!fTree || expr.empty())
200 return false;
201
202 fWebWindow->Send(0, "SUGGEST:"s + expr);
203
204 return true;
205}
206
207
208/////////////////////////////////////////////////////////////////////////////////
209/// Show or update viewer in web window
210/// If web browser already started - just refresh drawing like "reload" button does
211/// If no web window exists or \param always_start_new_browser configured, starts new window
212/// \param args arguments to display
213
214void RTreeViewer::Show(const RWebDisplayArgs &args, bool always_start_new_browser)
215{
216 std::string user_args = "";
217 if (!GetShowHierarchy()) user_args = "{ nobrowser: true }";
218 fWebWindow->SetUserArgs(user_args);
219
220 if (args.GetWidgetKind().empty())
221 const_cast<RWebDisplayArgs *>(&args)->SetWidgetKind("RTreeViewer");
222
223 if ((fWebWindow->NumConnections(true) == 0) || always_start_new_browser)
224 fWebWindow->Show(args);
225 else
226 Update();
227}
228
229//////////////////////////////////////////////////////////////////////////////////////////////
230/// Return address of web window used for tree viewer
231
232std::string RTreeViewer::GetWindowAddr() const
233{
234 return fWebWindow ? fWebWindow->GetAddr() : ""s;
235}
236
237//////////////////////////////////////////////////////////////////////////////////////////////
238/// Return URL of web window used for tree viewer
239/// See \ref ROOT::RWebWindow::GetUrl docu for more details
240
241std::string RTreeViewer::GetWindowUrl(bool remote)
242{
243 return fWebWindow ? fWebWindow->GetUrl(remote) : ""s;
244}
245
246//////////////////////////////////////////////////////////////////////////////////////////////
247/// Update tree viewer in all web displays
248
250{
251 SendCfg(0);
252}
253
254//////////////////////////////////////////////////////////////////////////////////////////////
255/// Send data for initialize viewer
256
257void RTreeViewer::SendCfg(unsigned connid)
258{
260
261 fWebWindow->Send(connid, json);
262}
263
264
265//////////////////////////////////////////////////////////////////////////////////////////////
266/// react on new connection
267
268void RTreeViewer::WebWindowConnect(unsigned connid)
269{
270 SendCfg(connid);
271}
272
273//////////////////////////////////////////////////////////////////////////////////////////////
274/// receive data from client
275
276void RTreeViewer::WebWindowCallback(unsigned connid, const std::string &arg)
277{
278 if (arg == "GETCFG"s) {
279
280 SendCfg(connid);
281
282 } else if (arg == "QUIT_ROOT"s) {
283
284 fWebWindow->TerminateROOT();
285
286 } if (arg.compare(0, 5, "DRAW:"s) == 0) {
287
288 if (!fTree) return;
289
290 auto newcfg = TBufferJSON::FromJSON<RConfig>(arg.substr(5));
291
292 if (newcfg) {
293 fCfg = *newcfg;
294 fTimer->TurnOn();
295 }
296 }
297}
298
299//////////////////////////////////////////////////////////////////////////////////////////////
300/// Format item name used in draw expression
301
302std::string RTreeViewer::FormatItemName(const std::string &name)
303{
304 std::string res = name;
305
306 std::string from = "/";
307 std::string to = "\\/";
308
309 size_t start_pos = 0;
310 while((start_pos = res.find(from, start_pos)) != std::string::npos) {
311 res.replace(start_pos, from.length(), to);
312 start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
313 }
314 return res;
315}
316
317
318//////////////////////////////////////////////////////////////////////////////////////////////
319/// Add branches to config
320
322{
323 if (!branches || (branches->GetLast() < 0))
324 return;
325
326 TIter iter(branches);
327
328 while (auto br = dynamic_cast<TBranch *>(iter())) {
329
330 auto leaves = br->GetListOfLeaves();
331
332 auto subbr = br->GetListOfBranches();
333
334 std::string brname = br->GetName();
335
336 TLeaf *leaf0 = (leaves->GetLast() == 0) ? dynamic_cast<TLeaf *>(leaves->At(0)) : nullptr;
337
338 auto brelem = dynamic_cast<TBranchElement *>(br);
339
340 std::string brfullname = br->GetFullName().Data();
341
342 if ((subbr->GetLast() < 0) && leaf0 && (brname == leaf0->GetName())) {
343
344 // ignore branches containing objects, see TBranchElement::GetTypeName()
345 if (brelem && (brelem->GetStreamerType() < 1 || brelem->GetStreamerType() > 59))
346 continue;
347
348 fCfg.fBranches.emplace_back(FormatItemName(brfullname), br->GetTitle() + " / "s + leaf0->GetTypeName());
349 continue;
350 }
351
352 TIter liter(leaves);
353 while (auto leaf = dynamic_cast<TLeaf *>(liter())) {
354
355 std::string leaffullname = leaf->GetFullName().Data();
356
357 // ignore counter leaf for STL container
358 if (brelem && brelem->GetStreamerType() == TStreamerInfo::kSTL && (leaves->GetLast() == 0) && (leaffullname == brfullname + "_"))
359 break;
360
361 fCfg.fBranches.emplace_back(FormatItemName(leaffullname), leaf->GetTitle() + " / "s + leaf->GetTypeName());
362 }
363
364 AddBranches(subbr);
365 }
366}
367
368
369//////////////////////////////////////////////////////////////////////////////////////////////
370/// Update RConfig data
371
373{
374 fCfg.fBranches.clear();
375
376 if (!fTree) return;
377
379
381
383
384 fCfg.fStep = 1;
386 if (fCfg.fLargerStep < 2) fCfg.fLargerStep = 2;
387}
388
389
390//////////////////////////////////////////////////////////////////////////////////////////////
391/// Invoke tree drawing
392
394{
395
396 fTimer->TurnOff();
397
398 UpdateConfig();
399
400 std::string expr = fCfg.fExprX;
401 if (!fCfg.fExprY.empty()) {
402 expr += ":"s;
403 expr += fCfg.fExprY;
404
405 if (!fCfg.fExprZ.empty()) {
406 expr += ":"s;
407 expr += fCfg.fExprZ;
408 }
409 }
410
412
413 auto old = gMonitoringWriter;
414 RTreeDrawMonitoring monitoring(50, *this);
415 gMonitoringWriter = &monitoring;
416
417 fLastSendProgress.clear();
418
419 fTree->Draw(expr.c_str(), fCfg.fExprCut.c_str(), fCfg.fOption.c_str(), nentries, fCfg.fFirst);
420
421 gMonitoringWriter = old;
422
423 if (!fLastSendProgress.empty())
424 SendProgress(-1.);
425
426 std::string canv_name;
427
428 if (gPad) {
429 if ((expr.find('\\') != std::string::npos) || (expr.find('#') != std::string::npos)) {
430 auto FixTitle = [](TNamed *obj) {
431 if (!obj) return;
432 TString title = obj->GetTitle();
433 title.ReplaceAll("\\/", "/");
434 title.ReplaceAll("#","\\#");
435 obj->SetTitle(title.Data());
436 };
437 TIter iter(gPad->GetListOfPrimitives());
438 while (auto obj = iter()) {
439 if (expr == obj->GetTitle()) {
440 FixTitle(dynamic_cast<TNamed *> (obj));
441 TH1 *hist = dynamic_cast<TH1 *> (obj);
442 if (hist) {
443 FixTitle(hist->GetXaxis());
444 FixTitle(hist->GetYaxis());
445 FixTitle(hist->GetZaxis());
446 }
447 }
448 }
449 }
450
451 gPad->Update();
452 canv_name = gPad->GetName();
453 }
454
455 // at the end invoke callback
456 if (fCallback)
457 fCallback(canv_name);
458}
459
460//////////////////////////////////////////////////////////////////////////////////////////////
461/// Send progress to the client
462
464{
465 std::string progress = "100";
466
467 if (nevent >= 0.) {
468
469 Long64_t first = fCfg.fFirst;
471 Long64_t last = nentries;
472 if ((fCfg.fNumber > 0) && (first + fCfg.fNumber < nentries))
473 last = first + fCfg.fNumber;
474
475 if (last > first) {
476 Double_t p = nevent / ( last - first + 0. ) * 100.;
477 if (p > 100) p = 100;
478 progress = std::to_string(p);
479 }
480 }
481
482 if (fLastSendProgress == progress)
483 return;
484
485 fLastSendProgress = progress;
486
487 if (fWebWindow->CanSend(0, true))
488 fWebWindow->Send(0, "PROGRESS:"s + progress);
489}
490
491//////////////////////////////////////////////////////////////////////////////////////////////
492/// Create new viewer
493/// Method used for plugin
494
496{
497 auto viewer = new RTreeViewer(t);
498
499 viewer->Show();
500
501 return viewer;
502}
503
nlohmann::json json
long Long_t
Definition RtypesCore.h:54
long long Long64_t
Definition RtypesCore.h:80
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char mode
char name[80]
Definition TGX11.cxx:110
int nentries
R__EXTERN TSystem * gSystem
Definition TSystem.h:555
R__EXTERN TVirtualMonitoringWriter * gMonitoringWriter
#define gPad
void Timeout() override
timeout handler used to process postponed requests in main ROOT thread
RTreeDrawInvokeTimer(Long_t milliSec, bool mode, RTreeViewer &viewer)
constructor
RTreeDrawMonitoring(Int_t period, RTreeViewer &viewer)
RTreeDrawMonitoring & operator=(const RTreeDrawMonitoring &)=delete
bool SendFileReadProgress(TFile *) override
RTreeDrawMonitoring(const RTreeDrawMonitoring &)=delete
bool SendInfoUser(const char *=nullptr) override
void SetLogLevel(const char *="WARNING") override
bool SendParameters(TList *, const char *=nullptr) override
bool SendFileOpenProgress(TFile *, TList *, const char *, bool=false) override
bool SendProcessingStatus(const char *, bool=false) override
bool SendProcessingProgress(Double_t nevent, Double_t, bool=false) override
bool SendFileWriteProgress(TFile *) override
void Verbose(bool) override
bool SendInfoDescription(const char *) override
bool SendFileCloseEvent(TFile *) override
bool SendInfoStatus(const char *) override
bool SendInfoTime() override
std::unique_ptr< RTreeDrawInvokeTimer > fTimer
! timer to invoke tree draw
void Show(const RWebDisplayArgs &args="", bool always_start_new_browser=false)
Show or update viewer in web window If web browser already started - just refresh drawing like "reloa...
void SendProgress(Double_t nevent=0.)
Send progress to the client.
void UpdateConfig()
Update RConfig data.
std::string FormatItemName(const std::string &name)
Format item name used in draw expression.
void InvokeTreeDraw()
Invoke tree drawing.
bool SuggestLeaf(const TLeaf *leaf)
Suggest to use leaf in the gui Normally just assign as last edited expression.
void SetTree(TTree *tree)
assign new TTree to the viewer
std::string GetWindowAddr() const
Return address of web window used for tree viewer.
std::string GetWindowUrl(bool remote)
Return URL of web window used for tree viewer See ROOT::RWebWindow::GetUrl docu for more details.
std::string fLastSendProgress
! last send progress to client
PerformDrawCallback_t fCallback
! callback invoked when tree draw performed
void Update()
Update tree viewer in all web displays.
std::shared_ptr< ROOT::RWebWindow > fWebWindow
! web window
static RTreeViewer * NewViewer(TTree *)
Create new viewer Method used for plugin.
void SendCfg(unsigned connid)
Send data for initialize viewer.
bool SuggestExpression(const std::string &expr)
Suggest to use expression in the gui Normally just assign as last edited expression.
virtual ~RTreeViewer()
destructor
void WebWindowConnect(unsigned connid)
react on new connection
bool GetShowHierarchy() const
Returns default hierarchy browser visibility.
TTree * fTree
! TTree to show
void AddBranches(TObjArray *branches)
Add branches to config.
void WebWindowCallback(unsigned connid, const std::string &arg)
receive data from client
RConfig fCfg
! configuration, exchanged between client and server
RTreeViewer(TTree *tree=nullptr)
constructor
bool SuggestBranch(const TBranch *branch)
Suggest to use branch in the gui Normally just assign as last edited expression.
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
const std::string & GetWidgetKind() const
returns widget kind
static std::shared_ptr< RWebWindow > Create()
Create new RWebWindow Using default RWebWindowsManager.
A Branch for the case of an object.
TString GetFullName() const override
Return the 'full' name of the branch.
A TTree is a list of TBranches.
Definition TBranch.h:93
TTree * GetTree() const
Definition TBranch.h:252
virtual TString GetFullName() const
Return the 'full' name of the branch.
Definition TBranch.cxx:2031
Int_t GetNleaves() const
Definition TBranch.h:249
static TString ToJSON(const T *obj, Int_t compact=0, const char *member_name=nullptr)
Definition TBufferJSON.h:75
@ kSkipTypeInfo
do not store typenames in JSON
Definition TBufferJSON.h:48
@ kNoSpaces
no new lines plus remove all spaces around "," and ":" symbols
Definition TBufferJSON.h:39
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
Definition TFile.h:53
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:59
TAxis * GetZaxis()
Definition TH1.h:326
TAxis * GetXaxis()
Definition TH1.h:324
TAxis * GetYaxis()
Definition TH1.h:325
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
virtual const char * GetTypeName() const
Definition TLeaf.h:139
TBranch * GetBranch() const
Definition TLeaf.h:116
virtual TString GetFullName() const
Return the full name (including the parent's branch names) of the leaf.
Definition TLeaf.cxx:224
A doubly linked list.
Definition TList.h:38
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
An array of TObjects.
Definition TObjArray.h:31
Int_t GetLast() const override
Return index of last object in array.
Basic string class.
Definition TString.h:139
const char * Data() const
Definition TString.h:376
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:704
virtual TTime Now()
Get current time in milliseconds since 0:00 Jan 1 1995.
Definition TSystem.cxx:463
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:416
Handles synchronous and a-synchronous timer events.
Definition TTimer.h:51
A TTree represents a columnar dataset.
Definition TTree.h:79
void Draw(Option_t *opt) override
Default Draw method for all objects.
Definition TTree.h:431
virtual Long64_t GetEntries() const
Definition TTree.h:463
virtual TObjArray * GetListOfBranches()
Definition TTree.h:488
static constexpr Long64_t kMaxEntries
Definition TTree.h:229
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
std::vector< RBranchInfo > fBranches