Cloning a histogram in PyROOT / Scope problems

Hello all,

I am trying to clone a histogram in PyROOT.

The histogram to be cloned is part of a user class that only has function scope. I thought by cloning and returning a new histogram, it wouldn’t disappear when the object that contained the original histogram disappeared. This, unfortunately, doesn’t seem to be the case.

I can manually create and fill and new TH1F histogram, but I was wondering if there was a better way.

Methods tried:

  • Clone method: newh = oldhist.Clone(“newhist”)
  • Copy constructor: newh = ROOT.TH1F( oldhist )
  • Python copy module: newh = copy.deepcopy( oldh )

The full code is attached at the end of this message.

Thank you,

Sean

[code]
#!/usr/bin/env python
"""
Normalize a root histogram and save the normalized histogram to disk.


Sean McDaniel - mcdaniel@nscl.msu.edu
Created: 20 Oct 2008
Last updated: 24 Nov 2008
"""

import sys
import os
import getopt

Cern ROOT bindings

import ROOT

User

from loadrootfile import SingleHistogram

def normalize(fname, area_norm):
"""Normalize passed file. Normalization can either be to bin contents or area
depending on the passed parameters.

"""

print "Processing file: ", os.path.split(fname)[1]

# Normalize histogram to unit area
h = SingleHistogram(fname)
print h.histogram
hscaled = h.histogram.Clone("hscaled")
integral = hscaled.Integral()

# Normalize by area (rather than bin content) if the option is passed
if area_norm:
    integral *= hscaled.GetBinWidth(0)
scale = 1/integral
print "Total area: ", integral
hscaled.Scale(scale)
return hscaled

def write(fname, histogram):
""“Write the new histogram to disk”""
base, ext = os.path.splitext(fname)
outfname = base + "_norm.root"
fout = ROOT.TFile(outfname,“NEW”)
histogram.Write()
fout.Close()

def main():
""“Execute program”""
# Parse command line options
try:
opts, args = getopt.getopt(sys.argv[1:],“ahd”,[“help”])
except getopt.error, msg:
print msg
print "for help use --help"
sys.exit(2)

# Set defaults
area_norm = False
display_hist = False

# Parse options
for o,a in opts:
    if o in ("-h", "--help"):
        print __doc__
        sys.exit(0)
    if o == "-a":
        area_norm = True
    if o == "-d":
        display_hist = True

# Setup canvas is the option is passed
if display_hist:
    canvas = ROOT.TCanvas("canvas","superposition",800,600)

# Process all files
for f in args:
    histogram = normalize(f, area_norm)
    print histogram
    histogram.Draw()
    raw_input()
    if display_hist:
        histogram.Draw()
        raw_input("Enter to continue...")
    write(f, histogram)

if name==“main”:
main()
print “Finished…”
[/code][/code]

Hi y’all,

Just a quick follow-up to my past post.

This works as expected,

import sys
import ROOT
from loadrootfile import SingleHistogram


def normalize(fname):
    hscaled = ROOT.TH1F("hscaled", "scaled histogram", 10, 0., 10.)
    return hscaled


def main():
    for f in sys.argv:
        histogram =  normalize(f)
        histogram.Draw()
        raw_input()


if __name__=="__main__":
    main()

but not this normalize function

def normalize(fname):
    h = SingleHistogram(fname)
    hscaled = h.histogram.Clone("hscaled")
    return hscaled

nor even this!

def normalize(fname):
    h = SingleHistogram(fname)

    # Explicitly copy
    h_old = h.histogram
    nbins = h_old.GetNbinsX()
    xlow = h_old.GetBinLowEdge(1)
    xup = h_old.GetBinLowEdge(nbins + 1)

    h_new = ROOT.TH1F("h_new", "new hist", nbins, xlow, xup)
    for bin in range(nbins+1):
        h_new.SetBinContent(bin, h_old.GetBinContent(bin) )

    return h_new

In cases 2 and 3 a PyROOT_NoneType object is returned.

Thank you for your help.

Sean

Sean,

I’m missing somethiing … what is module “loadrootfile” and what is this class (?) “SingleHistogram”?

Also, which version of ROOT are you using? There has been a recent change to the ownership behavior of Clone(), but that should not affect you.

Cheers,
Wim

Hi,

On possibility is that ‘SingelHistogram’ is opening a file and that the Cloned histogram get attached to (and thus deleted along with) the TFile object.

Cheers,
Philippe.

I have the same issue with ROOT 5.26 (compiled
with Python2.6 on Ubuntu 9.08). There is no way
one can clone a TH1F histogram in PyROOT

h1=file.Get(“test”)
h2=h1.Clone()

any operation with h2 changes the original h1.

cheers, Sergei

Sergei,

are you certain?[code]>>> a = ROOT.TH1F( “test”, “some title”, 100, 0., 1. )

b = a.Clone()
a.GetTitle()
‘some title’
b.SetTitle( “something different” )
a.GetTitle()
‘some title’
b.GetTitle()
‘something different’
a.SetBinContent(5,42.)
b.GetBinContent(5)
0.0
a.GetBinContent(5)
42.0
b.SetBinContent(5,13.)
a.GetBinContent(5)
42.0
[/code]
Cheers,
Wim

[quote=“wlav”]Sergei,

are you certain?[code]>>> a = ROOT.TH1F( “test”, “some title”, 100, 0., 1. )

b = a.Clone()
a.GetTitle()
‘some title’
b.SetTitle( “something different” )
a.GetTitle()
‘some title’
b.GetTitle()
‘something different’
a.SetBinContent(5,42.)
b.GetBinContent(5)
0.0
a.GetBinContent(5)
42.0
b.SetBinContent(5,13.)
a.GetBinContent(5)
42.0
[/code]
Cheers,
Wim[/quote]

Yes, that works. But as soon as you Clone it in a function and try to access
it from another it causes problems.

What happens if you use

gRoot.cd()

before cloning?

In my case that worked.

Hi,

note that in newer releases, “Clone” is a special case member function that returns objects owned by python.

Cheers,
Wim