Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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:
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
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
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 if (fWebWindow)
138 fWebWindow->Reset();
139}
140
141//////////////////////////////////////////////////////////////////////////////////////////////
142/// assign new TTree to the viewer
143
145{
146 fTree = tree;
147
148 // reset expression when new tree is assigned
149 fCfg.fExprX.clear();
150 fCfg.fExprY.clear();
151 fCfg.fExprZ.clear();
152 fCfg.fExprCut.clear();
153 fCfg.fNumber = 0;
154 fCfg.fFirst = 0;
155
156 UpdateConfig();
157
158 Update();
159}
160
161//////////////////////////////////////////////////////////////////////////////////////////////
162/// Suggest to use leaf in the gui
163/// Normally just assign as last edited expression
164
166{
167 const TBranch *branch = leaf ? leaf->GetBranch() : nullptr;
168
169 const TTree *tree = branch ? branch->GetTree() : nullptr;
170
171 if (!tree || (fTree != tree))
172 return false;
173
174 if ((const_cast<TBranch *>(branch)->GetListOfBranches()->GetLast() < 0) && (branch->GetNleaves() == 1)) {
175 std::string brname = branch->GetName();
176 if (brname == leaf->GetName())
177 return SuggestBranch(branch);
178 }
179
180 fWebWindow->Send(0, "SUGGEST:"s + FormatItemName(leaf->GetFullName().Data()));
181
182 return true;
183}
184
185//////////////////////////////////////////////////////////////////////////////////////////////
186/// Suggest to use branch in the gui
187/// Normally just assign as last edited expression
188
190{
191 const TTree *tree = branch ? branch->GetTree() : nullptr;
192
193 if (!tree || (fTree != tree))
194 return false;
195
196 fWebWindow->Send(0, "SUGGEST:"s + FormatItemName(branch->GetFullName().Data()));
197
198 return true;
199}
200
201//////////////////////////////////////////////////////////////////////////////////////////////
202/// Suggest to use expression in the gui
203/// Normally just assign as last edited expression
204
205bool RTreeViewer::SuggestExpression(const std::string &expr)
206{
207 if (!fTree || expr.empty())
208 return false;
209
210 fWebWindow->Send(0, "SUGGEST:"s + expr);
211
212 return true;
213}
214
215
216/////////////////////////////////////////////////////////////////////////////////
217/// Show or update viewer in web window
218/// If web browser already started - just refresh drawing like "reload" button does
219/// If no web window exists or \param always_start_new_browser configured, starts new window
220/// \param args arguments to display
221
223{
224 std::string user_args = "";
225 if (!GetShowHierarchy()) user_args = "{ nobrowser: true }";
226 fWebWindow->SetUserArgs(user_args);
227
228 if (args.GetWidgetKind().empty())
229 const_cast<RWebDisplayArgs *>(&args)->SetWidgetKind("RTreeViewer");
230
231 if ((fWebWindow->NumConnections(true) == 0) || always_start_new_browser)
232 fWebWindow->Show(args);
233 else
234 Update();
235}
236
237//////////////////////////////////////////////////////////////////////////////////////////////
238/// Return address of web window used for tree viewer
239
240std::string RTreeViewer::GetWindowAddr() const
241{
242 return fWebWindow ? fWebWindow->GetAddr() : ""s;
243}
244
245//////////////////////////////////////////////////////////////////////////////////////////////
246/// Return URL of web window used for tree viewer
247/// See \ref ROOT::RWebWindow::GetUrl docu for more details
248
250{
251 return fWebWindow ? fWebWindow->GetUrl(remote) : ""s;
252}
253
254//////////////////////////////////////////////////////////////////////////////////////////////
255/// Update tree viewer in all web displays
256
258{
259 SendCfg(0);
260}
261
262//////////////////////////////////////////////////////////////////////////////////////////////
263/// Send data for initialize viewer
264
265void RTreeViewer::SendCfg(unsigned connid)
266{
268
269 fWebWindow->Send(connid, json);
270}
271
272
273//////////////////////////////////////////////////////////////////////////////////////////////
274/// react on new connection
275
276void RTreeViewer::WebWindowConnect(unsigned connid)
277{
278 SendCfg(connid);
279}
280
281//////////////////////////////////////////////////////////////////////////////////////////////
282/// receive data from client
283
284void RTreeViewer::WebWindowCallback(unsigned connid, const std::string &arg)
285{
286 if (arg == "GETCFG"s) {
287
288 SendCfg(connid);
289
290 } else if (arg == "QUIT_ROOT"s) {
291
292 fWebWindow->TerminateROOT();
293
294 } if (arg.compare(0, 5, "DRAW:"s) == 0) {
295
296 if (!fTree) return;
297
298 auto newcfg = TBufferJSON::FromJSON<RConfig>(arg.substr(5));
299
300 if (newcfg) {
301 fCfg = *newcfg;
302 fTimer->TurnOn();
303 }
304 }
305}
306
307//////////////////////////////////////////////////////////////////////////////////////////////
308/// Format item name used in draw expression
309
310std::string RTreeViewer::FormatItemName(const std::string &name)
311{
312 std::string res = name;
313
314 std::string from = "/";
315 std::string to = "\/";
316
317 size_t start_pos = 0;
318 while((start_pos = res.find(from, start_pos)) != std::string::npos) {
319 res.replace(start_pos, from.length(), to);
320 start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
321 }
322 return res;
323}
324
325
326//////////////////////////////////////////////////////////////////////////////////////////////
327/// Add branches to config
328
330{
331 if (!branches || (branches->GetLast() < 0))
332 return;
333
334 TIter iter(branches);
335
336 while (auto br = dynamic_cast<TBranch *>(iter())) {
337
338 auto leaves = br->GetListOfLeaves();
339
340 auto subbr = br->GetListOfBranches();
341
342 std::string brname = br->GetName();
343
344 TLeaf *leaf0 = (leaves->GetLast() == 0) ? dynamic_cast<TLeaf *>(leaves->At(0)) : nullptr;
345
346 auto brelem = dynamic_cast<TBranchElement *>(br);
347
348 std::string brfullname = br->GetFullName().Data();
349
350 if ((subbr->GetLast() < 0) && leaf0 && (brname == leaf0->GetName())) {
351
352 // ignore branches containing objects, see TBranchElement::GetTypeName()
353 if (brelem && (brelem->GetStreamerType() < 1 || brelem->GetStreamerType() > 59))
354 continue;
355
356 fCfg.fBranches.emplace_back(FormatItemName(brfullname), br->GetTitle() + " / "s + leaf0->GetTypeName());
357 continue;
358 }
359
360 TIter liter(leaves);
361 while (auto leaf = dynamic_cast<TLeaf *>(liter())) {
362
363 std::string leaffullname = leaf->GetFullName().Data();
364
365 // ignore counter leaf for STL container
366 if (brelem && brelem->GetStreamerType() == TStreamerInfo::kSTL && (leaves->GetLast() == 0) && (leaffullname == brfullname + "_"))
367 break;
368
369 fCfg.fBranches.emplace_back(FormatItemName(leaffullname), leaf->GetTitle() + " / "s + leaf->GetTypeName());
370 }
371
373 }
374}
375
376
377//////////////////////////////////////////////////////////////////////////////////////////////
378/// Update RConfig data
379
381{
382 fCfg.fBranches.clear();
383
384 if (!fTree) return;
385
387
389
391
392 fCfg.fStep = 1;
394 if (fCfg.fLargerStep < 2) fCfg.fLargerStep = 2;
395}
396
397
398//////////////////////////////////////////////////////////////////////////////////////////////
399/// Invoke tree drawing
400
402{
403
404 fTimer->TurnOff();
405
406 UpdateConfig();
407
408 std::string expr = fCfg.fExprX;
409 if (!fCfg.fExprY.empty()) {
410 expr += ":"s;
411 expr += fCfg.fExprY;
412
413 if (!fCfg.fExprZ.empty()) {
414 expr += ":"s;
415 expr += fCfg.fExprZ;
416 }
417 }
418
420
421 auto old = gMonitoringWriter;
424
425 fLastSendProgress.clear();
426
427 fTree->Draw(expr.c_str(), fCfg.fExprCut.c_str(), fCfg.fOption.c_str(), nentries, fCfg.fFirst);
428
429 gMonitoringWriter = old;
430
431 if (!fLastSendProgress.empty())
432 SendProgress(-1.);
433
434 std::string canv_name;
435
436 if (gPad) {
437 if ((expr.find('\') != std::string::npos) || (expr.find('#') != std::string::npos)) {
438 auto FixTitle = [](TNamed *obj) {
439 if (!obj) return;
440 TString title = obj->GetTitle();
441 title.ReplaceAll("\/", "/");
442 title.ReplaceAll("#","\#");
443 obj->SetTitle(title.Data());
444 };
445 TIter iter(gPad->GetListOfPrimitives());
446 while (auto obj = iter()) {
447 if (expr == obj->GetTitle()) {
448 FixTitle(dynamic_cast<TNamed *> (obj));
449 TH1 *hist = dynamic_cast<TH1 *> (obj);
450 if (hist) {
451 FixTitle(hist->GetXaxis());
452 FixTitle(hist->GetYaxis());
453 FixTitle(hist->GetZaxis());
454 }
455 }
456 }
457 }
458
459 gPad->Update();
460 canv_name = gPad->GetName();
461 }
462
463 // at the end invoke callback
464 if (fCallback)
466}
467
468//////////////////////////////////////////////////////////////////////////////////////////////
469/// Send progress to the client
470
472{
473 std::string progress = "100";
474
475 if (nevent >= 0.) {
476
477 Long64_t first = fCfg.fFirst;
479 Long64_t last = nentries;
480 if ((fCfg.fNumber > 0) && (first + fCfg.fNumber < nentries))
481 last = first + fCfg.fNumber;
482
483 if (last > first) {
484 Double_t p = nevent / ( last - first + 0. ) * 100.;
485 if (p > 100) p = 100;
486 progress = std::to_string(p);
487 }
488 }
489
490 if (fLastSendProgress == progress)
491 return;
492
493 fLastSendProgress = progress;
494
495 if (fWebWindow->CanSend(0, true))
496 fWebWindow->Send(0, "PROGRESS:"s + progress);
497}
498
499//////////////////////////////////////////////////////////////////////////////////////////////
500/// Create new viewer
501/// Method used for plugin
502
504{
505 auto viewer = new RTreeViewer(t);
506
507 viewer->Show();
508
509 return viewer;
510}
511
nlohmann::json json
long Long_t
Definition RtypesCore.h:54
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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:572
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.
A TTree is a list of TBranches.
Definition TBranch.h:93
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:131
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:59
TAxis * GetZaxis()
Definition TH1.h:346
TAxis * GetXaxis()
Definition TH1.h:344
TAxis * GetYaxis()
Definition TH1.h:345
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
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:49
An array of TObjects.
Definition TObjArray.h:31
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:432
virtual Long64_t GetEntries() const
Definition TTree.h:464
virtual TObjArray * GetListOfBranches()
Definition TTree.h:529
static constexpr Long64_t kMaxEntries
Definition TTree.h:230
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
std::vector< RBranchInfo > fBranches