2 Utilities for plotting ROOT histograms in matplotlib.
5 from builtins
import range
7 Copyright (c) 2009-2010 Jeff Klukas <klukas@wisc.edu>
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 from rootplot
import utilities
36 import matplotlib
as mpl
37 import matplotlib.pyplot
as plt
38 import matplotlib.transforms
as transforms
43 _all_whitespace_string = re.compile(
r'\s*$')
49 """A container to hold the parameters from a 2D ROOT histogram."""
52 if 'replacements' in kwargs:
54 utilities.Hist2D.__init__(self, *args, **kwargs)
56 """Draw a contour plot."""
57 cs = plt.contour(self.
x, self.
y, self.
content, **kwargs)
58 plt.clabel(cs, inline=1, fontsize=10)
64 def col(self, **kwargs):
65 """Draw a colored box plot using :func:`matplotlib.pyplot.imshow`."""
67 kwargs[
'cmap'] = plt.get_cmap(kwargs[
'cmap'])
68 plot = plt.imshow(self.
content, interpolation=
'nearest',
71 aspect=
'auto', origin=
'lower', **kwargs)
75 Draw a colored box plot with a colorbar using
76 :func:`matplotlib.pyplot.imshow`.
78 plot = self.
col(**kwargs)
81 def box(self, maxsize=40, **kwargs):
83 Draw a box plot with size indicating content using
84 :func:`matplotlib.pyplot.scatter`.
86 The data will be normalized, with the largest box using a marker of
87 size maxsize (in points).
90 y = np.hstack([[yval
for i
in range(self.
nbinsx)]
for yval
in self.
y])
95 plot = plt.scatter(x, y, sizes, marker=
's', **kwargs)
98 """Return a ROOT.TH2F object with contents of this Hist2D."""
99 th2f = ROOT.TH2F(name,
"",
105 th2f.SetBinContent(ix + 1, iy + 1, self.
content[iy][ix])
109 """A container to hold the parameters from a ROOT histogram."""
112 if 'replacements' in kwargs:
114 utilities.Hist.__init__(self, *args, **kwargs)
116 """Apply bounds and text labels on x axis."""
120 rotation=rotation, ha=alignment)
124 """Apply bounds and text labels on y axis."""
128 rotation=rotation, va=alignment)
132 """Print the title and axis labels to the current figure."""
133 replacements = kwargs.get(
'replacements',
None)
or self.
replacements
137 def hist(self, label_rotation=0, label_alignment='center', **kwargs):
139 Generate a matplotlib hist figure.
141 All additional keyword arguments will be passed to
142 :func:`matplotlib.pyplot.hist`.
144 kwargs.pop(
'fmt',
None)
145 replacements = kwargs.get(
'replacements',
None)
or self.
replacements
149 weights = [1.e-10] * self.
nbins
150 plot = plt.hist(self.
x, weights=weights, bins=self.
xedges,
154 def errorbar(self, xerr=False, yerr=False, label_rotation=0,
155 label_alignment='center', **kwargs):
157 Generate a matplotlib errorbar figure.
159 All additional keyword arguments will be passed to
160 :func:`matplotlib.pyplot.errorbar`.
163 kwargs[
'xerr'] = self.
xerr
165 kwargs[
'yerr'] = self.
yerr
166 replacements = kwargs.get(
'replacements',
None)
or self.
replacements
167 errorbar = plt.errorbar(self.
x, self.
y,
172 def errorbarh(self, xerr=False, yerr=False, label_rotation=0,
173 label_alignment='center', **kwargs):
175 Generate a horizontal matplotlib errorbar figure.
177 All additional keyword arguments will be passed to
178 :func:`matplotlib.pyplot.errorbar`.
180 if xerr: kwargs[
'xerr'] = self.
yerr
181 if yerr: kwargs[
'yerr'] = self.
xerr
182 replacements = kwargs.get(
'replacements',
None)
or self.
replacements
183 errorbar = plt.errorbar(self.
y, self.
x,
188 def bar(self, xerr=False, yerr=False, xoffset=0., width=0.8,
189 label_rotation=0, label_alignment='center', **kwargs):
191 Generate a matplotlib bar figure.
193 All additional keyword arguments will be passed to
194 :func:`matplotlib.pyplot.bar`.
196 kwargs.pop(
'fmt',
None)
197 if xerr: kwargs[
'xerr'] = self.
av_xerr()
198 if yerr: kwargs[
'yerr'] = self.
av_yerr()
199 replacements = kwargs.get(
'replacements',
None)
or self.
replacements
200 ycontent = [self.
xedges[i] + self.
width[i] * xoffset
202 width = [x * width
for x
in self.
width]
203 bar = plt.bar(ycontent, self.
y, width,
207 def barh(self, xerr=False, yerr=False, yoffset=0., width=0.8,
208 label_rotation=0, label_alignment='center', **kwargs):
210 Generate a horizontal matplotlib bar figure.
212 All additional keyword arguments will be passed to
213 :func:`matplotlib.pyplot.bar`.
215 kwargs.pop(
'fmt',
None)
216 if xerr: kwargs[
'xerr'] = self.
av_yerr()
217 if yerr: kwargs[
'yerr'] = self.
av_xerr()
218 replacements = kwargs.get(
'replacements',
None)
or self.
replacements
219 xcontent = [self.
xedges[i] + self.
width[i] * yoffset
221 width = [x * width
for x
in self.
width]
222 barh = plt.barh(xcontent, self.
y, width,
230 A container to hold Hist objects for plotting together.
232 When plotting, the title and the x and y labels of the last Hist added
233 will be used unless specified otherwise in the constructor.
236 if 'replacements' in kwargs:
238 utilities.HistStack.__init__(self, *args, **kwargs)
241 def hist(self, label_rotation=0, **kwargs):
243 Make a matplotlib hist plot.
245 Any additional keyword arguments will be passed to
246 :func:`matplotlib.pyplot.hist`, which allows a vast array of
247 possibilities. Particlularly, the *histtype* values such as
248 ``'barstacked'`` and ``'stepfilled'`` give substantially different
249 results. You will probably want to include a transparency value
250 (i.e. *alpha* = 0.5).
252 contents = np.dstack([hist.y
for hist
in self.
hists])
253 xedges = self.
hists[0].xedges
254 x = np.dstack([hist.x
for hist
in self.
hists])[0]
255 labels = [hist.label
for hist
in self.
hists]
257 clist = [item[
'color']
for item
in self.
kwargs]
258 plt.gca().set_color_cycle(clist)
262 plot = plt.hist(x, weights=contents, bins=xedges,
263 label=labels, **kwargs)
266 from mpl_toolkits.mplot3d
import Axes3D
271 for i, hist
in enumerate(self.
hists):
272 if self.
title is not None: hist.title = self.
title
275 labels.append(hist.label)
276 all_kwargs = copy.copy(kwargs)
277 all_kwargs.update(self.
kwargs[i])
278 bar = ax.bar(hist.x, hist.y, zs=i, zdir=
'y', width=hist.width,
281 from matplotlib.ticker
import FixedLocator
282 locator = FixedLocator(list(
range(len(labels))))
283 ax.w_yaxis.set_major_locator(locator)
284 ax.w_yaxis.set_ticklabels(labels)
285 ax.set_ylim3d(-1, len(labels))
289 Make a matplotlib bar plot, with each Hist stacked upon the last.
291 Any additional keyword arguments will be passed to
292 :func:`matplotlib.pyplot.bar`.
296 for i, hist
in enumerate(self.
hists):
297 if self.
title is not None: hist.title = self.
title
300 all_kwargs = copy.copy(kwargs)
301 all_kwargs.update(self.
kwargs[i])
302 bar = hist.bar(bottom=bottom, **all_kwargs)
304 if not bottom: bottom = [0.
for i
in range(self.
hists[0].nbins)]
305 bottom = [sum(pair)
for pair
in zip(bottom, hist.y)]
309 Make a matplotlib hist plot, with each Hist stacked upon the last.
311 Any additional keyword arguments will be passed to
312 :func:`matplotlib.pyplot.hist`.
317 for i, hist
in enumerate(self.
hists):
319 cumhist = hist + cumhist
321 cumhist = copy.copy(hist)
322 if self.
title is not None: cumhist.title = self.
title
323 if self.
xlabel is not None: cumhist.xlabel = self.
xlabel
324 if self.
ylabel is not None: cumhist.ylabel = self.
ylabel
325 all_kwargs = copy.copy(kwargs)
326 all_kwargs.update(self.
kwargs[i])
327 zorder = 0 +
float(len(self) - i)/len(self)
328 plot = cumhist.hist(zorder=zorder, **all_kwargs)
333 Make a clustered bar plot.
335 Any additional keyword arguments will be passed to
336 :func:`matplotlib.pyplot.bar`.
339 spacer = (1. - width) / 2
340 width = width / len(self.
hists)
341 for i, hist
in enumerate(self.
hists):
342 if self.
title is not None: hist.title = self.
title
345 all_kwargs = copy.copy(kwargs)
346 all_kwargs.update(self.
kwargs[i])
347 bar = hist.bar(xoffset=width*i + spacer, width=width, **all_kwargs)
350 def barh(self, width=0.8, **kwargs):
352 Make a horizontal clustered matplotlib bar plot.
354 Any additional keyword arguments will be passed to
355 :func:`matplotlib.pyplot.bar`.
358 spacer = (1. - width) / 2
359 width = width / len(self.
hists)
360 for i, hist
in enumerate(self.
hists):
361 if self.
title is not None: hist.title = self.
title
364 all_kwargs = copy.copy(kwargs)
365 all_kwargs.update(self.
kwargs[i])
366 bar = hist.barh(yoffset=width*i + spacer, width=width, **all_kwargs)
371 Make a bar plot, with all Hists in the stack overlaid.
373 Any additional keyword arguments will be passed to
374 :func:`matplotlib.pyplot.bar`. You will probably want to set a
375 transparency value (i.e. *alpha* = 0.5).
378 for i, hist
in enumerate(self.
hists):
379 if self.
title is not None: hist.title = self.
title
382 all_kwargs = copy.copy(kwargs)
383 all_kwargs.update(self.
kwargs[i])
384 bar = hist.bar(**all_kwargs)
389 Make a matplotlib errorbar plot, with all Hists in the stack overlaid.
391 Passing 'offset=True' will slightly offset each dataset so overlapping
392 errorbars are still visible. Any additional keyword arguments will
393 be passed to :func:`matplotlib.pyplot.errorbar`.
396 for i, hist
in enumerate(self.
hists):
397 if self.
title is not None: hist.title = self.
title
400 all_kwargs = copy.copy(kwargs)
401 all_kwargs.update(self.
kwargs[i])
402 transform = plt.gca().transData
404 index_offset = (len(self.
hists) - 1)/2.
405 pixel_offset = 1./72 * (i - index_offset)
406 transform = transforms.ScaledTranslation(
407 pixel_offset, 0, plt.gcf().dpi_scale_trans)
408 transform = plt.gca().transData + transform
409 errorbar = hist.errorbar(transform=transform, **all_kwargs)
410 plots.append(errorbar)
414 Make a horizontal matplotlib errorbar plot, with all Hists in the
417 Any additional keyword arguments will be passed to
418 :func:`matplotlib.pyplot.errorbar`.
421 for i, hist
in enumerate(self.
hists):
422 if self.
title is not None: hist.title = self.
title
425 all_kwargs = copy.copy(kwargs)
426 all_kwargs.update(self.
kwargs[i])
427 errorbar = hist.errorbarh(**all_kwargs)
428 plots.append(errorbar)
434 """A wrapper for TFiles, allowing easier access to methods."""
435 def get(self, object_name, path=None):
437 return utilities.RootFile.get(self, object_name, path,
439 except ReferenceError
as e:
440 raise ReferenceError(e)
446 Modify a string based on a list of patterns and substitutions.
448 replacements should be a list of two-entry tuples, the first entry giving
449 a string to search for and the second entry giving the string with which
450 to replace it. If replacements includes a pattern entry containing
451 'use_regexp', then all patterns will be treated as regular expressions
456 if 'use_regexp' in [x
for x,y
in replacements]:
457 for pattern, repl
in [x
for x
in replacements
458 if x[0] !=
'use_regexp']:
459 string = re.sub(pattern, repl, string)
461 for pattern, repl
in replacements:
462 string = string.replace(pattern, repl)
463 if re.match(_all_whitespace_string, string):