首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用matplotlib自定义甘特图,并在图形上显示表示当前时间的垂直线?

如何使用matplotlib自定义甘特图,并在图形上显示表示当前时间的垂直线?
EN

Stack Overflow用户
提问于 2020-02-18 00:16:57
回答 2查看 1.5K关注 0票数 1

下面是我的Python代码,它基本上绘制了一个甘特图:

代码语言:javascript
复制
import pandas as pd
import random
from datetime import datetime
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
%matplotlib inline
import math
plt.style.use('ggplot')

df = pd.read_csv('zpp00141_new.csv')

def timestr_to_num(timestr):
    return mdates.date2num(datetime.strptime('0' + timestr if timestr[1] == ':' else timestr, '%I:%M:%S %p'))

df.rename(columns={"Earl. start / time": "start", "Latest finish / time": "finish"}, inplace = True)

df['Operation/Activity'] = df['Operation/Activity'].astype(str)

fig, ax = plt.subplots(figsize=(10, 5))
operations = pd.unique(df['Operation/Activity'])
#df.assign(start=df['Earl. start / time'])
colors = plt.cm.tab10.colors  # get a list of 10 colors
colors *= math.ceil(len(operations) / (len(colors)))  # repeat the list as many times as needed
for operation, color in zip(operations, colors):
    for row in df[df['Operation/Activity'] == operation].itertuples():
        left = timestr_to_num(row.start)
        right = timestr_to_num(row.finish)
        ax.barh(operation, left=left, width=right - left, height=3, color=color)
ax.set_xlim(timestr_to_num('07:00:00 AM'), timestr_to_num('4:30:00 PM'))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))  # display ticks as hours and minutes
ax.xaxis.set_major_locator(mdates.HourLocator(interval=1))  # set a tick every hour
ax.set_xlabel('Time')
ax.set_ylabel('Operation')
plt.tight_layout()
plt.show()

你可以在附加的图片上看到输出:

我想画一条垂直直线,它与x轴上的当前时间相对应。我试图将它添加到我的代码中来绘制它,但我不知道如何让它工作。我想可能是我的时间格式有问题,或者类似的问题:

代码语言:javascript
复制
plt.axvline(pd.Timestamp.now(),color='r')

我真的很感激在这件事上的任何帮助。这是一张所需输出的图片,我希望我的图是类似的:

此外,我想将另一个类别添加/附加到我的y轴“操作短文本”和“操作/活动”#中,这样它不仅可以显示操作编号,还可以反映它旁边的操作描述。要了解我的数据是什么样子,请看下面(第一行是标题):

代码语言:javascript
复制
Operation short text,Operation/Activity,Earl. start / time,Latest finish / time
Mount right racks,0250,7:00:00 AM,9:22:00 AM
Mount right side motion unit carriage,0251,9:22:00 AM,10:30:00 AM
Mount left side motion unit carriage,0252,10:30:00 AM,11:17:00 AM
Install motion unit complete,0253,11:17:00 AM,1:01:00 PM
Move machine to next step + EPA,0254,1:01:00 PM,3:30:00 PM
Mount Left Racks,0200,7:00:00 AM,9:12:00 AM
Mount cable motor & Lubricate guide carr,0201,9:12:00 AM,9:44:00 AM
Mount suction components,0202,9:44:00 AM,11:04:00 AM
Mount extraction,0203,11:04:00 AM,12:34:00 PM
Mount temporary diamond plates,0204,12:34:00 PM,1:04:00 PM
Mount piping inside,0205,1:04:00 PM,1:44:00 PM
Move Machine to next step + EPA,0206,1:44:00 PM,3:30:00 PM
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-02-19 16:20:59

最简单的方法似乎是按操作对数据帧进行排序,然后使用数据帧的索引作为y坐标绘制水平条形图。然后,反转y轴的限制(将其从高到低设置),在顶部获得编号最小的操作。(代码现在假设每个条形图将在新行上,而旧代码假设一个操作将有更多条形图)。

由于这些操作现在似乎属于一起,因此选择了具有连续颜色的色彩映射表,并且每次操作比前一个操作开始得更早时,颜色都会重新开始。请随意使用任何适合您目标的方案。

