Checking a checkBox in .docx form with Python using docx module - python

I am attempting to fill out a word document form with Python 2.7's docx module. I can modify text elements just fine but I am having difficulty figuring out how to check a yes or no checkbox.
How do I go about checking one the the checkboxes in the form. I have tried a few different ways but I think it all comes do to me not know how the docx xml is structured when it comes to check boxes.
Am I able to use the Bookmark property to find a specific checkbox and check it as seen in the picture below?
I have uploaded a copy of the test form to Google Drive here.

Ok, so after much frustration I finally figured out how to check a checkbox. There is a element within a checkbox element that signifies if the box is checked. I am essenially able to create that element with the following function.
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
def checkedElement():
elm = OxmlElement('w:checked')
elm.set(qn('w:val'),"true")
return elm
I can find all checkboxes within a table cell with the following function. Since the yes is always the first checkbox in each cell I can set the index for a yes check to 0 and a no check to index 1 and then I can append the checked element within the checkbox element:
def yesNoCheck(yes_no,tableIdx,coords):
print coords, yes_no
if yes_no == 'y':
index = 0
x = doc.tables[tableIdx].cell(coords[0],coords[1])._element.xpath('.//w:checkBox')
x[index].append(checkedElement())
elif yes_no == 'n':
index = 1
x = doc.tables[tableIdx].cell(coords[0],coords[1])._element.xpath('.//w:checkBox')
x[index].append(checkedElement())
else:
print "value was neither yes or no"
pass
here is my full code that I have written so far. I have a bunch of refactoring to do but it works great as of now. There are two tables in my .docx template and dictionary table1 and table2 contain the cell row and column coordinates. This script is used to fill out a required form using data published from ESRI's Survey123.
from docx import Document
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.shared import Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH
import arcpy
import datetime
import os
table1 = {
'BusinessName':[2,3],
'LicenseNumber':[2,14],
'OwnerName':[3,3],
'PhoneNumber':[3,14],
'BusinessAddress':[4,5],
'County':[4,14],
'City':[5,1],
'St':[5,8],
'Zip':[5,15],
'LicenceExpired':[6,1], #CheckBox
'DateExpired':[6,15],
'LicenceRenewal':[7,1], #CheckBox
'NumberDisplayed':[8,1], #CheckBox
'NameAddDisplayed':[10,1], #CheckBox
'VehicleInfoMatches':[12,1], #CheckBox
'DischargeValveCapped':[14,1], #CheckBox
'DischargeValveCapChained':[15,1], #CheckBox
'HoseDisinfectCarried':[16,1], #CheckBox
'VehicleAndTankClean':[17,1], #CheckBox
'FreeOfLeaks':[18,1] #CheckBox
}
table2 = {
'LandApplyWaste':[1,1], #Yes/No CheckBox
'LocationDescriptionAccurate':[6,1], #Yes/No CheckBox
'LocationDescriptionAccDesc':[6,5], #text
'Slope':[7,1], #Yes/No CheckBox
'DistanceNearestResidence':[8,1], #Yes/No CheckBox
'DistanceNearestWell':[9,1], #Yes/No CheckBox
'DistanceNearestStreamLakeEtc':[10,1], #Yes/No CheckBox
'SeptageIncorporated':[11,1], #Yes/No CheckBox
'InjectedIncorporated':[12,3], #Yes/No CheckBox, dependent on the septage incorporated being yes
'SeptageStabilized':[13,1], #Yes/No CheckBox
'HowIsLimeMixed':[14,3], #text dependent on if lime was used
'ConfiningLayerOrGroundwater':[15,1], #Yes/No CheckBox
'ConfiningLayerOrGroundwaterDesc':[16,3], #text
'CropGrown':[17,1], #Yes/No CheckBox
'CropGrownHowVerified':[19,3], #text
'LandAppCompliance':[20,1], #Yes/No CheckBox
'AdditionalComments':[22,3],
'SignDate':[22,13]
}
def checkedElement():
elm = OxmlElement('w:checked')
elm.set(qn('w:val'),"true")
return elm
def yesNoCheck(yes_no,tableIdx,coords):
print coords, yes_no
if yes_no == 'y':
index = 0
x = doc.tables[tableIdx].cell(coords[0],coords[1])._element.xpath('.//w:checkBox')
x[index].append(checkedElement())
elif yes_no == 'n':
index = 1
x = doc.tables[tableIdx].cell(coords[0],coords[1])._element.xpath('.//w:checkBox')
x[index].append(checkedElement())
else:
print "value was neither yes or no"
pass
def disposalMethodCheck(method, locationDec):
vals = {
'WastewaterTreatmentFacility':[20,1],
'LandApplication':[22,1],
'SanitaryLandfill':[24,1],
'SeptageLagoonOrDryingBed':[26,1]
}
if method != None:
row,col = vals[method]
checkBoxElm = doc.tables[0].cell(row,col)._element.xpath('.//w:checkBox')[0]
print "{0} Checked!".format(method)
checkBoxElm.append(checkedElement())
editTxt(locationDec,0,[row,6])
def editTxt(text, tblIdx, coords, alignment = WD_ALIGN_PARAGRAPH.LEFT, bold=True):
print text, coords
field = doc.tables[tblIdx].cell(coords[0],coords[1]).paragraphs[0]
field.text = text
field.alignment = alignment
field.runs[0].font.bold = bold
def addSig(sigJpgPath):
para = doc.tables[1].row_cells(23)[0].paragraphs[0]
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = para.add_run()
run.add_picture(sigJpgPath,width=Inches(1.34),height=Inches(.35))
fc = r"E:\PumperTruckInspectionFeatureClass"
arcpy.MakeFeatureLayer_management (fc, "PumperTruckInspections")
attach = r"PumperTruckInspection__ATTACH" #Where signatures are stored
def rows_as_dicts(cursor):
colnames = cursor.fields
for row in cursor:
yield dict(zip(colnames, row))
def dateString(date):
if date != None:
d = date.strftime('%m/%d/%Y')
return d
else:
print "no date"
return ''
def checkBusName(name):
if name != None:
return name
else:
return 'unknown'
with arcpy.da.SearchCursor(fc, '*') as sc:
for row in rows_as_dicts(sc):
doc = Document(r"path\to\TEMPLATE.docx")
t = datetime.datetime.now().strftime('%Y-%m-%d')
newDocName = checkBusName(row['BusinessName']) + t + '.docx'
editTxt(row['BusinessName'],0,table1['BusinessName'])
editTxt(row['LicenseNumber'],0,table1['LicenseNumber'])
editTxt(row['OwnerName'],0,table1['OwnerName'])
editTxt(row['PhoneNumber'],0,table1['PhoneNumber'])
editTxt(row['BusinessAddress'],0,table1['BusinessAddress'])
editTxt(row['County'],0,table1['County'])
editTxt(row['City'],0,table1['City'])
editTxt(row['St'],0,table1['St'])
editTxt(row['Zip'],0,table1['Zip'])
editTxt(dateString(row['DateExpired']),0,table1['DateExpired'])
yesNoCheck(row['LicenceExpired'],0, table1['LicenceExpired'])
yesNoCheck(row['LicenceRenewal'],0, table1['LicenceRenewal'])
yesNoCheck(row['NumberDisplayed'],0, table1['NumberDisplayed'])
yesNoCheck(row['NameAddDisplayed'],0, table1['NameAddDisplayed'])
yesNoCheck(row['VehicleInfoMatches'],0, table1['VehicleInfoMatches'])
yesNoCheck(row['DischargeValveCapped'],0, table1['DischargeValveCapped'])
yesNoCheck(row['DischargeValveCapChained'],0, table1['DischargeValveCapChained'])
yesNoCheck(row['HoseDisinfectCarried'],0, table1['HoseDisinfectCarried'])
yesNoCheck(row['VehicleAndTankClean'],0, table1['VehicleAndTankClean'])
yesNoCheck(row['FreeOfLeaks'],0, table1['FreeOfLeaks'])
disposalMethodCheck(row['DisposalMethod'],row['DisposalLocation'])
if row['DisposalMethod'] == 'LandApplication':
yesNoCheck(row['LandApplyWaste'],1,table2['LandApplyWaste'])
yesNoCheck(row['LocationDescriptionAccurate'],1,table2['LocationDescriptionAccurate'])
editTxt(row['LocationDescriptionAccDesc'],1,table2['LocationDescriptionAccDesc'])
yesNoCheck(row['Slope'],1,table2['Slope'])
yesNoCheck(row['DistanceNearestResidence'],1,table2['DistanceNearestResidence'])
yesNoCheck(row['DistanceNearestWell'],1,table2['DistanceNearestWell'])
yesNoCheck(row['DistanceNearestStreamLakeEtc'],1,table2['DistanceNearestStreamLakeEtc'])
yesNoCheck(row['SeptageIncorporated'],1,table2['SeptageIncorporated'])
yesNoCheck(row['InjectedIncorporated'],1,table2['InjectedIncorporated']) #might need a new method since its not yes/no
yesNoCheck(row['SeptageStabilized'],1,table2['SeptageStabilized'])
editTxt(row['HowIsLimeMixed'],1,table2['HowIsLimeMixed'])
yesNoCheck(row['ConfiningLayerOrGroundwater'],1,table2['ConfiningLayerOrGroundwater'])
editTxt(row['ConfiningLayerOrGroundwaterDescript'],1,table2['ConfiningLayerOrGroundwaterDescript'])
yesNoCheck(row['CropGrown'],1,table2['CropGrown'])
editTxt(row['CropGrownHowVerified'],1,table2['CropGrownHowVerified'])
yesNoCheck(row['LandAppCompliance'],1,table2['LandAppCompliance'])
editTxt(row['AdditionalComments'],1,table2['AdditionalComments'],bold=False)
where = "REL_GLOBALID = '{0}'".format(row['GlobalID'])
from pprint import pprint
with arcpy.da.SearchCursor(attach,['DATA', 'ATT_NAME', 'ATTACHMENTID'],where_clause=where) as cursor:
for r in rows_as_dicts(cursor):
pprint(r)
name = r['ATT_NAME']
attachment = r['DATA']
if name.split('_')[0] == 'InspectorSignature':
imagePath = os.path.join(name.split('_')[0] + "_" + )
open(("sig.jpeg"), 'wb').write(attachment.tobytes())
addSig("sig.jpeg")
break
editTxt(dateString(row['SignDate']),1,table2['SignDate'],alignment = WD_ALIGN_PARAGRAPH.CENTER,bold=False)
doc.save(newDocName)
del doc

I just created a checked checkbox in word and then recreated the xml codes. Compiled the whole in a function, you just have to pass the paragraph as an argument.
import docx
from docx import Document
from docx.shared import Inches
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
def addCheckedbox(para, box_id, name):
run = para.add_run()
tag = run._r
start = docx.oxml.shared.OxmlElement('w:bookmarkStart')
start.set(docx.oxml.ns.qn('w:id'), str(box_id - 1))
start.set(docx.oxml.ns.qn('w:name'), "_GoBack")
run2 = para.add_run()
tag2 = run2._r
fld = docx.oxml.shared.OxmlElement('w:fldChar')
fld.set(docx.oxml.ns.qn('w:fldCharType'), 'begin')
checker = docx.oxml.shared.OxmlElement('w:checkBox')
sizer = docx.oxml.shared.OxmlElement('w:sizeAuto')
checkValue = docx.oxml.shared.OxmlElement('w:default')
checkValue.set(docx.oxml.ns.qn('w:val'), '1')
checker.append(sizer)
checker.append(checkValue)
start.append(checker)
tag.append(start)
run3 = para.add_run()
tag3 = run3._r
instr = docx.oxml.OxmlElement('w:instrText')
instr.text = 'FORMCHECKBOX'
tag3.append(instr)
run4 = para.add_run()
tag4 = run4._r
fld2 = docx.oxml.shared.OxmlElement('w:fldChar')
fld2.set(docx.oxml.ns.qn('w:fldCharType'), 'end')
tag4.append(fld2)
run5 = para.add_run()
tag5 = run5._r
end = docx.oxml.shared.OxmlElement('w:bookmarkEnd')
end.set(docx.oxml.ns.qn('w:id'), str(box_id))
end.set(docx.oxml.ns.qn('w:name'), name)
tag5.append(end)
return

Related

Python tkinter widget tksheet problem with printing cell values

