8

我有一个脚本,它采用 pandas 数据框并将其分成几百块并将每个块保存为单独的 excel 文件。每个块将具有相同的列数,但行数会有所不同。我已经想出了如何使用 openpyxl 将所有其他必要的格式应用于这些文件,但我还没有确定应用边框的最快方法。另外,我认为我只是没有正确应用边框,因为下面的代码(我怀疑它不需要单独遍历每个单元格)没有应用任何边框。

from openpyxl.style import Border

wb = load_workbook(filename = _fname)
ws = wb.worksheets[0]  
for _row in ws.range('A1:L'+str(ws.get_highest_row() ) ):
    for _cell in _row:
            _cell.style.borders.left.border_style = Border.BORDER_THIN
            _cell.style.borders.right.border_style = Border.BORDER_THIN
            _cell.style.borders.top.border_style = Border.BORDER_THIN
            _cell.style.borders.bottom.border_style = Border.BORDER_THIN
wb.save(_fname)

所以这段代码有效,但它没有应用我期望的边框(excel中的默认边框),而且它比我想要的要多得多。我的期望是我应该能够做这样的事情:

from openpyxl.style import Border

wb = load_workbook(filename = _fname)
ws = wb.worksheets[0]

_range = ws.some_range_func('A1:L'+str(ws.get_highest_row() ) ):
    _range.style.borders.all_borders = Borders.BORDER_THIN

这个功能存在吗?如果没有,有人可以请至少解释一下如何应用默认边框样式而不是这个稍微厚一点的边框吗?Border.BORDER_THICK、Border.BORDER_MEDIUM、Border.BORDER_THIN 或 Border.BORDER_HAIR 似乎都不正确。

谢谢!

4

9 回答 9

8

可能这很方便:

from openpyxl.reader.excel import load_workbook
from openpyxl.style import Border

def set_border(ws, cell_range):
    rows = was[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")

它执行得相当快。

于 2013-10-08T09:23:40.273 回答
7

对于 openpyxl==3.0.5,以更 Python 的方式:

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') 
于 2020-11-25T01:40:02.620 回答
6

@Karimov 对回答进行了轻微修改
以下是您的代码应该如何

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

下面是使用列表推导的一种更快的方法:

 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]

你使用它的方式是:

self.__format_ws__(ws=writer.book.worksheets[0], cell_range='A1:G10')
于 2019-07-30T08:51:13.217 回答
4

适用于 openpyxl 2.3.5 的决定

from openpyxl.styles import Border, Side

def set_border(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.iter_rows(cell_range)
    for row in rows:
        for cell in row:
            cell.border = border

set_border(worksheet, 'A5:C10')
于 2017-03-30T06:08:24.103 回答
2

@user698585 您的方法看起来不错,但由于当前版本的 openpyxl 更改了实现,因此它不再起作用。所以这应该更新为例如

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

但它会导致错误,即不允许更改样式。作为一种解决方法,我刚刚定义了一个专用样式,但它们只是当前样式加上边框定义的重复 - 只有当您知道更改下的单元格是什么样式时才有效的解决方案。

    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'))))
于 2014-08-13T15:58:11.663 回答
1

如果您需要 pandas excel 数据框的样式(边框...),我的 fork 刚刚合并到 master https://github.com/pydata/pandas/pull/2370#issuecomment-10898427

至于你的边界问题。一次设置所有边框并不能在 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'

单独设置有效('瘦':'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'

可能是 openpyxl 中的错误。但没什么大不了的,只需在功能中设置底部、顶部、左侧、右侧

于 2012-11-30T18:36:58.710 回答
1
def set_border(ws, cell_range, style='thin'):
rows = ws[cell_range]
for row in rows:
    temp_row = copy(row[0].border)
    row[0].border = Border(left=Side(style=style), right=temp_row.right, top=temp_row.top, bottom=temp_row.bottom)

    temp_row = copy(row[-1].border)
    row[-1].border = Border(right=Side(style=style), left=temp_row.left, top=temp_row.top, bottom=temp_row.bottom)
for c in rows[0]:
    temp_row = copy(c.border)
    c.border = Border(top=Side(style=style), left=temp_row.left, bottom=temp_row.bottom, right=temp_row.right)
for c in rows[-1]:
    temp_row = copy(c.border)
    c.border = Border(bottom=Side(style=style), left=temp_row.left, top=temp_row.top, right=temp_row.right)

这样可以保留侧面的现有边框,您还可以设置边框样式

于 2021-01-28T12:00:38.263 回答
0

有同样的问题,但由于折旧找不到任何解决 2019 年此问题的方法。我有一些可以在下面工作的东西..可能会更好,但适用于所有意图和目的。

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'))
于 2019-06-07T13:26:02.260 回答
-1

似乎这个任务没有内置的,我们必须自己做一些步骤,比如:

#need make conversion from alphabet to number due to range function
def A2N(s,e):
    return range(ord(s), ord(e)+1)
#B1 is the border you defined
#Assume you trying border A1-Q1 ... A3-Q3
X = A2N('A','Q')
#print X    
your_desired_sheet_range_rows = range(1,4)
#need two loop to go through cells
for row in your_desired_sheet_rows:
    for col in X:
        ca = chr(col)
        sheet[ca+str(row)].border=B1
于 2017-09-26T03:10:46.033 回答