Search code examples
pythonmatplotlibtuplesbin-packing

Convert a list of 3-Tuples in to list of list for a matplot stacked bar chart


I have a list of 3 tuples to a bin packing problem solution that looks like this:

sorted_sol = [(0, 1, 170), (1, 1, 250), (2, 1, 250), (3, 1, 62), (3, 2, 30), (4, 1, 62), (4, 3, 62), (5, 2, 122), (6, 1, 212)]

As an example the first 3-Tuple means from length 0 cut 1 @ 170

I am trying to convert a list of 3-Tuples in to list of list for a matplot stacked bar chart but am struggling with the loop logic. The result should be.

import matplotlib.pyplot as plt
import numpy as np
bars = list(set([int(i[0]) for i in sorted_sol]))
#loop logic here to end up with data
b1 = [170, 250, 250, 62, 62, 122, 212]
b2 = [0,   0,   0,   30, 62, 122, 0]
b3 = [0,   0,   0,   30, 62, 0,   0]
b4 = [0,   0,   0,   0,  62, 0,   0]
data =[b1, b2, b3, b4]
for c in range(0, 3):
    if c == 0:
        plt.bar(bars, data[c])
    else:
        plt.bar(bars, data[c], bottom=data[c-1])
plt.show()

Additionally the bottom property doesn't seem to be working for me, in that it doesn't appear to stack the bars 3 & 4 correctly.


Solution

  • IIUC, something like this should work

    dx = max(x[0] for x in sorted_sol) + 1
    predata = []
    for x in range(dx):
        col_data = [tup[1:] for tup in sorted_sol if tup[0] == x]
        temp = [n * [y] for n, y in col_data]
        predata.append([i for sublist in temp for i in sublist])
    
    dy = max(len(x) for x in predata)
    data = [[i.pop() if i else 0 for i in predata] for _ in range(dy)]
    

    Output:

    [[170, 250, 250, 30, 62, 122, 212],
     [0, 0, 0, 30, 62, 122, 0],
     [0, 0, 0, 62, 62, 0, 0],
     [0, 0, 0, 0, 62, 0, 0]]
    

    The reason your plot doesn't work is because bottom needs to be the cumulative sum of the data. Try something like:

    bottom = 7 * [0]
    for i in range(4):
        plt.bar(range(7), data[c], bottom=bottom)
        bottom = [sum([a, b]) for a, b in zip(data[c], bottom)]
    

    If you use numpy, the addition on the last line can simply be data[i] + bottom

    enter image description here