Skip to content

Commit c4fec02

Browse files
committed
Added autofilter parameter to Excel output for both xlsxwriter and openpyxl engines.
1 parent ddd90b0 commit c4fec02

File tree

8 files changed

+49
-4
lines changed

8 files changed

+49
-4
lines changed

pandas/core/generic.py

+5
Original file line numberDiff line numberDiff line change
@@ -2145,6 +2145,7 @@ def to_excel(
21452145
inf_rep="inf",
21462146
verbose=True,
21472147
freeze_panes=None,
2148+
autofilter=False,
21482149
storage_options: StorageOptions = None,
21492150
) -> None:
21502151
"""
@@ -2210,6 +2211,9 @@ def to_excel(
22102211
freeze_panes : tuple of int (length 2), optional
22112212
Specifies the one-based bottommost row and rightmost column that
22122213
is to be frozen.
2214+
autofilter : bool, default False
2215+
Specifies whether filters should be added to the columns in the
2216+
spreadsheet.
22132217
{storage_options}
22142218
22152219
.. versionadded:: 1.2.0
@@ -2286,6 +2290,7 @@ def to_excel(
22862290
startrow=startrow,
22872291
startcol=startcol,
22882292
freeze_panes=freeze_panes,
2293+
autofilter=autofilter,
22892294
engine=engine,
22902295
storage_options=storage_options,
22912296
)

pandas/io/excel/_base.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,8 @@ def engine(self):
871871

872872
@abc.abstractmethod
873873
def write_cells(
874-
self, cells, sheet_name=None, startrow=0, startcol=0, freeze_panes=None
874+
self, cells, sheet_name=None, startrow=0, startcol=0,
875+
freeze_panes=None, autofilter=None
875876
):
876877
"""
877878
Write given formatted cells into Excel an excel sheet

pandas/io/excel/_odswriter.py

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def write_cells(
6262
startrow: int = 0,
6363
startcol: int = 0,
6464
freeze_panes: tuple[int, int] | None = None,
65+
autofilter: bool = False,
6566
) -> None:
6667
"""
6768
Write the frame cells using odf

pandas/io/excel/_openpyxl.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,8 @@ def _convert_to_protection(cls, protection_dict):
417417
return Protection(**protection_dict)
418418

419419
def write_cells(
420-
self, cells, sheet_name=None, startrow=0, startcol=0, freeze_panes=None
420+
self, cells, sheet_name=None, startrow=0, startcol=0,
421+
freeze_panes=None, autofilter=False
421422
):
422423
# Write the frame cells using openpyxl.
423424
sheet_name = self._get_sheet_name(sheet_name)
@@ -454,6 +455,9 @@ def write_cells(
454455
row=freeze_panes[0] + 1, column=freeze_panes[1] + 1
455456
)
456457

458+
max_row = 0
459+
max_col = 0
460+
457461
for cell in cells:
458462
xcell = wks.cell(
459463
row=startrow + cell.row + 1, column=startcol + cell.col + 1
@@ -501,6 +505,15 @@ def write_cells(
501505
for k, v in style_kwargs.items():
502506
setattr(xcell, k, v)
503507

508+
if startrow + cell.row > max_row:
509+
max_row = startrow + cell.row
510+
if startcol + cell.col > max_col:
511+
max_col = startcol + cell.col
512+
513+
if autofilter:
514+
from openpyxl.utils import get_column_letter
515+
wks.auto_filter.ref = "A1:" + get_column_letter(max_col + 1) + str(max_row)
516+
504517

505518
class OpenpyxlReader(BaseExcelReader):
506519
def __init__(

pandas/io/excel/_xlsxwriter.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,8 @@ def save(self):
208208
return self.book.close()
209209

210210
def write_cells(
211-
self, cells, sheet_name=None, startrow=0, startcol=0, freeze_panes=None
211+
self, cells, sheet_name=None, startrow=0, startcol=0, freeze_panes=None,
212+
autofilter=False
212213
):
213214
# Write the frame cells using xlsxwriter.
214215
sheet_name = self._get_sheet_name(sheet_name)
@@ -224,6 +225,9 @@ def write_cells(
224225
if validate_freeze_panes(freeze_panes):
225226
wks.freeze_panes(*(freeze_panes))
226227

228+
max_row = 0
229+
max_col = 0
230+
227231
for cell in cells:
228232
val, fmt = self._value_with_fmt(cell.val)
229233

@@ -248,3 +252,11 @@ def write_cells(
248252
)
249253
else:
250254
wks.write(startrow + cell.row, startcol + cell.col, val, style)
255+
256+
if startrow + cell.row > max_row:
257+
max_row = startrow + cell.row
258+
if startcol + cell.col > max_col:
259+
max_col = startcol + cell.col
260+
261+
if autofilter:
262+
wks.autofilter(0, 0, max_row, max_col)

pandas/io/excel/_xlwt.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ def save(self):
6666
self.book.save(self.handles.handle)
6767

6868
def write_cells(
69-
self, cells, sheet_name=None, startrow=0, startcol=0, freeze_panes=None
69+
self, cells, sheet_name=None, startrow=0, startcol=0,
70+
freeze_panes=None, autofilter=False,
7071
):
7172

7273
sheet_name = self._get_sheet_name(sheet_name)

pandas/io/formats/excel.py

+5
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@ def write(
786786
startrow=0,
787787
startcol=0,
788788
freeze_panes=None,
789+
autofilter=False,
789790
engine=None,
790791
storage_options: StorageOptions = None,
791792
):
@@ -801,6 +802,9 @@ def write(
801802
freeze_panes : tuple of integer (length 2), default None
802803
Specifies the one-based bottommost row and rightmost column that
803804
is to be frozen
805+
autofilter : bool, default False
806+
Specifies whether filters should be added to the columns in the
807+
spreadsheet.
804808
engine : string, default None
805809
write engine to use if writer is a path - you can also set this
806810
via the options ``io.excel.xlsx.writer``, ``io.excel.xls.writer``,
@@ -843,6 +847,7 @@ def write(
843847
startrow=startrow,
844848
startcol=startcol,
845849
freeze_panes=freeze_panes,
850+
autofilter=autofilter,
846851
)
847852
finally:
848853
# make sure to close opened file handles

pandas/tests/io/excel/test_writers.py

+7
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,13 @@ def test_freeze_panes(self, path):
12701270
result = pd.read_excel(path, index_col=0)
12711271
tm.assert_frame_equal(result, expected)
12721272

1273+
def test_autofilter(self, path):
1274+
expected = DataFrame([[1, 2], [3, 4]], columns=["col1", "col2"])
1275+
expected.to_excel(path, "Sheet1", autofilter=True)
1276+
1277+
result = pd.read_excel(path, index_col=0)
1278+
tm.assert_frame_equal(result, expected)
1279+
12731280
def test_path_path_lib(self, engine, ext):
12741281
df = tm.makeDataFrame()
12751282
writer = partial(df.to_excel, engine=engine)

0 commit comments

Comments
 (0)