Làm cách nào để vẽ một biểu đồ sao cho chiều cao của các thanh cộng lại bằng 1 trong matplotlib?


85

Tôi muốn vẽ biểu đồ chuẩn hóa từ một vectơ bằng cách sử dụng matplotlib. Tôi đã thử những cách sau:

plt.hist(myarray, normed=True)

cũng như:

plt.hist(myarray, normed=1)

nhưng không có tùy chọn nào tạo ra trục y từ [0, 1] sao cho chiều cao thanh của tổng biểu đồ bằng 1. Tôi muốn tạo một biểu đồ như vậy - tôi có thể làm như thế nào?


5
Tôi biết điều này là cũ, nhưng để tham khảo trong tương lai và bất kỳ ai truy cập trang này, loại trục này được gọi là trục "mật độ xác suất"!
ChristineB

Câu trả lời:


48

Sẽ hữu ích hơn nếu bạn đặt ra một ví dụ hoạt động hoàn chỉnh hơn (hoặc trong trường hợp này là không hoạt động).

Tôi đã thử những cách sau:

import numpy as np
import matplotlib.pyplot as plt

x = np.random.randn(1000)

fig = plt.figure()
ax = fig.add_subplot(111)
n, bins, rectangles = ax.hist(x, 50, density=True)
fig.canvas.draw()
plt.show()

Điều này thực sự sẽ tạo ra một biểu đồ biểu đồ thanh với trục y đi từ đó [0,1].

Hơn nữa, theo histtài liệu (tức là ax.hist?từ ipython), tôi nghĩ rằng tổng số tiền cũng ổn:

*normed*:
If *True*, the first element of the return tuple will
be the counts normalized to form a probability density, i.e.,
``n/(len(x)*dbin)``.  In a probability density, the integral of
the histogram should be 1; you can verify that with a
trapezoidal integration of the probability density function::

    pdf, bins, patches = ax.hist(...)
    print np.sum(pdf * np.diff(bins))

Thử điều này sau các lệnh trên:

np.sum(n * np.diff(bins))

Tôi nhận được giá trị trả lại 1.0như mong đợi. Hãy nhớ rằng điều normed=Trueđó không có nghĩa là tổng giá trị tại mỗi thanh sẽ là thống nhất, nhưng thay vì tích phân trên các thanh là thống nhất. Trong trường hợp của tôi np.sum(n)trả lại khoảng 7.2767.


3
Đúng, đó là một đồ thị mật độ xác suất, tôi nghĩ anh ấy muốn một đồ thị khối lượng xác suất.
NoName

200

Nếu bạn muốn tổng tất cả các thanh là khối thống nhất bằng nhau, hãy cân mỗi thùng bằng tổng số giá trị:

weights = np.ones_like(myarray) / len(myarray)
plt.hist(myarray, weights=weights)

Hy vọng rằng sẽ hữu ích, mặc dù chủ đề đã khá cũ ...

Lưu ý đối với Python 2.x: thêm ép kiểu float()cho một trong các toán tử của phép chia vì nếu không, bạn sẽ kết thúc bằng số không do phép chia số nguyên


8
Câu trả lời chính xác. Lưu ý rằng nếu myarray là một python array_likechứ không phải là một mảng numpy, bạn sẽ cần phải truyền len(myarray)tới float.
cmh

3
Ngoài ra nếu myarray đa chiều và bạn chỉ sử dụng một chiều, chẳng hạn như myarray [0 ,:], thì bạn có thể hoán đổi len (myarray) với np.size (myarray [0 ,:]) và điều đó sẽ hoạt động cùng một cách. (Nếu không, nó nói đối tượng là không callable.)
ChristineB

22

Tôi biết câu trả lời này là quá muộn vì câu hỏi là năm 2010 nhưng tôi đã gặp câu hỏi này khi chính tôi đang đối mặt với một vấn đề tương tự. Như đã nêu trong câu trả lời, chuẩn = True có nghĩa là tổng diện tích dưới biểu đồ bằng 1 nhưng tổng chiều cao không bằng 1. Tuy nhiên, tôi muốn, để thuận tiện cho việc giải thích vật lý của biểu đồ, hãy tạo một với tổng chiều cao bằng 1.

Tôi đã tìm thấy một gợi ý trong câu hỏi sau - Python: Biểu đồ với khu vực được chuẩn hóa thành một thứ khác ngoài 1

Nhưng tôi không thể tìm ra cách làm cho các thanh bắt chước tính năng histtype = "step" hist (). Điều này đã chuyển hướng tôi đến: Matplotlib - Biểu đồ từng bước với dữ liệu đã được bin

Nếu cộng đồng thấy điều đó có thể chấp nhận được, tôi nên đưa ra một giải pháp tổng hợp các ý tưởng từ cả hai bài đăng trên.

import matplotlib.pyplot as plt

# Let X be the array whose histogram needs to be plotted.
nx, xbins, ptchs = plt.hist(X, bins=20)
plt.clf() # Get rid of this histogram since not the one we want.

nx_frac = nx/float(len(nx)) # Each bin divided by total number of objects.
width = xbins[1] - xbins[0] # Width of each bin.
x = np.ravel(zip(xbins[:-1], xbins[:-1]+width))
y = np.ravel(zip(nx_frac,nx_frac))

plt.plot(x,y,linestyle="dashed",label="MyLabel")
#... Further formatting.

Điều này đã hoạt động tuyệt vời đối với tôi mặc dù trong một số trường hợp, tôi nhận thấy rằng "thanh" ngoài cùng bên trái hoặc "thanh" ngoài cùng bên phải của biểu đồ không đóng xuống bằng cách chạm vào điểm thấp nhất của trục Y. Trong trường hợp này, việc thêm một phần tử 0 vào đầu hoặc cuối của y sẽ đạt được kết quả cần thiết.

Tôi chỉ nghĩ rằng tôi sẽ chia sẻ kinh nghiệm của mình. Cảm ơn bạn.


tôi nghĩ rằng bạn cần chuẩn mực = True cũng như trong plt.hist. Ngoài ra trong Python 3, bạn phải sử dụng danh sách (zip (...)).
Sebastian Schmitz

11

Đây là một giải pháp đơn giản khác bằng cách sử dụng np.histogram()phương pháp.

myarray = np.random.random(100)
results, edges = np.histogram(myarray, normed=True)
binWidth = edges[1] - edges[0]
plt.bar(edges[:-1], results*binWidth, binWidth)

Bạn thực sự có thể kiểm tra xem tổng số tiền có lên đến 1 hay không với:

> print sum(results*binWidth)
1.0
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.