I am trying to get a histogram with already binned data. I have been trying to use bar()
for this, but I can\'t seem to figure out how to make it a stepped hist
The simplest solution is to convert your binned dataset to an un-binned, weighted dataset (with number of elements == number of bins). The unbinned dataset would consist of data values equal to the bin centres and weights equal to the values in each bin. For example let's say that your binned data is,
binedges = [0.0, 1.0, 2.0, 3.0]
ybinned = [11., 22., 33.]
The corresponding weighted dataset would be,
y = [0.5, 1.5, 2.5]
weights = [11., 22., 33.]
Note that the choice to use the bin centre is arbitrary, you could use any point within a bin. Once you have generated the un-binned dataset then you can use the normal matplotlib histogram plotting (i.e. Axes.hist).
An example implementation in python follows:
def plot_binned_data(axes, binedges, data,
*args, **kwargs):
#The dataset values are the bin centres
x = (binedges[1:] + binedges[:-1]) / 2.0
#The weights are the y-values of the input binned data
weights = data
return axes.hist(x, bins=binedges, weights=weights,
*args, **kwargs)
You can now have full access to all of the Axes.Histogram plotting options, including histtype="step"
to create the stepped histogram that you wanted.
An example using this function would be,
import numpy
import matplotlib.pyplot as plt
#Create a dataset
dataset = numpy.random.normal(size=100)
#Bin the dataset
binedges = numpy.linspace(-5.0, 5.0, num=10)
y, binedges = numpy.histogram(dataset, binedges)
#Plot the dataset
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
plot_binned_data(ax, binedges, y, histtype="step")
plt.show()
Hope that helps!
For some reason, the last bin isn't properly closed when I try it. It is not visible from the previous answers if the last line is showed, so I decided to make my own function, which does what I want.
def make_bar_contour_plot(ax,x_input,y_input):
x = list(np.ravel(zip(x_input[:-1],x_input[:-1]+1)))[1:]
x += [x[-1]+20] + [300]
y = list(np.ravel(zip(y_input,y_input))) +[0]
ax.plot(x,y,ls='steps')
return ax
The 20
and 300
that are added are my binsize and ending value respectively, and need to be adjusted if anyone wants to use this. x_input
and y_input
are the returning values from np.histogram
. My resulting plot (in blue the contour, plotted with above function. In red, the barplot of the same data):
From the accompanying source at http://matplotlib.sourceforge.net/examples/pylab_examples/histogram_demo_extended.html
here is how they drew that graph:
[snip]
and the bit you want appears to be
pylab.hist(x, bins=bins, histtype='step')
^
right here
Edit: if you want to know how hist() works, look at the source - it's defined in matplotlib/axes.py starting at line 7407.
Looking at line 7724,
x = np.zeros( 2*len(bins), np.float )
y = np.zeros( 2*len(bins), np.float )
for N bars, bins is an numpy.ndarray of N+1 values, being the edges for each bar. They twin the values for each bar (this is what fraxel is doing with np.ravel below) and shift the datapoints half a bar left to center them
x[0::2], x[1::2] = bins, bins
x -= 0.5*(bins[1]-bins[0])
set the height of each bar, twinned but offset by one (relative to the x values) to produce the step effect
# n is an array of arrays containing the number of items per bar
patches = [] # from line 7676
for m, c in zip(n, color):
y[1:-1:2], y[2::2] = m, m
patches.append(self.fill(x, y, closed=False, edgecolor=c, fill=False))
and the self.fill
bit is what actually draws the lines.
You could cheat, by offsetting your data and using plot
instead:
from matplotlib import pyplot
import numpy as np
#sample data:
x = np.arange(30)
y = np.cumsum(np.arange(30))
#offset the x for horizontal, repeat the y for vertical:
x = np.ravel(zip(x,x+1))
y = np.ravel(zip(y,y))
pyplot.plot(x,y)
pyplot.savefig('plt.png')
the plot: