How can I add labels to each step of this cumulative step function as shown in the attached screenshot?
import pandas as pd
df = pd.DataFrame({"year": range(1990, 2020, 4), "name": list("abcdefgh")})
df.year.hist(cumulative=True)
How can I add labels to each step of this cumulative step function as shown in the attached screenshot?
import pandas as pd
df = pd.DataFrame({"year": range(1990, 2020, 4), "name": list("abcdefgh")})
df.year.hist(cumulative=True)
You can iterate through the generated bars. Their x coordinate and width tell where they are located in the x-axis. The bar height gives the y value for the label. The positions on the x-axis will give a range that can be selected from the corresponding column of the dataframe. For the x-position of the label, the corresponding year can be used.
Some care needs to be taken, as the last value could fall outside the official range of the last bar. Also, increasing the y margin helps to fit all text into the plot.
import pandas as pd
df = pd.DataFrame({'year': range(1990, 2020, 4), 'name': [*'abcdefgh']})
ax = df.year.hist(cumulative=True)
for rect in ax.patches:
left = rect.get_x()
right = left + rect.get_width()
height = rect.get_height()
if rect == ax.patches[-1]: # make sure the last range is wide enough to include the last date
right += 1
df2 = df[(df['year'] >= left) & (df['year'] <= right)]
for year, name in zip(df2['year'], df2['name']):
ax.text(year, height, f'{name}\n', ha='left', va='center')
ax.margins(y=0.15) # we need more room for the last label
PS: To only write one label per bar, you could add a break
in the for
loop:
for year, name in zip(df2['year'], df2['name']):
ax.text(year, height, f'{name}\n', ha='left', va='center')
break
For the step plot, you could use:
import pandas as pd
df = pd.DataFrame({'year': range(1990, 2020, 4), 'name': [*'abcdefgh']})
ax = df.reset_index().plot(x='year', y='index', drawstyle="steps", legend=False)
for ind, (year, name) in enumerate(zip(df['year'], df['name'])):
ax.text(year, ind, f' {name}', ha='left', va='center')