6
import matplotlib.pyplot as plt
import numpy as np

randomnums = np.random.normal(loc=9,scale=6, size=400).astype(int)+15

Output:

array([25, 22, 19, 26, 24,  9, 19, 32, 30, 25, 29, 17, 21, 14, 17, 27, 27,
       28, 17, 17, 20, 21, 16, 28, 20, 24, 15, 20, 20, 13, 33, 21, 30, 27,
        8, 22, 24, 25, 23, 13, 24, 20, 16, 32, 15, 26, 34, 16, 21, 21, 28,
       22, 23, 18, 20, 22, 23, 22, 23, 26, 22, 25, 19, 29, 14, 27, 21, 23,
       24, 19, 25, 15, 22, 23, 19, 19, 23, 21, 22, 17, 25, 15, 24, 25, 23 ...
h = sorted(randomnums)
plt.hist(h,density=False)
plt.show()

Output:

Histogram

From my research I found only how to plot numbers on top of a bar chart, but what I want is to plot on top of a histogram chart. Is it possible?

honk
  • 9,137
  • 11
  • 75
  • 83

1 Answers1

14

An adapted version of the answer I linked in the comments of the question. Thanks a lot for the suggestions in the comments below this post!

import matplotlib.pyplot as plt
import numpy as np

h = np.random.normal(loc=9,scale=6, size=400).astype(int)+15

fig, ax = plt.subplots(figsize=(16, 10))
ax.hist(h, density=False)

for rect in ax.patches:
    height = rect.get_height()
    ax.annotate(f'{int(height)}', xy=(rect.get_x()+rect.get_width()/2, height), 
                xytext=(0, 5), textcoords='offset points', ha='center', va='bottom') 

...gives e.g. enter image description here

See also: matplotlib.axes.Axes.annotate.

FObersteiner
  • 22,500
  • 8
  • 42
  • 72
  • Just use `f'{int(height)}'` instead of the label to show the exact value. – JohanC Jan 10 '20 at 16:14
  • The call to `ax.hist(...)` returns a tuple whose first element is an array containing the number of elements per bin. This can be used as labels: `labels, _, _ = ax.hist(h, density=False)` instead of the generic `label i`. – Conner M. Jan 10 '20 at 16:15
  • To not have the position depend too much on the scale of the y-axis, you could just use `height` without adding 1, but adding a newline to the text. As in `ax.text(rect.get_x()+rect.get_width()/2, height, f'{int(height)}\n', ha='center', va='bottom')` – JohanC Jan 10 '20 at 16:17
  • @ConnerM.: that's really cool, thanks for the hint! Also JohanC! will make an edit... – FObersteiner Jan 10 '20 at 16:18
  • @JohanC: thanks for the newline suggestion. In any case, an ugliness can occur if a bar goes up to y max. - the label is then outside the frame. Specifying ylim could prevent this. – FObersteiner Jan 10 '20 at 16:29
  • Still bettter would be to use `ax.annotate` instead of `ax.text`. Then you can specify the offset as a visual distance. E.g. `ax.annotate(f'{int(height)}', xy=(rect.get_x()+rect.get_width()/2, height), xytext=(0, 5), textcoords='offset points', ha='center', va='bottom')` – JohanC Jan 10 '20 at 16:37
  • @JohanC: I feel I'm learning more than the guy who has asked the question ;-) Thanks again! – FObersteiner Jan 10 '20 at 16:47
  • Why use plt.subplots()? – João Vitor Gomes Jan 10 '20 at 18:03
  • Thanks for all the answers. Is it possible to detail more the x axis? Like having marks '5,7.5,10,12.5,15....42.5,45' ? I think I found how to: "plt.xticks(np.arange(min(h),max(h)+1,2))" – João Vitor Gomes Jan 10 '20 at 19:44