@@ -1579,6 +1579,14 @@ def _convert_to_protection(cls, protection_dict):
1579
1579
1580
1580
return Protection (** protection_dict )
1581
1581
1582
+ @classmethod
1583
+ def _to_excel_range (cls , startrow , startcol , endrow , endcol ):
1584
+ """Convert (zero based) numeric coordinates to excel range."""
1585
+ from openpyxl .utils .cell import get_column_letter
1586
+ return (f"{ get_column_letter (startcol + 1 )} { startrow + 1 } "
1587
+ ":"
1588
+ f"{ get_column_letter (endcol + 1 )} { endrow + 1 } " )
1589
+
1582
1590
def write_cells (self , cells , sheet_name = None , startrow = 0 , startcol = 0 ,
1583
1591
freeze_panes = None ):
1584
1592
# Write the frame cells using openpyxl.
@@ -1621,10 +1629,10 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0,
1621
1629
if cell .mergestart is not None and cell .mergeend is not None :
1622
1630
1623
1631
wks .merge_cells (
1624
- start_row = startrow + cell .row + 1 ,
1632
+ startrow = startrow + cell .row + 1 ,
1625
1633
start_column = startcol + cell .col + 1 ,
1626
1634
end_column = startcol + cell .mergeend + 1 ,
1627
- end_row = startrow + cell .mergestart + 1
1635
+ endrow = startrow + cell .mergestart + 1
1628
1636
)
1629
1637
1630
1638
# When cells are merged only the top-left cell is preserved
@@ -1645,6 +1653,65 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0,
1645
1653
for k , v in style_kwargs .items ():
1646
1654
setattr (xcell , k , v )
1647
1655
1656
+ def write_table (self , cells , sheet_name = None , startrow = 0 , startcol = 0 ,
1657
+ freeze_panes = None , header = True ):
1658
+ # Write the frame to an excel table using openpyxl.
1659
+
1660
+ from openpyxl .worksheet .table import Table , TableStyleInfo
1661
+ sheet_name = self ._get_sheet_name (sheet_name )
1662
+
1663
+ _style_cache = {}
1664
+
1665
+ if sheet_name in self .sheets :
1666
+ wks = self .sheets [sheet_name ]
1667
+ else :
1668
+ wks = self .book .create_sheet ()
1669
+ wks .title = sheet_name
1670
+ self .sheets [sheet_name ] = wks
1671
+
1672
+ if _validate_freeze_panes (freeze_panes ):
1673
+ wks .freeze_panes = wks .cell (row = freeze_panes [0 ] + 1 ,
1674
+ column = freeze_panes [1 ] + 1 )
1675
+
1676
+ header_rows = 1 if header > 0 else 0
1677
+
1678
+ n_cols = 0
1679
+ n_rows = 0
1680
+ header_cells = {}
1681
+ for cell in cells :
1682
+ val , fmt = self ._value_with_fmt (cell .val )
1683
+ if header and cell .row == 0 and cell .val :
1684
+ header_cells [cell .col ] = cell .val
1685
+ continue
1686
+ xcell = wks .cell (
1687
+ row = startrow + cell .row + 1 ,
1688
+ column = startcol + cell .col + 1 ,
1689
+ value = val ,
1690
+ )
1691
+ n_cols = max (n_cols , cell .col )
1692
+ n_rows = max (n_rows , cell .row )
1693
+
1694
+ # add generic name for every unnamed (index) column that is included
1695
+ [wks .cell (
1696
+ row = startrow + 1 ,
1697
+ column = startcol + col + 1 ,
1698
+ value = (str (header_cells [col ])
1699
+ if col in header_cells
1700
+ else f'Column{ col + 1 } ' ),
1701
+ ) for col in range (n_cols + 1 )]
1702
+
1703
+ ref = self ._to_excel_range (startrow , startcol , startrow + n_rows ,
1704
+ startcol + n_cols )
1705
+ tab = Table (displayName = "Table1" , ref = ref , headerRowCount = header_rows )
1706
+
1707
+ # Add a default style with striped rows
1708
+ style = TableStyleInfo (
1709
+ name = "TableStyleMedium9" , showFirstColumn = False ,
1710
+ showLastColumn = False , showRowStripes = True , showColumnStripes = False )
1711
+ tab .tableStyleInfo = style
1712
+
1713
+ wks .add_table (tab )
1714
+
1648
1715
1649
1716
register_writer (_OpenpyxlWriter )
1650
1717
@@ -1992,5 +2059,43 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0,
1992
2059
startcol + cell .col ,
1993
2060
val , style )
1994
2061
2062
+ def write_table (self , cells , sheet_name = None , startrow = 0 , startcol = 0 ,
2063
+ freeze_panes = None , header = True ):
2064
+ # Write the frame to an excel table using xlsxwriter.
2065
+ sheet_name = self ._get_sheet_name (sheet_name )
2066
+
2067
+ if sheet_name in self .sheets :
2068
+ wks = self .sheets [sheet_name ]
2069
+ else :
2070
+ wks = self .book .add_worksheet (sheet_name )
2071
+ self .sheets [sheet_name ] = wks
2072
+
2073
+ if _validate_freeze_panes (freeze_panes ):
2074
+ wks .freeze_panes (* (freeze_panes ))
2075
+
2076
+ n_cols = 0
2077
+ n_rows = 0
2078
+ header_cells = {}
2079
+ for cell in cells :
2080
+ val , fmt = self ._value_with_fmt (cell .val )
2081
+ if header and cell .row == 0 and cell .val :
2082
+ header_cells [cell .col ] = cell .val
2083
+ continue
2084
+ wks .write (startrow + cell .row ,
2085
+ startcol + cell .col ,
2086
+ val )
2087
+ n_cols = max (n_cols , cell .col )
2088
+ n_rows = max (n_rows , cell .row )
2089
+
2090
+ # add generic name for every unnamed (index) column that is included
2091
+ columns = [{'header' : str (header_cells [col ])
2092
+ if col in header_cells else f'Column{ col + 1 } ' }
2093
+ for col in range (n_cols + 1 )]
2094
+
2095
+ options = {'columns' : columns }
2096
+
2097
+ wks .add_table (startrow , startcol , startrow + n_rows ,
2098
+ startcol + n_cols , options )
2099
+
1995
2100
1996
2101
register_writer (_XlsxWriter )
0 commit comments