-1

I have a bar chart of data from 8 separate buildings, the data is separated by year, I'm trying to place the growth each building went through in the last year on top of the bar chart.

I have this written currently:

n_groups = 8

numbers_2017 = (122,96,42,23,23,22,0,0)

numbers_2018 = (284,224,122,52,41,24,3,1)


fig, ax = plt.subplots(figsize=(15, 10))

index = np.arange(n_groups)
bar_width = 0.35


events2017 = plt.bar(index, numbers_2017, bar_width,
                 alpha=0.7,
                 color='#fec615',
                 label='2017')

events2018 = plt.bar(index + bar_width, numbers_2018, bar_width,
                 alpha=0.7,
                 color='#044a05',
                 label='2018')

labels = ("8 specific buildings passed as strings")

labels = [ '\n'.join(wrap(l, 15)) for l in labels ]

plt.ylabel('Total Number of Events', fontsize=18, fontweight='bold', color = 'white')

plt.title('Number of Events per Building By Year\n', fontsize=20, fontweight='bold', color = 'white')

plt.xticks(index + bar_width / 2)

plt.yticks(color = 'white', fontsize=12)

ax.set_xticklabels((labels),fontsize=12, fontweight='bold', color = 'white')

plt.legend(loc='best', fontsize='xx-large')

plt.tight_layout()
plt.show()

Looking through similar questions on here many of them split the total count across all the bars, whereas I'm just trying to get a positive (or negative) growth percentage placed on top of the most recent year, 2018 in this case.

I found this excellent example online, however it does exactly what I explained earlier, splits up the percentages across the chart:

totals = []

# find the values and append to list
for i in ax.patches:
    totals.append(i.get_height())

# set individual bar lables using above list
total = sum(totals)

# set individual bar lables using above list
for i in ax.patches:
    # get_x pulls left or right; get_height pushes up or down
    ax.text(i.get_x()-.03, i.get_height()+.5, \
            str(round((i.get_height()/total)*100, 1))+'%', fontsize=15,
                color='dimgrey')

Please let me know if I can list any examples or images that would help, and if this is a dupe please don't hesitate to send me to a (RELEVANT) original and I can shut this question down, Thanks!

Sebastian Goslin
  • 477
  • 1
  • 3
  • 22
  • 1
    It's like fighting windmills, [see this comment from only moments ago](https://stackoverflow.com/questions/55143510/position-of-text-automatically-changes-on-graph?noredirect=1#comment97028635_55143510). – ImportanceOfBeingErnest Mar 13 '19 at 15:12
  • Going to the question you linked, and the two other problems you linked answering that one [this one](https://stackoverflow.com/questions/42697701/optimization-of-bar-plots-in-matplotlib-pandas) and [this one](https://stackoverflow.com/questions/55143510/position-of-text-automatically-changes-on-graph?noredirect=1#comment97028635_55143510), they don't answer my question, they show me how to put the specific n sizes of each bar on the plot, however I'm asking how to model the difference between the two, or how much the first bar **grew** from one year to the next as a **percentage**. – Sebastian Goslin Mar 13 '19 at 15:38
  • @ImportanceOfBeingErnest, the answer below addressed the context of my question, thank you for the links they are still very useful! – Sebastian Goslin Mar 13 '19 at 15:43
  • 1
    Sorry for the confusion. This link was not meant to directly answer your question, but to show how not so great answers accumulate on this topic. And while the one below does show how to get the correct text as labels, their positionning is again in data coordinates - which will make this work for exactly this specific problem, but not in general. – ImportanceOfBeingErnest Mar 13 '19 at 15:44
  • I understand, that was the issue I ran into looking for answers and I didn't want to post a redundant question, you said it perfectly in the other post, "there are two million answers to these questions with only a few actually being useful." – Sebastian Goslin Mar 13 '19 at 15:49

1 Answers1

1

I think you gave the answer yourself with the second part of code you gave. The only thing you had to do was change the ax to the object you wanted the text above, which in this case was events2018.

totals = []

for start, end in zip(events2017.patches, events2018.patches):
    if start.get_height() != 0:
        totals.append( (end.get_height() - start.get_height())/start.get_height() * 100)
    else:
        totals.append("NaN")

# set individual bar lables using above list
for ind, i in enumerate(events2018.patches):
    # get_x pulls left or right; get_height pushes up or down
    if totals[ind] != "NaN":
        plt.text(i.get_x(), i.get_height()+.5, \
            str(round((totals[ind]), 1))+'%', fontsize=15,
                color='dimgrey')
    else: 
        plt.text(i.get_x(), i.get_height()+.5, \
                 totals[ind], fontsize=15, color='dimgrey')
Rein K.
  • 141
  • 8
  • Ha! It semi-answers my question, so now I can display the percentage on the specific bar I want it doesn't actually model the growth, in this case I'm following the formula: ((ending number - starting number)/starting number)*100. So in this case the growth for the first building would be around 130%, but instead its just showing 37%. The example code I linked shows the height of the bars relative to each other but doesn't actually show the growth. Let me know if that makes sense! – Sebastian Goslin Mar 13 '19 at 15:18
  • 1
    Ah I see what you mean, I updated the answer accordingly. Note that I added a condition to check if the starting value is zero, since percentual growth from a zero-value does not make sense. You can of course adjust the "NaN" however you please. – Rein K. Mar 13 '19 at 15:37
  • Thank you for this, and for actually reading the **context** of the question! – Sebastian Goslin Mar 13 '19 at 15:39