Hello,
I am trying to modify a table to remove the borders around the first and last rows of a table. I realize that there is not a method for adjusting tcBorders in python-docx at this point. How do I insert some XML into the XML section? I need to insert this...
<w:tcBorders>
<w:top w:val="nil"/>
<w:left w:val="nil"/>
<w:bottom w:val="single" w:color="auto" w:space="0" w:sz="4"/>
<w:right w:val="nil"/>
</w:tcBorders>
To accomplish my goal.
I spent a good deal of time playing with some of the XML type functionality available. I am at a loss.
This is what is generated...
<w:tc>
<w:tcPr>
<w:tcW w:w="2160" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>Upper Left</w:t>
</w:r>
</w:p>
</w:tc>
This is what I need...
<w:tc>
<w:tcPr>
<w:tcW w:w="2160" w:type="dxa"/>
<w:tcBorders>
<w:top w:val="nil"/>
<w:left w:val="nil"/>
<w:bottom w:val="single" w:color="auto" w:space="0" w:sz="4"/>
<w:right w:val="nil"/>
</w:tcBorders>
</w:tcPr>
<w:p w:rsidRDefault="00777F07" w:rsidR="00D60748">
<w:r>
<w:t>Upper Left</w:t>
</w:r>
</w:p>
</w:tc>
This is what I have come up with so far...
# -*- coding: utf-8 -*-
"""
table.py
Generate a Word Document and manipulate the XML.
"""
from docx import Document
from docx.oxml.table import CT_Row, CT_Tc
d = Document()
d.add_heading('Test Table', level=3)
table = d.add_table(rows=4, cols=4, style='TableGrid')
table.rows[0].cells[0].text = "Upper Left"
table.rows[3].cells[3].text = "Lower Right"
lastRow = len(table.rows) - 1
tbl = table._tbl
rows = tbl.getchildren()
for row in rows:
if isinstance(row, CT_Row):
cells = row.getchildren()
if row.tr_idx == 0: # Top Row
print "Top Row"
for cell in cells:
if isinstance(cell, CT_Tc):
tcPr = cell.tcPr
print type(tcPr)
elif row.tr_idx == lastRow: # Bottom Row
print "Bottom Row"
for cell in cells:
if isinstance(cell, CT_Tc):
tcPr = cell.tcPr
print type(tcPr)
print cell.xml
d.save('originalTable.docx')
All help and suggestions are appreciated.
Thank you,
Willie
Hi. I tried to define a table style myself recently and met the same problem as yours. I found a solution and hope it is still helpful to you.
def modifyBorder(table):
tbl = table._tbl # get xml element in table
for cell in tbl.iter_tcs():
tcPr = cell.tcPr # get tcPr element, in which we can define style of borders
tcBorders = OxmlElement('w:tcBorders')
top = OxmlElement('w:top')
top.set(qn('w:val'), 'nil')
left = OxmlElement('w:left')
left.set(qn('w:val'), 'nil')
bottom = OxmlElement('w:bottom')
bottom.set(qn('w:val'), 'nil')
bottom.set(qn('w:sz'), '4')
bottom.set(qn('w:space'), '0')
bottom.set(qn('w:color'), 'auto')
right = OxmlElement('w:right')
right.set(qn('w:val'), 'nil')
tcBorders.append(top)
tcBorders.append(left)
tcBorders.append(bottom)
tcBorders.append(right)
tcPr.append(tcBorders)
After this modification, the table should be what you need. Actually I was inspired by https://github.com/python-openxml/python-docx/issues/105. Hope this will help.
Hi @KailiDing ,
I tried following your suggestion but for some reason, it does not add any border. I would quite like to circumvent defining a style in a template document as the borders required for my tables need to be added dynamically. Is there something glaringly obvious that I am missing?
Minimally reproducible example:
from docx import Document
from docx.oxml.table import CT_Row, CT_Tc
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
import pandas as pd
#setup
df = pd.DataFramedf = pd.DataFrame({"Variable1": {0:"var1", 1:"var1", 2:"var1", 3:"var1", 4:"var1", 5:"var1", 6:"var1", 7:"var2", 8:"var2",9:"var2",10: "var2",11: "var2",12: "var2",13: "var3",14: "var3",15: "var3",16: "var3",17: "var3",18: "var4",19: "var4",20: "var4",21: "var4",22: "var5",23: "var5",24: "var5",25: "var6",26: "var6",27: "var7"},
"Variable2": {0: "var2",1: "var3",2: "var4",3: "var5",4: "var6",5: "var7",6: "var8",7: "var3",8: "var4",9: "var5",10: "var6",11: "var7",12: "var8",13: "var4",14: "var5",15: "var6",16: "var7",17: "var8",18: "var5",19: "var6",20: "var7",21: "var8",22: "var6",23: "var7",24: "var8",25: "var7",26: "var8",27: "var8"},
"Correlation_Coefficient": {0: "0.44",1: "0.26",2: "0.22",3: "0.33",4: "-0.07",5: "0.08",6: "0.07",7: "0.26",8: "0.21",9: "0.31",10: "-0.06",11: "0.06",12: "0.15",13: "0.03",14: "0.70",15: "-0.75",16: "0.04",17: "0.01",18: "0.69",19: "0.60",20: "0.09",21: "0.05",22: "-0.13",23: "0.06",24: "0.02",25: "0.02",26: "0.02",27: "0.76"},
"CI_low": {0: "0.37",1: "0.17",2: "0.13",3: "0.25",4: "-0.15",5: "-0.01",6: "-0.02",7: "0.18",8: "0.12",9: "0.23",10: "-0.14",11: "-0.03",12: "0.06",13: "-0.06",14: "0.66",15: "-0.78",16: "-0.05",17: "-0.08",18: "0.64",19: "0.54",20: "-0.00",21: "-0.04",22: "-0.22",23: "-0.03",24: "-0.07",25: "-0.07",26: "-0.07",27: "0.72"},
"CI_high": {0: "0.51",1: "0.34",2: "0.30",3: "0.40",4: "0.02",5: "0.17",6: "0.16",7: "0.34",8: "0.29",9: "0.39",10: "0.03",11: "0.15",12: "0.23",13: "0.12",14: "0.75",15: "-0.71",16: "0.13",17: "0.09",18: "0.73",19: "0.65",20: "0.17",21: "0.14",22: "-0.04",23: "0.15",24: "0.10",25: "0.10",26: "0.10",27: "0.79"},
"pvalues": {0: "0.00",1: "0.00",2: "0.00",3: "0.00",4: "0.14",5: "0.07",6: "0.12",7: "0.00",8: "0.00",9: "0.00",10: "0.20",11: "0.18",12: "0.00",13: "0.47",14: "0.00",15: "0.00",16: "0.35",17: "0.88",18: "0.00",19: "0.00",20: "0.06",21: "0.28",22: "0.00",23: "0.18",24: "0.72",25: "0.72",26: "0.72",27: "0.00"}})
doc = Document()
table = doc.add_table(rows=len(df), cols=len(df.columns))
#writing some data
for i in range(0, len(df.columns)):
headings = table.rows[0].cells
headings[i].text = df.columns[i]
for i in range(1, len(df)):
for j in range(0, len(df.columns)):
row = table.rows[i].cells
row[j].text = str(df.iloc[i, j])
#border formatting attempt
tbl = table._tbl
for cell in tbl.iter_tcs():
tcPr = cell.tcPr
tcBorders = OxmlElement("w:tcBorders")
top = OxmlElement("w:top")
top.set(qn("w:val"), "nil")
left = OxmlElement("w:left")
left.set(qn("w:val"), "nil")
bottom = OxmlElement("w:bottom")
bottom.set(qn("w:val"), "nil")
bottom.set(qn("w:sz"), "4")
bottom.set(qn("w:space"), "0")
bottom.set(qn("w:color"), "auto")
right = OxmlElement("w:right")
right.set(qn("w:val"), "nil")
tcBorders.append(top)
tcBorders.append(left)
tcBorders.append(bottom)
tcBorders.append(right)
tcPr.append(tcBorders)
doc.save("test.docx")
Most helpful comment
Hi. I tried to define a table style myself recently and met the same problem as yours. I found a solution and hope it is still helpful to you.
After this modification, the table should be what you need. Actually I was inspired by https://github.com/python-openxml/python-docx/issues/105. Hope this will help.