I'm trying to print the value from a selected cell into the sheet widget, but every time it returns 'No cell is selected'. Here is the code snippet:
import tkinter as tk
import sqlite3
import tksheet
top = tk.Tk()
sheet = tksheet.Sheet(top, width=943)
sheet.place(relx = 0.0, rely = 0.1)
conn = sqlite3.connect('dbz/data.db')
c = conn.cursor()
c.execute('''SELECT * FROM table''')
rows = c.fetchall()
data = rows
sheet.set_sheet_data(data = data)
sheet.enable_bindings(("single_select",
"column_select",
"row_select",
"column_width_resize",
"row_height_resize",
"arrowkeys",
"right_click_popup_menu",
"rc_select",
"rc_insert_row",
"rc_delete_row",
"copy",
"cut",
"paste",
"delete",
"undo",
"edit_cell",
"drag_select"))
selected_cells = sheet.get_selected_cells()
def pr(e):
# If there is a selected cell, get the data for it
if selected_cells:
#row, column = selected_cells[0]
value = sheet.get_cell_data(r=row, c=column, return_copy=True)
print(value)
else:
print("No cell is selected")
sheet.bind("<1>", pr)
#sheet.bind("cell_update", update_record)
top.mainloop()
I tried most of the things I found in the documentation: https://github.com/ragardner/tksheet/wiki
get_sheet_data(return_copy = False, get_header = False, get_index = False)
get_cell_data(r, c, return_copy = True)
, etc. But nothing seems to work. I would very much appreciate any help. Thanks in advance.
this should work like you want.
Firstly, you need to identify which row and column was clicked. Really useful to get this information with sheet.identify_row and sheet.identify_column.
With sheet.cell_selected we can be sure that cell was actually clicked.
At the end, I've changed sheet.bind("<1>", pr) to sheet.bind("<ButtonPress-1>", pr).
def pr(event):
row = sheet.identify_row(event, exclude_index = False, allow_end = True)
column = sheet.identify_column(event, exclude_header = False, allow_end = True)
# If there is a selected cell, get the data for it
if sheet.cell_selected(row, column):
value = sheet.get_cell_data(row, column, return_copy = True)
print(value)
else:
print("No cell is selected")
sheet.bind("<ButtonPress-1>", pr)

How to stop streamlit to reseting after using .radio?

I have this code(A sample of a larger one).
import streamlit as st
from PIL import Image
import datetime as dt
from streamlit_option_menu import option_menu
img_16 = Image.open("PATH/81.png")
with st.container():
st.write("---")
left_column, middle_column, right_column = st.columns(3)
with left_column:
st.subheader(16)
st.image(img_16)
if st.button("Click me ⤵️",key=16):
st.write("""
Team: ABC\n
""" )
st.write("---")
condition_now = st.radio(label = "Have a live 🎤",options = ["ichi", "ni", "san"])
st.write('<style>div.row-widget.stRadio > div{flex-direction:row;}</style>', unsafe_allow_html=True)
if condition_now == "ichi":
st.write("ichi da!")
elif condition_now == "ni":
st.write("ni da!")
else:
st.write("san?")
After clicking the "click me" button
I want to choose one one the radio buttons, yet when I click on any radio button all will dissapear or get rest. How can I stop resetting?
The st.session_stat could be the key, but couldn't figure how.
adding st.button() to form is not supported, and st.button() has ephemeral
True states which are only valid for a single run.
Here you need to capture and save status of both button and Radio. Here is the code I tired and its not resetting radios
import streamlit as st
from PIL import Image
if 'bt_clkd' not in st.session_state:
st.session_state.bt_clkd = ''
if 'rd_clkd' not in st.session_state:
st.session_state.rd_clkd='film'
img_16 = Image.open("sampleImage.png")
with st.container():
st.write("---")
left_column, middle_column, right_column = st.columns([3,2,2],gap='small')
with left_column:
st.subheader(16)
st.image(img_16)
# n = st.session_state.bt
b = st.button("Click me ⤵️")
# b = st.button('ckick me',key='a')
if (b) or (st.session_state.bt_clkd== 'y'):
rd = st.radio('select choice',options=['film','surfing','reading'],key='rdkey',index=0,horizontal=True)
st.session_state.bt_clkd = 'y'
if (st.session_state.bt_clkd=='y') and (rd =='film'):
st.session_state.rd_clkd = 'film'
st.write('film!!')
elif (st.session_state.bt_clkd=='y') and (rd=='surfing'):
st.session_state.rd_clkd = 'surfing'
st.write('surfing!!')
else:
st.session_state.rd_clkd = 'reading'
st.write('reading!')

How to set print() to a docx python

