Apply borders to all cells in a range with openpyxl

后端 未结 8 746
面向向阳花
面向向阳花 2021-01-03 01:28

I have a script that takes a pandas dataframe and chops it up into several hundred chunks and saves each chunk as a separate excel file. Each chunk will have the same number

相关标签:
8条回答
  • 2021-01-03 01:42

    @user698585 your approach seems nice but it doesn't work anymore as the present version of the openpyxl change the implementation. So this should be updated into e.g.

        ws.cell(row=1, column=1).style.border.top.border_style = borders.BORDER_MEDIUM
    

    but it results with an error that changing the style is not allowed. As a workaround I just defined a dedicated styles, but they are just a duplication of the present styles plus border definition - not so good solution as works only if you know what style has the cell under the change.

        border_style = Style(font=Font(name='Console', size=10, bold=False,
                             color=Color(openpyxl.styles.colors.BLACK)),
                             fill=PatternFill(patternType='solid', fgColor=Color(rgb='00C5D9F1')),
                             border=Border(bottom=Side(border_style='medium', color=Color(rgb='FF000000'))))
    
    0 讨论(0)
  • 2021-01-03 01:44

    Had the same issue but couldn't find anything that fixes this problem for 2019 because of depreciation. I have something that works below.. could be better but works for all intends and purposes.

    def set_border(ws, cell_range):
        rows = ws[cell_range]
        for row in rows:
            if row == rows[0][0] or row == rows[0][-1] or row == rows[-1][0] or row == rows[-1][-1]:
                pass
            else:
                row[0].border = Border(left=Side(style='thin'))
                row[-1].border = Border(right=Side(style='thin'))
            for c in rows[0]:
                c.border = Border(top=Side(style='thin'))
            for c in rows[-1]:
                c.border = Border(bottom=Side(style='thin'))
        rows[0][0].border = Border(left=Side(style='thin'), top=Side(style='thin'))
        rows[0][-1].border = Border(right=Side(style='thin'), top=Side(style='thin'))
        rows[-1][0].border = Border(left=Side(style='thin'), bottom=Side(style='thin'))
        rows[-1][-1].border = Border(right=Side(style='thin'), bottom=Side(style='thin'))
    
    0 讨论(0)
  • 2021-01-03 01:46

    There is a slight modification to answer from @Karimov
    Below is how your code should be

    from openpyxl.styles import Border, Side, Font, Alignment
    
    def __format_ws__(self, ws, cell_range):
         border = Border(left=Side(border_style='thin', color='000000'),
                        right=Side(border_style='thin', color='000000'),
                        top=Side(border_style='thin', color='000000'),
                        bottom=Side(border_style='thin', color='000000'))
    
          rows = ws[cell_range]
          for row in rows:
              for cell in row:
                  cell.border = border
    
    

    A much faster way that uses list comprehension is below:

     def __format_ws__(self, ws, cell_range):
    
            #applying border and alignment
            font = Font(size=9)
            align=Alignment(horizontal='left', vertical='center')
            border = Border(left=Side(border_style='thin', color='000000'),
                            right=Side(border_style='thin', color='000000'),
                            top=Side(border_style='thin', color='000000'),
                            bottom=Side(border_style='thin', color='000000'))
    
            rows = [rows for rows in ws[cell_range]]
            flattened = [item for sublist in rows for item in sublist]
            [(setattr(cell,'border',border), setattr(cell,'font',font), setattr(cell,'alignment',align)) for cell in flattened]
    

    The way you use it is:

    self.__format_ws__(ws=writer.book.worksheets[0], cell_range='A1:G10')
    
    0 讨论(0)
  • 2021-01-03 01:52

    if you need styling (borders...) for pandas excel dataframe my fork just got merged into master https://github.com/pydata/pandas/pull/2370#issuecomment-10898427

    as for you borders problems. setting all borders at once does not seam to work in openpyxl.

    In [34]: c.style.borders.all_borders.border_style = openpyxl.style.Border.BORDER_THIN
    
    In [36]: c.style
    'Calibri':11:False:False:False:False:'none':False:'FF000000':'none':0:'FFFFFFFF':'FF000000':'none':'FF000000':'none':'FF000000':'none':'FF000000':'none':'FF000000':'none':'FF000000':0:'thin':'FF000000':'none':'FF000000':'none':'FF000000':'none':'FF000000':'none':'FF000000':'general':'bottom':0:False:False:0:'General':0:'inherit':'inherit'
    

    setting individually works ('thin':'FF000000')

    In [37]: c.style.borders.top.border_style = openpyxl.style.Border.BORDER_THIN
    
    In [38]: c.style
    Out[38]: 'Calibri':11:False:False:False:False:'none':False:'FF000000':'none':0:'FFFFFFFF':'FF000000':'none':'FF000000':'none':'FF000000':'thin':'FF000000':'none':'FF000000':'none':'FF000000':0:'thin':'FF000000':'none':'FF000000':'none':'FF000000':'none':'FF000000':'none':'FF000000':'general':'bottom':0:False:False:0:'General':0:'inherit':'inherit'
    

    maybe a bug in openpyxl. but no big deal just wrap setting bottom , top, left, right in function

    0 讨论(0)
  • 2021-01-03 01:54

    In more pythonic way for openpyxl==3.0.5:

    from openpyxl.styles import Border, Side
    
    def set_border(ws, cell_range):
        thin = Side(border_style="thin", color="000000")
        for row in ws[cell_range]:
            for cell in row:
                cell.border = Border(top=thin, left=thin, right=thin, bottom=thin)
    
    set_border(worksheet, 'A5:C10') 
    
    0 讨论(0)
  • 2021-01-03 02:02

    May be this is handy:

    from openpyxl.reader.excel import load_workbook
    from openpyxl.style import Border
    
    def set_border(ws, cell_range):
        rows = ws.range(cell_range)
        for row in rows:
            row[0].style.borders.left.border_style = Border.BORDER_THIN
            row[-1].style.borders.right.border_style = Border.BORDER_THIN
        for c in rows[0]:
            c.style.borders.top.border_style = Border.BORDER_THIN
        for c in rows[-1]:
            c.style.borders.bottom.border_style = Border.BORDER_THIN
    
    #usage example:
    ws = load_workbook('example.xlsx').get_active_sheet()
    set_broder(ws, "C3:H10")
    

    It performs reasonably fast.

    0 讨论(0)
提交回复
热议问题