3

I need to create a stacked bar chart using matplotlib. Each bar should be a stack of the parameters I am measuring. However, I want it to be interactive or dynamic so as when I click on one of the parameters (A,B,C) for example in the legend, it should make that parameter at the bottom of the stack so as we could have a better comparison between different candidates depending on the parameter we choose.

I got inspired from examples in matplotlib.. here is my code

import numpy as np
import matplotlib.pyplot as plt

N = 10  #could change

plt.figure()

A   = np.array([70, 88, 78, 93, 99, 58, 89, 66, 77, 78])
B = np.array([73, 65, 78, 87, 97, 57, 77, 88, 69, 78])
C = np.array([66, 98, 88, 67, 99, 88, 62, 70, 90, 73])


ind = np.arange(N)    # the x locations for the groups
width = 0.35       # the width of the bars: can also be len(x) sequence

p1 = plt.bar(ind, A,width, color='r')
p2 = plt.bar(ind, B, width, color='y', bottom=A)
p3 = plt.bar(ind, C, width, color='b', bottom=A+B)


plt.ylabel('Scores')
plt.title('Index')

plt.xticks(ind+width/2., ('1', '2', '3', '4', '5', '6', '7', '8', '9', '10'))#dynamic - fed

plt.yticks(np.arange(0,300,10))
plt.legend( (p1[0], p2[0], p3[0]), ('A','B','C') )
plt.grid(True)


plt.show()

Thank you... I hope I am clear enough

1 Answer 1

2

7 years later, but I thought I'd provide a solution for this using Python 3.6.0 and Matplotlib 2.0.0

import numpy as np
import matplotlib.pyplot as plt

#Variables
bar_a = np.array([70, 88, 78, 93, 99, 58, 89, 66, 77, 78])
bar_b = np.array([73, 65, 78, 87, 97, 57, 77, 88, 69, 78])
bar_c = np.array([66, 98, 88, 67, 99, 88, 62, 70, 90, 73])
xloc = np.arange(len(bar_a)) #Get a count of postions in bar_a instead of declaring 10.
width = 0.5  # the width of the bars: can also be len(x) sequence

#Plotting
fig = plt.figure(figsize=(6,6))
p1 = plt.bar(xloc, bar_a, width, color='r', label='A')
p2 = plt.bar(xloc, bar_b, width, color='y', bottom=bar_a, label='B')
p3 = plt.bar(xloc, bar_c, width, color='b', bottom=bar_a+bar_b, label='C')

plt.xticks(xloc+width/2., (str(num+1) for num in xloc)) #dynamic instead of ('1', '2', '3', '4', '5', '6', '7', '8', '9', '10'))
plt.yticks(np.arange(0,300,10))
plt.ylabel('Scores')
plt.title('Index')
leg = plt.legend()
plt.grid(True)

#For setting and selecting legend items
barcontainers = [p1, p2, p3] #List of BarContainers
legendentry = [] #Mathing Lenged Entry to bar container

#Set pickers on the legend
for legenditem in leg.get_patches():
    legenditem.set_picker(5)
    legendentry.append(legenditem) #Append to legend entry to a list so we can get the index later

#Function to redraw on picking
def onpick(event):
    tempbarcontainers = barcontainers[:] #Make a copy of barcontainers. Used for re-ordering of bars
    selectedforbottom = legendentry.index(event.artist) #Index of selected artist

    #Use the index of the selected Legend entry as the index of the barcontainer list.
    bottombars = tempbarcontainers[selectedforbottom].patches #Bottom bar will be the one selected
    tempbarcontainers.pop(selectedforbottom) #Pop the selected artist from the list
    midbars = tempbarcontainers[0].patches #Mid bars is first of remaining bars
    topbars = tempbarcontainers[1].patches #Top bar is second of remaining bars

    for bottom, mid, top in zip(bottombars,midbars,topbars):
        bottom.set_y(0) #Set the bottom of each selected bar to 0
        mid.set_y(bottom.get_height()) #Set the bottom of the second bar to the top of bottom bar
        top.set_y(bottom.get_height() + mid.get_height()) #Set the bottom of third bar to the top of the sum of other bars

    fig.canvas.draw() #Redraw the canvas

fig.canvas.mpl_connect('pick_event', onpick)

plt.show()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.