How to fix the max value of a stack bar chart's using matplotlib?
I'm trying to create a stack bar chart from 2 lists:
counts_start = [tensor(0.),
tensor(0.),
tensor(0.0050),
tensor(0.0100),
tensor(0.2833),
tensor(0.8250),
tensor(0.8917),
tensor(1.),
tensor(1.),
tensor(1.)]
counts_end = [tensor(0.1350),
tensor(0.1467),
tensor(0.1517),
tensor(0.2233),
tensor(0.2350),
tensor(0.2417),
tensor(0.4100),
tensor(0.4200),
tensor(0.4483),
tensor(0.4600)]
Following this I learned that I need the bottom
of each list to be the sum of all the lists that came before, so I got this code:
counts_start = [torch.tensor(0.),
torch.tensor(0.),
torch.tensor(0.0050),
torch.tensor(0.0100),
torch.tensor(0.2833),
torch.tensor(0.8250),
torch.tensor(0.8917),
torch.tensor(1.),
torch.tensor(1.),
torch.tensor(1.)]
plt.bar(indices_end,counts_end, color='r')
counts_end = [torch.tensor(0.1350),
torch.tensor(0.1467),
torch.tensor(0.1517),
torch.tensor(0.2233),
torch.tensor(0.2350),
torch.tensor(0.2417),
torch.tensor(0.4100),
torch.tensor(0.4200),
torch.tensor(0.4483),
torch.tensor(0.4600)]
indices_start = range(len(counts_start))
plt.bar(indices_start,counts_start, bottom=counts_end)
plt.show()
Which outputs
Each list has a probability value and hence the max is 1 and min is 0 which is where I need the bars to start and end but can't get it to work. Also note that the third and fourth columns have the blue color on top which makes it look like blue is of higher value (which is not).
I also tried replacing the second plt.bar
line with plt.bar(indices_start,[a_i - b_i for a_i, b_i in zip(counts_start, counts_end)], bottom=counts_end)
which outputs
Which is almost correct (the max is at 1), except that the first few columns have the wrong color (I think it's because of the negative value).
To clarify, I want the highest value for each column between the 2 lists to be the max value for the column. If there's a higher value in counts_start
list the blue color should be on top with it's value (e.g 0.8917), and the smaller value should be with a max of it's value (e.g 0.4100). So it will look like a column with 0-0.4100 red, and 0.4100-0.8917 blue. However, if there's a higher value in the counts_end
list (e.g 0.1517), the top part of that column should be red with the top of the column at 0.1517, and the blue color should be at it's corresponding value (e.g 0.0050). Which will look like a column with 0-0.0050 blue, and 0.0050-0.1517 red.
Solution 1:
If I understood correctly, you want to normalize your list values so that counts_start[i] + counts_end[i] == 1
.
This can be done by something like:
start = [0, 0, 0.005, 0.01, 0.2833, 0.825, 0.8917, 1, 1, 1]
end = [0.135, 0.1467, 0.1517, 0.2233, 0.235, 0.2417, 0.41, 0.42, 0.4483, 0.46]
new_start, new_end = [], []
for x, y in zip(start, end):
t = x + y
new_start.append(x / t)
new_end.append(y / t)
n = len(start)
plt.bar(range(n), new_end, color="r")
plt.bar(range(n), new_start, bottom=new_end)
plt.show()
Which produces the following plot:
EDIT: Ok, for that I believe you're going to need to keep track of 4 lists, like so:
start = [0, 0, 0.005, 0.01, 0.2833, 0.825, 0.8917, 1, 1, 1]
end = [0.135, 0.1467, 0.1517, 0.2233, 0.235, 0.2417, 0.41, 0.42, 0.4483, 0.46]
lo_start, hi_start, lo_end, hi_end = [], [], [], []
for x, y in zip(start, end):
if x > y:
a, b, c, d = 0, x - y, y, 0
else:
a, b, c, d = x, 0, 0, y - x
lo_start.append(a)
hi_start.append(b)
lo_end.append(c)
hi_end.append(d)
n = len(start)
offset = [max(x, y) for x, y in zip(lo_start, lo_end)]
plt.bar(range(n), lo_start, color="tab:blue")
plt.bar(range(n), lo_end, color="tab:red")
plt.bar(range(n), hi_start, bottom=offset, color="tab:blue")
plt.bar(range(n), hi_end, bottom=offset, color="tab:red")
plt.show()
Which produces: