简体   繁体   中英

Stacking multiple columns in a stacked bar plot using matplotlib in python 3

I am trying to generate a stacked bar plot to keep track of three parameters for every hour over multiple days. The picture of a sample plot is SamplePlot . However, I have had no success with plotting this in python. The fact that I am a beginner in python, makes matters worse.

Two attempts made previously to answer this questions are: Horizontal stacked bar chart in Matplotlib and stack bar plot in matplotlib and add label to each section (and suggestions) . However, I have not been able to achieve the desired results following any of the above solutions.

Can anyone please provide me with guidance as to how to generate the plot or point me in the direction?

Edit 1: The code that I have written is as follows:

import matplotlib.pyplot as plt; plt.rcdefaults()
import numpy as np
import matplotlib.pyplot as plt

status_day1 = [[0.2,0.3,0.5], [0.1,0.3,0.6], [0.4,0.4,0.2], [0.6,0.1,0.4]]
status_day2 = [[0.1,0.2,0.7], [0.3,0.2,0.5], [0.1,0.5,0.4], [0.2,0.5,0.3]]

day = ('Day1', 'Day2')

fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(111)
for x in range(0,4): #Looping through every hour
    for y in range(0,3): #Looping through every parameter
        if y==0:
            ax.bar(1, status_day1[x][y],color='b',align='center')
        elif y==1:
            ax.bar(1, status_day1[x][y],color='r',align='center')
        else:
            ax.bar(1, status_day1[x][y],color='g',align='center')
 # I am assuming that the three parameters for every hour are getting stacked on top of one another           
for x in range(0,4):
    for y in range(0,3):
        if y==0:
            ax.bar(1, status_day2[x][y],color='b',align='center')
        elif y==1:
            ax.bar(1, status_day2[x][y],color='r',align='center')
        else:
            ax.bar(1, status_day2[x][y],color='g',align='center') 

ax.set_xticklabels(day) 
ax.set_xlabel('Day')  
ax.set_ylabel('Hours') 
plt.show()

The undesired result that I get is: 不正确的情节

You need to keep track of the bottom of your bars, see the stacked bar plot example in the matplotlib docs: http://matplotlib.org/examples/pylab_examples/bar_stacked.html

Also, you can get rid of most of the more uglier loop code by using python's zip and enumerate functions as well as

for value in data:
     print(value)

instead of

for i in range(len(data)):
    print(data[i])

With this I get the expected result:

import matplotlib.pyplot as plt

status_day1 = [
    [0.2, 0.3, 0.5],
    [0.1, 0.3, 0.6],
    [0.4, 0.4, 0.2],
    [0.6, 0.1, 0.4],
]

status_day2 = [
    [0.1, 0.2, 0.7],
    [0.3, 0.2, 0.5],
    [0.1, 0.5, 0.4],
    [0.2, 0.5, 0.3],
]

days = ('Day1', 'Day2')

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(1, 1, 1)

for day, data in enumerate((status_day1, status_day2)):
    bottom = 0
    for hour in data:  # Looping through every hour
        for value, color in zip(hour, ('b', 'r', 'g')):
            ax.bar(
                day,
                value,
                bottom=bottom,
                color=color,
                align='center',
            )
            bottom += value


ax.set_xticks([0, 1])
ax.set_xticklabels(days)
ax.set_xlabel('Day')
ax.set_ylabel('Hours')
plt.show()

@MaxNoe has already answered the question quite elegantly by using zip and enumerate. However, for people who are not familiar with zip and enumerate, the following code achieves the desired results:

import matplotlib.pyplot as plt; plt.rcdefaults()
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

status_day1 = [[0.2,0.3,0.5], [0.1,0.3,0.6], [0.4,0.4,0.2], [0.6,0.1,0.3]]
status_day2 = [[0.1,0.2,0.7], [0.3,0.2,0.5], [0.1,0.5,0.4], [0.2,0.5,0.3]]

xval = [0.,1.,2.] #The places where the ticks are going to be on the x-axis

bottom_append = 0 #Counter to keep track of the bar (this is quite important)
fig = plt.figure(figsize=(5,5))
ax = fig.add_subplot(111)

for x in range(0,4): #Looping through every hour
    for y in range(0,3): #Looping through every parameter
        if y==0:
            if x==0:
                print(status_day1[x][y], bottom_append)
                ax.bar(0, status_day1[x][y], width = 0.3, color='blue',align='center')
                bottom_append = bottom_append+status_day1[x][y]
            else:
                print(status_day1[x][y], bottom_append)
                ax.bar(0, status_day1[x][y], width = 0.3, color='blue',align='center',bottom=bottom_append) 
                bottom_append = bottom_append+status_day1[x][y]
        elif y==1:
            print(status_day1[x][y], bottom_append)
            ax.bar(0, status_day1[x][y], width = 0.3, color='red',align='center', bottom=bottom_append)
            bottom_append = bottom_append+status_day1[x][y]
        else:
            print(status_day1[x][y], bottom_append)
            ax.bar(0, status_day1[x][y], width = 0.3, color='green',align='center', bottom=bottom_append)
            bottom_append = bottom_append+status_day1[x][y]

bottom_append = 0
# Code is exactly same as the above, only takes into account day2
for x in range(0,4): #Looping through every hour
    for y in range(0,3): #Looping through every parameter
        if y==0:
            if x==0:
                print(status_day2[x][y], bottom_append)
                ax.bar(1, status_day2[x][y], width = 0.3, color='blue',align='center')
                bottom_append = bottom_append+status_day2[x][y]
            else:
                print(status_day2[x][y], bottom_append)
                ax.bar(1, status_day2[x][y], width = 0.3, color='blue',align='center',bottom=bottom_append) 
                bottom_append = bottom_append+status_day2[x][y]
        elif y==1:
            print(status_day2[x][y], bottom_append)
            ax.bar(1, status_day2[x][y], width = 0.3, color='red',align='center', bottom=bottom_append)
            bottom_append = bottom_append+status_day2[x][y]
        else:
            print(status_day2[x][y], bottom_append)
            ax.bar(1, status_day2[x][y], width = 0.3, color='green',align='center', bottom=bottom_append)
            bottom_append = bottom_append+status_day2[x][y]          


# Setting the properties of the subplot in an attempt to beautify it
Label1 = mpatches.Patch(color='blue', label='Label1')
Label2 = mpatches.Patch(color='green', label='Label2')
Label3 = mpatches.Patch(color='red', label='Label3')
ax.legend(handles=[Label1, Label2, Label3], loc=1)            
ax.set_xticks(xval)         
ax.set_xticklabels(["Day1","Day2","Day3"])
ax.set_xlabel('Day')  
ax.set_ylabel('Hours') 
plt.show()  

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM