pythonpandasmatplotlib

Stacked Bar with values


    +------------+------+------+---------+
    | promo_name | in   | out  | model   |
    +------------+------+------+---------+
    | A          | 0,87 | 0,13 | plan    |
    +------------+------+------+---------+
    | B          | 0,77 | 0,23 | plan    |
    +------------+------+------+---------+
    | C          | 0,54 | 0,46 | plan    |
    +------------+------+------+---------+
    | A          | 0,59 | 0,41 | predict |
    +------------+------+------+---------+
    | B          | 0,50 | 0,50 | predict |
    +------------+------+------+---------+
    | C          | 0,46 | 0,54 | predict |
    +------------+------+------+---------+

Hello. I have a dataframe as in the table above, I would like to draw a stacked barplot with values, for example:

enter image description here

But so far it only works like this, my code is below:

ratio.set_index(['promo_name', 'model'], inplace=True)
ratio = ratio.reindex(index = [('A', 'plan'), ('A', 'predict'),
                              ('B', 'plan'), ('B', 'predict'),
                              ('C', 'plan'), ('C', 'predict')])
plt.rcParams["figure.figsize"] = (12,5)
ratio.plot(kind='bar', stacked=True)
plt.xticks(rotation=30)
plt.show()

But until I get the wrong thing, how do I fix it? Bar plot


Solution

  • Using matplotlib you can easily play around with the locations and widths of the bars:

     import matplotlib.pyplot as plt
    
    # plan, predict
    Aout = (0.87, 0.59)
    Ain = (0.13, 0.41)
    Bout = (0.77, 0.50)
    Bin = (0.23, 0.50)  
    Cout = (0.54, 0.46)
    Cin = (0.46, 0.54)
    width = 1.0       # the width of the bars
    
    A_positions = [0, 1]  # Positions for A bars
    p1A = plt.bar([0, 1], (1.0, 1.0), width, color='g', label='out')
    p2A = plt.bar([0, 1], Ain, width, color='b', label='in')
    
    B_positions = [3, 4]  # Positions for B bars
    p1B = plt.bar(B_positions, (1.0, 1.0), width, color='g')
    p2B = plt.bar(B_positions, Bin, width, color='b')
    
    C_positions = [6, 7]  # Positions for C bars
    p1C = plt.bar(C_positions, (1.0, 1.0), width, color='g')
    p2C = plt.bar(C_positions, Cin, width, color='b')
    
    positions = A_positions + B_positions + C_positions  # All together for ticks
    plt.xticks(positions, ('A (plan)', 'A (predict)', 'B (plan)', 'B (predict)', 'C (plan)', 'C (predict)'))
    plt.xticks(rotation=70)
    plt.yticks([1, 0])
    plt.legend()
    plt.tight_layout()
    

    And add text labels (you can play around with the location):

    plt.text(A_positions[0] - 0.25, Ain[0] / 2, str(Ain[0]))
    plt.text(A_positions[0] - 0.25, Aout[0] / 2, str(Aout[0]))
    plt.text(A_positions[1] - 0.25, Ain[1] / 2, str(Ain[1]))
    plt.text(A_positions[1] - 0.25, Aout[1] / 2 + 0.5, str(Aout[1]))
    
    plt.text(B_positions[0] - 0.25, Bin[0] / 2, str(Bin[0]))
    plt.text(B_positions[0] - 0.25, Bout[0] / 2, str(Bout[0]))
    plt.text(B_positions[1] - 0.25, Bin[1] / 2, str(Bin[1]))
    plt.text(B_positions[1] - 0.25, Bout[1] / 2 + 0.5, str(Bout[1]))
    
    
    plt.text(C_positions[0] - 0.25, Cin[0] / 2, str(Cin[0]))
    plt.text(C_positions[0] - 0.25, Cout[0] / 2 + 0.5, str(Cout[0]))
    plt.text(C_positions[1] - 0.25, Cin[1] / 2, str(Cin[1]))
    plt.text(C_positions[1] - 0.25, Cout[1] / 2 + 0.5, str(Cout[1]))
    

    enter image description here