Stacked bar chart with differently ordered colors using matplotlib
Asked Answered
E

2

5

I am a begginer of python. I am trying to make a horizontal barchart with differently ordered colors.

I have a data set like the one in the below:

dataset = [{'A':19, 'B':39, 'C':61, 'D':70},
           {'A':34, 'B':68, 'C':32, 'D':38},
           {'A':35, 'B':45, 'C':66, 'D':50},
           {'A':23, 'B':23, 'C':21, 'D':16}]
data_orders = [['A', 'B', 'C', 'D'], 
               ['B', 'A', 'C', 'D'], 
               ['A', 'B', 'D', 'C'], 
               ['B', 'A', 'C', 'D']]

The first list contains numerical data, and the second one contains the order of each data item. I need the second list here, because the order of A, B, C, and D is crucial for the dataset when presenting them in my case.

Using data like the above, I want to make a stacked bar chart like the picture in the below. It was made with MS Excel by me manually. What I hope to do now is to make this type of bar chart using Matplotlib with the dataset like the above one in a more automatic way. I also want to add a legend to the chart if possible.

Stacked Bar Chart with Differently Ordered Colors (An Example)

Actually, I have totally got lost in trying this by myself. Any help will be very, very helpful. Thank you very much for your attention!

Extravert answered 30/6, 2012 at 9:58 Comment(2)
take a look at this matplotlib.sourceforge.net/mpl_examples/pylab_examples/…Psychopath
Dear Ashwini, Thank you for this information. This is the example cited in the Matplotlib page? I was using this one as "textbook" but the problem was that it seemed beyond my capacity to "apply" this model to my actual purpose. This is why I posted my question! But your suggestion about enumerate would be a hint for me. Thanks a lot!Extravert
H
14

It's a long program, but it works, I added one dummy data to distinguish rows count and columns count:

import numpy as np
from matplotlib import pyplot as plt

dataset = [{'A':19, 'B':39, 'C':61, 'D':70},
           {'A':34, 'B':68, 'C':32, 'D':38},
           {'A':35, 'B':45, 'C':66, 'D':50},
           {'A':23, 'B':23, 'C':21, 'D':16},
           {'A':35, 'B':45, 'C':66, 'D':50}]
data_orders = [['A', 'B', 'C', 'D'], 
               ['B', 'A', 'C', 'D'], 
               ['A', 'B', 'D', 'C'], 
               ['B', 'A', 'C', 'D'],
               ['A', 'B', 'C', 'D']]
colors = ["r","g","b","y"]
names = sorted(dataset[0].keys())
values = np.array([[data[name] for name in order] for data,order in zip(dataset, data_orders)])
lefts = np.insert(np.cumsum(values, axis=1),0,0, axis=1)[:, :-1]
orders = np.array(data_orders)
bottoms = np.arange(len(data_orders))

for name, color in zip(names, colors):
    idx = np.where(orders == name)
    value = values[idx]
    left = lefts[idx]
    plt.bar(left=left, height=0.8, width=value, bottom=bottoms, 
            color=color, orientation="horizontal", label=name)
plt.yticks(bottoms+0.4, ["data %d" % (t+1) for t in bottoms])
plt.legend(loc="best", bbox_to_anchor=(1.0, 1.00))
plt.subplots_adjust(right=0.85)
plt.show()

the result figure is:

enter image description here

Habitue answered 30/6, 2012 at 13:22 Comment(2)
Thank you very much for your time for making all of this. This is very helpful!! I leanred a lot from your scripts.Extravert
A little improvement is to use barhSian
P
1
>>> dataset = [{'A':19, 'B':39, 'C':61, 'D':70},
           {'A':34, 'B':68, 'C':32, 'D':38},
           {'A':35, 'B':45, 'C':66, 'D':50},
           {'A':23, 'B':23, 'C':21, 'D':16}]

>>> data_orders = [['A', 'B', 'C', 'D'], 
               ['B', 'A', 'C', 'D'], 
               ['A', 'B', 'D', 'C'], 
               ['B', 'A', 'C', 'D']]
>>> for i,x in enumerate(data_orders):
     for y in x:
        #do something here with dataset[i][y]  in matplotlib
Psychopath answered 30/6, 2012 at 10:2 Comment(4)
Dear Ashwini, Thank you for your time to reply to my question. I will try my best to figure out how this can be used to solve my problem!Extravert
@Extravert another way could be to create a new list of lists in which data is already arranged as per data_orders.Psychopath
@Extravert [[dataset[i][y] for y in data_orders[i]] for i in range(len(data_orders))] would return [[19, 39, 61, 70], [68, 34, 32, 38], [35, 45, 50, 66], [23, 23, 21, 16]]Psychopath
The problem was my lack of understanding of how matplotlib works, but I probably got it because of your help! Thank you!Extravert

© 2022 - 2024 — McMap. All rights reserved.