Reputation: 5411
I'm generating a stacked bar chart in matplotlib (using Python 2.7 on Windows 7).
Since I want to use it to pairwise compare data from 2 data-sets, I would like to use different colors for every 2nd bar. Can anyone tell me how to achieve this?
My bar chart looks basically like this:
import numpy
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
IDs = ["1","A","2","B","3","C","4","D","5","E"]
N = len(IDs)
property1 = numpy.array([1,3,4,2,3,5,6,7,3,2])
property2 = numpy.array(range(10))
property3 = numpy.array(range(10,0,-1))
ind = numpy.arange(N)
width = 0.8
p1 = ax1.bar(ind, property1, width, color='red')
p2 = ax1.bar(ind, property2, width, color='blue', bottom=property1)
p3 = ax1.bar(ind, property3, width, color='green', bottom=property1 + property2)
plt.xticks(ind+width/2., IDs )
plt.show()
plt.close()
So I want to use one color scheme for the bars labelled with letters, another for those labelled with numbers (since e.g., "1" and "A" form a pair - they represent the same sample under 2 different experimental conditions, which is why I want them next to each other).
Ideally, if width could be adapted to leave no gap between the bars of a pair (but a gap between pairs), that would be really nice.
But right now, I have no idea how to go about this, so any advice would be great!
(I can use both "sets" of data individually, of that is easier? Maybe do two plots with wide gaps, intersected with each other?)
Upvotes: 3
Views: 5614
Reputation: 87386
You can do this more elegantly with slicing. A possibly better solution would be to de-interlace your data.
IDs = ["1","A","2","B","3","C","4","D","5","E"]
N = len(IDs)
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
set_count = 2
set_label = np.vstack([j*ones(len(IDs)//set_count) for j in range(set_count)]).T.ravel()
property1 = numpy.array([1,3,4,2,3,5,6,7,3,2])
property2 = numpy.array(range(10))
property3 = numpy.array(range(10,0,-1))
props = [property1,property2,property3]
ind = numpy.arange(N/set_count)
width = 0.9
b_width = 0.9/set_count
color_sets = [['red','green','blue'],['black','magenta','yellow']]
for j in range(set_count):
tmp_accum = np.zeros(len(props[0]))
for k in range(len(props)):
ax1.bar(ind +j*b_width, props[k][set_label==j], width=b_width, color=color_sets[j][k], bottom=tmp_accum[set_label==j])
tmp_accum += props[k]
lab_ind = []
for j in range(set_count):
lab_ind.append(ind + (j+.5)*b_width)
plt.xticks(np.vstack(lab_ind).T.ravel(), IDs )
It needs some sanity checks, but it works and should scale to more than 2 classes and more than 3 properties easily (you just need to make sure that all of your lengths sync up, using itertools.cycle
for the colors might help).
Upvotes: 5
Reputation: 5411
Found a way that works, although it seems pretty unelegant:
import numpy
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
IDs = ["1","A","2","B","3","C","4","D","5","E"]
N = len(IDs)
property1_1 = numpy.array([1,0,4,0,3,0,6,0,3,0])
property1_2 = numpy.array([0,3,0,2,0,5,0,7,0,2])
property2_1 = numpy.array([1,0,2,0,3,0,4,0,5,0])
property2_2 = numpy.array([0,6,0,7,0,8,0,9,0,10])
property3_1 = numpy.array([10,0,9,0,8,0,7,0,6,0])
property3_2 = numpy.array([0,5,0,4,0,3,0,2,0,1])
ind = numpy.arange(N)
width = 0.8
p1 = ax1.bar(ind, property1_1, width, color='red')
p2 = ax1.bar(ind, property2_1, width, color='blue', bottom=property1_1)
p3 = ax1.bar(ind, property3_1, width, color='green', bottom=property1_1 + property2_1)
p4 = ax1.bar(ind-0.2, property1_2, width, color='#FF6666')
p5 = ax1.bar(ind-0.2, property2_2, width, color='#6699FF', bottom=property1_2)
p6 = ax1.bar(ind-0.2, property3_2, width, color='#33CC33', bottom=property1_2+property2_2)
plt.xticks(ind+width/2., IDs )
plt.show()
plt.close()
This is how I did it for the sake of others having this issue. I don't think this is optimal and would appreciate additional answers.
Upvotes: 1