Skip to content

Commit 07c55d2

Browse files
Max BaakMax Baak
authored andcommitted
Added plotting methods for Categorize type histograms
To make plotting work for Categorize histograms, I had to add a CategorizeHistogram class to the file specialize.py, to add addImplicitMethods() to Categorize histograms, in order to ensure that the plotting functions are recognized in python. Similarly, in primitives/categorize.py I had to properly set the contentType of a Categorize object. (I copied the example of SparselyHistogram where required.) I only added matplotlib and ROOT plotting functions for Categorize histograms, as I'm not very familiar with bokey. The bokey plotting class for Categorize histograms is currently a dummy class.
1 parent 4f670b5 commit 07c55d2

File tree

5 files changed

+115
-2
lines changed

5 files changed

+115
-2
lines changed

histogrammar/plot/bokeh.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ def plotbokeh(self,glyphType="line",glyphSize=1,fillColor="red",lineColor="black
116116
return GlyphRenderer(glyph=glyph,data_source=source)
117117

118118

119+
class CategorizeHistogramMethods(object):
120+
pass
121+
122+
119123
class ProfileMethods(object):
120124
def plotbokeh(self,glyphType="line",glyphSize=1,fillColor="red",lineColor="black",lineAlpha=1,fillAlpha=0.1,lineDash='solid'):
121125

histogrammar/plot/matplotlib.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,70 @@ def bin_centers(self):
179179
bin_edges = self.bin_edges()
180180
centers = [(bin_edges[i]+bin_edges[i+1])/2. for i in range(len(bin_edges)-1)]
181181
return np.array(centers)
182+
183+
184+
class CategorizeHistogramMethods(object):
185+
def plotmatplotlib(self, name=None, **kwargs):
186+
"""
187+
name : title of the plot.
188+
kwargs : `matplotlib.patches.Rectangle` properties.
189+
190+
Returns a matplotlib.axes instance
191+
"""
192+
import matplotlib.pyplot as plt
193+
import numpy as np
194+
ax = plt.gca()
195+
196+
width = kwargs.pop('width',0.8)
197+
198+
labels = self.bin_labels()
199+
values = self.bin_entries()
200+
assert len(labels)==len(values), \
201+
'labels and values have different array lengths: %d vs %d.' % \
202+
(len(labels),len(values))
203+
204+
# plot histogram
205+
tick_pos = np.arange(len(labels)) + 0.5
206+
ax.bar(tick_pos - 0.4, values, width=width, **kwargs)
207+
208+
# set x-axis properties
209+
def xtick(lab):
210+
lab = str(lab)
211+
if len(lab) > 20:
212+
lab = lab[:17] + '...'
213+
return lab
214+
ax.set_xlim((0., float(len(labels))))
215+
ax.set_xticks(tick_pos)
216+
ax.set_xticklabels([xtick(lab) for lab in labels], fontsize=12, rotation=90)
217+
218+
# set title
219+
if name is not None:
220+
ax.set_title(name)
221+
else:
222+
ax.set_title(self.name)
223+
224+
return ax
225+
226+
def bin_entries(self):
227+
"""
228+
Returns bin values
229+
"""
230+
import numpy as np
231+
return np.array([self.bins[i].entries for i in self.bins])
232+
233+
def bin_labels(self):
234+
"""
235+
Returns bin labels
236+
"""
237+
import numpy as np
238+
labels = []
239+
for i,key in enumerate(self.bins.keys()):
240+
try:
241+
label = str(key)
242+
except:
243+
label = 'bin_%d' % i
244+
labels.append(label)
245+
return np.asarray(labels)
182246

183247

184248
class ProfileMethods(object):

histogrammar/plot/root.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,28 @@ def plotroot(self, name, title="", binType="D"):
8989
setTH1(self.entries, [self.bins[i].entries if i in self.bins else 0.0 for i in xrange(self.minBin, self.maxBin + 1)], 0.0, 0.0, th1)
9090
return th1
9191

92+
class CategorizeHistogramMethods(object):
93+
def plotroot(self, name, title="", binType="C"):
94+
""" Construct a ROOT histogram
95+
96+
:param str name: name of the histogram
97+
:param str title: title of the histogram (optional)
98+
:param str binType: histogram bin type. Default is "C" (char).
99+
:returns: ROOT histgram
100+
"""
101+
import ROOT
102+
constructor = getattr(ROOT, "TH1" + binType)
103+
th1 = constructor(name, title, len(self.bins), 0, 1)
104+
th1.SetMinimum(0)
105+
for i,key in enumerate(self.bins.keys()):
106+
b = self.bins[key]
107+
try:
108+
label = str(key)
109+
except:
110+
label = 'bin_%d' % i
111+
th1.Fill(label,b.entries)
112+
return th1
113+
92114
class ProfileMethods(object):
93115
def plotroot(self, name, title=""):
94116
import ROOT

histogrammar/primitives/categorize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def __init__(self, quantity, value=Count()):
8080
self.value = value
8181
self.bins = {}
8282
if value is not None:
83-
self.contentType = str(value.factory.name)
83+
self.contentType = value.name
8484
super(Categorize, self).__init__()
8585
self.specialize()
8686

histogrammar/specialized.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from histogrammar.primitives.irregularlybin import IrregularlyBin
2424
from histogrammar.primitives.select import Select
2525
from histogrammar.primitives.sparselybin import SparselyBin
26+
from histogrammar.primitives.categorize import Categorize
2627
from histogrammar.primitives.stack import Stack
2728
from histogrammar.util import serializable
2829

@@ -36,10 +37,14 @@ def Histogram(num, low, high, quantity, selection=unweighted):
3637
Count.ing(), Count.ing(), Count.ing(), Count.ing()))
3738

