Helpex - Trao đổi & giúp đỡ Đăng nhập
106

Làm thế nào để vẽ nhiều thanh trong matplotlib, khi tôi cố gắng gọi hàm thanh nhiều lần, chúng chồng lên nhau và như hình bên dưới chỉ có thể nhìn thấy giá trị cao nhất màu đỏ. Làm cách nào để vẽ nhiều thanh có ngày tháng trên trục x?

Cho đến nay, tôi đã thử điều này:

import matplotlib.pyplot as plt
import datetime

x = [
    datetime.datetime(2011, 1, 4, 0, 0),
    datetime.datetime(2011, 1, 5, 0, 0),
    datetime.datetime(2011, 1, 6, 0, 0)
]
y = [4, 9, 2]
z = [1, 2, 3]
k = [11, 12, 13]

ax = plt.subplot(111)
ax.bar(x, y, width=0.5, color='b', align='center')
ax.bar(x, z, width=0.5, color='g', align='center')
ax.bar(x, k, width=0.5, color='r', align='center')
ax.xaxis_date()

plt.show()

Tôi hiểu rồi:

Python matplotlib nhiều thanh

Kết quả sẽ giống như vậy, nhưng với ngày tháng nằm trên trục x và các thanh nằm cạnh nhau:

Python matplotlib nhiều thanh

106 hữu ích 3 bình luận 327k xem chia sẻ
125
import matplotlib.pyplot as plt
from matplotlib.dates import date2num
import datetime

x = [
    datetime.datetime(2011, 1, 4, 0, 0),
    datetime.datetime(2011, 1, 5, 0, 0),
    datetime.datetime(2011, 1, 6, 0, 0)
]
x = date2num(x)

y = [4, 9, 2]
z = [1, 2, 3]
k = [11, 12, 13]

ax = plt.subplot(111)
ax.bar(x-0.2, y, width=0.2, color='b', align='center')
ax.bar(x, z, width=0.2, color='g', align='center')
ax.bar(x+0.2, k, width=0.2, color='r', align='center')
ax.xaxis_date()

plt.show()

Python matplotlib nhiều thanh

Tôi không biết "các giá trị y cũng chồng chéo" có nghĩa là gì, đoạn mã sau có giải quyết được vấn đề của bạn không?

ax = plt.subplot(111)
w = 0.3
ax.bar(x-w, y, width=w, color='b', align='center')
ax.bar(x, z, width=w, color='g', align='center')
ax.bar(x+w, k, width=w, color='r', align='center')
ax.xaxis_date()
ax.autoscale(tight=True)

plt.show()

Python matplotlib nhiều thanh

125 hữu ích 5 bình luận chia sẻ
67

Vấn đề với việc sử dụng ngày làm giá trị x là nếu bạn muốn có một biểu đồ thanh như trong hình thứ hai của mình, chúng sẽ sai. Bạn nên sử dụng biểu đồ thanh xếp chồng lên nhau (các màu chồng lên nhau) hoặc nhóm theo ngày (ngày "giả" trên trục x, về cơ bản chỉ nhóm các điểm dữ liệu).

import numpy as np
import matplotlib.pyplot as plt

N = 3
ind = np.arange(N)  # the x locations for the groups
width = 0.27       # the width of the bars

fig = plt.figure()
ax = fig.add_subplot(111)

yvals = [4, 9, 2]
rects1 = ax.bar(ind, yvals, width, color='r')
zvals = [1,2,3]
rects2 = ax.bar(ind+width, zvals, width, color='g')
kvals = [11,12,13]
rects3 = ax.bar(ind+width*2, kvals, width, color='b')

ax.set_ylabel('Scores')
ax.set_xticks(ind+width)
ax.set_xticklabels( ('2011-Jan-4', '2011-Jan-5', '2011-Jan-6') )
ax.legend( (rects1[0], rects2[0], rects3[0]), ('y', 'z', 'k') )

def autolabel(rects):
    for rect in rects:
        h = rect.get_height()
        ax.text(rect.get_x()+rect.get_width()/2., 1.05*h, '%d'%int(h),
                ha='center', va='bottom')

autolabel(rects1)
autolabel(rects2)
autolabel(rects3)

plt.show()

Python matplotlib nhiều thanh

67 hữu ích 5 bình luận chia sẻ
32

Tôi biết rằng điều này là về matplotlib, nhưng sử dụng pandasseaborncó thể giúp bạn tiết kiệm rất nhiều thời gian:

