IU Tips

Archicadの情報からガントチャートを作る

2026.02.02

こんにちは。
IU BIM STUDIOの原田です。
今回は、前回ステップ図作成のために入力したステップ情報を元にガントチャートを作成したいと思います。

前回の内容はこちらを参照してください。

プロパティの設定

今回ガントチャートを作成するにあたり、プロパティを追加しました。
「工程表に出力」という名前で、True/False型にしています。

モデルに入力はされているが工程表には不要という要素をこれであらかじめ除外することができます。
今回は仮設や樹木などの要素は除外に設定しています。

工程表に出力というプロパティを追加したところ

日程情報の入力

前回入力したのはあくまでステップの番号で工程表に入力する日付ではありません。そのため、ステップと日付を紐づけるためのデータが必要になります。

今回はExcelでステップに対応する日付を入力します。

Excelで日付を設定したところ

上記のようにExcelに入力しました。

ステップと開始日、終了日をどのように紐づけるかは、複数の方法があると思います。

・画像のようにステップに対し開始日と終了日を設定する方法
・次のステップの開始日を終了日とする方法
・開始日と作業日数を設定する方法
・そもそもステップ番号ではなく開始日をArchicadに入力する方法
などがあります。

この辺りは情報をどう管理したいかにもよりますし、自分たちに合った方法を選ぶのが良いでしょう。
今回は各ステップ番号に対し開始日と終了日の両方を設定していく方法にします。

ライブラリのインストール

今回はガントチャートを作成するのにPlotlyというライブラリを使用します。
Plotlyは手軽にグラフを作成できるライブラリです。
他にはpandasとarchicadのライブラリを使用します。必要に応じてインストールしてください。

pip install plotly pandas archicad

ライブラリの読込

それではコードを書いていきます。
ライブラリを読み込み、Archicad APIのお決まりのコードを書いておきます。

import pandas as pd
import plotly.express as px
from archicad import ACConnection

conn: ACConnection = ACConnection.connect()
acc = conn.commands
act = conn.types
acu = conn.utilities

Excelデータの読込

次に、Excelに入力した日程を読み込み、各要素に日程を割り当てるための辞書を作成します。
キーはステップの番号で、その下に開始日と終了日を入れておきます。

def create_date_dict(file_path: str) -> dict:
    date_df = pd.read_excel(file_path)
    date_dict = {}
    for _, row in date_df.iterrows():
        date_dict[row["ステップ"]] = {"開始日": row["開始日"], "終了日": row["終了日"]}

    return date_dict

file_path = "工程表.xlsx"
date_dict = create_date_dict(file_path)

この辞書を使ってモデル要素に対して日程を割り当てていきます。

辞書を作成するときにExcel側でステップの番号が重複していると辞書のデータが上書きされますので気を付けましょう。
今回はステップ番号の重複チェックのコードは省略しますが、ヒューマンエラーは必ずあるものなので、必要に応じて作ればよいかと思います。

プロパティ値の取得

ガントチャートを作成するにあたり、必要なプロパティの値を取得します。

def get_property_ids() -> list[act.PropertyId]:
    property_ids = []
    property_ids.append(acu.GetBuiltInPropertyId("General_ElementID"))
    property_ids.append(acu.GetBuiltInPropertyId("General_Type"))
    property_ids.append(acu.GetUserDefinedPropertyId("ステップ", "開始"))
    property_ids.append(acu.GetUserDefinedPropertyId("ステップ", "工程表に出力"))

    return property_ids

property_ids = get_property_ids()
elements = acc.GetAllElements()
property_values_of_elements = acc.GetPropertyValuesOfElements(
    elements, property_ids
)

今回使うのは要素ID、要素タイプ、開始ステップ、工程表に出力の4プロパティを使用します。これらのPropertyIDを取得しリストにしてから、モデル内の全要素を取得しPropertyIDに対応するプロパティの値を取得します。

データの作成

ExcelとArchicadの情報を整理し、工程表に表示するデータを作成します。

