ROOT Version: 6.04/16 Platform: SLC 6 Compiler: Not Provided
I am having an issue with Adding TGraphs to a TMultiGraph in pyROOT.
The attached code produces a segmentation fault (also attached). While the log points to BuildLegend() I have tested and traced the problem to the TMultiGraph::Add() function. Commenting this out allows the script to run, but obviously with an empty TMultiGraph. Am I specifying something incorrectly?
I suspect there is an issue with the scope of the original TGraph objects, though in this use case I am not sure I see an obvious solution… I attempted to work around this by appending each TGraph to a list and then adding them to the TMultiGraph in a second loop over that list. It did not resolve as the list objects were stored with a strange type. [e.g. “AttributeError: ‘PyROOT_NoneType’ object has no attribute ‘GetName’”]
My interpretation of what is happening: (Not a CS person)
TMultiGraph.Add() simply adds a pointer to the TGraph object’s memory location. When the next iteration of the loop is executed python clears the TGraph and releases the memory. Thus the TMultiGraph has pointers to TGraphs that no longer exist.
By doing a copy.deepcopy() to a TGraph with a higher scope and adding the copied object to the TMultiGraph rather than the original, this can be avoided. However, one must know ahead of time how many times the loop will execute to create enough TGraphs before loop execution.
Again, the key is that the Add() function does NOT make a copy of the TGraph object within the memory allocated for the TMultiGraph, it simply creates a pointer to the original TGraph’s memory location so TMultiGraph can attempt to access memory locations which are no longer allocated.
Is it possible to modify the TMultiGraph memory allocation to preserve the TGraphs which have been “Added”? I think it is a bit more intuitive for the user… However, I do not know what kind of other issues this would create.
If the problem is what you report, then the TGraph instances could be decoupled from the Python garbage collection like so: ROOT.SetOwnership(graph, False)
This way, then the Python graphs go out of scope, they will not delete their internal C++ graphs, which live also in the multi-graph.