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/** \class ROOT::RTreeViewer
106\ingroup webwidgets
107
108\brief Web-based %ROOT TTree viewer
109*/
110
111
112//////////////////////////////////////////////////////////////////////////////////////////////
113/// constructor
114
116{
118 fWebWindow->SetDefaultPage("file:rootui5sys/tree/index.html");
119
120 // this is call-back, invoked when message received via websocket
121 fWebWindow->SetConnectCallBack([this](unsigned connid) { WebWindowConnect(connid); });
122 fWebWindow->SetDataCallBack([this](unsigned connid, const std::string &arg) { WebWindowCallback(connid, arg); });
123 fWebWindow->SetGeometry(900, 700); // configure predefined window geometry
124 fWebWindow->SetConnLimit(1); // allow the only connection
125 fWebWindow->SetMaxQueueLength(30); // number of allowed entries in the window queue
126
127 if (tree) SetTree(tree);
128
129 fTimer = std::make_unique<RTreeDrawInvokeTimer>(10, true, *this);
130}
131
132//////////////////////////////////////////////////////////////////////////////////////////////
133/// destructor
134
136{
137
138}
139
140//////////////////////////////////////////////////////////////////////////////////////////////
141/// assign new TTree to the viewer
142
144{
145 fTree = tree;
146
147 // reset expression when new tree is assigned
148 fCfg.fExprX.clear();
149 fCfg.fExprY.clear();
150 fCfg.fExprZ.clear();
151 fCfg.fExprCut.clear();
152 fCfg.fNumber = 0;
153 fCfg.fFirst = 0;
154
155 UpdateConfig();
156
157 Update();
158}
159
160//////////////////////////////////////////////////////////////////////////////////////////////
161/// Suggest to use leaf in the gui
162/// Normally just assign as last edited expression
163
165{
166 const TBranch *branch = leaf ? leaf->GetBranch() : nullptr;
167
168 const TTree *tree = branch ? branch->GetTree() : nullptr;
169
170 if (!tree || (fTree != tree))
171 return false;
172
173 if ((const_cast<TBranch *>(branch)->GetListOfBranches()->GetLast() < 0) && (branch->GetNleaves() == 1)) {
174 std::string brname = branch->GetName();
175 if (brname == leaf->GetName())
176 return SuggestBranch(branch);
177 }
178
179 fWebWindow->Send(0, "SUGGEST:"s + FormatItemName(leaf->GetFullName().Data()));
180
181 return true;
182}
183
184//////////////////////////////////////////////////////////////////////////////////////////////
185/// Suggest to use branch in the gui
186/// Normally just assign as last edited expression
187
189{
190 const TTree *tree = branch ? branch->GetTree() : nullptr;
191
192 if (!tree || (fTree != tree))
193 return false;
194
195 fWebWindow->Send(0, "SUGGEST:"s + FormatItemName(branch->GetFullName().Data()));
196
197 return true;
198}
199
200//////////////////////////////////////////////////////////////////////////////////////////////
201/// Suggest to use expression in the gui
202/// Normally just assign as last edited expression
203
204bool RTreeViewer::SuggestExpression(const std::string &expr)
205{
206 if (!fTree || expr.empty())
207 return false;
208
209 fWebWindow->Send(0, "SUGGEST:"s + expr);
210
211 return true;
212}
213
214
215/////////////////////////////////////////////////////////////////////////////////
216/// Show or update viewer in web window
217/// If web browser already started - just refresh drawing like "reload" button does
218/// If no web window exists or \param always_start_new_browser configured, starts new window
219/// \param args arguments to display
220
221void RTreeViewer::Show(const RWebDisplayArgs &args, bool always_start_new_browser)
222{
223 std::string user_args = "";
224 if (!GetShowHierarchy()) user_args = "{ nobrowser: true }";
225 fWebWindow->SetUserArgs(user_args);
226
227 if (args.GetWidgetKind().empty())
228 const_cast<RWebDisplayArgs *>(&args)->SetWidgetKind("RTreeViewer");
229
230 if ((fWebWindow->NumConnections(true) == 0) || always_start_new_browser)
231 fWebWindow->Show(args);
232 else
233 Update();
234}
235
236//////////////////////////////////////////////////////////////////////////////////////////////
237/// Return address of web window used for tree viewer
238
239std::string RTreeViewer::GetWindowAddr() const
240{
241 return fWebWindow ? fWebWindow->GetAddr() : ""s;
242}
243
244//////////////////////////////////////////////////////////////////////////////////////////////
245/// Return URL of web window used for tree viewer
246/// See \ref ROOT::RWebWindow::GetUrl docu for more details
247
248std::string RTreeViewer::GetWindowUrl(bool remote)
249{
250 return fWebWindow ? fWebWindow->GetUrl(remote) : ""s;
251}
252
253//////////////////////////////////////////////////////////////////////////////////////////////
254/// Update tree viewer in all web displays
255
257{
258 SendCfg(0);
259}
260
261//////////////////////////////////////////////////////////////////////////////////////////////
262/// Send data for initialize viewer
263
264void RTreeViewer::SendCfg(unsigned connid)
265{
267
268 fWebWindow->Send(connid, json);
269}
270
271
272//////////////////////////////////////////////////////////////////////////////////////////////
273/// react on new connection
274
275void RTreeViewer::WebWindowConnect(unsigned connid)
276{
277 SendCfg(connid);
278}
279
280//////////////////////////////////////////////////////////////////////////////////////////////
281/// receive data from client
282
283void RTreeViewer::WebWindowCallback(unsigned connid, const std::string &arg)
284{
285 if (arg == "GETCFG"s) {
286
287 SendCfg(connid);
288
289 } else if (arg == "QUIT_ROOT"s) {
290
291 fWebWindow->TerminateROOT();
292
293 } if (arg.compare(0, 5, "DRAW:"s) == 0) {
294
295 if (!fTree) return;
296
297 auto newcfg = TBufferJSON::FromJSON<RConfig>(arg.substr(5));
298
299 if (newcfg) {
300 fCfg = *newcfg;
301 fTimer->TurnOn();
302 }
303 }
304}
305
306//////////////////////////////////////////////////////////////////////////////////////////////
307/// Format item name used in draw expression
308
309std::string RTreeViewer::FormatItemName(const std::string &name)
310{
311 std::string res = name;
312
313 std::string from = "/";
314 std::string to = "\\/";
315
316 size_t start_pos = 0;
317 while((start_pos = res.find(from, start_pos)) != std::string::npos) {
318 res.replace(start_pos, from.length(), to);
319 start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
320 }
321 return res;
322}
323
324
325//////////////////////////////////////////////////////////////////////////////////////////////
326/// Add branches to config
327
329{
330 if (!branches || (branches->GetLast() < 0))
331 return;
332
333 TIter iter(branches);
334
335 while (auto br = dynamic_cast<TBranch *>(iter())) {
336
337 auto leaves = br->GetListOfLeaves();
338
339 auto subbr = br->GetListOfBranches();
340
341 std::string brname = br->GetName();
342
343 TLeaf *leaf0 = (leaves->GetLast() == 0) ? dynamic_cast<TLeaf *>(leaves->At(0)) : nullptr;
344
345 auto brelem = dynamic_cast<TBranchElement *>(br);
346
347 std::string brfullname = br->GetFullName().Data();
348
349 if ((subbr->GetLast() < 0) && leaf0 && (brname == leaf0->GetName())) {
350
351 // ignore branches containing objects, see TBranchElement::GetTypeName()
352 if (brelem && (brelem->GetStreamerType() < 1 || brelem->GetStreamerType() > 59))
353 continue;
354
355 fCfg.fBranches.emplace_back(FormatItemName(brfullname), br->GetTitle() + " / "s + leaf0->GetTypeName());
356 continue;
357 }
358
359 TIter liter(leaves);
360 while (auto leaf = dynamic_cast<TLeaf *>(liter())) {
361
362 std::string leaffullname = leaf->GetFullName().Data();
363
364 // ignore counter leaf for STL container
365 if (brelem && brelem->GetStreamerType() == TStreamerInfo::kSTL && (leaves->GetLast() == 0) && (leaffullname == brfullname + "_"))
366 break;
367
368 fCfg.fBranches.emplace_back(FormatItemName(leaffullname), leaf->GetTitle() + " / "s + leaf->GetTypeName());
369 }
370
371 AddBranches(subbr);
372 }
373}
374
375
376//////////////////////////////////////////////////////////////////////////////////////////////
377/// Update RConfig data
378
380{
381 fCfg.fBranches.clear();
382
383 if (!fTree) return;
384
386
388
390
391 fCfg.fStep = 1;
393 if (fCfg.fLargerStep < 2) fCfg.fLargerStep = 2;
394}
395
396
397//////////////////////////////////////////////////////////////////////////////////////////////
398/// Invoke tree drawing
399
401{
402
403 fTimer->TurnOff();
404
405 UpdateConfig();
406
407 std::string expr = fCfg.fExprX;
408 if (!fCfg.fExprY.empty()) {
409 expr += ":"s;
410 expr += fCfg.fExprY;
411
412 if (!fCfg.fExprZ.empty()) {
413 expr += ":"s;
414 expr += fCfg.fExprZ;
415 }
416 }
417
419
420 auto old = gMonitoringWriter;
421 RTreeDrawMonitoring monitoring(50, *this);
422 gMonitoringWriter = &monitoring;
423
424 fLastSendProgress.clear();
425
426 fTree->Draw(expr.c_str(), fCfg.fExprCut.c_str(), fCfg.fOption.c_str(), nentries, fCfg.fFirst);
427
428 gMonitoringWriter = old;
429
430 if (!fLastSendProgress.empty())
431 SendProgress(-1.);
432
433 std::string canv_name;
434
435 if (gPad) {
436 if ((expr.find('\\') != std::string::npos) || (expr.find('#') != std::string::npos)) {
437 auto FixTitle = [](TNamed *obj) {
438 if (!obj) return;
439 TString title = obj->GetTitle();
440 title.ReplaceAll("\\/", "/");
441 title.ReplaceAll("#","\\#");
442 obj->SetTitle(title.Data());
443 };
444 TIter iter(gPad->GetListOfPrimitives());
445 while (auto obj = iter()) {
446 if (expr == obj->GetTitle()) {
447 FixTitle(dynamic_cast<TNamed *> (obj));
448 TH1 *hist = dynamic_cast<TH1 *> (obj);
449 if (hist) {
450 FixTitle(hist->GetXaxis());
451 FixTitle(hist->GetYaxis());
452 FixTitle(hist->GetZaxis());
453 }
454 }
455 }
456 }
457
458 gPad->Update();
459 canv_name = gPad->GetName();
460 }
461
462 // at the end invoke callback
463 if (fCallback)
464 fCallback(canv_name);
465}
466
467//////////////////////////////////////////////////////////////////////////////////////////////
468/// Send progress to the client
469
471{
472 std::string progress = "100";
473
474 if (nevent >= 0.) {
475
476 Long64_t first = fCfg.fFirst;
478 Long64_t last = nentries;
479 if ((fCfg.fNumber > 0) && (first + fCfg.fNumber < nentries))
480 last = first + fCfg.fNumber;
481
482 if (last > first) {
483 Double_t p = nevent / ( last - first + 0. ) * 100.;
484 if (p > 100) p = 100;
485 progress = std::to_string(p);
486 }
487 }
488
489 if (fLastSendProgress == progress)
490 return;
491
492 fLastSendProgress = progress;
493
494 if (fWebWindow->CanSend(0, true))
495 fWebWindow->Send(0, "PROGRESS:"s + progress);
496}
497
498//////////////////////////////////////////////////////////////////////////////////////////////
499/// Create new viewer
500/// Method used for plugin
501
503{
504 auto viewer = new RTreeViewer(t);
505
506 viewer->Show();
507
508 return viewer;
509}
510
nlohmann::json json
long Long_t
Definition RtypesCore.h:54
long long Long64_t
Definition RtypesCore.h:69
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:561
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
Web-based ROOT TTree viewer.
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:327
TAxis * GetXaxis()
Definition TH1.h:325
TAxis * GetYaxis()
Definition TH1.h:326
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:528
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