Skip to content

Instantly share code, notes, and snippets.

@Cyril-Pop
Last active May 28, 2022 07:45
Show Gist options
  • Save Cyril-Pop/e492a7b75560cb17f323c075e384166a to your computer and use it in GitHub Desktop.
Save Cyril-Pop/e492a7b75560cb17f323c075e384166a to your computer and use it in GitHub Desktop.
import clr
import sys
import re
import System
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS
#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
my_path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments)
reDir = System.IO.DirectoryInfo(re.__file__)
path_py3_lib = reDir.Parent.Parent.FullName
sys.path.append(path_py3_lib + r'\Lib\site-packages')
import pandas as pd
import numpy as np
from typing import Union
import webbrowser
import codecs
from bs4 import BeautifulSoup as bs
class WrapDFrame():
dictUnitValue = {}
def __init__(self, data: Union[DB.ViewSchedule , pd.core.frame.DataFrame]):
self.lstError = []
if isinstance(data, pd.DataFrame):
self._df = data
elif isinstance(data, pd.Series):
self._df = data.to_frame()
else:
self._df = self.__getDF_From_View(data)
#
def __getDF_From_View(self, data):
"""
convert Schedule to DataFrame (private method)
"""
viewschedule = data
outvalue = []
if viewschedule.ViewType == ViewType.PanelSchedule:
tabledata = viewschedule.GetSectionData(SectionType.Body)
else:
tabledata = viewschedule.GetTableData().GetSectionData(SectionType.Body)
#
paraSchNames = []
nbrCol = tabledata.NumberOfColumns
nbrRow = tabledata.NumberOfRows
for r in range(nbrRow):
if r == 0:
for c in range(nbrCol):
paraSchNames.append(viewschedule.GetCellText(SectionType.Body, r, c))
else:
temp = []
unit_header = []
#get values by Rows
for c in range(nbrCol):
unitType = tabledata.GetCellSpec(r,c)
is_unitType = True if len(unitType.TypeId) > 0 else False
#
if tabledata.GetCellType(r,c) == CellType.Text or tabledata.GetCellType(r,c) == CellType.ParameterText:
valueCell = tabledata.GetCellText(r,c)
valueCell, unitstr = self.__to_Float(valueCell) if is_unitType else (valueCell, "")
temp.append(valueCell)
unit_header.append(unitstr)
#
elif tabledata.GetCellType(r,c) == CellType.Parameter:
try:
valueCell = viewschedule.GetParamValue(SectionType.Body, r , c )
valueCell, unitstr = self.__to_Float(valueCell) if is_unitType else (valueCell, "")
temp.append(valueCell)
unit_header.append(unitstr)
except:
valueCell = viewschedule.GetCellText(SectionType.Body, r , c )
valueCell, unitstr = self.__to_Float(valueCell) if is_unitType else (valueCell, "")
temp.append(valueCell)
unit_header.append(unitstr)
#
elif tabledata.GetCellType(r,c) == CellType.CalculatedValue:
valueCell = tabledata.GetCellCalculatedValue(r,c)
valueCell, unitstr = self.__to_Float(valueCell) if is_unitType else (valueCell, "")
temp.append(valueCell)
unit_header.append(unitstr)
if len(temp) >= 1:
# replace empty value by NaN
temp = [x if x != "" else np.nan for x in temp]
outvalue.append(temp)
df = pd.DataFrame(data = outvalue, columns= paraSchNames)
for nameCol, nameUnit in zip(df.columns, unit_header):
self.__class__.dictUnitValue[nameCol] = nameUnit
# remove blank line
df = df.drop(0, axis = 0)
return df
@property
def UnwrapDFrame(self):
"""
return the unwrap Panda DataFrame
"""
return self._df
def Append(self, *args, **kwargs):
"""
method to call the 'append' DataFrame method to concat 2 DataFrames
"""
if isinstance(args[0], WrapDFrame):
# uwrap fist item
args = list(args)
args[0] = args[0].UnwrapDFrame
args = tuple(args)
new_df = self.UnwrapDFrame.append(args, kwargs)
return WrapDFrame(new_df)
def ToHTML(self):
"""
convert DataFrame to Html and open it
"""
filename = my_path + '\\htmlDataFrame.html'
htmlDf = """\
<html>
<head>
<style>
table, th, td {{font-size:10pt; border:1px solid black; border-collapse:collapse; text-align:left;}}
th, td {{padding: 5px;}}
tr:nth-child(even) {{background: #E0E0E0;}}
tr:hover {{background: silver; cursor: pointer;}}
</style>
</head>
<body>
{0}
</body>
</html>
""".format(self.UnwrapDFrame.to_html())
#
# add unit in tooltip with bs4
soup = bs(htmlDf, 'html.parser')
tables = soup.find_all('table')
for table in tables:
rows = table.find_all('tr')
row = rows[0]
cols = row.find_all('th')
for ele in cols:
if ele.string is not None:
unit = self.__class__.dictUnitValue.get(ele.string.strip())
if unit is not None:
print("pass")
try:
ele["title"] = unit
except:
import traceback
self.lstError.append([ele.string, traceback.format_exc()])
htmlDf = soup.prettify()
#
#with open(filename, 'w') as f:
with codecs.open(filename, "w", encoding="utf-8") as f:
f.write( htmlDf)
webbrowser.open_new_tab(filename)
def __to_Float(self, x):
"""
convert value cell to float and get suffix unit
"""
sgA = re.match(r'([+-]?\d*.?\d+)\s(.+)', x)
sgB = re.match(r'([+-]?\d*.?\d+)', x)
if sgA is not None:
return float(sgA.group(1).replace(',','.')), sgA.group(2)
elif sgB is not None:
return float(sgB.group(1).replace(',','.')), ""
else:
return x, ""
OUT = WrapDFrame
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment