CodingCat
CodingCat

Reputation: 5411

Alternate colors in stacked matplotlib bar

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

Answers (2)

tacaswell
tacaswell

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).

image of results

Upvotes: 5

CodingCat
CodingCat

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

Related Questions