Apply borders to all cells in a range with openpyxl
我有一个脚本,该脚本需要一个熊猫数据框并将其切成几百个块,并将每个块另存为单独的excel文件。每个块将具有相同的列数,但行数会有所不同。我已经弄清楚了如何使用openpyxl将所有其他必要的格式应用于这些文件,但是我尚未确定应用边框的最快方法。另外,我认为我只是没有正确地应用边框,因为下面的代码(我怀疑不需要单独遍历每个单元格)不应用任何边框。
1 2 3 4 5 6 7 8 9 10 11 | 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中的默认边框),并且比我希望的执行了更多的步骤。我的期望是我应该能够执行以下操作:
1 2 3 4 5 6 7 | 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似乎都不正确。
谢谢!
也许这很方便:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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") |
它执行得相当快。
适用于openpyxl 2.3.5的决定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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') |
@Karimov有一个稍作修改的答案
下面是您的代码应如何
1 | from openpyxl.styles import Border, Side, Font, Alignment |
1 2 3 4 5 6 7 8 9 10 | 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 |
下面是使用列表理解的一种更快的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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] |
您使用它的方式是:
1 | self.__format_ws__(ws=writer.book.worksheets[0], cell_range='A1:G10') |
@ user698585,您的方法似乎不错,但由于当前版本的openpyxl更改了实现,因此它不再起作用。因此,应将其更新为
1 | ws.cell(row=1, column=1).style.border.top.border_style = borders.BORDER_MEDIUM |
但是会导致错误,即不允许更改样式。
作为一种解决方法,我仅定义了一种专用样式,但是它们仅是当前样式和边框定义的复制品-仅当您知道哪种样式使单元格发生变化时,这种解决方案才有效。
1 2 3 4 | 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')))) |
如果您需要为熊猫Excel数据框设置样式(边框...),那么我的fork刚刚被合并到master中
https://github.com/pydata/pandas/pull/2370#issuecomment-10898427
至于你边界问题。
一次设置所有边界在openpyxl中无法正常工作。
1 2 3 4 | 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' |
单独设置有效(" thin":" FF000000")
1 2 3 4 | 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中的错误。但没什么大不了的,只是在功能上包装设置底部,顶部,左侧,右侧
曾经有过同样的问题,但由于折旧,找不到任何可以解决此问题的方法(2019年)。我在下面有一些可行的方法..可能更好,但可以满足所有意图和目的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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')) |
似乎没有内置此任务,我们必须自己做一些步骤,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 | #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 |