【问题标题】:Python matplotlib bars overlapping although width < 1Python matplotlib条虽然宽度<1但重叠
【发布时间】:2017-09-12 11:59:43
【问题描述】:

我正在尝试使用 matplotlib 绘制许多条形图,x 轴正好有 26 个时间戳/槽,y 轴有两个整数。对于大多数数据集,这可以很好地缩放,但在某些情况下,matplotlib 会让条形重叠:

Left overlapping and not aligned to xticks, right one OK

Overlapping

因此,尽管我的宽度设置为 0.1 并且我的数据集有 26 个值,但我没有为它们重叠的条提供足够的空间,我检查了这些值。

我绘制这些图表的代码如下:

# Plot something
rows = len(data_dict) // 2 + 1
fig = plt.figure(figsize=(15, 5*rows))
gs1 = gridspec.GridSpec(rows, 2)
grid_x = 0
grid_y = 0

for dataset_name in data_dict:
    message1_list = []
    message2_list = []
    ts_list = []
    slot_list = []
    for slot, counts in data_dict[dataset_name].items():
        slot_list.append(slot)
        message1_list.append(counts["Message1"])
        message2_list.append(counts["Message2"])
        ts_list.append(counts["TS"])

    ax = fig.add_subplot(gs1[grid_y, grid_x])

    ax.set_title("Activity: " + dataset_name, fontsize=24)
    ax.set_xlabel("Timestamps", fontsize=14)
    ax.set_ylabel("Number of messages", fontsize=14)

    ax.xaxis_date()
    hfmt = matplotdates.DateFormatter('%d.%m,%H:%M')
    ax.xaxis.set_major_formatter(hfmt)

    ax.set_xticks(ts_list)
    plt.setp(ax.get_xticklabels(), rotation=60, ha='right')
    ax.tick_params(axis='x', pad=0.75, length=5.0)

    rects = ax.bar(ts_list, message2_list, align='center', width=0.1)
    rects2 = ax.bar(ts_list, message1_list, align='center', width=0.1, bottom=message2_list)

    # update grid position
    if (grid_x == 1):
        grid_x = 0
        grid_y += 1
    else:
        grid_x = 1


plt.tight_layout(0.01)
plt.savefig(r"output_files\activity_barcharts.svg",bbox_inches='tight')
plt.gcf().clear()

输入数据如下所示(带有重叠条的绘图示例,第二张图片)

    slot - message1 - message2 - timestamp
    0 - 0 - 42 - 2017-09-11 07:59:53.517000+00:00
    1 - 0 - 4 - 2017-09-11 09:02:28.827875+00:00
    2 - 0 - 0 - 2017-09-11 10:05:04.138750+00:00
    3 - 0 - 0 - 2017-09-11 11:07:39.449625+00:00
    4 - 0 - 0 - 2017-09-11 12:10:14.760500+00:00
    5 - 0 - 0 - 2017-09-11 13:12:50.071375+00:00
    6 - 0 - 13 - 2017-09-11 14:15:25.382250+00:00
    7 - 0 - 0 - 2017-09-11 15:18:00.693125+00:00
    8 - 0 - 0 - 2017-09-11 16:20:36.004000+00:00
    9 - 0 - 0 - 2017-09-11 17:23:11.314875+00:00
    10 - 0 - 0 - 2017-09-11 18:25:46.625750+00:00
    11 - 0 - 0 - 2017-09-11 19:28:21.936625+00:00
    12 - 0 - 0 - 2017-09-11 20:30:57.247500+00:00
    13 - 0 - 0 - 2017-09-11 21:33:32.558375+00:00
    14 - 0 - 0 - 2017-09-11 22:36:07.869250+00:00
    15 - 0 - 0 - 2017-09-11 23:38:43.180125+00:00
    16 - 0 - 0 - 2017-09-12 00:41:18.491000+00:00
    17 - 0 - 0 - 2017-09-12 01:43:53.801875+00:00
    18 - 0 - 0 - 2017-09-12 02:46:29.112750+00:00
    19 - 0 - 0 - 2017-09-12 03:49:04.423625+00:00
    20 - 0 - 0 - 2017-09-12 04:51:39.734500+00:00
    21 - 0 - 0 - 2017-09-12 05:54:15.045375+00:00
    22 - 0 - 0 - 2017-09-12 06:56:50.356250+00:00
    23 - 0 - 0 - 2017-09-12 07:59:25.667125+00:00
    24 - 0 - 20 - 2017-09-12 09:02:00.978000+00:00
    25 - 0 - 0 - 2017-09-12 10:04:36.288875+00:00

有谁知道如何防止这种情况发生? 我为每个图表准确计算了 26 个条形图,并且实际上希望它们具有相同的宽度。我还尝试将 0 替换为 1e-5,但这并不能防止任何重叠(另一篇文章提出)。

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    条形的width数据单位的宽度。 IE。如果你想有一个宽度为 1 分钟的栏,你可以将 width 设置为

    plt.bar(..., width=1./(24*60.))
    

    因为 matplotlib 中日期时间轴的数值轴单位是天,一天有 24*60 分钟。

    对于条形宽度的自动确定,您可能会说希望条形宽度为输入时间列表中任意两个连续值之间的最小差值。在这种情况下,类似下面的东西就可以解决问题

    import numpy as np
    import matplotlib.pyplot as plt
    import datetime
    import matplotlib.dates
    
    t = [datetime.datetime(2017,9,12,8,i) for i in range(60)]
    x = np.random.rand(60)
    
    td = np.diff(t).min()
    s1 = matplotlib.dates.date2num(datetime.datetime.now())
    s2 = matplotlib.dates.date2num(datetime.datetime.now()+td)
    
    plt.bar(t, x, width=s2-s1, ec="k")
    
    plt.show()
    

    【讨论】:

    • 非常感谢!这有很大帮助!然而我想知道,我可以在哪里或如何查找当前存在的数据单元。我的意思是,在日期时间的情况下,我不清楚这是“分钟”、“小时”等。你知道是否有一些我忽略的文档或其他查找方式吗?
    • 我加了一句matplotlib中datetime轴的数值轴单位是天,一天有24*60分钟。这在文档中可能不太明显,但是当知道数字格式是由 date2num 的返回给出的并且返回的天数如 the matplotlib.dates documentation 所见时,这一点就变得很明显了。
    • 好的,再次非常感谢!这解释了很多。在我到目前为止发现的帖子中,所有 cmets 都声称宽度必须小于 1,我认为这在全球范围内都是正确的……这在我的情况下显然不是正确的。
    • 我认为在问题中说明这一点会有所帮助;事实上,您发现其他帖子声称宽度必须小于 1,包括指向这些帖子的链接会使问题更清晰,因此更容易理解。
    • 好的,谢谢你告诉我。以后我会尝试添加此类信息。
    猜你喜欢
    • 1970-01-01
    • 2015-09-09
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    • 1970-01-01
    • 2013-12-06
    • 2015-12-25
    • 2020-01-05
    相关资源
    最近更新 更多