def validate_property(property_values_of_element: act.PropertyValuesWrapper) -> bool:
    for property_value in property_values_of_element.propertyValues:
        match property_value.propertyValue.status:
            case "notAvailable":
                return False
            case "normal":
                pass
            case _:
                raise ValueError

    return True

def create_tasks(
    property_values_of_elements: list[act.PropertyValuesWrapper], date_dict: dict
) -> pd.DataFrame:
    tasks = []
    for property_values_of_element in property_values_of_elements:
        property_is_available = validate_property(property_values_of_element)

        if not property_is_available:
            continue

        property_values = property_values_of_element.propertyValues
        to_be_exported = property_values[3].propertyValue.value

        if not to_be_exported:
            continue

        name = property_values[0].propertyValue.value
        type = property_values[1].propertyValue.value
        start_step = property_values[2].propertyValue.value

        start_date = date_dict[start_step]["開始日"]
        finish_date = date_dict[start_step]["終了日"]

        task = [name, start_date, finish_date, type]
        tasks.append(task)

    df = pd.DataFrame(tasks, columns=["Task", "Start", "Finish", "Type"])
    return df

tasks = create_tasks(property_values_of_elements, date_dict)

validate_property関数はプロパティが使用可能かをチェックする関数です。

Archicadの設定でプロパティが使用可能になっていない場合、後のプロパティ値取得時にエラーが発生しますので、先に取得した全てのプロパティが使用可能であることをチェックします。

使用可能でないものがあった場合はスキップします。

今回のモデルではこれでOKでしたが、想定しない要素が来た場合はエラーを発生させるようにしています。

create_tasks関数は個別の工程表の項目(ここではタスクとします)を作成する関数です。各要素に対して情報を整理し、タスクを作成していきます。

まずは先ほどのvalidate_property関数を使い、プロパティが使用可能でないものはスキップします。

次に、「工程表に出力」プロパティの値を取得し、Falseになっているものはスキップします。

不要なものをスキップしたら事前に作成した辞書を使い、ステップ番号から開始日と終了日を取得します。

これらを最終的にpandasのDataFrameにして返します。

工程表の作成

最後に作成したデータから工程表を作成します。

sorted_tasks = tasks.sort_values(
    ["Start", "Type", "Task"], ascending=[True, True, True]
).reset_index(drop=True)

fig = px.timeline(
    sorted_tasks,
    x_start="Start",
    x_end="Finish",
    y="Task",
    color="Type",
    category_orders={"Task": sorted_tasks["Task"]},
)

fig.show()

Plotlyで並び替えもできますが、細かい並び替えはDataFrameの時点でしておく方が楽なようですので、DataFrameを開始日、要素タイプ、要素IDの順で並び替えます。

次に、plotlyのtimelineを使ってガントチャートを作成します。

Pythonを実行するとブラウザが開き、下記のようなガントチャートを作成できます。

表示された工程表

初期状態では数が多いため、タスクの文字は表示されていないものもあります。

工程表を拡大したところ

工程表は拡大することができ、カーソルを合わせることで情報も見ることができます。

柱のみ表示したところ

凡例の部分をクリックすると対応する部分を非表示にできます。ただ、Y軸の要素IDは表示されたままで、バーのサイズ調整などはされません。

Plotlyはユーザーの操作に対応した再描画は難しく、他のライブラリを使う必要があるようです。要素をフィルタして見たい場合などはGUIを作ってDataFrameをフィルタした方が簡単かもしれません。

まとめ

今回はステップ図に使用した番号を元に工程表を作成しました。

今回のケースではExcelの表を使い、ステップ番号から直接ガントチャートを作成しましたが、これは方法の一つにすぎません。

直接表を作らずに一度プロパティに日程を入力することもできます。

その方法に正解はなく、各プロジェクトでどのデータをどう管理したいかという方針の元に決められるべきです。日程の情報を他にも利用したいなら一度プロパティに保存した方がよいでしょう。

