I have two lists given. One, named "bin_edge", represents the lower and upper borders of 24 bins by 25 values. The second, named "counts", represents the according counts (=values) of each bin.
My aim is, if possible, to get a Matplotlib histogram that should look like somewhat that:
So, the first difficulty I face is that the first bin is a section located between the first two values of bin_edge
, the second bin is a section between the second and the third element of bin_edge
and so on...
Means that one value of counts
is connected to the two bounds (lower and upper bound) of the bin_edge
list.
And the second sticking point: I would like to draw logarithmic x and y axes.
The code I was trying:
bin_edge = [0.36, 0.46, 0.66, 1.00, 1.30, 1.70, 2.20, 3.00, 4.00,
5.20, 6.50, 8.00, 10.00, 12.00, 14.00, 16.00, 18.00,
20.00, 22.00, 25.00, 28.00, 31.00, 34.00, 37.00, 40.00]
counts = [159746491, 9316595, 855578, 166092, 151198, 41293, 51051,
26098, 38536, 1172, 2.872e-12, 24598, 3.27097e-12, 3.86874e-12,
4.46613e-12, 5.06328e-12, 5.6602754e-12, 6.2571442e-12, 4.6652e-12,
5.26229e-12, 5.8592429e-12, 0, 7.052837e-12, 0]
plt.hist([counts], bins=bin_edge)
plt.xscale('log')
plt.yscale('log')
plt.xlabel('Size / µm')
plt.ylabel('counts')
plt.title('Histogram')
plt.show()
This leads to an empty plot.
Any other solutions beside Matplotlib including bokeh are welcome, of course as well :-)
CodePudding user response:
As you already have the heights for each bin, you should create a bar plot.
The x-values should be the bin edges, except for the last. By default, the bars are centered; you need align='edge'
to align them with the bin edges. The widths of the bars are the differences of the bin edges.
from matplotlib import pyplot as plt
from matplotlib.ticker import FormatStrFormatter
import numpy as np
bin_edge = [0.36, 0.46, 0.66, 1.00, 1.30, 1.70, 2.20, 3.00, 4.00,
5.20, 6.50, 8.00, 10.00, 12.00, 14.00, 16.00, 18.00,
20.00, 22.00, 25.00, 28.00, 31.00, 34.00, 37.00, 40.00]
counts = [159746491, 9316595, 855578, 166092, 151198, 41293, 51051,
26098, 38536, 1172, 2.872e-12, 24598, 3.27097e-12, 3.86874e-12,
4.46613e-12, 5.06328e-12, 5.6602754e-12, 6.2571442e-12, 4.6652e-12,
5.26229e-12, 5.8592429e-12, 0, 7.052837e-12, 0]
fig, ax = plt.subplots(figsize=(12, 5))
ax.bar(x=bin_edge[:-1], height=counts, width=np.diff(bin_edge), align='edge', fc='MediumOrchid', ec='black')
ax.set_xscale('log')
ax.set_yscale('log')
ax.set_xlabel('Size / µm')
ax.set_ylabel('counts')
ax.set_title('Histogram')
ax.margins(x=0.01) # less margin left and right
ax.xaxis.set_major_formatter(FormatStrFormatter('%g'))
ax.xaxis.set_minor_formatter(FormatStrFormatter('%g'))
# "length" is the length of the tick mark, it also changes the text offset
# "labelsize" is the fontsize of the tick label
ax.tick_params(axis='x', which='minor', length=5, labelsize=8)
ax.tick_params(axis='x', which='major', length=10, labelsize=12)
plt.tight_layout()
plt.show()