I have a code, that get selenium information and i need to print this information to the docx, but by template. Here i get information with help of print() (to set some part )
Stuyvesant High School
General Information
School Name:
Stuyvesant High School
Principal:
Mr. Eric Contreras
Principal’s E-mail:
ECONTRE#SCHOOLS.NYC.GOV
Type:
Regular school
Grade Span:
9-12
Address:
345 Chambers Street, New York, NY 10282
I printing this information in console, but i need print this information to the docx.
Here the part of code, where i print:
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
import openpyxl
import docx
from docx.shared import Pt
List = []
wb = openpyxl.load_workbook('D:\INSPR\Rating_100_schools\Top-100.xlsx')
sheet = wb['RI']
tuple(sheet['A1':'A100']) # Get all cells from A1 to A100.
for rowOfCellObjects in sheet['A1':'A100']:
for cellObj in rowOfCellObjects:
List.append(cellObj.value)
School_list_result = []
State = sheet.title
driver = webdriver.Chrome(executable_path='D:\chromedriver') #any path
def check_xpath(xpath):
try:
element = driver.find_element_by_xpath(xpath)
School_list_result.append(element.text)
except NoSuchElementException:
School_list_result.append("No data.")
def check_text(partial_link_text):
try:
element_text = driver.find_element_by_partial_link_text(partial_link_text)
School_list_result.append(element_text.get_attribute("href"))
except NoSuchElementException:
School_list_result.append("No data.")
def check_click(clicker):
try:
element_click = driver.find_element_by_partial_link_text(clicker)
element_click.click()
except NoSuchElementException:
print("No click.")
def get_url(url, _xpath, send_keys):
driver.get(url)
try:
_element = driver.find_element_by_xpath(_xpath)
_element.clear()
driver.implicitly_wait(10)
_element.send_keys(schools, send_keys)
_element.send_keys(u'\ue007')
driver.implicitly_wait(10)
except NoSuchElementException:
print("No data.")
for schools in List[98:100]:
#-----------------------------------------GREAT SCHOOLS-------------------------------------------
get_url("https://www.google.com/", '//*[#id="tsf"]/div[2]/div[1]/div[1]/div/div[2]/input'," " + State + " greatschools")
_clicker = driver.find_element_by_xpath('//*[#id="rso"]/div[1]/div/div[1]/a/h3').click()
check_xpath('//*[#id="hero"]/div/div[1]/h1') #School Name
check_xpath('/html/body/div[6]/div[8]/div/div[1]/div/div/div[2]/div[1]/div[2]/span[1]') #Principal
check_text('Principal email') #Principal’s E-mail
check_xpath('//*[#id="hero"]/div/div[2]/div[2]/div[3]/div[2]') #Grade Span
check_xpath('//*[#id="hero"]/div/div[2]/div[1]/div[1]/div[1]/div[1]/a/div/span[2]') #Address
check_xpath('/html/body/div[6]/div[8]/div/div[1]/div/div/div[2]/div[2]/span/a') #Phone
check_text('Website') #Website
check_xpath('//*[#id="hero"]/div/div[2]/div[1]/div[1]/div[1]/div[2]/a') #Associations/Communities
check_xpath('//*[#id="hero"]/div/div[2]/div[2]/div[1]/div/a/div[1]/div') #GreatSchools Rating
check_xpath('//*[#id="Students"]/div/div[2]/div[1]/div[2]') #Enrollment by Race/Ethnicity
#-----------------------------------------NCES-------------------------------------------
driver.implicitly_wait(10)
get_url("https://nces.ed.gov/search/index.asp?q=&btnG=Search#gsc.tab=0", '//*[#id="qt"]', " " + State)
check_click('Search for Public Schools - ')
driver.implicitly_wait(10)
check_xpath('/html/body/div[1]/div[3]/table/tbody/tr[4]/td/table/tbody/tr[7]/td[1]/font[2]') #School type
check_xpath('/html/body/div[1]/div[3]/table/tbody/tr[4]/td/table/tbody/tr[7]/td[3]/font') #Charter
check_xpath('/html/body/div[1]/div[3]/table/tbody/tr[12]/td/table/tbody/tr[3]/td/table/tbody/tr[2]/td/table/tbody')
#Enrollment by Gender
check_xpath('/html/body/div[1]/div[3]/table/tbody/tr[12]/td/table/tbody/tr[1]/td/table/tbody/tr[2]') #Enrollment by Grade
#-----------------------------------------USNEWS-------------------------------------------
driver.implicitly_wait(10)
url = "https://www.usnews.com/education/best-high-schools/new-york/rankings"
driver.get(url)
check_click(schools)
driver.implicitly_wait(10)
check_xpath('//*[#id="app"]/div/div/div/div[1]/div/div/div[2]/div[1]/div[2]/p[3]') #U.S.News Rankings
#-----------------------------------------PUBLIC REVIEW-------------------------------------------
driver.implicitly_wait(10)
get_url("https://www.google.com/", '//*[#id="tsf"]/div[2]/div[1]/div[1]/div/div[2]/input', " " + State + " publicschoolreview")
clicker = driver.find_element_by_partial_link_text('(2020)').click()
driver.implicitly_wait(10)
check_xpath('//*[#id="quick_stats"]/div/div[2]/ul/li[2]/strong') #Total # Students
check_xpath('//*[#id="total_teachers_data_row"]/td[2]') #Full-Time Teachers
check_xpath('//*[#id="quick_stats"]/div/div[2]/ul/li[3]/strong') #Student/Teacher Ratio
#-----------------------------------------PRINT INFOFMATION-------------------------------------------
print(" ---------------------------------------------------------------"+"\n",
" \033[1m", schools,"\033[0m"+"\n",
" ---------------------------------------------------------------"+"\n",
" \033[1mGeneral Information\033[0m "+"\n",
"\033[1mSchool Name:\n\033[0m",School_list_result[0]+"\n",
"\033[1mPrincipal:\n\033[0m",School_list_result[1]+"\n",
"\033[1mPrincipal’s E-mail:\n\033[0m",School_list_result[2]+"\n",
"\033[1mType:\n\033[0m",School_list_result[10]+"\n",
"\033[1mGrade Span:\n\033[0m",School_list_result[3]+"\n",
"\033[1mAddress:\n\033[0m",School_list_result[4]+"\n",
"\033[1mPhone:\n\033[0m",School_list_result[5]+"\n",
"\033[1mWebsite:\n\033[0m",School_list_result[6]+"\n",
"\033[1mAssociations/Communities:\n\033[0m",School_list_result[7]+"\n",
"\033[1mGreatSchools Summary Rating:\n\033[0m",School_list_result[8]+"\n",
"\033[1mU.S.News Rankings:\n\033[0m",School_list_result[14]+"\n",
" \033[1mSchool Details\033[0m"+"\n",
"\033[1mTotal # Students:\n\033[0m",School_list_result[15]+"\n",
"\033[1mFull-Time Teachers:\n\033[0m",School_list_result[16]+"\n",
"\033[1mStudent/Teacher Ratio:\n\033[0m",School_list_result[17]+"\n",
"\033[1mCharter:\n\033[0m",School_list_result[11]+"\n",
"\033[1mMagnet: \n\033[0m","No""\n",
" \033[1mEnrollment Data\033[0m"+"\n",
"\033[1mEnrollment by Race/Ethnicity: \n\033[0m",School_list_result[9]+"\n",
"\033[1mEnrollment by Gender: \n\033[0m",School_list_result[12]+"\n",
"\033[1mEnrollment by Grade: \n\033[0m",School_list_result[13]+"\n",
()
)
print()
School_list_result.clear()
What i need: print this result not into console by template, but into a docx by template.
And one more: if you know how to not using indexing (like: School_list_result[0]), please tell me.
I assume you are on a windows operating system just as I do, and know how to download python packages:
Install docx and python-docx modules (they are different, make sure you have installed both)
use the following code:
School_list_result = [
"Stuyvesant High School",
"Mr. Eric Contreras",
"ECONTRE#SCHOOLS.NYC.GOV",
"Regular school",
"9-12",
"345 Chambers Street, New York, NY 10282",
]
headers = [
"School Name: ",
"Principal: ",
"Principal's Email: ",
"Type: ",
"Grade Span: ",
"Address: ",
]
def print_into_one_doc():
import os
from docx import Document
from docx.shared import RGBColor
from docx.shared import Pt
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
# after you create a docx file, make sure you double click to open it, write some stuff, press ctrl + s, delete what you have written, press ctrl + s, close the document
# delete what you have written. Otherwise python-docx reports a Package Not Find Error.
p = input('hold shift key right click, copy and paste the file path of docx here: ')
if p[0] == '"' or p[0] == "'":
# validate path
p = p[1:-1]
p = os.path.abspath(p)
doc = Document(p)
h = doc.add_paragraph()
# make title align to center
h.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
r = h.add_run(School_list_result[0])
# set title color
r.font.color.rgb = RGBColor(54, 95, 145)
# set title size
r.font.size = Pt(36)
doc.add_paragraph('\n')
su = doc.add_paragraph()
ru = su.add_run('General Information')
ru.font.size = Pt(30)
for i, d in enumerate(headers):
sp = doc.add_paragraph()
rp = sp.add_run(headers[i])
rp.bold = True
rp.font.size = Pt(23)
sm = doc.add_paragraph()
rm = sm.add_run(School_list_result[i])
rm.font.size = Pt(22)
rm.italic = True
doc.add_page_break()
doc.save(p)
print_into_one_doc()
If you have a list, which contains School_list_result, iterate it through, here is an example:
List_of_school_list_result = [
[
"Stuyvesant High School",
"Mr. Eric Contreras",
"ECONTRE#SCHOOLS.NYC.GOV",
"Regular school",
"9-12",
"345 Chambers Street, New York, NY 10282",
],
[
"Great Lake College",
"Mr. Jason Madunic",
"MADUNIC#SCHOOLS.VIC.GOV",
"Public school",
"6-12",
"167A High Street, Melbourne, VIC 3228",
],
]
headers = [
"School Name: ",
"Principal: ",
"Principal's Email: ",
"Type: ",
"Grade Span: ",
"Address: ",
]
def print_all_into_one_doc():
import os
from docx import Document
from docx.shared import RGBColor
from docx.shared import Pt
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
# after you create a new docx file, double click to open it, write some stuff, press ctrl + s, delete what you have written, press ctrl + s, close the document
# Otherwise python-docx reports a Package Note Find Error.
p = input('hold shift key right click, copy and paste the file path of docx here: ')
if p[0] == '"' or p[0] == "'":
# validate path
p = p[1:-1]
p = os.path.abspath(p)
doc = Document(p)
# iterate List of all school
for j in List_of_school_list_result:
h = doc.add_paragraph()
# make title align to center
h.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
r = h.add_run(j[0])
# set title color: you can adjust any color of title here
r.font.color.rgb = RGBColor(54, 95, 145)
# set title size
r.font.size = Pt(36)
doc.add_paragraph('\n')
su = doc.add_paragraph()
ru = su.add_run('General Information')
ru.font.size = Pt(30)
for i, d in enumerate(headers):
sp = doc.add_paragraph()
rp = sp.add_run(headers[i])
rp.bold = True
rp.font.size = Pt(23)
sm = doc.add_paragraph()
rm = sm.add_run(j[i])
rm.font.size = Pt(22)
rm.italic = True
doc.add_page_break()
doc.save(p)
print_all_into_one_doc()
Let's make it simple, what you need to do is:
create a list named List_of_school_list_result, dump your data in, each of them should be one single record of a certain school.
in any location, create a new docx file, double click to open it, write some stuff, press ctrl + s, delete what you have written, press ctrl + s, close the document.
go to the directory where your docx file is, hold on shift, right click, copy as path.
make sure docx and python-docx are installed, run the code, when you are asked to input the path, paste it in from your clipboard. (Please make sure you use an absolute path, which is a full directory with root c, a relative path may not work).
PS: the reason that you have to open the docx file after create, is that Microsoft Word 2005+ docx file have 3 modes. first, if it's brand new after creation, it's in binary format. second, if we open it to edit, it generates a $cache.docx file as hidden into same level directory to ensure performance and secure data just in case of crash. third, if it's edited and saved, the format will be turned into XML, which is EDITABLE using python-docx module.
PS: the Result class below provides a clear way for creating List_of_school_list_result:
class Result:
def __init__(self, length):
self.l = length
self.res = []
self.col = []
def push(self, string):
self.col.append(string)
if(len(self.col) == self.l):
self.res.append(self.col)
self.col = []
def publish(self):
return self.res
r = Result(6) # pass in the length of the headers, then all you need, is to call `r.push()` over and over again. after that, assign it to `List_of_school_list_result`
r.push('school name 1')
r.push('principal name 1')
r.push('principal email 1')
r.push('school type 1')
r.push('grad span 1')
r.push('address 1')
r.push('school name 2')
r.push('principal name 2')
r.push('principal email 2')
r.push('school type 2')
r.push('grad span 2')
r.push('address 2')
List_of_school_list_result = r.publish()
Complete version of code:
headers = [
"School Name: ",
"Principal: ",
"Principal's Email: ",
"Type: ",
"Grade Span: ",
"Address: ",
]
class Result:
def __init__(self, length):
self.l = length
self.res = []
self.col = []
def push(self, string):
self.col.append(string)
if(len(self.col) == self.l):
self.res.append(self.col)
self.col = []
def publish(self):
return self.res
r = Result(len(headers))
# call r.push() over and over again, until all the string data is passed in.
''' for example
r.push('school name 1')
r.push('principal name 1')
r.push('principal email 1')
r.push('school type 1')
r.push('grad span 1')
r.push('address 1')
r.push('school name 2')
r.push('principal name 2')
r.push('principal email 2')
r.push('school type 2')
r.push('grad span 2')
r.push('address 2')
'''
List_of_school_list_result = r.publish()
def print_all_into_one_doc():
import os
from docx import Document
from docx.shared import RGBColor
from docx.shared import Pt
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
# after you create a new docx file, double click to open it, write some stuff, press ctrl + s, delete what you have written, press ctrl + s, close the document
# Otherwise python-docx reports a Package Note Find Error.
p = input('hold shift key right click, copy and paste the file path of docx here: ')
if p[0] == '"' or p[0] == "'":
# validate path
p = p[1:-1]
p = os.path.abspath(p)
doc = Document(p)
# iterate List of all school
for j in List_of_school_list_result:
h = doc.add_paragraph()
# make title align to center
h.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
r = h.add_run(j[0])
# set title color: you can adjust any color of title here
r.font.color.rgb = RGBColor(54, 95, 145)
# set title size
r.font.size = Pt(36)
doc.add_paragraph('\n')
su = doc.add_paragraph()
ru = su.add_run('General Information')
ru.font.size = Pt(30)
for i, d in enumerate(headers):
sp = doc.add_paragraph()
rp = sp.add_run(headers[i])
rp.bold = True
rp.font.size = Pt(23)
sm = doc.add_paragraph()
rm = sm.add_run(j[i])
rm.font.size = Pt(22)
rm.italic = True
doc.add_page_break()
doc.save(p)
print_all_into_one_doc()

