Add support for Pandas DataFrames in IfcCSV and clean up function signatures

This commit is contained in:
Dion Moult
2023-06-07 15:59:20 +10:00
parent 02462c1209
commit 2896c23143
2 changed files with 49 additions and 53 deletions
@@ -150,14 +150,9 @@ class ExportIfcCsv(bpy.types.Operator):
selector = ifcopenshell.util.selector.Selector() selector = ifcopenshell.util.selector.Selector()
results = selector.parse(ifc_file, props.ifc_selector) results = selector.parse(ifc_file, props.ifc_selector)
ifc_csv = ifccsv.IfcCsv() ifc_csv = ifccsv.IfcCsv()
ifc_csv.output = self.filepath attributes = [a.name for a in props.csv_attributes]
ifc_csv.attributes = [a.name for a in props.csv_attributes] sep = props.csv_custom_delimiter if props.csv_delimiter == "CUSTOM" else props.csv_delimiter
ifc_csv.selector = selector ifc_csv.export(ifc_file, results, attributes, output=self.filepath, format=args.format, delimiter=sep)
if props.csv_delimiter == "CUSTOM":
ifc_csv.delimiter = props.csv_custom_delimiter
else:
ifc_csv.delimiter = props.csv_delimiter
ifc_csv.export(ifc_file, results)
return {"FINISHED"} return {"FINISHED"}
@@ -182,12 +177,8 @@ class ImportIfcCsv(bpy.types.Operator):
else: else:
ifc_file = ifcopenshell.open(props.csv_ifc_file) ifc_file = ifcopenshell.open(props.csv_ifc_file)
ifc_csv = ifccsv.IfcCsv() ifc_csv = ifccsv.IfcCsv()
ifc_csv.output = self.filepath sep = props.csv_custom_delimiter if props.csv_delimiter == "CUSTOM" else props.csv_delimiter
if props.csv_delimiter == "CUSTOM": ifc_csv.Import(ifc_file, self.filepath, delimiter=sep)
ifc_csv.delimiter = props.csv_custom_delimiter
else:
ifc_csv.delimiter = props.csv_delimiter
ifc_csv.Import(ifc_file)
if not props.should_load_from_memory: if not props.should_load_from_memory:
ifc_file.write(props.csv_ifc_file) ifc_file.write(props.csv_ifc_file)
purge_module_data() purge_module_data()
+44 -39
View File
@@ -42,6 +42,12 @@ except:
pass # No XLSX support pass # No XLSX support
try:
import pandas as pd
except:
pass # No Pandas support
class IfcAttributeSetter: class IfcAttributeSetter:
@staticmethod @staticmethod
def set_element_key(ifc_file, element, key, value): def set_element_key(ifc_file, element, key, value):
@@ -139,15 +145,14 @@ class IfcAttributeSetter:
class IfcCsv: class IfcCsv:
def __init__(self): def __init__(self, output="", delimiter=","):
self.headers = []
self.results = [] self.results = []
self.attributes = [] self.dataframe = None
self.output = ""
self.format = "csv"
self.delimiter = ","
def export(self, ifc_file, elements): def export(self, ifc_file, elements, attributes, output=None, format=None, delimiter=","):
self.ifc_file = ifc_file self.ifc_file = ifc_file
self.results = []
for element in elements: for element in elements:
result = [] result = []
if hasattr(element, "GlobalId"): if hasattr(element, "GlobalId"):
@@ -155,33 +160,35 @@ class IfcCsv:
else: else:
result.append(None) result.append(None)
for index, attribute in enumerate(self.attributes): for index, attribute in enumerate(attributes or []):
if "*" in attribute: if "*" in attribute:
self.attributes.extend(self.get_wildcard_attributes(attribute)) attributes.extend(self.get_wildcard_attributes(attribute))
del self.attributes[index] del attributes[index]
for attribute in self.attributes: for attribute in attributes:
result.append(ifcopenshell.util.selector.get_element_value(element, attribute)) result.append(ifcopenshell.util.selector.get_element_value(element, attribute))
self.results.append(result) self.results.append(result)
self.headers = ["GlobalId"] self.headers = ["GlobalId"]
self.headers.extend(self.attributes) self.headers.extend(attributes or [])
if self.format == "csv": if format == "csv":
self.export_csv() self.export_csv(output, delimiter=delimiter)
elif self.format == "ods": elif format == "ods":
self.export_ods() self.export_ods(output)
elif self.format == "xlsx": elif format == "xlsx":
self.export_xlsx() self.export_xlsx(output)
elif format == "pd":
return self.export_pd()
def export_csv(self): def export_csv(self, output, delimiter=None):
with open(self.output, "w", newline="", encoding="utf-8") as f: with open(output, "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f, delimiter=self.delimiter) writer = csv.writer(f, delimiter=delimiter)
writer.writerow(self.headers) writer.writerow(self.headers)
for row in self.results: for row in self.results:
writer.writerow(row) writer.writerow(row)
def export_ods(self): def export_ods(self, output):
self.doc = OpenDocumentSpreadsheet() self.doc = OpenDocumentSpreadsheet()
self.colours = { self.colours = {
@@ -218,12 +225,12 @@ class IfcCsv:
table.addElement(tr) table.addElement(tr)
self.doc.spreadsheet.addElement(table) self.doc.spreadsheet.addElement(table)
if self.output[-4:].lower() == ".ods": if output[-4:].lower() == ".ods":
self.output = self.output[0:-4] output = output[0:-4]
self.doc.save(self.output, True) self.doc.save(output, True)
def export_xlsx(self): def export_xlsx(self, output):
self.workbook = Workbook(self.output) self.workbook = Workbook(output)
self.colours = { self.colours = {
"h": "dc8774", # Header "h": "dc8774", # Header
@@ -254,6 +261,10 @@ class IfcCsv:
self.workbook.close() self.workbook.close()
def export_pd(self):
self.dataframe = pd.DataFrame(self.results, columns=self.headers)
return self.dataframe
def get_wildcard_attributes(self, attribute): def get_wildcard_attributes(self, attribute):
results = set() results = set()
pset_qto_name = attribute.split(".", 1)[0] pset_qto_name = attribute.split(".", 1)[0]
@@ -266,9 +277,10 @@ class IfcCsv:
results.update([p.Name for p in element.Quantities]) results.update([p.Name for p in element.Quantities])
return ["{}.{}".format(pset_qto_name, n) for n in results] return ["{}.{}".format(pset_qto_name, n) for n in results]
def Import(self, ifc_file): def Import(self, ifc_file, table, delimiter=","):
with open(self.output, newline="", encoding="utf-8") as f: # Currently only supports CSV.
reader = csv.reader(f, delimiter=self.delimiter) with open(table, newline="", encoding="utf-8") as f:
reader = csv.reader(f, delimiter=delimiter)
headers = [] headers = []
for row in reader: for row in reader:
if not headers: if not headers:
@@ -303,18 +315,11 @@ if __name__ == "__main__":
if args.export: if args.export:
ifc_file = ifcopenshell.open(args.ifc) ifc_file = ifcopenshell.open(args.ifc)
selector = ifcopenshell.util.selector.Selector() results = ifcopenshell.util.selector.Selector.parse(ifc_file, args.query)
results = selector.parse(ifc_file, args.query)
ifc_csv = IfcCsv() ifc_csv = IfcCsv()
ifc_csv.output = args.spreadsheet ifc_csv.export(ifc_file, results, args.arguments or [], output=args.spreadsheet, format=args.format)
ifc_csv.format = args.format
ifc_csv.attributes = args.arguments if args.arguments else []
ifc_csv.selector = selector
ifc_csv.export(ifc_file, results)
elif getattr(args, "import"): elif getattr(args, "import"):
ifc_csv = IfcCsv() ifc_csv = IfcCsv()
ifc_csv.output = args.spreadsheet
ifc_csv.format = args.format
ifc_file = ifcopenshell.open(args.ifc) ifc_file = ifcopenshell.open(args.ifc)
ifc_csv.Import(ifc_file) ifc_csv.Import(ifc_file, args.spreadsheet)
ifc_file.write(args.ifc) ifc_file.write(args.ifc)