ARCHICADBIMPython開発
IFC の情報を Excel に書き出す
2025.05.12
2025.05.12
こんにちは。IU BIM STUDIO 原田です。
今回は IFC モデルの情報を Excel に書き出す方法を紹介します。
IFC モデルには多くの情報が入っており、それを有効活用することが業務効率化につながります。
使いやすい形式に情報を取り出す方法の一例として Excel を使ってみましょう。
今回のモデルは Archicad のサンプルモデルを使用しています。
また、IFC 変換設定を変更し、全てのプロパティを出力するようにしています。
IFC には数多くのタイプがあります。
そのため全てを取り出すと膨大な量になるため、取得したい IFC タイプを決めておきます。
ifc_types = [
"IfcSpace",
"IfcWall",
"IfcColumn",
"IfcBeam",
"IfcSlab",
"IfcRoof",
"IfcFooting",
"IfcDoor",
"IfcWindow",
"IfcCovering",
"IfcBuildingElementProxy",
]
今回は上記の要素を取得します。
前回モデルを IFC タイプから情報を取得する方法を紹介しましたが、今回は別の方法を試してみます。
モデル要素とプロパティはIfcRelDefinedPropertiesという要素で紐付けられています。それから情報を取得して行きます。
import ifcopenshell
model = ifcopenshell.open("sample_model.ifc")
property_relations = model.by_type("IfcRelDefinesByProperties")
では、プロパティのリレーションから情報を取得していきます。
取得したリレーションはモデル要素とそれに紐づくプロパティセットで一つの単位になっています。
この情報の中から必要なものを取得し、整理していきます。
まずモデル要素側の必要な情報として GUID と IFC タイプを取得します。
property_data = []
for relation in property_relations:
object_id = relation.RelatedObjects[0].GlobalId
element_type = relation.RelatedObjects[0].is_a()
次にプロパティセットの名前を取得しておきます。
プロパティは文字列系の属性情報と数値情報に分かれているようなので、それらが存在するかをチェックしておき、別々に内容を取得していきます。
存在チェックをしておかないと、どちらかのプロパティが無かった時にエラーが発生します。
for relation in property_relations:
#中略
property_set_name = relation.RelatingPropertyDefinition.Name
has_properties = hasattr(relation.RelatingPropertyDefinition, "HasProperties")
has_quantities = hasattr(relation.RelatingPropertyDefinition, "Quantities")
これらはプロパティセットの中に配列として入っていますので、for 文で個別に取得していきます。
for relation in property_relations:
#中略
if has_properties:
for property in relation.RelatingPropertyDefinition.HasProperties:
property_name = property.Name
property_value = property.NominalValue.wrappedValue
property_name_merged = property_set_name + "_" + property_name
property_data.append(
(
element_type,
object_id,
property_name_merged,
property_value,
)
)
プロパティ情報を取得し、IFCタイプ、GUID、プロパティ名、プロパティ値をセットにしてリストに保存していきます。
今回はプロパティセット名とプロパティ名はアンダースコアで連結します。
データを扱う際に見出しが2行になると取り扱いが面倒なためです。
次に数値情報を取得していきます。
for relation in property_relations:
#中略
if has_quantities:
for quantity in relation.RelatingPropertyDefinition.Quantities:
property_name = quantity.Name
match quantity.is_a():
case "IfcQuantityLength":
property_value = quantity.LengthValue
case "IfcQuantityArea":
property_value = quantity.AreaValue
case "IfcQuantityVolume":
property_value = quantity.VolumeValue
case "IfcQuantityCount":
property_value = quantity.CountValue
case _:
property_value = None
property_name_merged = property_set_name + "_" + property_name
property_data.append(
(
element_type,
object_id,
property_name_merged,
property_value,
)
)
数値情報の場合、情報の格納場所が違うため条件分岐して取得していきます。
プロパティのデータ型に合わせて条件分岐していきます。
今回は長さ、面積、体積、個数を取得しましたが、他のデータ型があれば状況に応じて増やす必要があります。
IFCからの情報を取得し終えたら、これを整理していきます。
取得したデータを整理するのに pandas を使用します。
pandasはデータの処理や分析をするためのpythonライブラリです。
作成したリストを使ってpandasのデータフレームを作成します。
import pandas as pd
df = pd.DataFrame(property_data, columns=["Type", "ObjectID", "Property", "Value"])
pandas の ExcelWriter を使って、データをExcel形式に書出していきます。
この時に、IFC タイプごとにシートを分けたいので、最初に指定した IFC タイプごとにループで処理します。
pandas で Type 列が指定と合致するものに絞り込み、シートの内容を取得します。
そして、現状は縦持ちのデータになっているため、pandas の pivot 関数で横持ちのデータに変換します。縦持ちというのは先ほど作成したリストのような同じ形式のデータが複数個あるもの、横持ちというのはExcel の表などでよく使う縦と横の交点に値がある形式のデータのことです。
Excelのピボットテーブルの使用前、使用後という感じでしょうか。
そして、ピボットした表を Excel に書き込みます。
file_name = "property_data.xlsx"
with pd.ExcelWriter(file_name) as writer:
for ifc_type in ifc_types:
filtered_df = df[df["Type"] == ifc_type]
df_pivot = filtered_df.pivot(
index="ObjectID", columns="Property", values="Value"
)
df_pivot.to_excel(writer, sheet_name=ifc_type)
GUIDを行、プロパティ名を列、プロパティ値を交点の値とした、横持ちのExcelデータを作成します。
以上で、IFC モデルのプロパティを Excel に書き出せました。
IFC には大量の情報があり、それをうまく使うことが重要です。
ただ、Archicad の場合でいうと ArchiCADProperties にはオブジェクトのパラメータの情報も出力されます。管理していない情報が大量に出力されるとデータとしての信頼性が下がる恐れがあります。
どの情報を管理すべきかを明確にし、きちんと整理された情報を扱う運用が大事なのかなと思います。
今回は以上です。
最後までお読みいただきありがとうございました。
以下にコード全文を載せておきます。
import ifcopenshell
import pandas as pd
ifc_types = [
"IfcSpace",
"IfcWall",
"IfcColumn",
"IfcBeam",
"IfcSlab",
"IfcRoof",
"IfcFooting",
"IfcDoor",
"IfcWindow",
"IfcCovering",
"IfcBuildingElementProxy",
]
def get_property_data(property_relations) -> tuple:
property_data = []
for relation in property_relations:
object_id = relation.RelatedObjects[0].GlobalId
element_type = relation.RelatedObjects[0].is_a()
property_set_name = relation.RelatingPropertyDefinition.Name
has_properties = hasattr(relation.RelatingPropertyDefinition, "HasProperties")
has_quantities = hasattr(relation.RelatingPropertyDefinition, "Quantities")
if has_properties:
for proterty in relation.RelatingPropertyDefinition.HasProperties:
property_name = proterty.Name
property_value = proterty.NominalValue.wrappedValue
property_name_merged = property_set_name + "_" + property_name
property_data.append(
(
element_type,
object_id,
property_name_merged,
property_value,
)
)
if has_quantities:
for quantity in relation.RelatingPropertyDefinition.Quantities:
property_name = quantity.Name
match quantity.is_a():
case "IfcQuantityLength":
property_value = quantity.LengthValue
case "IfcQuantityArea":
property_value = quantity.AreaValue
case "IfcQuantityVolume":
property_value = quantity.VolumeValue
case "IfcQuantityCount":
property_value = quantity.CountValue
case _:
property_value = None
property_name_merged = property_set_name + "_" + property_name
property_data.append(
(
element_type,
object_id,
property_name_merged,
property_value,
)
)
return property_data
def main():
model = ifcopenshell.open("sample_model.ifc")
property_relations = model.by_type("IfcRelDefinesByProperties")
property_data = get_property_data(property_relations)
df = pd.DataFrame(property_data, columns=["Type", "ObjectID", "Property", "Value"])
file_name = "property_data.xlsx"
with pd.ExcelWriter(file_name) as writer:
for ifc_type in ifc_types:
filtered_df = df[df["Type"] == ifc_type]
df_pivot = filtered_df.pivot(
index="ObjectID", columns="Property", values="Value"
)
df_pivot.to_excel(writer, sheet_name=ifc_type)
if __name__ == "__main__":
main()