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_t SendFileCloseEvent(TFile * /*file*/) override { return kFALSE; }
50 Bool_t SendFileReadProgress(TFile * /*file*/) override { return kFALSE; }
51 Bool_t SendFileWriteProgress(TFile * /*file*/) override { return kFALSE; }
52
53 Bool_t SendParameters(TList * /*valuelist*/, const char * /*identifier*/ = nullptr) override { return kFALSE; }
54 Bool_t SendInfoTime() override { return kFALSE; }
55 Bool_t SendInfoUser(const char * /*user*/ = nullptr) override { return kFALSE; }
56 Bool_t SendInfoDescription(const char * /*jobtag*/) override { return kFALSE; }
57 Bool_t SendInfoStatus(const char * /*status*/) override { return kFALSE; }
58
59 Bool_t SendFileOpenProgress(TFile * /*file*/, TList * /*openphases*/, const char * /*openphasename*/,
60 Bool_t /*forcesend*/ = kFALSE) override
61 {
62 return kFALSE;
63 }
64
65 Bool_t SendProcessingStatus(const char * /*status*/, Bool_t /*restarttimer*/ = kFALSE) override { return kFALSE; }
66 Bool_t SendProcessingProgress(Double_t nevent, Double_t /*nbytes*/, Bool_t /*force*/ = kFALSE) override
67 {
68 long long millisec = gSystem->Now();
69
71 return kTRUE;
72
73 fLastProgressSendTm = millisec;
74
76
77 fViewer.SendProgress(nevent);
78
79 return kTRUE;
80 }
81 void SetLogLevel(const char * /*loglevel*/ = "WARNING") override {}
82 void Verbose(Bool_t /*onoff*/) override {}
83};
84
85
87public:
89
90 /// constructor
91 RTreeDrawInvokeTimer(Long_t milliSec, Bool_t 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, kTRUE, *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 URL 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/// Update tree viewer in all web displays
239
241{
242 SendCfg(0);
243}
244
245//////////////////////////////////////////////////////////////////////////////////////////////
246/// Send data for initialize viewer
247
248void RTreeViewer::SendCfg(unsigned connid)
249{
251
252 fWebWindow->Send(connid, json);
253}
254
255
256//////////////////////////////////////////////////////////////////////////////////////////////
257/// react on new connection
258
259void RTreeViewer::WebWindowConnect(unsigned connid)
260{
261 SendCfg(connid);
262}
263
264//////////////////////////////////////////////////////////////////////////////////////////////
265/// receive data from client
266
267void RTreeViewer::WebWindowCallback(unsigned connid, const std::string &arg)
268{
269 if (arg == "GETCFG"s) {
270
271 SendCfg(connid);
272
273 } else if (arg == "QUIT_ROOT"s) {
274
275 fWebWindow->TerminateROOT();
276
277 } if (arg.compare(0, 5, "DRAW:"s) == 0) {
278
279 if (!fTree) return;
280
281 auto newcfg = TBufferJSON::FromJSON<RConfig>(arg.substr(5));
282
283 if (newcfg) {
284 fCfg = *newcfg;
285 fTimer->TurnOn();
286 }
287 }
288}
289
290//////////////////////////////////////////////////////////////////////////////////////////////
291/// Format item name used in draw expression
292
293std::string RTreeViewer::FormatItemName(const std::string &name)
294{
295 std::string res = name;
296
297 std::string from = "/";
298 std::string to = "\\/";
299
300 size_t start_pos = 0;
301 while((start_pos = res.find(from, start_pos)) != std::string::npos) {
302 res.replace(start_pos, from.length(), to);
303 start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
304 }
305 return res;
306}
307
308
309//////////////////////////////////////////////////////////////////////////////////////////////
310/// Add branches to config
311
313{
314 if (!branches || (branches->GetLast() < 0))
315 return;
316
317 TIter iter(branches);
318
319 while (auto br = dynamic_cast<TBranch *>(iter())) {
320
321 auto leaves = br->GetListOfLeaves();
322
323 auto subbr = br->GetListOfBranches();
324
325 std::string brname = br->GetName();
326
327 TLeaf *leaf0 = (leaves->GetLast() == 0) ? dynamic_cast<TLeaf *>(leaves->At(0)) : nullptr;
328
329 auto brelem = dynamic_cast<TBranchElement *>(br);
330
331 std::string brfullname = br->GetFullName().Data();
332
333 if ((subbr->GetLast() < 0) && leaf0 && (brname == leaf0->GetName())) {
334
335 // ignore branches containing objects, see TBranchElement::GetTypeName()
336 if (brelem && (brelem->GetStreamerType() < 1 || brelem->GetStreamerType() > 59))
337 continue;
338
339 fCfg.fBranches.emplace_back(FormatItemName(brfullname), br->GetTitle() + " / "s + leaf0->GetTypeName());
340 continue;
341 }
342
343 TIter liter(leaves);
344 while (auto leaf = dynamic_cast<TLeaf *>(liter())) {
345
346 std::string leaffullname = leaf->GetFullName().Data();
347
348 // ignore counter leaf for STL container
349 if (brelem && brelem->GetStreamerType() == TStreamerInfo::kSTL && (leaves->GetLast() == 0) && (leaffullname == brfullname + "_"))
350 break;
351
352 fCfg.fBranches.emplace_back(FormatItemName(leaffullname), leaf->GetTitle() + " / "s + leaf->GetTypeName());
353 }
354
355 AddBranches(subbr);
356 }
357}
358
359
360//////////////////////////////////////////////////////////////////////////////////////////////
361/// Update RConfig data
362
364{
365 fCfg.fBranches.clear();
366
367 if (!fTree) return;
368
370
372
374
375 fCfg.fStep = 1;
377 if (fCfg.fLargerStep < 2) fCfg.fLargerStep = 2;
378}
379
380
381//////////////////////////////////////////////////////////////////////////////////////////////
382/// Invoke tree drawing
383
385{
386
387 fTimer->TurnOff();
388
389 UpdateConfig();
390
391 std::string expr = fCfg.fExprX;
392 if (!fCfg.fExprY.empty()) {
393 expr += ":"s;
394 expr += fCfg.fExprY;
395
396 if (!fCfg.fExprZ.empty()) {
397 expr += ":"s;
398 expr += fCfg.fExprZ;
399 }
400 }
401
403
404 auto old = gMonitoringWriter;
405 RTreeDrawMonitoring monitoring(50, *this);
406 gMonitoringWriter = &monitoring;
407
408 fLastSendProgress.clear();
409
410 fTree->Draw(expr.c_str(), fCfg.fExprCut.c_str(), fCfg.fOption.c_str(), nentries, fCfg.fFirst);
411
412 gMonitoringWriter = old;
413
414 if (!fLastSendProgress.empty())
415 SendProgress(-1.);
416
417 std::string canv_name;
418
419 if (gPad) {
420 if ((expr.find("\\") != std::string::npos) || (expr.find("#") != std::string::npos)) {
421 auto FixTitle = [](TNamed *obj) {
422 if (!obj) return;
423 TString title = obj->GetTitle();
424 title.ReplaceAll("\\/", "/");
425 title.ReplaceAll("#","\\#");
426 obj->SetTitle(title.Data());
427 };
428 TIter iter(gPad->GetListOfPrimitives());
429 while (auto obj = iter()) {
430 if (expr == obj->GetTitle()) {
431 FixTitle(dynamic_cast<TNamed *> (obj));
432 TH1 *hist = dynamic_cast<TH1 *> (obj);
433 if (hist) {
434 FixTitle(hist->GetXaxis());
435 FixTitle(hist->GetYaxis());
436 FixTitle(hist->GetZaxis());
437 }
438 }
439 }
440 }
441
442 gPad->Update();
443 canv_name = gPad->GetName();
444 }
445
446 // at the end invoke callback
447 if (fCallback)
448 fCallback(canv_name);
449}
450
451//////////////////////////////////////////////////////////////////////////////////////////////
452/// Send progress to the client
453
455{
456 std::string progress = "100";
457
458 if (nevent >= 0.) {
459
462 Long64_t last = nentries;
463 if ((fCfg.fNumber > 0) && (first + fCfg.fNumber < nentries))
464 last = first + fCfg.fNumber;
465
466 if (last > first) {
467 Double_t p = nevent / ( last - first + 0. ) * 100.;
468 if (p > 100) p = 100;
469 progress = std::to_string(p);
470 }
471 }
472
473 if (fLastSendProgress == progress)
474 return;
475
476 fLastSendProgress = progress;
477
478 if (fWebWindow->CanSend(0, kTRUE))
479 fWebWindow->Send(0, "PROGRESS:"s + progress);
480}
481
482//////////////////////////////////////////////////////////////////////////////////////////////
483/// Create new viewer
484/// Method used for plugin
485
487{
488 auto viewer = new RTreeViewer(t);
489
490 viewer->Show();
491
492 return viewer;
493}
494
nlohmann::json json
long Long_t
Definition RtypesCore.h:54
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
long long Long64_t
Definition RtypesCore.h:80
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
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:560
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_t mode, RTreeViewer &viewer)
constructor
Bool_t SendFileCloseEvent(TFile *) override
Bool_t SendProcessingProgress(Double_t nevent, Double_t, Bool_t=kFALSE) override
Bool_t SendFileOpenProgress(TFile *, TList *, const char *, Bool_t=kFALSE) override
RTreeDrawMonitoring(Int_t period, RTreeViewer &viewer)
RTreeDrawMonitoring & operator=(const RTreeDrawMonitoring &)=delete
RTreeDrawMonitoring(const RTreeDrawMonitoring &)=delete
Bool_t SendInfoTime() override
void SetLogLevel(const char *="WARNING") override
Bool_t SendFileWriteProgress(TFile *) override
Bool_t SendProcessingStatus(const char *, Bool_t=kFALSE) override
Bool_t SendInfoUser(const char *=nullptr) override
Bool_t SendInfoDescription(const char *) override
Bool_t SendInfoStatus(const char *) override
Bool_t SendFileReadProgress(TFile *) override
void Verbose(Bool_t) override
Bool_t SendParameters(TList *, const char *=nullptr) 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 URL address of web window used for tree viewer.
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 composed of a header, followed by consecutive data records (TKey instances) with a wel...
Definition TFile.h:53
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:58
TAxis * GetZaxis()
Definition TH1.h:324
TAxis * GetXaxis()
Definition TH1.h:322
TAxis * GetYaxis()
Definition TH1.h:323
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:380
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:450
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:403
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
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
Definition first.py:1
Definition tree.py:1
std::vector< RBranchInfo > fBranches