Python-PPTX: Changing table style or adding borders to cells

I've started putting together some code to take Pandas data and put it into a PowerPoint slide. The template I'm using defaults to Medium Style 2 - Accent 1 which would be fine as changing the font and background are fairly easy, but there doesn't appear to be an implemented portion to python-pptx that allows for changing cell borders. Below is my code, open to any solution. (Altering the XML or changing the template default to populate a better style would be good options for me, but haven't found good documentation on how to do either). Medium Style 4 would be ideal for me as it has exactly the borders I'm looking for.
import pandas
import numpy
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
#Template Location
tmplLoc = 'C:/Desktop/'
#Read in Template
prs = Presentation(tmplLoc+'Template.pptx')
#Import data as Pandas Dataframe - dummy data for now
df = pandas.DataFrame(numpy.random.randn(10,10),columns=list('ABCDEFGHIJ'))
#Determine Table Header
header = list(df.columns.values)
#Determine rows and columns
in_rows = df.shape[0]
in_cols = df.shape[1]
#Insert table from C1 template
slide_layout = prs.slide_layouts[11]
slide = prs.slides.add_slide(slide_layout)
#Set slide title
title_placeholder = slide.shapes.title
title_placeholder.text = "Slide Title"
#Augment placeholder to be a table
placeholder = slide.placeholders[1]
graphic_frame = placeholder.insert_table(rows = in_rows+1, cols = in_cols)
table = graphic_frame.table
#table.apply_style = 'MediumStyle4'
#table.apply_style = 'D7AC3CCA-C797-4891-BE02-D94E43425B78'
#Set column widths
table.columns[0].width = Inches(2.23)
table.columns[1].width = Inches(0.9)
table.columns[2].width = Inches(0.6)
table.columns[3].width = Inches(2)
table.columns[4].width = Inches(0.6)
table.columns[5].width = Inches(0.6)
table.columns[6].width = Inches(0.6)
table.columns[7].width = Inches(0.6)
table.columns[8].width = Inches(0.6)
table.columns[9].width = Inches(0.6)
#total_width = 2.23+0.9+0.6+2+0.6*6
#Insert data into table
for rows in xrange(in_rows+1):
for cols in xrange(in_cols):
#Write column titles
if rows == 0:
table.cell(rows, cols).text = header[cols]
table.cell(rows, cols).text_frame.paragraphs[0].font.size=Pt(14)
table.cell(rows, cols).text_frame.paragraphs[0].font.color.rgb = RGBColor(255, 255, 255)
table.cell(rows, cols).fill.solid()
table.cell(rows, cols).fill.fore_color.rgb=RGBColor(0, 58, 111)
#Write rest of table entries
else:
table.cell(rows, cols).text = str("{0:.2f}".format(df.iloc[rows-1,cols]))
table.cell(rows, cols).text_frame.paragraphs[0].font.size=Pt(10)
table.cell(rows, cols).text_frame.paragraphs[0].font.color.rgb = RGBColor(0, 0, 0)
table.cell(rows, cols).fill.solid()
table.cell(rows, cols).fill.fore_color.rgb=RGBColor(255, 255, 255)
#Write Table to File
prs.save('C:/Desktop/test.pptx')
Maybe not really clean code but allowed me to adjust all borders of all cells in a table:
from pptx.oxml.xmlchemy import OxmlElement
def SubElement(parent, tagname, **kwargs):
element = OxmlElement(tagname)
element.attrib.update(kwargs)
parent.append(element)
return element
def _set_cell_border(cell, border_color="000000", border_width='12700'):
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
for lines in ['a:lnL','a:lnR','a:lnT','a:lnB']:
ln = SubElement(tcPr, lines, w=border_width, cap='flat', cmpd='sng', algn='ctr')
solidFill = SubElement(ln, 'a:solidFill')
srgbClr = SubElement(solidFill, 'a:srgbClr', val=border_color)
prstDash = SubElement(ln, 'a:prstDash', val='solid')
round_ = SubElement(ln, 'a:round')
headEnd = SubElement(ln, 'a:headEnd', type='none', w='med', len='med')
tailEnd = SubElement(ln, 'a:tailEnd', type='none', w='med', len='med')
Based on this post: https://groups.google.com/forum/#!topic/python-pptx/UTkdemIZICw
In case someone else comes across this issue again, some changes should be made to the solution posted by JuuLes87 to avoid that Microsoft Office PowerPoint requires to repair the generated presentation.
After carefully inspecting the xml string of the table generated by pptx, I found that the requirement to repair the presentation seemed to be due to the duplicated nodes of 'a:lnL' or 'a:lnR' or 'a:lnT' or 'a:lnB' in the children elements of 'a:tcPr'. So we only need to remove nodes of ['a:lnL','a:lnR','a:lnT','a:lnB'] before these nodes are inserted as below.
from pptx.oxml.xmlchemy import OxmlElement
def SubElement(parent, tagname, **kwargs):
element = OxmlElement(tagname)
element.attrib.update(kwargs)
parent.append(element)
return element
def _set_cell_border(cell, border_color="000000", border_width='12700'):
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
for lines in ['a:lnL','a:lnR','a:lnT','a:lnB']:
# Every time before a node is inserted, the nodes with the same tag should be removed.
tag = lines.split(":")[-1]
for e in tcPr.getchildren():
if tag in str(e.tag):
tcPr.remove(e)
# end
ln = SubElement(tcPr, lines, w=border_width, cap='flat', cmpd='sng', algn='ctr')
solidFill = SubElement(ln, 'a:solidFill')
srgbClr = SubElement(solidFill, 'a:srgbClr', val=border_color)
prstDash = SubElement(ln, 'a:prstDash', val='solid')
round_ = SubElement(ln, 'a:round')
headEnd = SubElement(ln, 'a:headEnd', type='none', w='med', len='med')
tailEnd = SubElement(ln, 'a:tailEnd', type='none', w='med', len='med')
I had a hard time figuring out why this wasn't working. For anyone else struggling with this, I had to add the following to the end of the function:
return cell
When using, you want to use the function as such:
cell = _set_cell_border(cell)

