#!/usr/bin/env python # coding: utf-8 # In[1]: import numpy as np import pandas as pd import regex as re import streamlit as st import pickle import io import simplejson as json import base64 import uuid # In[2]: def decodeIfc(txt): # In regex "\" is hard to manage in Python... I use this workaround txt = txt.replace('\\', 'µµµ') txt = re.sub('µµµX2µµµ([0-9A-F]{4,})+µµµX0µµµ', decodeIfcX2, txt) txt = re.sub('µµµSµµµ(.)', decodeIfcS, txt) txt = re.sub('µµµXµµµ([0-9A-F]{2})', decodeIfcX, txt) txt = txt.replace('µµµ','\\') return txt def decodeIfcX2(match): # X2 encodes characters with multiple of 4 hexadecimal numbers. return ''.join(list(map(lambda x : chr(int(x,16)), re.findall('([0-9A-F]{4})',match.group(1))))) def decodeIfcS(match): return chr(ord(match.group(1))+128) def decodeIfcX(match): # Sometimes, IFC files were made with old Mac... wich use MacRoman encoding. num = int(match.group(1), 16) if (num <= 127) | (num >= 160): return chr(num) else: return bytes.fromhex(match.group(1)).decode("macroman") def convert_unicode_string(row, column_name): return decodeIfc(row[column_name]) def decode_cobie(cobie_df): columns_to_decode = ['Name', 'TypeName', 'Description'] for column_to_decode in columns_to_decode: cobie_df[column_to_decode] = cobie_df.apply( convert_unicode_string, column_name=column_to_decode, axis=1 ) return cobie_df # In[3]: def combine_type_component(cobie_type_df, cobie_component_df): cobie_type_df.rename(columns={ 'Name':'TypeName', 'ExtObject':'TypeExtObject', 'ExtIdentifier':'TypeExtIdentifier', }, inplace=True) cobie_type_component = pd.merge( cobie_component_df[[ 'Name','TypeName', 'Space', 'ExtObject', 'ExtIdentifier', 'SerialNumber', ]], cobie_type_df[[ 'TypeName', 'Category', 'Description', 'Manufacturer', 'ModelNumber', 'TypeExtObject', 'TypeExtIdentifier', ]], on='TypeName', how='left', ) return cobie_type_component # In[4]: def combine_full_component_system(cobie_flat, cobie_system_df): cobie_system_df.rename(columns={ 'Name':'SystemName', 'Description':'SystemDescription', 'Category':'SystemCategory', 'ComponentNames':'Name', }, inplace=True) system_all = cobie_system_df.explode(column='Name') cobie_flat = pd.merge( cobie_flat, system_all[[ 'SystemName', 'SystemDescription', 'SystemCategory', 'Name', ]], on='Name', how='left', ) cobie_flat = cobie_flat[[ 'Name', 'TypeName', 'Description', 'Category', 'SystemName', 'SystemDescription', 'SystemCategory', 'Space', 'ExtObject', 'ExtIdentifier', 'SerialNumber', 'Manufacturer', 'ModelNumber', 'TypeExtObject', 'TypeExtIdentifier', ]] cobie_flat = cobie_flat.drop_duplicates( subset=['ExtIdentifier'], ) return cobie_flat # In[5]: def download_button(object_to_download, download_filename, button_text, pickle_it=False): """ Generates a link to download the given object_to_download. Params: ------ object_to_download: The object to be downloaded. download_filename (str): filename and extension of file. e.g. mydata.csv, some_txt_output.txt download_link_text (str): Text to display for download link. button_text (str): Text to display on download button (e.g. 'click here to download file') pickle_it (bool): If True, pickle file. Returns: ------- (str): the anchor tag to download object_to_download Examples: -------- download_link(your_df, 'YOUR_DF.csv', 'Click to download data!') download_link(your_str, 'YOUR_STRING.txt', 'Click to download text!') """ if pickle_it: try: object_to_download = pickle.dumps(object_to_download) except pickle.PicklingError as e: st.write(e) return None else: if isinstance(object_to_download, bytes): pass elif isinstance(object_to_download, pd.DataFrame): #object_to_download = object_to_download.to_csv(index=False) towrite = io.BytesIO() object_to_download = object_to_download.to_excel( towrite, encoding='utf-8', index=False, header=True, na_rep='' ) towrite.seek(0) # Try JSON encode for everything else else: object_to_download = json.dumps(object_to_download) try: # some strings <-> bytes conversions necessary here b64 = base64.b64encode(object_to_download.encode()).decode() except AttributeError as e: b64 = base64.b64encode(towrite.read()).decode() button_uuid = str(uuid.uuid4()).replace('-', '') button_id = re.sub('\d+', '', button_uuid) custom_css = f""" """ dl_link = custom_css + f'{button_text}

' return dl_link # In[7]: # In[8]: # In[9]: # In[10]: # In[11]: # In[12]: # In[13]: # In[ ]: cobie_file_button = st.text_input("Dropbox link to COBie file", key="cobie_file_button") # In[ ]: if cobie_file_button: cobie_file_path = st.session_state.cobie_file_button if '=0' in cobie_file_path: cobie_file_path = cobie_file_path.replace('=0', '=1') cobie_file = pd.ExcelFile(cobie_file_path) cobie_floor_df = cobie_file.parse(sheet_name = 'Floor', dtype={'ExtIdentifier':str, 'Name':str}) cobie_space_df = cobie_file.parse(sheet_name = 'Space', dtype={'ExtIdentifier':str, 'Name':str}) cobie_type_df = cobie_file.parse(sheet_name = 'Type', dtype={'ExtIdentifier':str, 'Description':str, 'Name':str}) cobie_system_df = cobie_file.parse(sheet_name = 'System', dtype={'ExtIdentifier':str, 'Description':str, 'Name':str}) cobie_component_df = cobie_file.parse(sheet_name = 'Component', dtype={'ExtIdentifier':str, 'Space':str, 'Description':str, 'Name':str}) cobie_type_component = combine_type_component(cobie_type_df, cobie_component_df) cobie_flat = combine_full_component_system(cobie_type_component, cobie_system_df) cobie_flat = decode_cobie(cobie_flat) file_name = 'cobie_flat.xlsx' download_button_str = download_button(cobie_flat, file_name, f'Click here to download {file_name}', pickle_it=False) st.markdown(download_button_str, unsafe_allow_html=True)