【问题标题】:Matplotlib: Formatting time on x-axis of stacked horizontal bar graphMatplotlib:在堆叠水平条形图的 x 轴上格式化时间
【发布时间】:2017-05-30 22:41:09
【问题描述】:

我正在尝试使用 matplotlib 在堆叠的水平条形图中绘制用户在不同任务上花费的时间量。 x轴是时间。条形图的每个部分代表在任务上花费的时间量。但是,我得到了一个格式不正确的意外图表。图表的格式要求我在图表上放大很远才能看到所有的条形图。

该图确实符合我的需要,但起初它看起来像这样:original graph

为了得到这个,我必须放大很远:zoomed-in graph

除了第一个和最后一个数据点之外,放大后的图表似乎具有正确的条形比例。

我的数据是timedelta 对象的列表,因此可以将它们添加在一起。我正在将它们转换为 datetime 对象以绘制数据。

给我不想要的结果的代码是:

import matplotlib.pyplot as plt
from datetime import datetime
from datetime import timedelta
import matplotlib.dates as dt

def sum_times(data, N):
    '''sums the first N datetime elements in a list
       changes from timedelta object to datetime object
    '''
    # initialize
    summ = datetime(1900, 1, 1, 0, 0, 0)
    for i in range(len(data[0:N])):
        summ += data[i]
    return summ

start_date = datetime(1900, 1, 1, 0, 0, 0)
times = [timedelta(0, 737), 
         timedelta(0, 110), 
         timedelta(0, 356), 
         timedelta(0, 171), 
         timedelta(0, 306)]

fig, ax1 = plt.subplots(1,1, sharex=True, sharey=True)

ax1.set_title("Bug being fixed")
ax1.set_xlabel('time')
ax1.xaxis_date()

# the graph uses datetime objects
ax1.barh(1, times[0] + start_date)
ax1.barh(1, times[1] + start_date, left=sum_times(times, 1))
ax1.barh(1, times[2] + start_date, left=sum_times(times, 2))
ax1.barh(1, times[3] + start_date, left=sum_times(times, 3))
ax1.barh(1, times[4] + start_date, left=sum_times(times, 4))

ax1.set_xticks(range(1,10))   # arbitrary 

plt.show()

如何更改格式?

我曾尝试将ax1.set_xticklabels()datetimetimedelta 对象一起使用,但出现异常:ValueError: ordinal must be >= 1

当我使用时

ax1.xaxis.set_major_locator(dt.MinuteLocator(interval=60))
ax1.xaxis.set_major_formatter(dt.DateFormatter('%M:%S'))

格式仍然不正确。

我正在使用 python 3.6、matplotlib、PyDev IDE 和 Windows 8。

如果有任何库更适合显示此类数据或可以补充 matplotlib/pyplot,我将不胜感激使用一个解决方案。

另外,我尝试使用循环自动调用ax1.barh(...),但图形窗口不显示并且变得无响应。由于我想绘制更大的数据集,我可以使用更优雅的解决方案。

【问题讨论】:

    标签: python python-3.x datetime matplotlib graph


    【解决方案1】:

    根据@rvd 提供的建议,我提出了一个使用熊猫的更好的解决方案。就格式而言,它仍然不理想,但我不需要为了看到我的图表而将其放大得离谱,并且数据是成比例的。

    下面是使用 pandas 让它工作得更好一点的代码:

    import pandas as pd
    import matplotlib.pyplot as plt
    from datetime import datetime
    from datetime import timedelta
    import matplotlib.dates as dt
    
    times = [timedelta(0, 737), 
             timedelta(0, 110), 
             timedelta(0, 356), 
             timedelta(0, 171), 
             timedelta(0, 306)]
    
    start_date = datetime(1900, 1, 1, 0, 0, 0)
    times_datetime = [start_date + times[i] for i in range(len(times))]
    # pandas requires numerical data on dependent axis
    times_num = dt.date2num(times_datetime)
    # to make times_num proportionally correct
    for i in range(len(times_num)):
        times_num[i] -= dt.date2num(start_date)
        
    df = pd.DataFrame([times_num], index=['bugs'])
    fig, ax1 = plt.subplots(1,1, sharex=True, sharey=True)
    df.plot(kind='barh', ax=ax1, stacked=True)
    plt.show()
    

    这会产生:

    x 轴刻度可能不是时间,但数据可视化更符合我正在寻找的内容。

    谢谢!

    【讨论】:

      【解决方案2】:

      在 Python 中使用 pandas 库在这里可能会派上用场,因为对时间序列分析和绘图的支持比 matplotlib(基于它构建的)更加原生和直观。如果您有 CSV 文件形式的数据,请使用 df = pandas.read_csv(FILEPATH) 将数据加载到数据框中,并使用 df.plot() 进行绘图。如果您正在寻找更复杂或响应式的图表,请务必查看 Plotly - 您可以简单地将库导入 python 并更轻松地制作时间序列的响应式图表。

      【讨论】:

      • 那么这能解决问题吗?您需要在这里说明使用 pandas 会有什么帮助。以及为什么。
      • @rvd dr.plot() 会生成水平条形图吗?如何将 pandas 用于堆叠的水平条形图?
      • 是的 - 您可以使用 df.plot(y=DEPENDENT_VARIABLE, kind='barh') 来实现这一点。要堆叠条形图,您可以使用在 matplotlib 中使用的相同轴共享方法,并为 df.plot() 提供一个 ax 参数
      • 要添加 x-label,请在 plot() 调用之后使用 plt.xlabel('times')。看来您发现我的回答很有帮助-如果您可以投票并选择它,那将意义重大:)
      • 谢谢您,您的回答确实对我有所帮助,但我发现它有些含糊。
      猜你喜欢
      • 2015-02-11
      • 2012-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-15
      • 2021-03-18
      • 2021-08-07
      相关资源
      最近更新 更多