0
from pptx.enum.text import PP_ALIGN
from pptx.util import Inches, Mm, Pt, Emu
from pptx.enum.dml import MSO_FILL_TYPE
from pptx.oxml.xmlchemy import OxmlElement
from datetime import date
import pandas as pd
import numpy as np

#region Read in the Template and load it
path = "Template/Template.pptx"
prs = Presentation(path)
#endregion

#region Functions
def SubElement(parent, tagname, **kwargs):
    element = OxmlElement(tagname)
    element.attrib.update(kwargs)
    parent.append(element)
    return element


def _set_cell_border(cell, border_color="FFFFFF", border_width='12700'):
    """ Hack function to enable the setting of border width and border color
        - bottom border only at present
        (c) Steve Canny
    """
    tc = cell._tc
    tcPr = tc.get_or_add_tcPr()

    lnB = SubElement(tcPr, 'a:lnB', w=border_width, cap='flat', cmpd='sng', algn='ctr')
    solidFill = SubElement(lnB, 'a:NoFill')

#endregion
#region Dataframe
df = pd.DataFrame()
df["name"] = ["Nick","Gaetano", "George", "Jason","Death", "God", 'Stan', "Satan","Beel","Nick","Gaetano", "George", "Jason","Death", "God", 'Stan', "Satan","Beel"]
df["Restaurant Manager"] = ["Sam","Mason", "Sam", "Mason","Mason","Sam","Sam","Sam","Mason","Sam","Mason", "Sam", "Mason","Mason","Sam","Sam","Sam","Mason"]
df["Score"] = np.random.randint(5,30,size=18)
df['Percentile Rank'] = np.random.randint(5,101,size=18)
df["Restaurant Name"] = ["Elise","Bob","Death","Elise","Bob","Death","Elise","Bob","Death","Elise","Bob","Death","Elise","Bob","Death","Elise","Bob","Death"]
df = df[df.groupby(['Restaurant Name', 'Restaurant Manager']).cumcount() < 3]

#endregion

#region Get layout info
#slide = prs.slides.add_slide(prs.slide_layouts[3])
#for shape in slide.placeholders:
#    print('%d %s' % (shape.placeholder_format.idx, shape.name))

#endregion

#region Slide #3 Table
slide_layout = prs.slide_layouts[3]
slide = prs.slides.add_slide(slide_layout)
placeholder = slide.placeholders[0]
placeholder.text = "Restaurant TABLE Analysis"
table_placeholder = slide.shapes[1]
shape = table_placeholder.insert_table(rows=13, cols=14)
table = shape.table


#endregion

#region Setting Table Parameters
# Setting the backfround colour to invsible for the rows
for row in table.rows:
    for cell in row.cells:
        for paragraph in cell.text_frame.paragraphs:
            paragraph.font.size = Pt(1) # set font size to 1

rownumbers= [1,7]
colnumbers = [4,9]

for i in rownumbers:
    row = table.rows[i] # select row
    for cell in row.cells:
        cell.text_frame.paragraphs[0].font.size = Pt(1)  # set font size to 1 pt
        cell.fill.background()  # set background to be transparent

    row.height = Mm(2) # set height

# Setting the backfround colour to invsible for the columns
for i in colnumbers:
    column = table.columns[i] # select column
    column_index = i
    for row in table.rows:
        cell = row.cells[column_index]
        cell.text_frame.paragraphs[0].font.size = Pt(1)  # set font size to 1 pt
        cell.fill.background()  # set background to be transparent
    column.width = Mm(2) # set width


# Merging the cells in the rows
for row_index in rownumbers:
    first_cell_index = 0  # index of the first cell in the row
    last_cell_index = len(table.columns) - 1  # index of the last cell in the row
    row = table.rows[row_index]
    first_cell = row.cells[first_cell_index]
    last_cell = row.cells[last_cell_index]
    first_cell.merge(last_cell)  # merge the cells
#endregion

#region Creating Tables
# Group the data by the 'Restaurant Name' column
groups = df.groupby('Restaurant Name')

# Set the starting index
i = 0

# Iterate through the groups
for name, group in groups:
    # Insert the group name (i.e. the restaurant name) into the first cell
    cell = table.cell(0, i)
    cell.text = name
    cell.text_frame.paragraphs[0].font.size = Pt(18)
    # cell.text_frame.paragraphs[0].font.name = 'Arial' # font style
    cell.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
    cell3 = table.cell(0, i+3)
    cell.merge(cell3)

    # Group the data in the current group by the 'Restaurant Manager' column
    df_manager_grouped = group.groupby('Restaurant Manager')

    i_2 = 2
    # Iterate through the subgroups
    for manager_name, manager_group in df_manager_grouped:
        # Insert the group name (i.e. the restaurant manager name) into the second cell
        cell = table.cell(i_2, i)
        cell.text = manager_name
        cell.text_frame.paragraphs[0].font.size = Pt(12)
        cell.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
        cell3 = table.cell(i_2,i+3)
        cell.merge(cell3)

        # Insert the remaining data for the current subgroup
        # Set the row index
        row_index = i_2 + 2
        for index in range(len(manager_group)):

            # Insert the data into the cells
            cell = table.cell(row_index, i)
            cell.text = str(index + 1)
            cell.text_frame.paragraphs[0].font.size = Pt(12)
            cell.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
            cell = table.cell(row_index, i + 1)
            cell.text = manager_group.iloc[index]['name']
            cell.text_frame.paragraphs[0].font.size = Pt(12)
            cell.text_frame.paragraphs[0].alignment = PP_ALIGN.LEFT
            cell = table.cell(row_index, i + 2)
            cell.text = str(manager_group.iloc[index]['Score'])
            cell.text_frame.paragraphs[0].font.size = Pt(12)
            cell.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
            cell = table.cell(row_index, i + 3)
            cell.text = str(manager_group.iloc[index]['Percentile Rank'])
            cell.text_frame.paragraphs[0].font.size = Pt(12)
            cell.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER

            # Increment the row index
            row_index += 1

        i_2 += 6

    # Increment the index
    i += 5

