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 "TLeaf.h"
22#include "TH1.h"
23#include "TAxis.h"
24
25
26#include "TTimer.h"
27#include "TBufferJSON.h"
28
29
30namespace ROOT {
31namespace Experimental {
32
33
34class TProgressTimer : public TTimer {
36public:
37 TProgressTimer(RTreeViewer &viewer, Int_t period) : TTimer(period, kTRUE), fViewer(viewer)
38 {
39 }
40
41 Bool_t Notify() override
42 {
44 return kTRUE;
45 }
46};
47
48} // namespace Experimental
49} // namespace ROOT
50
51
52using namespace ROOT::Experimental;
53using namespace std::string_literals;
54
55
56//////////////////////////////////////////////////////////////////////////////////////////////
57/// constructor
58
60{
62 fWebWindow->SetDefaultPage("file:rootui5sys/tree/index.html");
63
64 // this is call-back, invoked when message received via websocket
65 fWebWindow->SetConnectCallBack([this](unsigned connid) { WebWindowConnect(connid); });
66 fWebWindow->SetDataCallBack([this](unsigned connid, const std::string &arg) { WebWindowCallback(connid, arg); });
67 fWebWindow->SetGeometry(900, 700); // configure predefined window geometry
68 fWebWindow->SetConnLimit(1); // allow the only connection
69 fWebWindow->SetMaxQueueLength(30); // number of allowed entries in the window queue
70
71 if (tree) SetTree(tree);
72}
73
74//////////////////////////////////////////////////////////////////////////////////////////////
75/// destructor
76
78{
79
80}
81
82//////////////////////////////////////////////////////////////////////////////////////////////
83/// assign new TTree to the viewer
84
86{
87 fTree = tree;
88
89 // reset expression when new tree is assigned
90 fCfg.fExprX.clear();
91 fCfg.fExprY.clear();
92 fCfg.fExprZ.clear();
93 fCfg.fExprCut.clear();
94 fCfg.fNumber = 0;
95 fCfg.fFirst = 0;
96
98
99 Update();
100}
101
102//////////////////////////////////////////////////////////////////////////////////////////////
103/// Suggest to use leaf in the gui
104/// Normally just assign as last edited expression
105
107{
108 const TBranch *branch = leaf ? leaf->GetBranch() : nullptr;
109
110 const TTree *tree = branch ? branch->GetTree() : nullptr;
111
112 if (!tree || (fTree != tree))
113 return false;
114
115 if ((const_cast<TBranch *>(branch)->GetListOfBranches()->GetLast() < 0) && (branch->GetNleaves() == 1)) {
116 std::string brname = branch->GetName();
117 if (brname == leaf->GetName())
118 return SuggestBranch(branch);
119 }
120
121 fWebWindow->Send(0, "SUGGEST:"s + FormatItemName(leaf->GetFullName().Data()));
122
123 return true;
124}
125
126//////////////////////////////////////////////////////////////////////////////////////////////
127/// Suggest to use branch in the gui
128/// Normally just assign as last edited expression
129
131{
132 const TTree *tree = branch ? branch->GetTree() : nullptr;
133
134 if (!tree || (fTree != tree))
135 return false;
136
137 fWebWindow->Send(0, "SUGGEST:"s + FormatItemName(branch->GetFullName().Data()));
138
139 return true;
140}
141
142//////////////////////////////////////////////////////////////////////////////////////////////
143/// Suggest to use expression in the gui
144/// Normally just assign as last edited expression
145
146bool RTreeViewer::SuggestExpression(const std::string &expr)
147{
148 if (!fTree || expr.empty())
149 return false;
150
151 fWebWindow->Send(0, "SUGGEST:"s + expr);
152
153 return true;
154}
155
156
157/////////////////////////////////////////////////////////////////////////////////
158/// Show or update viewer in web window
159/// If web browser already started - just refresh drawing like "reload" button does
160/// If no web window exists or \param always_start_new_browser configured, starts new window
161/// \param args arguments to display
162
163void RTreeViewer::Show(const RWebDisplayArgs &args, bool always_start_new_browser)
164{
165 std::string user_args = "";
166 if (!GetShowHierarchy()) user_args = "{ nobrowser: true }";
167 fWebWindow->SetUserArgs(user_args);
168
169 if (args.GetWidgetKind().empty())
170 const_cast<RWebDisplayArgs *>(&args)->SetWidgetKind("RTreeViewer");
171
172 if ((fWebWindow->NumConnections(true) == 0) || always_start_new_browser)
173 fWebWindow->Show(args);
174 else
175 Update();
176}
177
178//////////////////////////////////////////////////////////////////////////////////////////////
179/// Return URL address of web window used for tree viewer
180
181std::string RTreeViewer::GetWindowAddr() const
182{
183 return fWebWindow ? fWebWindow->GetAddr() : ""s;
184}
185
186//////////////////////////////////////////////////////////////////////////////////////////////
187/// Update tree viewer in all web displays
188
190{
191 SendCfg(0);
192}
193
194//////////////////////////////////////////////////////////////////////////////////////////////
195/// Send data for initialize viewer
196
197void RTreeViewer::SendCfg(unsigned connid)
198{
200
201 fWebWindow->Send(connid, json);
202}
203
204
205//////////////////////////////////////////////////////////////////////////////////////////////
206/// react on new connection
207
208void RTreeViewer::WebWindowConnect(unsigned connid)
209{
210 SendCfg(connid);
211}
212
213//////////////////////////////////////////////////////////////////////////////////////////////
214/// receive data from client
215
216void RTreeViewer::WebWindowCallback(unsigned connid, const std::string &arg)
217{
218 if (arg == "GETCFG"s) {
219
220 SendCfg(connid);
221
222 } else if (arg == "QUIT_ROOT"s) {
223
224 fWebWindow->TerminateROOT();
225
226 } if (arg.compare(0, 5, "DRAW:"s) == 0) {
227
228 InvokeTreeDraw(arg.substr(5));
229 }
230}
231
232//////////////////////////////////////////////////////////////////////////////////////////////
233/// Format item name used in draw expression
234
235std::string RTreeViewer::FormatItemName(const std::string &name)
236{
237 std::string res = name;
238
239 std::string from = "/";
240 std::string to = "\\/";
241
242 size_t start_pos = 0;
243 while((start_pos = res.find(from, start_pos)) != std::string::npos) {
244 res.replace(start_pos, from.length(), to);
245 start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
246 }
247 return res;
248}
249
250
251//////////////////////////////////////////////////////////////////////////////////////////////
252/// Add branches to config
253
255{
256 if (!branches || (branches->GetLast() < 0))
257 return;
258
259 TIter iter(branches);
260
261 while (auto br = dynamic_cast<TBranch *>(iter())) {
262
263 auto leaves = br->GetListOfLeaves();
264
265 auto subbr = br->GetListOfBranches();
266
267 std::string brname = br->GetName();
268
269 TLeaf *leaf0 = (leaves->GetLast() == 0) ? dynamic_cast<TLeaf *>(leaves->At(0)) : nullptr;
270
271 auto brelem = dynamic_cast<TBranchElement *>(br);
272
273 std::string brfullname = br->GetFullName().Data();
274
275 if ((subbr->GetLast() < 0) && leaf0 && (brname == leaf0->GetName())) {
276
277 // ignore branches containing objects, see TBranchElement::GetTypeName()
278 if (brelem && (brelem->GetStreamerType() < 1 || brelem->GetStreamerType() > 59))
279 continue;
280
281 fCfg.fBranches.emplace_back(FormatItemName(brfullname), br->GetTitle() + " / "s + leaf0->GetTypeName());
282 continue;
283 }
284
285 TIter liter(leaves);
286 while (auto leaf = dynamic_cast<TLeaf *>(liter())) {
287
288 std::string leaffullname = leaf->GetFullName().Data();
289
290 // ignore counter leaf for STL container
291 if (brelem && brelem->GetStreamerType() == TStreamerInfo::kSTL && (leaves->GetLast() == 0) && (leaffullname == brfullname + "_"))
292 break;
293
294 fCfg.fBranches.emplace_back(FormatItemName(leaffullname), leaf->GetTitle() + " / "s + leaf->GetTypeName());
295 }
296
297 AddBranches(subbr);
298 }
299}
300
301
302//////////////////////////////////////////////////////////////////////////////////////////////
303/// Update RConfig data
304
306{
307 fCfg.fBranches.clear();
308
309 if (!fTree) return;
310
312
314
316
317 fCfg.fStep = 1;
319 if (fCfg.fLargerStep < 2) fCfg.fLargerStep = 2;
320}
321
322
323//////////////////////////////////////////////////////////////////////////////////////////////
324/// Invoke tree drawing
325
326void RTreeViewer::InvokeTreeDraw(const std::string &json)
327{
328 auto newcfg = TBufferJSON::FromJSON<RConfig>(json);
329
330 if (!newcfg || !fTree) return;
331
332 fCfg = *newcfg;
333
334 UpdateConfig();
335
336 std::string expr = fCfg.fExprX;
337 if (!fCfg.fExprY.empty()) {
338 expr += ":"s;
339 expr += fCfg.fExprY;
340
341 if (!fCfg.fExprZ.empty()) {
342 expr += ":"s;
343 expr += fCfg.fExprZ;
344 }
345 }
346
348
349 if (!fProgrTimer)
350 fProgrTimer = std::make_unique<TProgressTimer>(*this, 50);
351
353
354 fLastSendProgress.clear();
355
356 // SendProgress();
357
358 fProgrTimer->TurnOn();
359
360 fTree->Draw(expr.c_str(), fCfg.fExprCut.c_str(), fCfg.fOption.c_str(), nentries, fCfg.fFirst);
361
362 fProgrTimer->TurnOff();
363
364 if (!fLastSendProgress.empty())
365 SendProgress(true);
366
367 std::string canv_name;
368
369 if (gPad) {
370 if ((expr.find("\\") != std::string::npos) || (expr.find("#") != std::string::npos)) {
371 auto FixTitle = [](TNamed *obj) {
372 if (!obj) return;
373 TString title = obj->GetTitle();
374 title.ReplaceAll("\\/", "/");
375 title.ReplaceAll("#","\\#");
376 obj->SetTitle(title.Data());
377 };
378 TIter iter(gPad->GetListOfPrimitives());
379 while (auto obj = iter()) {
380 if (expr == obj->GetTitle()) {
381 FixTitle(dynamic_cast<TNamed *> (obj));
382 TH1 *hist = dynamic_cast<TH1 *> (obj);
383 if (hist) {
384 FixTitle(hist->GetXaxis());
385 FixTitle(hist->GetYaxis());
386 FixTitle(hist->GetZaxis());
387 }
388 }
389 }
390 }
391
392 gPad->Update();
393 canv_name = gPad->GetName();
394
395
396 }
397
398 // at the end invoke callback
399 if (fCallback)
400 fCallback(canv_name);
401}
402
403//////////////////////////////////////////////////////////////////////////////////////////////
404/// Send progress to the client
405
406void RTreeViewer::SendProgress(bool completed)
407{
408 std::string progress = "100";
409
410 if (!completed) {
411
414 Long64_t last = nentries;
415 if ((fCfg.fNumber > 0) && (first + fCfg.fNumber < nentries))
416 last = first + fCfg.fNumber;
417
418 Long64_t current = fTree->GetReadEntry();
419
420 if (last > first)
421 progress = std::to_string((current - first + 1.) / ( last - first + 0. ) * 100.);
422 }
423
424 if (fLastSendProgress == progress)
425 return;
426
427 fLastSendProgress = progress;
428
429 fWebWindow->Send(0, "PROGRESS:"s + progress);
430}
431
432//////////////////////////////////////////////////////////////////////////////////////////////
433/// Create new viewer
434/// Method used for plugin
435
437{
438 auto viewer = new RTreeViewer(t);
439
440 viewer->Show();
441
442 return viewer;
443}
444
nlohmann::json json
long long Long64_t
Definition RtypesCore.h:80
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
char name[80]
Definition TGX11.cxx:110
int nentries
#define gPad
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 UpdateConfig()
Update RConfig data.
std::string FormatItemName(const std::string &name)
Format item name used in draw expression.
bool SuggestLeaf(const TLeaf *leaf)
Suggest to use leaf in the gui Normally just assign as last edited expression.
std::string fLastSendProgress
! last send progress to client
void SetTree(TTree *tree)
assign new TTree to the viewer
void SendProgress(bool completed=false)
Send progress to the client.
std::string GetWindowAddr() const
Return URL address of web window used for tree viewer.
bool GetShowHierarchy() const
Returns default hierarchy browser visibility.
void Update()
Update tree viewer in all web displays.
void InvokeTreeDraw(const std::string &json)
Invoke tree drawing.
static RTreeViewer * NewViewer(TTree *)
Create new viewer Method used for plugin.
PerformDrawCallback_t fCallback
! callback invoked when tree draw performed
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
std::unique_ptr< TProgressTimer > fProgrTimer
! timer used to get draw progress
void AddBranches(TObjArray *branches)
Add branches to config.
std::shared_ptr< RWebWindow > fWebWindow
! web window
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
TTree * fTree
! TTree to show
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.
Bool_t Notify() override
This method must be overridden to handle object notification.
TProgressTimer(RTreeViewer &viewer, Int_t period)
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:89
TTree * GetTree() const
Definition TBranch.h:248
virtual TString GetFullName() const
Return the 'full' name of the branch.
Definition TBranch.cxx:1977
Int_t GetNleaves() const
Definition TBranch.h:245
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
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
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
Handles synchronous and a-synchronous timer events.
Definition TTimer.h:51
A TTree represents a columnar dataset.
Definition TTree.h:79
virtual void SetTimerInterval(Int_t msec=333)
Definition TTree.h:642
void Draw(Option_t *opt) override
Default Draw method for all objects.
Definition TTree.h:428
virtual Long64_t GetEntries() const
Definition TTree.h:460
virtual Long64_t GetReadEntry() const
Definition TTree.h:506
virtual TObjArray * GetListOfBranches()
Definition TTree.h:485
static constexpr Long64_t kMaxEntries
Definition TTree.h:226
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