🦔

python-ganttのタスクをCSVで定義して編集しやすくした

2021/01/30に公開

概要

python-ganttというパッケージを使うとSVG形式のきれいなガントチャートを作ることができます。
しかしタスクが増えてくると更新が難しくなるためCSV形式でタスクを管理するようにしました。
副次的にタスクを定義する順番を気にする必要が無くなり更新が簡単になったので紹介します。

前提条件

Pythonの実行環境を構築できることを前提としています。

ガントチャートとは

ガントチャートとは横軸に日付、縦軸にタスクを並べ、タスクの実施期間を棒で表現したグラフです。
数多くのタスクからできているプロジェクトの全体像を分かりやすく表示できます。

python-gantt

ガントチャートを書くためにpython-ganttを使います。

Python-Gantt make possible to easily draw gantt charts from Python. Output format is SVG.

まずはサンプルファイルを実行してガントチャートを生成してみましょう。初めにpython-ganttをインストールします。

pip install python-gantt

次に、上記の公式サイトにあるサンプルコードをexample.pyとして保存します。同じ内容のファイル( ("01"の部分だけ"1"に変えています)をpastebinに準備したので次のコマンドでダウンロードできます。

wget -O example.py https://pastebin.com/raw/8GLdmZ7T

example.pyを実行するとガントチャートがSVG形式で書き出されます。

>>> tree .
.
└── example.py
>>> python example.py
>>> tree .
.
├── example.py
├── test.svg
├── test_full.svg
├── test_full2.svg
├── test_p1.svg
├── test_p2.svg
├── test_resources.svg
├── test_weekly.svg
└── tree.txt

タスクをcsv形式にまとめる

タスクが増えてくるとファイルが長くなって更新が難しくなると感じました。
そこでgantt.Task()に渡す引数をCSVファイルに分離して管理することにしました。

例として上記のexample.pyのタスク引数をCSV形式に書き直します。ここで1つのプロジェクトにつき1つのCSVファイルを割り当てることにして、異なるプロジェクトのタスクの間には依存関係が無いものとしました。

example.py
...
# 元々のタスク
t1 = gantt.Task(name='tache1', start=datetime.date(2014, 12, 25), duration=4, percent_done=44, resources=[rANO], color="#FF8080")
t2 = gantt.Task(name='tache2', start=datetime.date(2014, 12, 28), duration=6, resources=[rJLS])
t7 = gantt.Task(name='tache7', start=datetime.date(2014, 12, 28), duration=5, percent_done=50)
t3 = gantt.Task(name='tache3', start=datetime.date(2014, 12, 25), duration=4, depends_of=[t1, t7, t2], resources=[rJLS])
t4 = gantt.Task(name='tache4', start=datetime.date(2015,  1,  1), duration=4, depends_of=t1, resources=[rJLS])
t5 = gantt.Task(name='tache5', start=datetime.date(2014, 12, 23), duration=3)
t6 = gantt.Task(name='tache6', start=datetime.date(2014, 12, 25), duration=4, depends_of=t7, resources=[rANO])
t8 = gantt.Task(name='tache8', start=datetime.date(2014, 12, 25), duration=4, depends_of=t7, resources=[rANO, rJLS])
...

このパラメータを2つのCSV形式に書き直します。

gantt_args1.csv
name,start,depends_of,duration,percent_done,resources,color,id
tache1,2014-12-25,None,4,44,ANO,#FF8080,1
tache2,2014-12-28,None,6,0,JLS,#c70039,2
tache3,2014-12-25,1:2:6,5,50,ANO:JLS,#f37121,3
tache4,2015-01-01,1,4,40,JLS,#c0e218,4
tache6,2014-12-25,6,4,0,ANO:JLS,#f37121,5
tache7,2014-12-28,None,6,0,JLS,#c0e218,6
tache8,today,6,4,0,ANO:JLS,#111d5e,7
gantt_args2.csv
name,start,depends_of,duration,percent_done,resources,color,id
tache5,2014-12-23,None,3,0,ANO:JLS,#f37121,1

このときに困ったのがタスク間の依存関係で、example.pyではdepents_ofに渡すタスクオブジェクトは事前に作成されている必要があります (t3に渡しているt1, t2, t7など)。作成されていなければエラーになって実行できません。

そこでタスクを定義するCSVファイルではidの列を追加してタスクに固有のIDを付けるようにし、depends_ofにはこのIDを指定するようにしました。そしてタスクを定義する順番を決定する関数を作成して依存関係を解決することにしました。

タスクを定義する順番に注意する必要がなくなりタスクの編集が楽になりました。

CSVファイルからgantt.Projectを作成する

さて、上記のCSVファイルを元にgantt.Projectを作成します。これを行うプログラムをPyPIに公開しました(python-gantt-csv)。python-gantt-csvをインストールします。

pip install python-gantt-csv

パッケージのアーカイブファイルの中にサンプルコードとcsvファイルがあるので、ダウンロードして移動します。

wget https://files.pythonhosted.org/packages/65/dd/f7d6500325ec4ebaab956a914b94827b49fe9b32f2dcbbef6e5c8489e7e2/python-gantt-csv-0.2.1.tar.gz
tar -xvf python-gantt-csv-0.2.1.tar.gz
cd python-gantt-csv-0.2.1/example/

example.pyを実行するとガントチャートがSVG形式で書き出されます。

python example.py

test_full.png
CSVから生成したガントチャート

以下の箇所でCSVファイルのパスを受け取ってgantt.Projectを作成しています。

python-gantt-csv/example/example.py
...
from gantt_csv import create_project_from_csv, RESOURCES
...
    p1 = create_project_from_csv(csv_path)
...

CSV形式でのタスク引数の定義方法

値がない場合はNoneと書き、複数ある場合はコロン (:)で分けるように定義しました。
例外としてstart列にtodayと書いた場合は読み込むプログラム側で実行した日付に読み替えます。
こうしておくとtodayを指定したタスクはガントチャートを作成した日始まりになって便利です。

name value
name str
start 'today' or iso format date (Ex: '2014-12-26')
duration int
percent_done int
resources None or str or colon separated str (Ex: 'ANO:JLS')
depends_of 'None' or unique str or colon separated unique str (Ex: '1:2')
color Hex color (Ex: #FF8080)
id unique str

Sublime Textのビルド設定

普段使うときはコマンドをすぐ実行できるようにビルドの設定をしています。

~/.config/sublime-text-3/Packages/User/build_gantt_csv.sublime-build
{
    "shell_cmd": "~/venv/bin/python ~/example.py",
    "file_patterns": ["gantt_tasks*.csv"]
}

Sublime TextでCSVファイルを編集する際のこまごまとした話

Sublime Textを使ってCSVファイルを編集する際の小技を紹介します。

start列はISO形式の日付(例: 2020-12-12)を指定します。日付を入力しやすくするためAPIを定義してます。

~/.config/sublime-text-3/Packages/User/api_today.py
import sublime
import sublime_plugin
from datetime import date

class TodayCommand(sublime_plugin.EventListener):
    def on_query_completions(self, view, prefix, locations):
        return    [
            [ "today\t", str(date.today()) ]
        ]

todayの後にタブキーを押すとISOフォーマットで今日の日付を挿入します。

today↹ -> 2020-12-12

CSVファイルを編集する際にはAdvanced CSVパッケージを使って列を成形すると少し見やすくなります。

スペースを削除して列を最小化: Ctrl+Comma, comma
スペースを追加して列を成形 : Ctrl+Comma, Space

また、Ctrl+Shift+Up/Downで行を移動して、ガントチャートに表示する順番を簡単に変更できます。これもCSV形式にしたメリットの1つです。

まとめ

  1. python-ganttを使うとSVG形式のガントチャートを簡単に生成できる
  2. タスク定義をCSVファイルで行うようにした
  3. Sublime Textのビルドを設定するとタスクの編集からガントチャート生成までが簡単にできて便利

Discussion