# center the table horizontally and vertically
slide_width = prs.slide_width
table_width = shape.width
shape.left  = round((slide_width - table_width) / 2)


cell = table.cell(6,4)
_set_cell_border(cell)

#endregion

prs.save('test.pptx')

As the title states, I want to remove the borders of a specific cell but for some reason my code is unable to do so. I have attempted the proposed solutions found here (Python-PPTX: Changing table style or adding borders to cells) but no matter what I do, I am unable to do so.

Preferably I would like to be able to specify which border I want to remove (i.e. Remove only the top.. or remove both top and bottom) but I think I will be able to figure it out once I know how to remove all the borders.

Any help would be much appreciated.

  • If you look at the latest answer posted to the previous post that you linked, the answer states that you need to change the `_set_cell_border()` function to `return cell` at the end of the function, and then you'll need to change the line calling it to `cell = _set_cell_border(cell)`. I'm currently trying to test, but I am running into import issues with pptx importing collections.Container. PS: Your example code seems to be missing `from pptx import Presentation` – nigh_anxiety Jan 05 '23 at 05:22

1 Answers1

0

I have managed to figure it out...

#region Functions
def SubElement(parent, tagname, **kwargs):
    element = OxmlElement(tagname)
    element.attrib.update(kwargs)
    parent.append(element)
    return element


def set_cell_border_top_bottom(cell, border_color="db0404", border_width='12700'):
    tc = cell._tc
    tcPr = tc.get_or_add_tcPr()
    for lines in ['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='0', 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')

    return cell

def set_cell_border_left_right(cell, border_color="db0404", border_width='12700'):
    tc = cell._tc
    tcPr = tc.get_or_add_tcPr()
    for lines in ['a:lnL', 'a:lnR']:

        # 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='0', 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')

    return cell




#endregion
#region Dataframe
df = pd.DataFrame()
df["name"] = ["Nick","Gaetano", "George", "Jason","Death", "God", 'Stan', "Satan","Beel","Nick","Gaetano", "George", "Jason","Death", "God", 'Stan', "Satan","Beel"]
df["Restaurant Manager"] = ["Sam","Mason", "Sam", "Mason","Mason","Sam","Sam","Sam","Mason","Sam","Mason", "Sam", "Mason","Mason","Sam","Sam","Sam","Mason"]
df["Score"] = np.random.randint(5,30,size=18)
df['Percentile Rank'] = np.random.randint(5,101,size=18)
df["Restaurant Name"] = ["Elise","Bob","Death","Elise","Bob","Death","Elise","Bob","Death","Elise","Bob","Death","Elise","Bob","Death","Elise","Bob","Death"]
df = df[df.groupby(['Restaurant Name', 'Restaurant Manager']).cumcount() < 3]

#endregion

#region Get layout info
#slide = prs.slides.add_slide(prs.slide_layouts[3])
#for shape in slide.placeholders:
#    print('%d %s' % (shape.placeholder_format.idx, shape.name))

#endregion

#region Title Slide #1

title_slide_layout = prs.slide_layouts[0]
slide = prs.slides[0]  # Get the first slide in the presentation
placeholder = slide.placeholders[0]
placeholder.text = "This is a test of the emergency broadcast system"
placeholder = slide.placeholders[1]
placeholder.text = str(date.today())

#endregion


#region Slide #3 Table
slide_layout = prs.slide_layouts[3]
slide = prs.slides.add_slide(slide_layout)
placeholder = slide.placeholders[0]
placeholder.text = "Restaurant TABLE Analysis"
table_placeholder = slide.shapes[1]
shape = table_placeholder.insert_table(rows=13, cols=14)
table = shape.table


#endregion

#region Setting Table Parameters
rownumbers= [1,7]
colnumbers = [4,9]

for i in colnumbers:
    column = table.columns[i] # select column
    column_index = i
    for row in table.rows:
        cell = row.cells[column_index]
        cell = set_cell_border_top_bottom(cell)

for i in rownumbers:
    row = table.rows[i] # select row
    for cell in row.cells:
        cell = set_cell_border_left_right(cell)

# Setting the backfround colour to invsible for the rows
for row in table.rows:
    for cell in row.cells:
        for paragraph in cell.text_frame.paragraphs:
            paragraph.font.size = Pt(1) # set font size to 1


for i in rownumbers:
    row = table.rows[i] # select row
    for cell in row.cells:
        cell.text_frame.paragraphs[0].font.size = Pt(1)  # set font size to 1 pt
        cell.fill.background()  # set background to be transparent

    row.height = Mm(2) # set height

# Setting the backfround colour to invsible for the columns
for i in colnumbers:
    column = table.columns[i] # select column
    column_index = i
    for row in table.rows:
        cell = row.cells[column_index]
        cell.text_frame.paragraphs[0].font.size = Pt(1)  # set font size to 1 pt
        cell.fill.background()  # set background to be transparent
    column.width = Mm(2) # set width


# Merging the cells in the rows
for row_index in rownumbers:
    first_cell_index = 0  # index of the first cell in the row
    last_cell_index = len(table.columns) - 1  # index of the last cell in the row
    row = table.rows[row_index]
    first_cell = row.cells[first_cell_index]
    last_cell = row.cells[last_cell_index]
    first_cell.merge(last_cell)  # merge the cells
#endregion

The issue occurs because of the the merging of cells. This was causing a conflict with removing the borders.

If anyone wants to remove the borders of a cell, you must first remove the borders of the cells before merging anything.