3839
def SparselyHistogram(binWidth, quantity, selection=unweighted, origin=0.0):
39-
"Convenience function for creating a sparsely binned histogram."
40+
"""Convenience function for creating a sparsely binned histogram."""
4041
return Select.ing(selection,
4142
SparselyBin.ing(binWidth, quantity, Count.ing(), Count.ing(), origin))
4243

44+
def CategorizeHistogram(quantity, selection=unweighted):
45+
"""Convenience function for creating a categorize histogram."""
46+
return Select.ing(selection, Categorize.ing(quantity, Count.ing()))
47+
4348
def Profile(num, low, high, binnedQuantity, averagedQuantity, selection=unweighted):
4449
"""Convenience function for creating binwise averages."""
4550
return Select.ing(selection,
@@ -139,6 +144,21 @@ def confidenceIntervalValues(self,absz=1.0):
139144
from math import sqrt
140145
return map(lambda v: absz*sqrt(v), [v.entries for _, v in sorted(self.bins.items())])
141146

147+
class CategorizeHistogramMethods(Categorize,
148+
histogrammar.plot.root.CategorizeHistogramMethods,
149+
histogrammar.plot.bokeh.CategorizeHistogramMethods,
150+
histogrammar.plot.matplotlib.CategorizeHistogramMethods):
151+
152+
"""Methods that are implicitly added to container combinations that look like categorical histograms."""
153+
154+
@property
155+
def name(self):
156+
return "Categorize"
157+
158+
@property
159+
def factory(self):
160+
return Categorize
161+
142162
class ProfileMethods(Bin,
143163
histogrammar.plot.root.ProfileMethods,
144164
histogrammar.plot.bokeh.ProfileMethods,
@@ -326,6 +346,9 @@ def addImplicitMethods(container):
326346
elif isinstance(container, SparselyBin) and container.contentType == "Count" and all(isinstance(v, Count) for v in container.bins.values()):
327347
container.__class__ = SparselyHistogramMethods
328348

349+
elif isinstance(container, Categorize) and container.contentType == "Count" and all(isinstance(v, Count) for v in container.bins.values()):
350+
container.__class__ = CategorizeHistogramMethods
351+
329352
elif isinstance(container, Bin) and all(isinstance(v, Average) for v in container.values):
330353
container.__class__ = ProfileMethods
331354

0 commit comments

Comments
 (0)