Skip to content

Commit b19ae90

Browse files
committed
Support more styles for xlsxwriter
1 parent b555c43 commit b19ae90

File tree

1 file changed

+103
-25
lines changed

1 file changed

+103
-25
lines changed

pandas/io/excel.py

+103-25
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,63 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0,
15961596
startcol + cell.col,
15971597
val, style)
15981598

1599+
# Map from openpyxl-oriented styles to flatter xlsxwriter representation
1600+
STYLE_MAPPING = [
1601+
(('font', 'name'), 'font_name'),
1602+
(('font', 'sz'), 'font_size'),
1603+
(('font', 'size'), 'font_size'),
1604+
(('font', 'color', 'rgb'), 'font_color'),
1605+
(('font', 'b'), 'bold'),
1606+
(('font', 'bold'), 'bold'),
1607+
(('font', 'i'), 'italic'),
1608+
(('font', 'italic'), 'italic'),
1609+
(('font', 'u'), 'underline'),
1610+
(('font', 'underline'), 'underline'),
1611+
(('font', 'strike'), 'font_strikeout'),
1612+
(('font', 'vertAlign'), 'font_script'),
1613+
(('font', 'vertalign'), 'font_script'),
1614+
(('number_format', 'format_code'), 'num_format'),
1615+
(('number_format',), 'num_format'),
1616+
(('protection', 'locked'), 'locked'),
1617+
(('protection', 'hidden'), 'hidden'),
1618+
(('alignment', 'horizontal'), 'align'),
1619+
(('alignment', 'vertical'), 'valign'),
1620+
(('alignment', 'text_rotation'), 'rotation'),
1621+
(('alignment', 'wrap_text'), 'text_wrap'),
1622+
(('alignment', 'indent'), 'indent'),
1623+
(('alignment', 'shrink_to_fit'), 'shrink'),
1624+
(('fill', 'patternType'), 'pattern'),
1625+
(('fill', 'patterntype'), 'pattern'),
1626+
(('fill', 'fill_type'), 'pattern'),
1627+
(('fill', 'start_color', 'rgb'), 'fg_color'),
1628+
(('fill', 'fgColor', 'rgb'), 'fg_color'),
1629+
(('fill', 'fgcolor', 'rgb'), 'fg_color'),
1630+
(('fill', 'start_color'), 'fg_color'),
1631+
(('fill', 'fgColor'), 'fg_color'),
1632+
(('fill', 'fgcolor'), 'fg_color'),
1633+
(('fill', 'end_color', 'rgb'), 'bg_color'),
1634+
(('fill', 'bgColor', 'rgb'), 'bg_color'),
1635+
(('fill', 'bgcolor', 'rgb'), 'bg_color'),
1636+
(('fill', 'end_color'), 'bg_color'),
1637+
(('fill', 'bgColor'), 'bg_color'),
1638+
(('fill', 'bgcolor'), 'bg_color'),
1639+
(('border', 'color', 'rgb'), 'border_color'),
1640+
(('border', 'color'), 'border_color'),
1641+
(('border', 'style'), 'border'),
1642+
(('border', 'top', 'color', 'rgb'), 'top_color'),
1643+
(('border', 'top', 'color'), 'top_color'),
1644+
(('border', 'top', 'style'), 'top'),
1645+
(('border', 'right', 'color', 'rgb'), 'right_color'),
1646+
(('border', 'right', 'color'), 'right_color'),
1647+
(('border', 'right', 'style'), 'right'),
1648+
(('border', 'bottom', 'color', 'rgb'), 'bottom_color'),
1649+
(('border', 'bottom', 'color'), 'bottom_color'),
1650+
(('border', 'bottom', 'style'), 'bottom'),
1651+
(('border', 'left', 'color', 'rgb'), 'left_color'),
1652+
(('border', 'left', 'color'), 'left_color'),
1653+
(('border', 'left', 'style'), 'left'),
1654+
]
1655+
15991656
def _convert_to_style(self, style_dict, num_format_str=None):
16001657
"""
16011658
converts a style_dict to an xlsxwriter format object
@@ -1610,35 +1667,56 @@ def _convert_to_style(self, style_dict, num_format_str=None):
16101667
return None
16111668

16121669
# Create a XlsxWriter format object.
1613-
xl_format = self.book.add_format()
1670+
props = {}
16141671

16151672
if num_format_str is not None:
1616-
xl_format.set_num_format(num_format_str)
1673+
props['num_format'] = num_format_str
16171674

16181675
if style_dict is None:
1619-
return xl_format
1620-
1621-
# Map the cell font to XlsxWriter font properties.
1622-
if style_dict.get('font'):
1623-
font = style_dict['font']
1624-
if font.get('bold'):
1625-
xl_format.set_bold()
1626-
1627-
# Map the alignment to XlsxWriter alignment properties.
1628-
alignment = style_dict.get('alignment')
1629-
if alignment:
1630-
if (alignment.get('horizontal') and
1631-
alignment['horizontal'] == 'center'):
1632-
xl_format.set_align('center')
1633-
if (alignment.get('vertical') and
1634-
alignment['vertical'] == 'top'):
1635-
xl_format.set_align('top')
1636-
1637-
# Map the cell borders to XlsxWriter border properties.
1638-
if style_dict.get('borders'):
1639-
xl_format.set_border()
1640-
1641-
return xl_format
1676+
return self.book.add_format(props)
1677+
1678+
if 'borders' in style_dict:
1679+
style_dict['border'] = style_dict.pop('borders')
1680+
1681+
for src, dst in self.STYLE_MAPPING:
1682+
# src is a sequence of keys into a nested dict
1683+
# dst is a flat key
1684+
if dst in props:
1685+
continue
1686+
v = style_dict
1687+
for k in src:
1688+
try:
1689+
v = v[k]
1690+
except (KeyError, TypeError):
1691+
break
1692+
else:
1693+
props[dst] = v
1694+
1695+
if isinstance(props.get('pattern'), string_types):
1696+
# TODO: support other fill patterns
1697+
props['pattern'] = 0 if props['pattern'] == 'none' else 1
1698+
1699+
for k in ['border', 'top', 'right', 'bottom', 'left']:
1700+
if isinstance(props.get(k), string_types):
1701+
try:
1702+
props[k] = ['none', 'thin', 'medium', 'dashed', 'dotted',
1703+
'thick', 'double', 'hair', 'mediumDashed',
1704+
'dashDot', 'mediumDashDot', 'dashDotDot',
1705+
'mediumDashDotDot', 'slantDashDot'].\
1706+
index(props[k])
1707+
except ValueError:
1708+
props[k] = 2
1709+
1710+
if isinstance(props.get('font_script'), string_types):
1711+
props['font_script'] = ['baseline', 'superscript', 'subscript'].\
1712+
index(props['font_script'])
1713+
1714+
if isinstance(props.get('underline'), string_types):
1715+
props['underline'] = {'none': 0, 'single': 1, 'double': 2,
1716+
'singleAccounting': 33,
1717+
'doubleAccounting': 34}[props['underline']]
1718+
1719+
return self.book.add_format(props)
16421720

16431721

16441722
register_writer(_XlsxWriter)

0 commit comments

Comments
 (0)