otsdaq_utilities
v2_05_02_indev
|
The JSROOT project intends to implement ROOT graphics for web browsers. Reading of binary ROOT files is supported. It is the successor of the JSRootIO project.
In most practical cases it is not necessary to install JSROOT - it can be used directly from project web sites https://root.cern/js/ and http://jsroot.gsi.de/.
When required, there are following alternatives to install JSROOT on other web servers:
bower install jsroot
One could use JSROOT directly from local file system. If source code was unpacked/checked-out in /home/user/jsroot/
subfolder, one could just open it in browser with file:///home/user/jsroot/index.htm address.
The main page of the JSROOT project provides the possibility to interactively open ROOT files and draw objects like histogram or canvas.
To automate files loading and objects drawing, one can provide number of URL parameters in address string like:
For instance:
Following layouts are supported:
When specifying files
, items
or opts
parameters, array of strings could be provided like `files=['file1.root','file2.root']. One could skip quotes when specifying elements names
items=[file1.root/hpx,file2.root/hpy]or
opts=['',colz]`.
As item name, URL to existing image can be provided like item=img:http://server/image.png
. Such image will be just inserted in the existing layout. One could specify option "scale"
to automatically scale image to available space.
Many examples of URL string usage can be found on JSROOT examples page.
One can very easy integrate JSROOT graphic into arbitrary HTML pages using a iframe tag:
<iframe width="700" height="400" src="https://root.cern/js/latest/?nobrowser&file=../files/hsimple.root&item=hpxpy&opt=colz"> </iframe>
List of supported classes and draw options:
More examples of supported classes can be found on: https://root.cern/js/latest/examples.htm
In the URL string one could use "+" sign to specify objects superposition:
Analogue, one could specify individual draw options for superimposed objects
Here "logy" option will be used for "hpx1" item and "hist" option for "hprof;1" item.
While draw option can include "+" sign itself, for superposition one could specify arrays of items and draw options like:
JSROOT provides possibility to display TTree data, using TTree::Draw syntax:
Histogram ranges and binning defined after reading first 1000 entries from the tree. Like in ROOT, one could configure histogram binning and range directly:
One and two dimensional draw expressions can be resulted into TGraph object, using ">>Graph" as output:
For any integer value one can accumulate histogram with value bits distribution, specifying as output ">>bits(16)" or ">>bits":
There is special handling of TBits objects:
It is allowed to use different expressions with branch values:
Such expression can include arithmetical operations and all methods, provided in JavaScript Math class:
In the expression one could use "Entry$" and "Entries$" variables.
One also could specify cut condition, separating it with "::" from the rest draw expression like:
Contrary to the normal ROOT, JSROOT allows to use "(expr?res1:res2)" operator (placed into brackets):
It is possible to "dump" content of any branch (by default - first 10 entries):
Or one could dump values produced with draw expression (also first 10 entries by default):
Working with array indexes is supported. By default, all elements in array are used for the drawing. One could specify index for any array dimension (-1 means last element in the array). For instance, dump last element from event.fTracks
array:
For any array or collection kind one could extract its size with expression:
At the end of expression one can add several parameters with the syntax:
<draw_expession>;par1name:par1value;par2name:par2value
Following parameters are supported:
Example - opt=event.fTracks[].fTriggerBits;entries:1000;first:200;maxrange:25
JSROOT implements display of TGeo objects like:
Following classes are supported by geometry viewer:
Following draw options could be specified (separated by semicolon or ';'):
In the URL string several global settings can be changed:
It is possible to display only part of geometry model. For instance, one could select sub-item like:
Or one can use simple selection syntax (work only with first-level volumes):
Syntax uses '+' sign to enable visibility flag of specified volume and '-' sign to disable visibility. One could use wildcard symbol like '+TUBE1*'.
Another way to configure visibility flags is usage of ROOT macros, which typically looks like:
{ TGeoManager::Import("http://root.cern/files/alice2.root"); gGeoManager->DefaultColors(); // gGeoManager->SetVisLevel(4); gGeoManager->GetVolume("HALL")->InvisibleAll(); gGeoManager->GetVolume("ZDCC")->InvisibleAll(); gGeoManager->GetVolume("ZDCA")->InvisibleAll(); ... gGeoManager->GetVolume("ALIC")->Draw("ogl"); new TBrowser; }
Example of such macro can be found in root tutorials.
From provided macro only following calls will be executed in JSROOT:
gGeoManager->DefaultColors()
gGeoManager->GetVolume("HALL")->InvisibleAll()
gGeoManager->GetVolume("HALL")->SetTransparency(30)
gGeoManager->GetVolume("HALL")->SetLineColor(5)
gGeoManager->GetVolume("ALIC")->Draw("ogl")
All other will be ignored.
Example of major LHC detectors:
Other detectors examples:
Together with geometry one could display tracks (TEveTrack) and hits (TEvePointSet, TPolyMarker3D) objects. Either one do it interactively by drag and drop, or superimpose drawing with +
sign like:
There is a problem of correct rendering of transparent volumes. To solve problem in general is very expensive (in terms of computing power), therefore several approximation solution can be applied:
In principle, one could open any ROOT file placed in the web, providing the full URL to it like:
But one should be aware of Same-origin policy, when the browser blocks requests to files from domains other than current web page. To enable CORS on Apache web server, hosting ROOT files, one should add following lines to .htaccess
file:
<IfModule mod_headers.c> <FilesMatch "\.root"> Header set Access-Control-Allow-Origin "*" Header set Access-Control-Allow-Headers "range" Header set Access-Control-Expose-Headers "content-range,content-length,accept-ranges" Header set Access-Control-Allow-Methods "HEAD,GET" </FilesMatch> </IfModule>
More details about configuring of CORS headers can be found here.
Alternative - enable CORS requests in the browser. It can be easily done with CORS Everywhere plugin for the Firefox browser or Allow CORS plugin for the Chrome browser.
Next solution - install JSROOT on the server hosting ROOT files. In such configuration JSROOT does not issue CORS requests, therefore server and browsers can be used with their default settings. A simplified variant of such solution - copy only the top index.htm file from JSROOT package and specify the full path to JSRootCore.js script like:
... <script type="text/javascript" src="https://root.cern/js/latest/scripts/JSRootCore.js?gui"></script> ...
In the <div>
element with "simpleGUI" id one can specify many custom parameters, which are allowed in the URL string:
... <div id="simpleGUI" path="files/path" files="userfile1.root;subdir/usefile2.root"> loading scripts ... </div> ...
JSROOT can read files from local file system using HTML5 FileReader functionality. Main limitation here - user should interactively select files for reading. There is button __"..."__ on the main JSROOT page, which starts file selection dialog. If valid ROOT file is selected, JSROOT will be able to normally read content of such file.
One could try to invoke such dialog with "localfile" parameter in URL string:
It could happen, that due to security limitations automatic popup will be blocked.
For debuging purposes one can install JSROOT on local file system and let read ROOT files from the same location. Like:
But this works only with Firefox.
THttpServer provides http access to objects from running ROOT application. JSROOT is used to implement the user interface in the web browsers.
The layout of the main page coming from THttpServer is similar to the file I/O one. One could browse existing items and display them. A snapshot of running server can be seen on the demo page.
One could also specify similar URL parameters to configure the displayed items and drawing options.
It is also possible to display one single item from the THttpServer server like:
https://root.cern/js/latest/httpserver.C/Files/job1.root/hpxpy/draw.htm?opt=colz
The best possibility to organize the monitoring of data from a running application is to use THttpServer. In such case the client can always access the latest changes and request only the items currently displayed in the browser. To enable monitoring, one should activate the appropriate checkbox or provide monitoring parameter in the URL string like:
https://root.cern/js/latest/httpserver.C/Files/job1.root/hprof/draw.htm?monitoring=1000
The parameter value is the update interval in milliseconds.
Solid file-based monitoring (without integration of THttpServer into application) can be implemented in JSON format. There is the TBufferJSON class, which is capable to convert any (beside TTree) ROOT object into JSON. Any ROOT application can use such class to create JSON files for selected objects and write such files in a directory, which can be accessed via web server. Then one can use JSROOT to read such files and display objects in a web browser.
There is a demonstration page showing such functionality: https://root.cern/js/latest/demo/demo.htm. This demo page reads in cycle 20 json files and displays them.
If one has a web server which already provides such JSON file, one could specify the URL to this file like:
https://root.cern/js/latest/demo/demo.htm?addr=../httpserver.C/Canvases/c1/root.json.gz
Here the same problem with Cross-Origin Request can appear. If the web server configuration cannot be changed, just copy JSROOT to the web server itself.
Theoretically, one could use binary ROOT files to implement monitoring. With such approach, a ROOT-based application creates and regularly updates content of a ROOT file, which can be accessed via normal web server. From the browser side, JSROOT could regularly read the specified objects and update their drawings. But such solution has three major caveats.
First of all, one need to store the data of all objects, which only potentially could be displayed in the browser. In case of 10 objects it does not matter, but for 1000 or 100000 objects this will be a major performance penalty. With such big amount of data one will never achieve higher update rate.
The second problem is I/O. To read the first object from the ROOT file, one need to perform several (about 5) file-reading operations via http protocol. There is no http file locking mechanism (at least not for standard web servers), therefore there is no guarantee that the file content is not changed/replaced between consequent read operations. Therefore, one should expect frequent I/O failures while trying to monitor data from ROOT binary files. There is a workaround for the problem - one could load the file completely and exclude many partial I/O operations by this. To achieve this with JSROOT, one should add "+" sign at the end of the file name. Of course, it only could work for small files.
If somebody still wants to use monitoring of data from ROOT files, could try link like:
In this particular case, the histogram is not changing.
JSROOT can be used in arbitrary HTML pages and disaplay data, produced without ROOT-based applications.
Many different examples of JSROOT API usage can be found on JSROOT API examples page.
Before JSROOT can be used, all appropriate scripts should be loaded. HTML pages where JSROOT is used should include the JSRootCore.js script. The <head>
section of the HTML page should have the following line:
<script type="text/javascript" src="https://root.cern/js/latest/scripts/JSRootCore.js?2d"></script>
Here, the default location of JSROOT is specified. One could have a local copy on the file system or on a private web server. When JSROOT is used with THttpServer, the address looks like:
<script type="text/javascript" src="http://your_root_server:8080/jsrootsys/scripts/JSRootCore.js?2d"></script>
In URL string with JSRootCore.js script one can specify which JSROOT functionality should be loaded:
+ '2d' basic drawing functionality, support TPad/TCanvas/TFrame + 'hist' histograms drawing + 'more2d' more classes for 2D drawing like TH2/TF1/TEllipse + '3d' 3D drawing for 2D/3D histograms + 'geo' 3D drawing of TGeo classes + 'io' binary file I/O + 'tree' TTree functionality + 'math' advanced mathemathical functions + 'mathjax' loads MathJax.js and use it for latex output + 'openui5' load and configure OpenUI5 toolkit + 'gui' default gui for offline/online applications + 'load' name of user script(s) to load + 'onload' name of function to call when scripts loading completed + 'nocache' avoid use of cache for loading of JSROOT scripts
For instance, to load functionality with normal 2D graphics and binary ROOT files support, one should specify:
<script type="text/javascript" src="https://root.cern/js/latest/scripts/JSRootCore.min.js?2d&io"></script>
One could use minified version of all scripts (as shown in example) - this reduce page loading time significantly.
After main JSRootCore.js script is loaded, one can configure different options in JSROOT.gStyle object. It is instance of the TStyle object and contains similar properties. For instance, one can change stat format:
JSROOT.gStyle.fStatFormat = "7.5g"
Or specify custom format for the X/Y object values:
JSROOT.gStyle.XValuesFormat = "4.2g" JSROOT.gStyle.YValuesFormat = "6.1f"
When JSROOT installed with bower package manager, one could re-use basic libraries like d3.js
or three.js
from bower itself. For that one should add bower
into URL:
<script type="text/javascript" src="vendor/jsroot/scripts/JSRootCore.js?bower&2d&io"></script>
Bower support will be automatically enabled when script path conatin __"bower_components/jsroot/"__ string.
One also could use bower and gulp to produce single script with all libraries included. This is shown in the example https://github.com/root-project/jsroot/tree/master/demo/gulp
It is strongly recommended to use JSON when communicating with ROOT application. THttpServer provides a JSON representation for every registered object with an url address like:
http://your_root_server:8080/Canvases/c1/root.json
Such JSON representation generated using the TBufferJSON class. One could create JSON file for any ROOT object directly, just writing in the code:
... obj->SaveAs("file.json"); ...
To access data from a remote web server, it is recommended to use the XMLHttpRequest class. JSROOT provides a special method to create such object and properly handle it in different browsers. For receiving JSON from a server one could use following code:
var req = JSROOT.NewHttpRequest("http://your_root_server:8080/Canvases/c1/root.json", 'object', userCallback); req.send(null);
In the callback function one gets JavaScript object (or null in case of failure)
If JSON string was obtained by different method, it should be parsed with:
var obj = JSROOT.parse(json_string);
After an object has been created, one can directly draw it. If HTML page has <div>
element:
... <div id="drawing"></div> ...
One could use the JSROOT.draw function:
JSROOT.draw("drawing", obj, "colz");
The first argument is the id of the HTML div element, where drawing will be performed. The second argument is the object to draw and the third one is the drawing option.
Here is complete running example ans source code:
var filename = "https://root.cern/js/files/th2ul.json.gz"; JSROOT.NewHttpRequest(filename, 'object', function(obj) { JSROOT.draw("drawing", obj, "lego"); }).send();
In very seldom cases one need to access painter object, created in JSROOT.draw() function. This can be done via call back (forth argument) like:
JSROOT.draw("drawing", obj, "colz", function(painter) { console.log('Object type in painter', painter.GetObject()._typename); });
One is also able to update the drawing with a new version of the object:
// after some interval request object again JSROOT.redraw("drawing", obj2, "colz");
The JSROOT.redraw() function will call JSROOT.draw if the drawing was not performed before.
In the case when changing of HTML layout leads to resize of element with JSROOT drawing, one should call JSROOT.resize() to let JSROOT adjust drawing size. One should do:
JSROOT.resize("drawing");
As second argument one could specify exact size for draw elements like:
JSROOT.resize("drawing", { width: 500, height: 200 } );
To correctly cleanup JSROOT drawings from HTML element, one should call:
JSROOT.cleanup("drawing");
JSROOT defines the TFile class, which can be used to access binary ROOT files. One should always remember that all I/O operations are asynchronous in JSROOT. Therefore, callback functions are used to react when the I/O operation completed. For example, reading an object from a file and displaying it will look like:
var filename = "https://root.cern/js/files/hsimple.root"; JSROOT.OpenFile(filename, function(file) { file.ReadObject("hpxpy;1", function(obj) { JSROOT.draw("drawing", obj, "colz"); }); });
Here is running example and source code
Simple TTree::Draw operation can be performed with following code:
var filename = "https://root.cern/js/files/hsimple.root"; JSROOT.OpenFile(filename, function(file) { file.ReadObject("ntuple;1", function(obj) { JSROOT.draw("drawing", obj, "px:py::pz>5"); }); });
To get access to selected branches, one should use TSelector class:
var filename = "https://root.cern/js/files/hsimple.root"; JSROOT.OpenFile(filename, function(file) { file.ReadObject("ntuple;1", function(tree) { var selector = new JSROOT.TSelector(); selector.AddBranch("px"); selector.AddBranch("py"); var cnt = 0, sumpx = 0, sumpy = 0; selector.Begin = function() { // function called before reading of TTree starts } selector.Process = function() { // function called for every entry sumpx += this.tgtobj.px; sumpy += this.tgtobj.py; cnt++; } selector.Terminate = function(res) { if (!res || (cnt===0)) return; var meanpx = sumpx/cnt, meanpy = sumpy/cnt; console.log('Results', meanpx, meanpy); } tree.Process(selector); }); });
Here is running example and source code
This examples shows how read TTree from binary file and create JSROOT.TSelector object. Logically it is similar to original TSelector class - for every read entry TSelector::Process() method is called. Selected branches can be accessed from tgtobj data member. At the end of tree reading TSelector::Terminate() method will be called.
As second parameter of tree.Process() function one could provide object with arguments
var args = { numentries: 1000, firstentry: 500 }; tree.Process(selector, args);
Any supported TGeo object can be drawn with normal JSROOR.draw() function.
If necessary, one can create three.js model for supported object directly and use such model separately. This can be done with the function:
var opt = { numfaces: 100000}; var obj3d = JSROOT.GEO.build(obj, opt); scene.add( obj3d );
Following options can be specified:
When transparent volumes appeared in the model, one could use JSROOT.GEO.produceRenderOrder() function to correctly set rendering order. It should be used as:
JSROOT.GEO.produceRenderOrder(scene, camera.position, 'box');
Following methods can be applied: "box", "pnt", "size", "ray" and "dflt". See more info in draw options description for TGeo classes.
Here is running example and source code.
Starting from version 5.2.0, JSROOT can be used in Node.js. To install it, use:
[shell] npm install jsroot
To use in the Node.js scripts, one should add following line:
var jsroot = require('jsroot');
Using JSROOT functionality, one can open binary ROOT files (local and remote), parse ROOT JSON, create SVG output. For example, to create SVG image with lego plot, one should do:
var jsroot = require("jsroot"); var fs = require("fs"); jsroot.OpenFile("https://root.cern/js/files/hsimple.root", function(file) { file.ReadObject("hpx;1", function(obj) { jsroot.MakeSVG( { object: obj, option: "lego2", width: 1200, height: 800 }, function(svg) { fs.writeFileSync("lego2.svg", svg); }); }); });
It is also possible to convert any JavaScript object into ROOT JSON string, using JSROOT.toJSON() function. Like:
var jsroot = require("jsroot"); var fs = require("fs"); jsroot.OpenFile("https://root.cern/js/files/hsimple.root", function(file) { file.ReadObject("hpxpy;1", function(obj) { var json = jsroot.toJSON(obj); fs.writrFileSync("hpxpy.json", json); }); });
Such JSON string could be parsed by any other JSROOT-based application.
OpenUI5 is a web toolkit for developers to ease and speed up the development of full-blown HTML5 web applications. Since version 5.3.0 JSROOT provides possibility to use OpenUI5 functionality together with JSROOT.
First problem is bootstraping of OpenUI5. Most easy solution - specify openui5 URL parameter when loading JSROOT:
<script type="text/javascript" src="https://root.cern/js/latest/scripts/JSRootCore.min.js?openui5&onload=doInit"> </script>
JSROOT uses https://openui5.hana.ondemand.com to load latest stable version of OpenUI5. After loading is completed, one can use sap
to access openui5 functionality. Like:
<script type="text/javascript"> function doInit() { jQuery.sap.registerModulePath("NavExample", "./"); new sap.m.App ({ pages: [ new sap.m.Page({ title: "Nav Container", enableScrolling : true, content: [ new sap.ui.core.ComponentContainer({ name : "NavExample" })] }) ] }).placeAt("content"); } </script>
There are small details when using OpenUI5 with THttpServer. First of all, location of JSROOT scripts should be specified as jsrootsys/scripts/JSRootCore.js
. And when trying to access files from local disk, one should specify /currentdir/
folder:
jQuery.sap.registerModulePath("NavExample", "/currentdir/");
JSROOT provides example showing usage of JSROOT drawing in the OpenUI5, source code can be found in repository.