python で json形式のタスク情報から html形式のガントチャートを作成するプログラムを作ってみました
特に説明はなしです 💦
実際に動かして試してみて楽しんでみてください ('ω')ノシ
ちゃんと動けば、gantt.html が出力されて、ブラウザに読み込ませると下図のようになります (*´ω`*)
ではでは・・・
まずは anaconda 環境に必要なライブラリのインストールする
pip install pandas
pip install plotly
sample.json という名前のタスク情報を記したファイルを作成する
{
"title": "戦国時代(+450年)",
"tasks": [
{
"id": "task1",
"name": "織田信長",
"start": "1984-06-23",
"end": "2032-06-21",
"owner": "織田信長",
"progress": 70,
"summary": "",
"memo": "",
"milestones": []
},
{
"id": "task2",
"name": "豊臣秀吉",
"start": "1987-03-17",
"end": "2048-09-18",
"owner": "豊臣秀吉",
"progress": 40,
"summary": "",
"memo": "",
"milestones": [
{"name": "天下統一", "date": "2040-01-01"}
]
},
{
"id": "task3",
"name": "徳川家康",
"start": "2043-01-31",
"end": "2066-06-01",
"owner": "徳川家康",
"progress": 90,
"summary": "",
"memo": "",
"milestones": [
{"name": "征夷大将軍就任", "date": "2053-01-01"},
{"name": "大坂夏の陣", "date": "2065-01-01"}
]
}
]
}
肝心かなめのプログラムはこちらです
これで動かしてみてください ('ω')ノシimport json
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime
# -----------------------------
# JSON読み込み
# -----------------------------
with open("sample.json", encoding="utf-8") as f:
root = json.load(f)
TITLE = root["title"]
data = root["tasks"]
rows = []
completed_rows = []
remaining_rows = []
milestones = []
# -----------------------------
# データ整形
# -----------------------------
for t in data:
start = pd.to_datetime(t["start"]).normalize()
end = pd.to_datetime(t["end"]).normalize()
duration = end - start
progress_end = (start + duration * (t["progress"] / 100)).normalize()
# hover用情報
rows.append({
"Task": t["name"],
"Start": start,
"Finish": end,
"Owner": t["owner"],
"Summary": t["summary"],
"Memo": t["memo"],
"StartStr": start.strftime("%Y-%m-%d"),
"FinishStr": end.strftime("%Y-%m-%d")
})
# 完了部分
if progress_end > start:
completed_rows.append({
"Task": t["name"],
"Start": start,
"Finish": progress_end
})
# 未完了部分
if progress_end < end:
remaining_rows.append({
"Task": t["name"],
"Start": progress_end,
"Finish": end,
"Owner": t["owner"]
})
# マイルストーン
for ms in t["milestones"]:
ms_date = pd.to_datetime(ms["date"]).normalize()
milestones.append({
"Task": t["name"],
"Date": ms_date,
"Label": f'{ms["name"]}\n{ms_date.strftime("%Y-%m-%d")}'
})
df = pd.DataFrame(rows)
completed_df = pd.DataFrame(completed_rows)
remaining_df = pd.DataFrame(remaining_rows)
ms_df = pd.DataFrame(milestones)
# -----------------------------
# ガント(未完了)
# -----------------------------
fig = px.timeline(
remaining_df,
x_start="Start",
x_end="Finish",
y="Task",
color="Owner",
hover_data=[]
)
fig.update_yaxes(autorange="reversed")
# ★バー枠線なし
fig.update_traces(marker_line_width=0)
# -----------------------------
# hover情報追加
# -----------------------------
for _, r in df.iterrows():
fig.add_trace(go.Scatter(
x=[r["Start"]],
y=[r["Task"]],
mode="markers",
marker=dict(size=0),
showlegend=False,
hovertemplate=
f"<b>{r['Task']}</b><br>"
f"担当: {r['Owner']}<br>"
f"開始: {r['StartStr']}<br>"
f"終了: {r['FinishStr']}<br>"
f"概要: {r['Summary']}<br>"
f"メモ: {r['Memo']}<extra></extra>"
))
# -----------------------------
# 完了バー(グレー)
# -----------------------------
if not completed_df.empty:
fig_completed = px.timeline(
completed_df,
x_start="Start",
x_end="Finish",
y="Task"
)
for trace in fig_completed.data:
trace.marker.color = "lightgray"
trace.marker.line.width = 0
trace.showlegend = False
fig.add_trace(trace)
# -----------------------------
# マイルストーン
# -----------------------------
for _, r in ms_df.iterrows():
fig.add_trace(go.Scatter(
x=[r["Date"]],
y=[r["Task"]],
mode="markers+text",
marker=dict(size=12, color="red", symbol="diamond"),
text=r["Label"],
textposition="top center",
showlegend=False
))
# -----------------------------
# 今日ライン
# -----------------------------
today = pd.to_datetime(datetime.now()).normalize()
fig.add_shape(
type="line",
x0=today,
x1=today,
y0=0,
y1=1,
xref="x",
yref="paper",
line=dict(color="black", width=2, dash="dash")
)
fig.add_annotation(
x=today,
y=1,
xref="x",
yref="paper",
text="Today",
showarrow=False,
yshift=10
)
# -----------------------------
# 軸の日付表示形式
# -----------------------------
fig.update_xaxes(tickformat="%Y-%m-%d")
# -----------------------------
# タイトル
# -----------------------------
fig.update_layout(
title=TITLE,
title_x=0.5
)
# -----------------------------
# 出力
# -----------------------------
fig.write_html("gantt.html")
print("gantt.html を出力しました")
0 件のコメント:
コメントを投稿