Add label values to bar chart and line chart

Question:

I have created a bar chart and a line chart using two different y-axes for the following dataframe.

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({'DXC':['T1', 'H1', 'HP', 'T1_or_H1_or_HP'], 
                   'Count': [2485, 5595, 3091, 9933],
                   'percent':[1.06, 2.39, 1.31, 4.23]}) 

              DXC  Count  percent
0              T1   2485     1.06
1              H1   5595     2.39
2              HP   3091     1.31
3  T1_or_H1_or_HP   9933     4.23

Using the following code, I can also display values next to each bar in the bar chart. However, I have not been successful thus far in my attempts to also display the label (percent) values for the line plot.

fig=plt.figure()
#AX: bar chart 
ax=df["Count"].plot(kind="bar", color="orange")
ax.set_ylabel("Counts")
ax.set_xlabel("")
ax.set_ylim(0,20000)

for tick in ax.get_xticklabels():
    tick.set_rotation(0)

#AX2: Create secondary y-axis with same x-axis as above for plotting percent values
ax2=ax.twinx()
ax2.plot(ax.get_xticks(),df["percent"], color="red", linewidth=4, marker = "o")
ax2.grid(False)
ax2.set_ylabel("Percent", color = "red")
ax2.set_ylim(0,4.5)
ax2.tick_params(labelcolor="red", axis='y')


def add_value_labels(ax, spacing=5):
    for i in ax.patches:
        y_value = i.get_height()
        x_value = i.get_x() + i.get_width() / 2
        space = spacing
        va = 'bottom'
        # Use Y value as label and format number with no decimal place
        label = "{:.0f}".format(y_value)
    # Create annotation
    ax.annotate(label,(x_value, y_value), xytext=(0, space), textcoords="offset points", ha='center',  va=va)                                                     

    
add_value_labels(ax)
plt.show()

Can somebody suggest how to display labels for both bar plot and line plot in the same figure?

Asked By: veg2020

||

Answers:

Here is a modified function that will achieve the required task. The trick is to extract the x and y values based on the type of the chart you have. For a line chart, you can use ax.lines[0] and then get_xdata and get_ydata

def add_value_labels(ax, typ, spacing=5):
    space = spacing
    va = 'bottom'

    if typ == 'bar':
        for i in ax.patches:
            y_value = i.get_height()
            x_value = i.get_x() + i.get_width() / 2

            label = "{:.0f}".format(y_value)
            ax.annotate(label,(x_value, y_value), xytext=(0, space), 
                    textcoords="offset points", ha='center', va=va)     
    if typ == 'line':
        line = ax.lines[0]
        for x_value, y_value in zip(line.get_xdata(), line.get_ydata()):
            label = "{:.2f}".format(y_value)
            ax.annotate(label,(x_value, y_value), xytext=(0, space), 
                textcoords="offset points", ha='center', va=va)   

add_value_labels(ax, typ='bar')
add_value_labels(ax2, typ='line')

enter image description here

Answered By: Sheldore
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# create the bar plot for the Count column and specify the yticks
ax = df.Count.plot(kind='bar', color='tab:orange', rot=0, yticks=range(0, 20001, 2500), figsize=(9, 5), ylabel='Counts')

# add bar labels
ax.bar_label(ax.containers[0])

# add the line plot for the percent column and specify the yticks and secondary_y
ax2 = df.percent.plot(marker='.', yticks=np.arange(0, 5, 0.5), secondary_y=True, ax=ax, ylabel='Percent')

# annotate the line by iterating through each row with itertuples
for row in df.itertuples():
    ax2.annotate(text=row.percent, xy=(row.Index, row.percent))

enter image description here

Answered By: Trenton McKinney