df = pd.DataFrame(zip(x*3, ["y"]*3+["z"]*3+["k"]*3, y+z+k), columns=["time", "kind", "data"])
plt.figure(figsize=(10, 6))
sns.barplot(x="time", hue="kind", y="data", data=df)
plt.show()

Python matplotlib nhiều thanh

32 hữu ích 4 bình luận chia sẻ
26

sau khi tìm kiếm một giải pháp tương tự và không tìm thấy bất kỳ điều gì đủ linh hoạt, tôi quyết định viết hàm của riêng mình cho nó. Nó cho phép bạn có bao nhiêu thanh cho mỗi nhóm tùy thích và chỉ định cả chiều rộng của một nhóm cũng như chiều rộng riêng lẻ của các thanh trong nhóm.

Thưởng thức:

from matplotlib import pyplot as plt


def bar_plot(ax, data, colors=None, total_width=0.8, single_width=1, legend=True):
    """Draws a bar plot with multiple bars per data point.

    Parameters
    ----------
    ax : matplotlib.pyplot.axis
        The axis we want to draw our plot on.

    data: dictionary
        A dictionary containing the data we want to plot. Keys are the names of the
        data, the items is a list of the values.

        Example:
        data = {
            "x":[1,2,3],
            "y":[1,2,3],
            "z":[1,2,3],
        }

    colors : array-like, optional
        A list of colors which are used for the bars. If None, the colors
        will be the standard matplotlib color cyle. (default: None)

    total_width : float, optional, default: 0.8
        The width of a bar group. 0.8 means that 80% of the x-axis is covered
        by bars and 20% will be spaces between the bars.

    single_width: float, optional, default: 1
        The relative width of a single bar within a group. 1 means the bars
        will touch eachother within a group, values less than 1 will make
        these bars thinner.

    legend: bool, optional, default: True
        If this is set to true, a legend will be added to the axis.
    """

    # Check if colors where provided, otherwhise use the default color cycle
    if colors is None:
        colors = plt.rcParams['axes.prop_cycle'].by_key()['color']

    # Number of bars per group
    n_bars = len(data)

    # The width of a single bar
    bar_width = total_width / n_bars

    # List containing handles for the drawn bars, used for the legend
    bars = []

    # Iterate over all data
    for i, (name, values) in enumerate(data.items()):
        # The offset in x direction of that bar
        x_offset = (i - n_bars / 2) * bar_width + bar_width / 2

        # Draw a bar for every value of that type
        for x, y in enumerate(values):
            bar = ax.bar(x + x_offset, y, width=bar_width * single_width, color=colors[i % len(colors)])

        # Add a handle to the last drawn bar, which we'll need for the legend
        bars.append(bar[0])

    # Draw legend if we need
    if legend:
        ax.legend(bars, data.keys())


if __name__ == "__main__":
    # Usage example:
    data = {
        "a": [1, 2, 3, 2, 1],
        "b": [2, 3, 4, 3, 1],
        "c": [3, 2, 1, 4, 2],
        "d": [5, 9, 2, 1, 8],
        "e": [1, 3, 2, 2, 3],
        "f": [4, 3, 1, 1, 4],
    }

    fig, ax = plt.subplots()
    bar_plot(ax, data, total_width=.8, single_width=.9)
    plt.show()

Đầu ra:

Python matplotlib nhiều thanh

26 hữu ích 3 bình luận chia sẻ
0

Tôi đã thực hiện giải pháp này: nếu bạn muốn vẽ nhiều hơn một ô trong một hình, hãy đảm bảo trước khi vẽ các ô tiếp theo, bạn đã đặt quyền matplotlib.pyplot.hold(True) để có thể thêm các ô khác.

Liên quan đến các giá trị ngày giờ trên trục X, một giải pháp sử dụng sự liên kết của các thanh phù hợp với tôi. Khi bạn tạo một biểu đồ thanh khác matplotlib.pyplot.bar(), chỉ cần sử dụng align='edge|center'và thiết lập width='+|-distance'.

Khi bạn đặt tất cả các thanh (ô) bên phải, bạn sẽ thấy các thanh tốt.

0 hữu ích 1 bình luận chia sẻ
0

Không làm điều này với matplotlib là cách phức tạp hơn. Tốt nhất là sử dụng seaborn:

tại đây: https://seaborn.pydata.org/generated/seaborn.barplot.html

0 hữu ích 0 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ python matplotlib , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading