2013-09-27 475 views
15

Tôi cần một số trợ giúp tạo một bộ biểu đồ thanh xếp chồng lên nhau trong python với matlibplot. Mã cơ bản của tôi là dưới đây nhưng vấn đề của tôi là làm thế nào để tạo ra giá trị cho dưới cùng cho bất kỳ phần tử nào vượt ra ngoài phần thứ hai hiệu quả. Tôi có thể lấy ví dụ đồ thị để ngăn xếp một cách chính xác (luôn a, b, c, d từ dưới lên trên)Biểu đồ thanh xếp chồng matplotlib hiệu quả hơn - cách tính các giá trị dưới cùng

import numpy as np 
import matplotlib.pyplot as plt 

ind = np.arange(3) 

a = [3,6,9] 
b = [2,7,1] 
c = [0,3,1] 
d = [4,0,3] 

p1 = plt.bar(ind, a, 1, color='#ff3333') 
p2 = plt.bar(ind, b, 1, color='#33ff33', bottom=a) 
p3 = plt.bar(ind, c, 1, color='#3333ff', bottom=[a[j] +b[j] for j in range(len(a))]) 
p4 = plt.bar(ind, d, 1, color='#33ffff', bottom=[a[j] +b[j] +c[j] for j in range(len(a))]) 

plt.show() 

mã cuối cùng của tôi có thể có số lượng rất lớn các quán bar và các chức năng bao giờ mở rộng đáy = [.. .] không thể là giải pháp tốt nhất. Nó sẽ là tuyệt vời nếu bạn cũng có thể giải thích làm thế nào tôi cần phải lấy được giá trị. Có chức năng numpy không.

Cảm ơn bạn rất nhiều !!! PS Tôi đã tìm kiếm câu trả lời nhưng tôi không hiểu những gì tôi có thể tìm thấy.

Trả lời

28

Tôi vừa mới gặp phải vấn đề tương tự. Sau đó tôi quyết định kết thúc tất cả trong một lớp học tuyệt vời. Đối với bất cứ ai quan tâm đến bạn nhận được một thi hành một thanh biểu đồ lớp xếp chồng lên nhau ở đây:

https://github.com/minillinim/stackedBarGraph

Nó cho phép các đồ thị có quy mô xếp chồng lên nhau cũng như thiết lập độ rộng thanh và thiết lập chiều cao (với inners quy mô).

Cho một tập dữ liệu như thế này:

d = np.array([[101.,0.,0.,0.,0.,0.,0.], 
        [92.,3.,0.,4.,5.,6.,0.], 
        [56.,7.,8.,9.,23.,4.,5.], 
        [81.,2.,4.,5.,32.,33.,4.], 
        [0.,45.,2.,3.,45.,67.,8.], 
        [99.,5.,0.,0.,0.,43.,56.]]) 

    d_heights = [1.,2.,3.,4.,5.,6.] 
    d_widths = [.5,1.,3.,2.,1.,2.] 
    d_labels = ["fred","julie","sam","peter","rob","baz"] 
    d_colors = ['#2166ac', 
       '#fee090', 
       '#fdbb84', 
       '#fc8d59', 
       '#e34a33', 
       '#b30000', 
       '#777777'] 

Nó có thể làm cho hình ảnh như thế này:

stacked bar graph

GPLv3 với tình yêu.

+0

Cảm ơn - làm thế nào tôi có thể nhận khoảng cách giữa các thanh? – Matt

+0

Tôi đã cập nhật mã để cho phép các khoảng trống. Nó thực sự khá đơn giản, nếu bạn khấu trừ một số tiền cố định từ độ rộng của các thanh sau đó nó có hiệu quả thu nhỏ chúng. Sau đó nó chỉ là vấn đề chơi với xlims. Các cuộc gọi chức năng chính bây giờ có hai paramters mới, khoảng cách và endGaps, Hai hình ảnh dưới đây cho thấy các ví dụ về việc sử dụng. – minillinim

+0

Yêu gói của minillinim. Nó cảm thấy quá dễ dàng. Để thêm chú giải, nếu bạn đặt màu với một mảng như 'stacked_colors = ['# 2166ac', '# fee090', '# fdbb84']' và 'cols = stacked_colors', thì việc thêm chú thích vào một âm mưu làm từ một DataFrame gấu trúc: 'huyền thoại = [] i = 0 cho cột trong df.columns: legends.append (mpatches.Patch (color = stacked_colors [i], label = cột)) i + = 1 plt.legend (handles = legends) ' –