由于datetime.strptime仅查看时间,因此它将获得默认日期(1900年1月1日)。所以你对“现在”时间使用相同的转换的方法是非常正确的。

请注意,pd.read_csv的类型嗅探器为操作列提供了浮点型格式。您可以阻止这种情况,给它显式的转换信息。例如,pd.read_csv(..., converters={1: str})将第二列作为字符串。

代码语言:javascript
复制
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from datetime import datetime
import pandas as pd
import math
# % matplotlib inline

def timestr_to_num(timestr):
    return mdates.date2num(datetime.strptime('0' + timestr if timestr[1] == ':' else timestr, '%I:%M:%S %p'))

plt.style.use('ggplot')
# df = pd.read_csv('zpp00141_new.csv')
columns = ['Operation short text', 'Operation/Activity', 'Earl. start / time', 'Latest finish / time']
rows = [['Mount right racks', '0250', '7:00:00 AM', '9:22:00 AM'],
        ['Mount right side motion unit carriage', '0251', '9:22:00 AM', '10:30:00 AM'],
        ['Mount left side motion unit carriage', '0252', '10:30:00 AM', '11:17:00 AM'],
        ['Install motion unit complete', '0253', '11:17:00 AM', '1:01:00 PM'],
        ['Move machine to next step + EPA', '0254', '1:01:00 PM', '3:30:00 PM'],
        ['Mount Left Racks', '0200', '7:00:00 AM', '9:12:00 AM'],
        ['Mount cable motor & Lubricate guide carr', '0201', '9:12:00 AM', '9:44:00 AM'],
        ['Mount suction components', '0202', '9:44:00 AM', '11:04:00 AM'],
        ['Mount extraction', '0203', '11:04:00 AM', '12:34:00 PM'],
        ['Mount temporary diamond plates', '0204', '12:34:00 PM', '1:04:00 PM'],
        ['Mount piping inside', '0205', '1:04:00 PM', '1:44:00 PM'],
        ['Move Machine to next step + EPA', '0206', '1:44:00 PM', '3:30:00 PM']]
df = pd.DataFrame(data=rows, columns=columns)
df.rename(columns={"Earl. start / time": "start", "Latest finish / time": "finish"}, inplace=True)

df['Operation/Activity'] = df['Operation/Activity'].astype(int)
df.sort_values('Operation/Activity', ascending=True, inplace=True, ignore_index=True)

fig, ax = plt.subplots(figsize=(10, 5))

#colors = plt.cm.tab10.colors  # get a list of 10 colors
cmap = plt.cm.get_cmap('plasma_r')
colors = [cmap(i/9) for i in range(10)]   # get a list of 10 colors

previous_start = math.inf  # 'previous_start' helps to indicate we're starting again from the left
color_start = 0
for row in df.itertuples():
    left = timestr_to_num(row.start)
    right = timestr_to_num(row.finish)
    if left <= previous_start:
        color_start = row.Index
    ax.barh(row.Index, left=left, width=right - left, height=1, color=colors[(row.Index - color_start) % len(colors)])
    previous_start = left
ax.set_xlim(timestr_to_num('7:00:00 AM'), timestr_to_num('4:30:00 PM'))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))  # display ticks as hours and minutes
ax.xaxis.set_major_locator(mdates.HourLocator(interval=1))  # set a tick every hour
ax.set_xlabel('Time')
ax.set_ylabel('Operation')
ax.set_ylim(len(df), -1)  # set the limits and reverse the order
ax.set_yticks(range(len(df)))
# ax.set_yticklabels(list(df['Operation/Activity']))
ax.set_yticklabels(list(df['Operation short text']))

now = datetime.now().strftime('%I:%M:%S %p')
ax.axvline(x=timestr_to_num(now),color='r')

plt.tight_layout()
plt.show()

票数 1
EN

Stack Overflow用户

发布于 2020-02-18 22:15:00

我可以使用下面的代码绘制一条垂直线:

代码语言:javascript
复制
now = datetime.now()
now = now.strftime('%I:%M:%S %p')
plt.axvline(x=timestr_to_num(now),color='r')

我基本上将"now“时间转换为特定的格式,然后使用我在开始时定义的timestr_to_num再次转换它。

但是,我仍然需要一些帮助来将辅助值添加到我的y轴值(操作简短文本)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60266460

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档