2 from pathlib
import Path
3 from typing
import Optional, Dict, List
14 import matplotlib.pyplot
18 class Model(pydantic.BaseModel):
25 min: Optional[float] =
None
26 max: Optional[float] =
None
27 label: Optional[str] =
None
36 histograms: Dict[str, HistConfig] = pydantic.Field(default_factory=dict)
37 extra_histograms: List[Extra] = pydantic.Field(default_factory=list)
38 exclude: List[str] = pydantic.Field(default_factory=list)
47 infile: Path = typer.Argument(
48 ..., exists=
True, dir_okay=
False, help=
"The input ROOT file"
50 treename: str = typer.Argument(..., help=
"The tree to look up branched from"),
51 outpath: Path = typer.Argument(
52 "outfile", dir_okay=
False, help=
"The output ROOT file"
54 config_file: Optional[Path] = typer.Option(
60 help=
"A config file following the input spec. By default, all branches will be plotted.",
62 mode: Mode = typer.Option(Mode.recreate, help=
"Mode to open ROOT file in"),
63 plots: Optional[Path] = typer.Option(
68 help=
"If set, output plots individually to this directory",
70 plot_format: str = typer.Option(
71 "pdf",
"--plot-format",
"-f", help=
"Format to write plots in if --plots is set"
73 silent: bool = typer.Option(
74 False,
"--silent",
"-s", help=
"Do not print any output"
76 dump_yml: bool = typer.Option(
False, help=
"Print axis ranges as yml"),
79 Script to plot all branches in a TTree from a ROOT file, with optional configurable binning and ranges.
80 Also allows setting extra expressions to be plotted as well.
83 rf = uproot.open(infile)
86 outfile = getattr(uproot, mode.value)(outpath)
88 if config_file
is None:
91 with config_file.open()
as fh:
92 config = Config.parse_obj(yaml.safe_load(fh))
97 print(config.extra_histograms, file=sys.stderr)
99 for df
in tree.iterate(library=
"ak", how=dict):
100 for col
in df.keys():
101 if any([re.match(ex, col)
for ex
in config.exclude]):
103 h = histograms.get(col)
104 values = awkward.flatten(df[col], axis=
None)
109 for ex, data
in config.histograms.items():
110 if re.match(ex, col):
125 if found.min
is None:
126 found.min = awkward.min(values)
128 if found.max
is None:
129 found.max = awkward.max(values)
131 if found.min == found.max:
137 found.nbins, found.min, found.max, name=found.label
or col
144 for extra
in config.extra_histograms:
145 h = histograms.get(extra.name)
147 calc = eval(extra.expression)
148 values = awkward.flatten(calc, axis=
None)
150 if extra.min
is None:
151 extra.min = awkward.min(values)
152 if extra.max
is None:
153 extra.max = awkward.max(values)
155 if extra.min == extra.max:
164 name=extra.label
or extra.name,
168 histograms[extra.name] = h
171 if plots
is not None:
172 plots.mkdir(parents=
True, exist_ok=
True)
174 for k, h
in histograms.items():
184 k=k, b=len(ax.edges) - 1, min=ax.edges[0], max=ax.edges[-1]
191 if plots
is not None:
192 fig, ax = matplotlib.pyplot.subplots()
194 h.plot(ax=ax, flow=
None)
197 fig.savefig(
str(plots / f
"{k}.{plot_format}"))
198 matplotlib.pyplot.close()
201 if __name__ ==
"__main__":