欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用Python画作业调度甘特图

程序员文章站 2022-05-22 12:40:44
...

一、背景

之前研究过遗传算法解决经典作业调度问题柔性作业调度问题,并将调度结果使用matlab画甘特图(用任意多颜色表示任意多工件),还是挺有成就感的。但是使用Matlab画出甘特图后没法很好地整合到如网站等类似生产环境。最近恰好被一个爱好者咨询到了,且自己最近因为工作原因也在学习Python,也就想是否可以通过Python画出优雅的甘特图。还真有类似的解决方案:Matplotlib方案实用代码Python(七)甘特图画法 和 Plotly方案
Gantt Charts in Python

二、方案比较

Matplotlib方案

  • Matplotlib相对比较成熟,文案显示比较优雅,但缺点是没法很好地以时间为单位显示作业调度过程,没法很好地整合到生产环境。

Plotly方案

  • Plotly是也是Python的一个开源库,有单独的甘特图API支持,比较方便。另外,其作业调度的时间显示比较灵活,可以很好整合到生产环境。该类库也有个缺点:原生API没法在作业调度信息上很好地显示作业调度信息,如工件A的第三道工序的耗费时间。幸好,可以通过layout.annotations配置来解决这个问题。

三、实现方案

以柔性作业调度问题用例MK01的最佳调度图

使用Python画作业调度甘特图

未使用annotations进行配置修改画图效果

使用Python画作业调度甘特图

Matlab方案甘特图

使用Python画作业调度甘特图

三、代码清单

import time
import plotly as py
import plotly.figure_factory as ff

# x轴, 对应于画图位置的起始坐标x
# start, time, of, every, task, , //每个工序的开始时间
n_start_time = [0, 0, 2, 6, 0, 0, 3, 4, 10, 13, 4, 3, 10, 6, 12, 4, 5, 6, 14, 7, 9, 9, 16, 7, 11, 14, 15, 12, 16, 17,
                16, 15, 18, 19, 19, 20, 21, 20, 22, 21, 24, 24, 25, 27, 30, 30, 27, 25, 28, 33, 36, 33, 30, 37, 37]
# length, 对应于每个图形在x轴方向的长度
# duration, time, of, every, task, , //每个工序的持续时间
n_duration_time = [6, 2, 1, 6, 4, 3, 1, 6, 3, 3, 2, 1, 2, 1, 2, 1, 1, 3, 2, 2, 6, 2, 1, 4, 4, 2, 6, 6, 1, 2, 1, 4, 6, 1,
                   6, 1, 1, 1, 5, 6, 1, 6, 4, 3, 6, 1, 6, 3, 2, 6, 1, 4, 6, 1, 3]

# y轴, 对应于画图位置的起始坐标y
# bay, id, of, every, task, , ==工序数目,即在哪一行画线
n_bay_start = [1, 5, 5, 1, 2, 4, 5, 5, 4, 4, 3, 0, 5, 2, 5, 0, 0, 3, 5, 0, 3, 0, 5, 2, 2, 0, 3, 1, 0, 5, 4, 2, 1, 0, 5,
               0, 0, 2, 0, 3, 2, 1, 2, 0, 1, 0, 3, 4, 5, 3, 0, 2, 5, 2, 0]

# 工序号,可以根据工序号选择使用哪一种颜色
# n_job_id = [1, 9, 8, 2, 0, 4, 6, 9, 9, 0, 6, 4, 7, 1, 5, 8, 3, 8, 2, 1, 1, 8, 9, 6, 8, 5, 8, 4, 2, 0, 6, 7, 3, 0, 2, 1, 7, 0, 4, 9, 3, 7, 5, 9, 5, 2, 4, 3, 3, 7, 5, 4, 0, 6, 5]
n_job_id = ['B', 'J', 'I', 'C', 'A', 'E', 'G', 'J', 'J', 'A', 'G', 'E', 'H', 'B', 'F', 'I', 'D', 'I', 'C', 'B', 'B',
            'I', 'J', 'G', 'I', 'F', 'I', 'E', 'C', 'A', 'G', 'H', 'D', 'A', 'C', 'B', 'H', 'A', 'E', 'J', 'D', 'H',
            'F', 'J', 'F', 'C', 'E', 'D', 'D', 'H', 'F', 'E', 'A', 'G', 'F']

op = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']

colors = ('rgb(46, 137, 205)',
          'rgb(114, 44, 121)',
          'rgb(198, 47, 105)',
          'rgb(58, 149, 136)',
          'rgb(107, 127, 135)',
          'rgb(46, 180, 50)',
          'rgb(150, 44, 50)',
          'rgb(100, 47, 150)',
          'rgb(58, 100, 180)',
          'rgb(150, 127, 50)')

millis_seconds_per_minutes = 1000 * 60
start_time = time.time() * 1000

job_sumary = {}


# 获取工件对应的第几道工序
def get_op_num(job_num):
    index = job_sumary.get(str(job_num))
    new_index = 1
    if index:
        new_index = index + 1
    job_sumary[str(job_num)] = new_index
    return new_index


def create_draw_defination():
    df = []
    for index in range(len(n_job_id)):
        operation = {}
        # 机器,纵坐标
        operation['Task'] = 'M' + str(n_bay_start.__getitem__(index) + 1)
        operation['Start'] = start_time.__add__(n_start_time.__getitem__(index) * millis_seconds_per_minutes)
        operation['Finish'] = start_time.__add__(
            (n_start_time.__getitem__(index) + n_duration_time.__getitem__(index)) * millis_seconds_per_minutes)
        # 工件,
        job_num = op.index(n_job_id.__getitem__(index)) + 1
        operation['Resource'] = 'J' + str(job_num)
        df.append(operation)
    df.sort(key=lambda x: x["Task"], reverse=True)
    return df


def draw_prepare():
    df = create_draw_defination()
    return ff.create_gantt(df, colors=colors, index_col='Resource',
                           title='mk01的一个最佳调度', show_colorbar=True,
                           group_tasks=True, data=n_duration_time,
                           showgrid_x=True, showgrid_y=True)


def add_annotations(fig):
    y_pos = 0
    for index in range(len(n_job_id)):
        # 机器,纵坐标
        y_pos = n_bay_start.__getitem__(index)

        x_start = start_time.__add__(n_start_time.__getitem__(index) * millis_seconds_per_minutes)
        x_end = start_time.__add__(
            (n_start_time.__getitem__(index) + n_duration_time.__getitem__(index)) * millis_seconds_per_minutes)
        x_pos = (x_end - x_start) / 2 + x_start

        # 工件,
        job_num = op.index(n_job_id.__getitem__(index)) + 1
        text = 'J(' + str(job_num) + "," + str(get_op_num(job_num)) + ")=" + str(n_duration_time.__getitem__(index))
        # text = 'T' + str(job_num) + str(get_op_num(job_num))
        text_font = dict(size=14, color='black')
        fig['layout']['annotations'] += tuple(
            [dict(x=x_pos, y=y_pos, text=text, textangle=-30, showarrow=False, font=text_font)])


def draw_fjssp_gantt():
    fig = draw_prepare()
    add_annotations(fig)
    py.offline.plot(fig, filename='fjssp-gantt-picture')


if __name__ == '__main__':
    draw_fjssp_gantt()

四、相关文档