在 matplotlib 中如何在同一张图中绘制多个 Y 值与不同时间戳的多个 X 值?

3

我是matplotlib的新手,请原谅我的无知并帮助我解决这个问题。基本上,我有以下数据,这些数据由其他Python脚本在CSV文件中生成。

CSV1: 时间戳,数据1

23:04:17, 1163557.14 bps
23:04:27, 1137578.47 bps
23:04:37, 1139094.66 bps
23:04:47, 1095752.97 bps
23:04:57, 1264145.01 bps

CSV2:时间戳,数据2


23:04:21, 1011000.00 bps
23:04:31, 1011000.00 bps
23:04:41, 1011000.00 bps
23:04:51, 1014000.00 bps
23:05:01, 1008000.00 bps

CSV3:时间戳,数据3

23:05:28, 1109617.96 bps
23:05:38, 1139177.95 bps
23:05:48, 1108110.09 bps
23:05:58, 1107078.94 bps
23:06:08, 1163406.80 bps

我想要的是将时间沿着X轴展示,将三个Y值分别显示为"data1"、"data2"和"data3"。这些数据每10秒采集一次,但它们不一定同步。因此,我不能有一个单独的数组来表示X轴。但我希望将它们全部显示在同一张图表上以便比较。我该如何解决这个问题?
非常感谢提供任何样例代码或文档。
**编辑:**
本质上我的问题是数据按照不同的时间戳进行索引,但我想将它们绘制在同一张图表上。我该怎么做?
编辑2:
感谢大家的帮助,这真的很有用。现在这是我有的代码:
    import csv
    import sys
    import datetime
    import random
    import matplotlib.pyplot as plt
    from matplotlib.dates import MinuteLocator, SecondLocator, DateFormatter

    time_e_z_raw_list = []
    bitrate_e_z_list = []
    time_i_z_raw_list = []
    bitrate_i_z_list = []
    time_i_query_z_raw_list = []
    bitrate_i_q_z_raw_list = []

    f_enc_z = open(sys.argv[1], 'rt')
    f_ing_z = open(sys.argv[2], 'rt')
    f_ing_q_z = open(sys.argv[3], 'rt')

    try:
        reader1 = csv.reader(f_enc_z)
        for row in reader1:
            bitrate = row[1]
            time_e_z_raw_list.append(row[0])
            bitrate_e_z_list.append(bitrate[:-4])
        reader3 = csv.reader(f_ing_z)
        for row in reader3:
            bitrate = row[1]
            time_i_z_raw_list.append(row[0])
            bitrate_i_z_list.append(bitrate[:-4])
        reader4 = csv.reader(f_ing_q_z)
        for row in reader4:
            bitrate = row[1]
            time_i_q_z_raw_list.append(row[0])
            bitrate_i_q_z_raw_list.append(bitrate[:-4])

    finally:
        f_enc_z.close()
        f_ing_z.close()
        f_ing_q_z.close()

    time_e_z_list = [datetime.datetime.strptime(s, '%H:%M:%S') for s in         time_e_z_raw_list]
    time_i_z_list = [datetime.datetime.strptime(s, '%H:%M:%S') for s in     time_i_z_raw_list]
    time_i_q_z_list = [datetime.datetime.strptime(s, '%H:%M:%S') for s in time_i_q_z_raw_list]

    fig = plt.figure(figsize=(18,16))

    plt.plot(time_e_z_list, bitrate_e_z_list, label="label1", lw=1)
    plt.plot(time_i_z_list, bitrate_i_z_list, label="label2", lw=1)
    plt.plot(time_i_q_z_list, bitrate_i_z_list, label="label3", lw=1)

    minutes = MinuteLocator()
    seconds = SecondLocator()

    ax = plt.gca()
    ax.xaxis.set_major_locator(minutes)
    ax.xaxis.set_minor_locator(seconds)
    ax.xaxis.set_major_formatter(DateFormatter("%H:%M:%S"))
    plt.xlabel('time')
    plt.ylabel('bitrate in bps')
    plt.grid()
    plt.legend(loc='upper right')

    plt.gcf().autofmt_xdate()

    plt.show()

问题在于当时间戳跨越3个小时以上时,绘图会变得失真。我该如何确保X轴显示的范围根据我采样的时间戳范围动态调整?通常我运行4个小时,并每20秒采集一次数据点。因此当我绘制图形时,我得到了一个非常糟糕的图形。我该怎么解决它?然而,当我有少量数据时,我会得到一个正确的图形。

2个回答

3

好的,我更新了我的初始答案。以下是可能的解决方案之一。但由于你提到了一个CSV文件,你可能需要查看如何在Pandas中处理时间序列。

import datetime
import random
import matplotlib.pyplot as plt

data1 = (1163557.14, 1137578.47, 1139094.66)
times1_raw = ('23:04:17', '23:04:27', '23:04:37')
times1 = [datetime.datetime.strptime(s, '%H:%M:%S') for s in times1_raw]

data2 = (1011000.00, 1011000.00, 1011000.00)
times2_raw = ('23:04:21', '23:04:31', '23:04:41')
times2 = [datetime.datetime.strptime(s, '%H:%M:%S') for s in times2_raw]

fig = plt.figure(figsize=(8,6))

plt.plot(times1, data1, label='data1', lw=2, marker='o')
plt.plot(times2, data2, label='data2', lw=2, marker='s')
plt.xlabel('time in seconds')
plt.ylabel('speed in bps')
plt.grid()
plt.legend(loc='upper right')

plt.gcf().autofmt_xdate()

plt.show()

enter image description here


我希望时间戳也能保持完整。因此,我希望时间戳沿着X轴运行。只是data1和data2的数据点相差几秒钟。是否可以在X轴上显示时间戳? - rajath26
很高兴听到这个消息。也许你可以提供一些图片来展示这个问题的实际情况。 - user2489252

0
这是我解决这个问题的方法。
首先,尝试利用datetime模块。在处理时间戳数据时,它是一个救星。
我们知道时间步长中最小的增量是一秒钟。因此,让我们首先创建一个包含所有可能时间的列表。
import matplotlib.pyplot as plt  
import datetime

start_date = datetime.datetime(2014,6,17,23,4,17)
end_date = datetime.datetime(2014,6,17,23,6,8)
number_seconds = (end_date - start_date).seconds

time_stamps = [start_date + datetime.timedelta(seconds=t) for t in range(number_seconds)]

现在,列表time_stamps是一个datetime对象,根据您的示例数据,我认为您只想从时间戳中获取小时:分钟:秒。我们可以轻松地使用另一个列表推导式来实现这个目标:
time_stamps_fmt = [datetime.datetime.strftime(t,'%H:%m:%S') for t in time_stamps]

现在让我们创建一个空数组来存储bps数据:

bps_1 = np.zeros([number_seconds],dtype('float'))
bps_2 = np.zeros([number_seconds],dtype('float'))
bps_3 = np.zeros([number_seconds],dtype('float'))

然后将bps_1/2/3的相应索引填充到.csv文件中的时间戳。如果找不到时间戳,请在该索引处插入np.nan,并且matplotlib应将其视为缺失值而不绘制任何内容。

您可以使用xticks显示时间戳作为x标签:

plt.xticks(np.arange(number_seconds), time_stamps_fmt)

这是一个有趣的方式,你提出了@N1B4。但如果我运行超过4个小时,你认为每秒索引一次会有帮助吗? - rajath26
你至少需要以一秒的间隔存储数据,因为这是包含所有数据的最小频率。但是你需要绘制每个数据点吗?考虑到每分钟平均值或 10 分钟平均值如何? - N1B4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接