Change histogram names in a root file

ROOT version: 6.08.06

I have an input file with multiple folders and histograms.

Some of these histograms have names that contain “EWCorr” and i need to rename them all so that they only contain “EW” instead and do so in the file so that the change persists when i read it later in my analysis program.

What is the best way to do that (ideally in pyroot) for all histograms in all (sub)folders.

For just one histogram i tried to do

    infile = ROOT.TFile("input/ExportHistograms_AllVars_Unblinded.root", "UPDATE")
    print(infile)
    test = infile.Get("SRPtZ100to200/WZRest/all/M_WZ_SRPtZ100to200_WZRest_all_theo_NLOOnlyEWCorr_Unc_rewtDY_3Z__1up")
    print(test)
    name = test.GetName()
    test.SetName(name.replace("NLOOnlyEWCorr", "NLOOnlyEW"))
    print(test)
    test.Write()
    test2 = infile.Get("SRPtZ100to200/WZRest/all/M_WZ_SRPtZ100to200_WZRest_all_theo_NLOOnlyEWC_Unc_rewtDY_3Z__1up")
    print(test2)
    test3 = infile.Get("M_WZ_SRPtZ100to200_WZRest_all_theo_NLOOnlyEWC_Unc_rewtDY_3Z__1up")
    print(test3)

but the output is

<ROOT.TFile object ("input/ExportHistograms_AllVars_Unblinded.root") at 0x4401960>
<ROOT.TH1D object ("M_WZ_SRPtZ100to200_WZRest_all_theo_NLOOnlyEWCorr_Unc_rewtDY_3Z__1up") at 0x4600240>
<ROOT.TH1D object ("M_WZ_SRPtZ100to200_WZRest_all_theo_NLOOnlyEW_Unc_rewtDY_3Z__1up") at 0x4600240>
<ROOT.TObject object at 0x(nil)>
<ROOT.TObject object at 0x(nil)>

Cheers
Jan-Eric

Why not using the command line tool rootmv ? it is like the unix command mv but for root files.

% rootmv -h 
usage: rootmv [-h] [-c COMPRESS] [-i] [--recreate] SOURCE [SOURCE ...] DEST

Move objects from ROOT files to another

positional arguments:
  SOURCE                Source file
  DEST                  Destination file

options:
  -h, --help            show this help message and exit
  -c COMPRESS, --compress COMPRESS
                        change the compression settings of the destination
                        file (if not already existing).
  -i, --interactive     prompt before every removal.
  --recreate            recreate the destination file.

Examples:
- rootmv source.root:hist* dest.root
  Move all histograms whose named starts with 'hist' from 'source.root' to 'dest.root'.

- rootmv source1.root:hist1 source2.root:hist2 dest.root
  Move histograms 'hist1' from 'source1.root' and 'hist2' from 'source2.root' to 'dest.root'.

- rootmv --recreate source.root:hist dest.root
  Recreate the destination file 'dest.root' and move the histogram named 'hist' from 'source.root' into it.

- rootmv -c 1 source.root:hist dest.root
  Change the compression level of the destination file 'dest.root' and move the histogram named 'hist' from 'source.root' into it. For more information about compression settings of ROOT file, please look at the reference guide available on the ROOT site.

Thanks for the suggestions,

sadly it does not seem like it allows me to easily change the names if i dont know the full name at the start, right?

I have over 100 histograms and i know i can target them with something like inputfile:*NLOOnlyEWCorr* but what do i do to rename them to the equivalent but with the “Corr” removed. They all have a different prefix and postfix and i dont know how to retain that in the move/rename.

Hello,

Perhaps you can treat this task as you wout treat bulk renaming of files in a directory? For this, you can use rootmv as @couet proposed as well as rootls and chain the two with the shell?

Cheers,
D

1 Like

I think i got a bash script now that calls rootls to get me the names of all the histograms and i can probably iterate over that and call rootmv on each. However the issue is now that rootls does not give me the full path and i need that for rootmv

What i effectively need is something that would do

rootmv my_inputfile:**EWCorr_* my_inputfile:**EW_*

Hi,

I think that operation is not supported.

Best,
D

That might be a bit tricky but you can do something like:

  1. create a small shell script rename.sh doing:
fhistname = $1
... some "sed" command creating "newhistname" from "histname"
rootmv $histname $newhistname
  1. execute de following command:
rootls -1 yourfile.root | sed -e "s/^/rename.sh /" > renameall.sh
  1. execute renameall.sh

also, the filename should be somehow passed to rename.sh (iin $2).

steps 1 and to can be grouped in one script maybe…

but you get the idea…

I hope it helps.

So i think i got it to this bash script

#!/usr/bin/env bash

inputfile="input/ExportHistograms_AllVars_Unblinded.root"
files=$(rootls "$inputfile:*/*/all/*all_theo_NLOOnlyEWCorr_*")
printf '%s\n' "$files" | while IFS="" read -r l; do array+=("$l"); done
for segment in $array
do
    IFS=" " read -r -A line <<< "$segment"
    for file in $line
    do
        echo "$file"
        changedname=${file/EWCorr/EW}
        echo "$changedname"
        echo rootmv $inputfile:$file $inputfile:$changedname
    done
done

With the only problem now being that $file only contains the final histogram name and not the full path. So the final rootmv (which i just echo atm) does not work because it can not find the histogram (and would put it in the wrong place anyway.


Edit:

This is the final script i am using now.

#!/usr/bin/env bash

inputfile="input/ExportHistograms_AllVars_Unblinded.root"
files=$(rootls "$inputfile:*/*/*/*_theo_NLOOnlyEWCorr_*")
printf '%s\n' "$files" | while IFS="" read -r l; do array+=("$l"); done
for segment in $array
do
    IFS=" " read -r -A line <<< "$segment"
    for file in $line
    do
        echo "$file"
        changedname=${file/EWCorr/EW}
        echo "$changedname"
        IFS='_' read -r -A filepath <<< "$changedname"
        if [[ "${filepath[2]}" = SR* ]]
        then
            region="${filepath[2]}"
            sample="${filepath[3]}"
            channel="${filepath[4]}"
        else
            region="${filepath[3]}"
            sample="${filepath[4]}"
            channel="${filepath[5]}"
        fi
        originalpath="$region/$sample/$channel/$file"
        newpath="$region/$sample/$channel/$changedname"
        echo rootmv $inputfile:$originalpath $inputfile:$newpath
        rootmv $inputfile:$originalpath $inputfile:$newpath
    done
done

But the only reason it works is because i can reconstruct the full path from the final histogram name. Still do not know how to do this if i could not.

1 Like