プロジェクトによって仕事の仕方が違う以上、唯一の正解はありません。このような事例を参考にしつつ、自分たちはどうしたいか、現状の方法をどう変えれば効率化できるかを考えることがDXにつながります。

いずれにしても、必要な情報を整理し、どう連携させるかが重要です。

今回はステップ図のために入力した番号から工程の日付を作成しました。

レイヤーを使ってステップ図を作った場合、このような情報の連携ができなくなったり、難しくなったりします。レイヤーは工程を管理するための情報ではないからです。

このようなことは従来のワークフローを維持したままBIMソフト上で無理矢理辻褄を合わせることで起きがちです。BIMに適した形に業務を変え、管理すべき情報を適した方式で管理することが重要です。

このような無理矢理なBIMソフトの使い方をしていないか振り返ってみましょう。

ただ、BIMソフトが発展してきたとはいえ、現状の機能ではできないこともまだまだ多いです。そのようなときにプログラミングができるとできることが増えます。最適なデータ管理をするために、業務の変革とプログラミングによる効率化を目指してみましょう。

今回は以上です。

最後までお読みいただきありがとうございました。

以下にコード全文を載せておきます。

import pandas as pd
import plotly.express as px
from archicad import ACConnection

conn: ACConnection = ACConnection.connect()
acc = conn.commands
act = conn.types
acu = conn.utilities


def create_date_dict(file_path: str) -> dict:
    date_df = pd.read_excel(file_path)
    date_dict = {}
    for _, row in date_df.iterrows():
        date_dict[row["ステップ"]] = {"開始日": row["開始日"], "終了日": row["終了日"]}

    return date_dict


def get_property_ids() -> list[act.PropertyId]:
    property_ids = []
    property_ids.append(acu.GetBuiltInPropertyId("General_ElementID"))
    property_ids.append(acu.GetBuiltInPropertyId("General_Type"))
    property_ids.append(acu.GetUserDefinedPropertyId("ステップ", "開始"))
    property_ids.append(acu.GetUserDefinedPropertyId("ステップ", "工程表に出力"))

    return property_ids


def validate_property(property_values_of_element: act.PropertyValuesWrapper) -> bool:
    for property_value in property_values_of_element.propertyValues:
        match property_value.propertyValue.status:
            case "notAvailable":
                return False
            case "normal":
                pass
            case _:
                raise ValueError

    return True


def create_tasks(
    property_values_of_elements: list[act.PropertyValuesWrapper], date_dict: dict
) -> pd.DataFrame:
    tasks = []
    for property_values_of_element in property_values_of_elements:
        property_is_available = validate_property(property_values_of_element)

        if not property_is_available:
            continue

        property_values = property_values_of_element.propertyValues
        to_be_exported = property_values[3].propertyValue.value

        if not to_be_exported:
            continue

        name = property_values[0].propertyValue.value
        type = property_values[1].propertyValue.value
        start_step = property_values[2].propertyValue.value

        start_date = date_dict[start_step]["開始日"]
        finish_date = date_dict[start_step]["終了日"]

        task = [name, start_date, finish_date, type]
        tasks.append(task)

    df = pd.DataFrame(tasks, columns=["Task", "Start", "Finish", "Type"])
    return df


def main():
    file_path = "工程表.xlsx"
    date_dict = create_date_dict(file_path)
    property_ids = get_property_ids()
    elements = acc.GetAllElements()
    property_values_of_elements = acc.GetPropertyValuesOfElements(
        elements, property_ids
    )

    tasks = create_tasks(property_values_of_elements, date_dict)

    sorted_tasks = tasks.sort_values(
        ["Start", "Type", "Task"], ascending=[True, True, True]
    ).reset_index(drop=True)

    fig = px.timeline(
        sorted_tasks,
        x_start="Start",
        x_end="Finish",
        y="Task",
        color="Type",
        category_orders={"Task": sorted_tasks["Task"]},
    )

    fig.show()


if __name__ == "__main__":
    main()