JSROOT StoreJSON() produce a json that the root console (c++) does not parse

Hello,

as mentioned in our previous post (JSROOT download ROOT file displayed in a web page) we are very happy that JSROOT now implements the StoreJSON() function, which allows to get the json representation of a Canvas object.
We load a root file (generated server side with root c++ for cosmic-rays data) and then we display it in on our web page with JSROOT, with the URL?file=… syntax.
This works fine and the user experience is really positive.
Then in the web page with JSROOT we access the Canvas object of the displayed drawing and with ProduceJSON() we get its json representation.
We then send this json representation to the server where we try to parse it in root c++ with code like:

TCanvas * ca = nullptr;
ca = (TCanvas *)TBufferJSON::ConvertFromJSON(json)

or else with

TCanvas * ca1 = nullptr;
TBufferJSON::FromJSON(ca1, json)

In both cases the above parse fails, most commonly with the following error:

root [2] TBufferJSON::ConvertFromJSON(json)
Error in TRint::HandleTermInput(): std::out_of_range caught: key ‘fUniqueID’ not found

We would kindly like to ask you:

  • Are we are doing something wrong ?

  • Is the json generated with JSROOT ProduceJSON() ok for the root c++ code to parse it ? If so, why are we getting the above error ?

We tried a number of different root files, in the end for our tests we resorted to non cosmic ray data, but just a simple canvas with a h1 plot.

To debug the matter I compared:

  • the json produced server side with c++ the metod TBufferJSON::ConvertToJSON()

with

-the json produced on the web page with JSROOT ProduceJSON()

The server side json generated (TBufferJSON::ConvertToJSON)is much longer, but I was able to remove quite a big part that is non essential at this point (Palettes mainly) and have it successfully re-parsed with the c++ method TBufferJSON::ConvertFromJSON(json)

In the end I found that the main difference for the json c++ generated and the json JSROOT generated (for the same plot) are in the “fLines”: { sections where:

json for the same plot root c++ generated is:

“fLines”: {
“_typename”: “TList”,
“name”: “TList”,
“arr”: [{
“_typename”: “TLatex”,
“fUniqueID”: 0,
“fBits”: 50331648,
“fName”: “”,
“fTitle”: “h1”,
“fTextAngle”: 0,
“fTextSize”: 0.0368,
“fTextAlign”: 0,
“fTextColor”: 0,
“fTextFont”: 0,
“fX”: 0,
“fY”: 0,
“fLineColor”: 1,
“fLineStyle”: 1,
“fLineWidth”: 2,
“fLimitFactorSize”: 3,
“fOriginSize”: 0.0367999991774559
}, {

json for the same plot JSROOT generated is:

    "fLines": {
      "_typename": "TList",
      "name": "TList",
      "arr": [{
        "_typename": "TLatex",
        "fTitle": "h1",
        "fTextColor": 1
      }, {

Please can you help us out on this matter ?
Can the JSROOT generated json (JSROOT.ProduceJSON()) be parsed back on the server side with root c++ TBufferJSON::ConvertFromJSON(json) ?

Thank you very much !
L.

Hi,

First of all, not all classes can be read from JSON.
Especially those with custom streamers.
But many useful cases are covered - normally canvas or histograms can be read.

Main limitation - such JSON should be generated by ConvertToJSON method.
You can transfer it to client, carefully modify it, but again - JSON should be generated by c++ code.

If objected generated in JavaScript, such conversion not always works.
Your example is exactly such a case - TLatex object, generated in JavaScript, does not have all necessary attributes. I could fix your particular usecase, but this will not solve generic problem.

Regards,
Sergey

Hi,

thanks for your prompt answer.

Our final goal would be as following:

  1. server side c++ produces a root file
  2. JSROOT displays it on a web page
  3. Users accessing the above web page can modify the JSROOT drawing using the JSROOT functionalities, ex: right-click, change colors, etc.
  4. The user asks for the drawing he/she has modified in step 3) to became a root file
  5. The web page uses JSROOT ProduceJSON to get the json representation of the modified drawing
  6. The web page sends the json of the modified drawing to the server
  7. The server gets the json sent in step 6) and attemps to parse it as a root object with TBufferJSON::ConvertFromJSON

I understand that there are limitations and maybe we should have to pre-process the json in step 7, but it is not very clear to us how we could do it and which sections we should fix.

Do you think we could be able to reach our goal in step 7 ? If so, could you give us some advice ?

At the moment the root file we generate in step 1 has always the same structure a Canvas, with a TGraph, etc. (although the data in it may vary)

If you would be so kind as to fix the TLatex case, it may be useful, even if it does not solve the generic problem.

Finally, if so you wish, I can send you one of the real root file we use for cosmic rays data, if you think that can help to understand the problem at hand.

Thanks again a lot, we really appreciate it !
Regards,
L.

Hi,

That you describe is extreme case - the whole JSROOT graphics should be rechecked in respect of this requirement.

TLatex is good example here - on JSROOT side I do not use many ROOT attributes and ignore them when adding new text lines to stat box. Problem actually is here:

This I can fix easily, but other problems can arise.

Therefore I cannot guarantee that step 7 can be achieved for all kinds of drawing supported in JSROOT.

Yes, it will be very useful if you can provide your sample data and I can check all steps you mention.

Regards,
Sergey

P.S. There is one small issue - I will be in vacations for next three week and cannot guarantee that I will be able to help you immediately

Hi,

thank you very much for your prompt answer !

I understand that JSROOT cannot cover all possible cases and produce a json that can be always parsed back with TBufferJSON::ConvertFromJSON, all the same, maybe we can get to the result in step 7 for the root files we generate as of today.

For this purpouse I have attached a sample of our cosmic-ray root, so that you can tell us what your opinion is, and what we could possibly do.

The Latex issue seems to be one that appears quite often in our tests, if this is also your assumption, we would kindly like to ask you to please fix it of course when you have time for it.

Thank you very much for mentioning the vacations issue, we too will be taking vacations in the coming weeks, both in July and in August, so maybe we will be able to get in touch in the first half of August, or else at the end of it.

Given the vacations period, maybe this post will be automatically closed, so, I guess we can reach each other via email, or open a new post, linked to this.

Thansk again for your support, really appreciated !
Regards,
L.cosmic-rays.root (31.9 KB)

Hi,

I made several modification in dev version, which improve JSROOT.StoreJSON() functionality when TGraph is drawn. Now produced JSON (with TCanvas inside) can be parsed on C++ side. There are still some small issues with produced TCanvas object (title is not redrawn correctly when moved), but probably @couet will help to resolve it.

Main problem with your approach - you sends some ROOT object (like TGraph) to JSROOT for drawing. When you are using JSROOT.StoreJSON() function, TCanvas object is created in JavaScript. And such JSON send to C++ for parsing, which is very challenging for such complex class. There are two better solutions.

  1. Create TCanvas with all needed objects already on C++ side and send such canvas to JSROOT. This is more safe solution.

  2. Or when creating JSON in JavaScript, use only object which is really drawn. Like:

    JSROOT.draw(“divid”, obj, “”, function(painter)
    var json = JSROOT.toJSON(painter.GetObject());
    });

Means if TGraph is draw - you will store only TGraph into JSON. Drawback - not all attributes (like zooming) will be stored together.

And final remark - JSROOT.StoreJSON() still may not work for some particular classes. Most probably THStack and TMultiGraph will not work. Therefore if you see any problems - please report them.

Regards,
Sergey

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.