create and assign subcategories in revit using python

I have a question for some of you who are familiar with the Revit API and python:
I’ve been using the spring nodes package in dynamo to create a rather large series of freeform objects each in their own family. The way that the FamilyInstance.ByGeometry works, it takes a list of solids and creates a family instance for each using a template family file. The result is quite good. (spring nodes can be found here: https://github.com/dimven/SpringNodes)
However, the drawback is that that now I have roughly 200 separate instances, so to make changes to each is rather painful. I thought at first it would be possible to use dynamo to create a new subcategory and set the solid inside each family instance to this new subcategory. Unfortunately, I realized this is not possible since dynamo cannot be open in two different Revit environments simultaneously (the project I am working in and each instance of the family). This leads me to look to see if I can do this using python.
I have used python in rhino and can get along pretty well, I am still learning the Revit API however. But basically my idea would be to:
1. select a series of family instances in the Revit project environment
2. loop through each instance
3. save it to a specified location
4. create a new subcategory in each family instances (the subcategory would the same for all the selected family instances)
5. select the solid in each in instance
6. set the solid to this newly created subcategory
7. close the family instance and save
My question for you is does this sound like it is achievable based on your knowledge of the Revit API?
Many thanks for your time and advice.
UPDATE:
I've found a section in the revit api that describes what i'm looking to do: http://help.autodesk.com/view/RVT/2015/ENU/?guid=GUID-FBF9B994-ADCB-4679-B50B-2E9A1E09AA48
I've made a first pass at inserting this into the python code of the dynamo node. The rest of the code works fine except for the new section im adding (see below). Please excuse the variables, I am simply keeping with logic of the original author of the code i am hacking:
(Note: the variables come in are in arrays)
#set subcategory
try:
#create new sucategory
fam_subcat = famdoc.Settings.Categories.NewSubcategory(fam_cat, get_Item(subcat1.Name))
#assign the mataterial(fam_mat.Id) to the subcategory
fam_subcat.Material = famdoc.GetElement(fam_mat.Id)
#assign the subcategory to the element (s2)
s2.Subcategory = fam_subcat
except: pass
Any help or advice with this section of code would be much appreciated.
UPDATE:
See full code below for context of the section in question:
#Copyright(c) 2015, Dimitar Venkov
# #5devene, dimitar.ven#gmail.com
import clr
import System
from System.Collections.Generic import *
pf_path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86)
import sys
sys.path.append("%s\IronPython 2.7\Lib" %pf_path)
import traceback
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
app = DocumentManager.Instance.CurrentUIApplication.Application
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import StructuralType
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
def tolist(obj1):
if hasattr(obj1,"__iter__"): return obj1
else: return [obj1]
def output1(l1):
if len(l1) == 1: return l1[0]
else: return l1
def PadLists(lists):
len1 = max([len(l) for l in lists])
for i in xrange(len(lists)):
if len(lists[i]) == len1:
continue
else:
len2 = len1 - len(lists[i])
for j in xrange(len2):
lists[i].append(lists[i][-1])
return lists
class FamOpt1(IFamilyLoadOptions):
def __init__(self):
pass
def OnFamilyFound(self,familyInUse, overwriteParameterValues):
return True
def OnSharedFamilyFound(self,familyInUse, source, overwriteParameterValues):
return True
geom = tolist(IN[0])
fam_path = IN[1]
names = tolist(IN[2])
category = tolist(IN[3])
material = tolist(IN[4])
isVoid = tolist(IN[5])
subcategory = tolist(IN[6])
isRvt2014 = False
if app.VersionName == "Autodesk Revit 2014": isRvt2014 = True
units = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits
factor = UnitUtils.ConvertToInternalUnits(1,units)
acceptable_views = ["ThreeD", "FloorPlan", "EngineeringPlan", "CeilingPlan", "Elevation", "Section"]
origin = XYZ(0,0,0)
str_typ = StructuralType.NonStructural
def NewForm_background(s1, name1, cat1, isVoid1, mat1, subcat1):
t1 = TransactionManager.Instance
TransactionManager.ForceCloseTransaction(t1)
famdoc = doc.Application.NewFamilyDocument(fam_path)
message = None
temp_path = System.IO.Path.GetTempPath()
sat_path = "%s%s.sat" % (temp_path, name1)
try:
if factor != 1:
s1 = s1.Scale(factor)
sat1 = Geometry.ExportToSAT(s1, sat_path)
satOpt = SATImportOptions()
satOpt.Placement = ImportPlacement.Origin
satOpt.Unit = ImportUnit.Foot
view_fec = FilteredElementCollector(famdoc).OfClass(View)
view1 = None
for v in view_fec:
if str(v.ViewType) in acceptable_views:
view1 = v
break
t1.EnsureInTransaction(famdoc)
satId = famdoc.Import(sat1, satOpt, view1)
opt1 = Options()
opt1.ComputeReferences = True
el1 = famdoc.GetElement(satId)
geom1 = el1.get_Geometry(opt1)
enum = geom1.GetEnumerator()
enum.MoveNext()
geom2 = enum.Current.GetInstanceGeometry()
enum2 = geom2.GetEnumerator()
enum2.MoveNext()
s1 = enum2.Current
famdoc.Delete(satId)
TransactionManager.ForceCloseTransaction(t1)
System.IO.File.Delete(sat_path)
except:
message = traceback.format_exc()
pass
if message == None:
try:
save_path = "%s%s.rfa" % (temp_path, name1)
SaveAsOpt = SaveAsOptions()
SaveAsOpt.OverwriteExistingFile = True
t1.EnsureInTransaction(famdoc)
#set the category
try:
fam_cat = famdoc.Settings.Categories.get_Item(cat1.Name)
famdoc.OwnerFamily.FamilyCategory = fam_cat
except: pass
s2 = FreeFormElement.Create(famdoc,s1)
if isVoid1:
void_par = s2.get_Parameter("Solid/Void")
void_par.Set(1)
void_par2 = famdoc.OwnerFamily.get_Parameter("Cut with Voids When Loaded")
void_par2.Set(1)
else: #voids do not have a material value
try:
mat_fec = FilteredElementCollector(famdoc).OfClass(Material)
for m in mat_fec:
if m.Name == mat1:
fam_mat = m
break
mat_par = s2.get_Parameter("Material")
mat_par.Set(fam_mat.Id)
except: pass
#set subcategory
try:
#create new sucategory
fam_subcat = document.Settings.Categories.NewSubcategory(document.OwnerFamily.FamilyCategory, get_Item(subcat1.Name))
#assign the mataterial(fam_mat.Id) to the subcategory
fam_subcat.Material = famdoc.GetElement(fam_mat.Id)
#assign the subcategory to the element (s2)
s2.Subcategory = fam_subcat
except: pass
TransactionManager.ForceCloseTransaction(t1)
famdoc.SaveAs(save_path, SaveAsOpt)
family1 = famdoc.LoadFamily(doc, FamOpt1())
famdoc.Close(False)
System.IO.File.Delete(save_path)
symbols = family1.Symbols.GetEnumerator()
symbols.MoveNext()
symbol1 = symbols.Current
t1.EnsureInTransaction(doc)
if not symbol1.IsActive: symbol1.Activate()
inst1 = doc.Create.NewFamilyInstance(origin, symbol1, str_typ)
TransactionManager.ForceCloseTransaction(t1)
return inst1.ToDSType(False), family1.ToDSType(False)
except:
message = traceback.format_exc()
return message
else:
return message
def NewForm_background_R16(s1, name1, cat1, isVoid1, mat1, subcat1):
t1 = TransactionManager.Instance
TransactionManager.ForceCloseTransaction(t1)
famdoc = doc.Application.NewFamilyDocument(fam_path)
message = None
temp_path = System.IO.Path.GetTempPath()
sat_path = "%s%s.sat" % (temp_path, name1)
try:
if factor != 1:
s1 = s1.Scale(factor)
sat1 = Geometry.ExportToSAT(s1, sat_path)
satOpt = SATImportOptions()
satOpt.Placement = ImportPlacement.Origin
satOpt.Unit = ImportUnit.Foot
view_fec = FilteredElementCollector(famdoc).OfClass(View)
view1 = None
for v in view_fec:
if str(v.ViewType) in acceptable_views:
view1 = v
break
t1.EnsureInTransaction(famdoc)
satId = famdoc.Import(sat1, satOpt, view1)
opt1 = Options()
opt1.ComputeReferences = True
el1 = famdoc.GetElement(satId)
geom1 = el1.get_Geometry(opt1)
enum = geom1.GetEnumerator()
enum.MoveNext()
geom2 = enum.Current.GetInstanceGeometry()
enum2 = geom2.GetEnumerator()
enum2.MoveNext()
s1 = enum2.Current
famdoc.Delete(satId)
TransactionManager.ForceCloseTransaction(t1)
System.IO.File.Delete(sat_path)
except:
message = traceback.format_exc()
pass
if message == None:
try:
save_path = "%s%s.rfa" % (temp_path, name1)
SaveAsOpt = SaveAsOptions()
SaveAsOpt.OverwriteExistingFile = True
t1.EnsureInTransaction(famdoc)
#set the category
try:
fam_cat = famdoc.Settings.Categories.get_Item(cat1.Name)
famdoc.OwnerFamily.FamilyCategory = fam_cat
except: pass
s2 = FreeFormElement.Create(famdoc,s1)
if isVoid1:
void_par = s2.LookupParameter("Solid/Void")
void_par.Set(1)
void_par2 = famdoc.OwnerFamily.LookupParameter("Cut with Voids When Loaded")
void_par2.Set(1)
else: #voids do not have a material value
try:
mat_fec = FilteredElementCollector(famdoc).OfClass(Material)
for m in mat_fec:
if m.Name == mat1:
fam_mat = m
break
mat_par = s2.LookupParameter("Material")
mat_par.Set(fam_mat.Id)
except: pass
#apply same subcategory code as before
#set subcategory
try:
#create new sucategory
fam_subcat = famdoc.Settings.Categories.NewSubcategory(fam_cat, get_Item(subcat1.Name))
#assign the mataterial(fam_mat.Id) to the subcategory
fam_subcat.Material = famdoc.GetElement(fam_mat.Id)
#assign the subcategory to the element (s2)
s2.Subcategory = fam_subcat
except: pass
TransactionManager.ForceCloseTransaction(t1)
famdoc.SaveAs(save_path, SaveAsOpt)
family1 = famdoc.LoadFamily(doc, FamOpt1())
famdoc.Close(False)
System.IO.File.Delete(save_path)
symbols = family1.GetFamilySymbolIds().GetEnumerator()
symbols.MoveNext()
symbol1 = doc.GetElement(symbols.Current)
t1.EnsureInTransaction(doc)
if not symbol1.IsActive: symbol1.Activate()
inst1 = doc.Create.NewFamilyInstance(origin, symbol1, str_typ)
TransactionManager.ForceCloseTransaction(t1)
return inst1.ToDSType(False), family1.ToDSType(False)
except:
message = traceback.format_exc()
return message
else:
return message
if len(geom) == len(names) == len(category) == len(isVoid) == len(material) == len(subcategory):
if isRvt2014:
OUT = output1(map(NewForm_background, geom, names, category, isVoid, material, subcategory))
else:
OUT = output1(map(NewForm_background_R16, geom, names, category, isVoid, material, subcategory))
elif len(geom) == len(names):
padded = PadLists((geom, category, isVoid, material, subcategory))
p_category = padded[1]
p_isVoid = padded[2]
p_material = padded[3]
p_subcategory = padded [4]
if isRvt2014:
OUT = output1(map(NewForm_background, geom, names, p_category, p_isVoid, p_material, p_subcategory))
else:
OUT = output1(map(NewForm_background_R16, geom, names, p_category, p_isVoid, p_material, subcategory))
else: OUT = "Make sure that each geometry\nobject has a unique family name."
Update:
Was able to get it working:
try:
#create new sucategory
fam_subcat = famdoc.Settings.Categories.NewSubcategory(famdoc.OwnerFamily.FamilyCategory, subcat1)
#assign the mataterial(fam_mat.Id) to the subcategory
#fam_subcat.Material = famdoc.GetElement(fam_mat.Id)
#assign the subcategory to the element (s2)
s2.Subcategory = fam_subcat
except: pass
As I answered on your initial query per email, what you are aiming for sounds perfectly feasible to me in the Revit API. Congratulations on getting as far as you have. Looking at the link to the Revit API help file and developer guide that you cite above, it seems that the code has to be executed in the family document while defining the family. The context in which you are trying to execute it is not clear. Have you used EditFamily to open the family definition document? What context are you executing in?

Categories