5
[sum(values) for values in zip(a, b, c)] 

Trong Python 2 bạn cũng có thể làm

map(sum, zip(a, b, c)) 

nhưng Python 3 sẽ cần

list(map(sum, zip(a, b, c))) 

đó là ít tốt đẹp.


Bạn có thể gói gọn này:

def sumzip(*items): 
    return [sum(values) for values in zip(*items)] 

và sau đó làm

p1 = plt.bar(ind, a, 1, color='#ff3333') 
p2 = plt.bar(ind, b, 1, color='#33ff33', bottom=sumzip(a)) 
p3 = plt.bar(ind, c, 1, color='#3333ff', bottom=sumzip(a, b)) 
p4 = plt.bar(ind, d, 1, color='#33ffff', bottom=sumzip(a, b, c)) 

quá.


Nếu a, b, cd là mảng NumPy bạn cũng có thể làm sum([a, b, c]):

a = np.array([3,6,9]) 
b = np.array([2,7,1]) 
c = np.array([0,3,1]) 
d = np.array([4,0,3]) 

p1 = plt.bar(ind, a, 1, color='#ff3333') 
p2 = plt.bar(ind, b, 1, color='#33ff33', bottom=sum([a])) 
p3 = plt.bar(ind, c, 1, color='#3333ff', bottom=sum([a, b])) 
p4 = plt.bar(ind, d, 1, color='#33ffff', bottom=sum([a, b, c])) 
14

Chuyển đổi giá trị của bạn để NumPy mảng sẽ làm cho cuộc sống của bạn dễ dàng hơn:

data = np.array([a, b, c, d]) 
bottom = np.cumsum(data, axis=0) 
colors = ('#ff3333', '#33ff33', '#3333ff', '#33ffff') 

plt.bar(ind, data[0], color=colors[0]) 
for j in xrange(1, data.shape[0]): 
    plt.bar(ind, data[1], color=colors[j], bottom=bottom[i-1]) 

Ngoài ra, để loại bỏ trường hợp đặc biệt khó chịu cho thanh đầu tiên:

data = np.array([a, b, c, d]) 
bottom = np.vstack((np.zeros((data.shape[1],), dtype=data.dtype), 
        np.cumsum(data, axis=0)[:-1])) 
colors = ('#ff3333', '#33ff33', '#3333ff', '#33ffff') 
for dat, col, bot in zip(data, colors, bottom): 
    plt.bar(ind, dat, color=col, bottom=bot) 
+4

Nếu bạn đang sử dụng matplotlib, mọi thứ sẽ kết thúc dưới dạng một biến thể bên dưới _anyway_. Cũng có thể làm cho cuộc sống của bạn trở nên dễ chịu;) – tacaswell

+0

cảm ơn, làm thế nào tôi có thể thêm nhãn vào đó? Tôi có một danh sách các nhãn/tên cho mỗi chuỗi mà tôi sắp xếp, nhưng mặc dù tôi đã thử nhưng tôi không thể đưa chúng ra đúng cách. Tôi cũng đã cố gắng để chạy một huyền thoại đơn giản như dưới đây nhưng nó đã không thực sự làm việc .: 'code'plt.legend ((pl [0], pm [0], ph [0], pa [0]) , ('L', 'M', 'H', 'Tại'), bbox_to_anchor = [1.05, 0.5], loc = 'center') –

1

Tôi giải quyết nó như thế này:

import numpy as np 

dates = # somehow get a list of dates 
labels = # a list of various labels 
colors = # somehow get a list of colors 

margin_bottom = np.zeros(dates) 

for index, label in enumerate(labels): 
    values = # get your values for the label at index-th position from somewhere 
    ax.bar(
     dates, values, 
     align='center', label=label, color=colors[index], bottom=margin_bottom 
    ) 
    margin_bottom += values # here you simply add it to the previous margin 
    # margin_bottom is a numpy array, adding a list will not change that 

Nó tương tự như một số giải pháp khác, nhưng nó không đòi hỏi tất cả các lợi nhuận được bảo quản ở mọi thời đại. Thay vào đó nó "xây dựng" các ngăn xếp từ dưới lên, thêm nhiều hơn và nhiều lợi nhuận hơn với mỗi lần lặp lại.