Skip to content

ENH: Added ability to freeze panes from DataFrame.to_excel() (#15160) #15291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

jeffcarey
Copy link
Contributor

@jeffcarey jeffcarey commented Feb 2, 2017

The ability to freeze panes has been added to the to_excel() method on data frames. The parameter is a tuple of 2 integers, representing the bottom-most row and right-most column to freeze, respectively. (This is the same format xlsxwriter uses). The default value is None, resulting in no freezing.

Example usage:
df.to_excel(writer, sheet_name='Sheet1', freeze_panes=(1,1))

The following engines are supported:
xlsxwriter
xlwt
openpyxl22

The parameter exists for openpyxl20 and openpyxl1 but it has no effect, in anticipation of support for these versions being dropped (#15184).

Can one of the maintainers confirm this approach for engine support is adequate, or suggest an alternative? Once that is settled I can write a test to create a workbook using each engine and then try reading it back in using openpyxl.

@codecov-io
Copy link

codecov-io commented Feb 2, 2017

Codecov Report

Merging #15291 into master will increase coverage by <.01%.
The diff coverage is 95%.

@@            Coverage Diff             @@
##           master   #15291      +/-   ##
==========================================
+ Coverage   90.36%   90.37%   +<.01%     
==========================================
  Files         135      135              
  Lines       49438    49452      +14     
==========================================
+ Hits        44675    44690      +15     
+ Misses       4763     4762       -1
Impacted Files Coverage Δ
pandas/core/generic.py 96.33% <ø> (ø)
pandas/io/excel.py 79.64% <100%> (+0.24%)
pandas/core/frame.py 97.82% <83.33%> (-0.05%)
pandas/util/testing.py 81.97% <ø> (+0.18%)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d6f8b46...cef8fce. Read the comment docs.

@jreback jreback added Enhancement IO Excel read_excel, to_excel labels Feb 2, 2017
@jreback
Copy link
Contributor

jreback commented Feb 2, 2017

seems reasonable to me. yeah I wouldn't worry about supporting older version of openpyxl.

not sure how to test this (except for a smoke test I think).

@@ -1322,6 +1327,10 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0):
wks.title = sheet_name
self.sheets[sheet_name] = wks

if freeze_panes is not None:
wks.freeze_panes = wks.cell(row=freeze_panes[0] + 1,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vaidate that its a len 2 tuples

@@ -1404,6 +1414,11 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0):
wks = self.book.add_sheet(sheet_name)
self.sheets[sheet_name] = wks

if freeze_panes is not None:
wks.set_panes_frozen(True)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

@@ -1529,6 +1545,9 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0):

style_dict = {}

if freeze_panes is not None:
wks.freeze_panes(*(freeze_panes))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same (you may want to make a general validation for this somewhere)

@jreback
Copy link
Contributor

jreback commented Feb 2, 2017

pls add a whatsnew note, update docs in io.rst (maybe put a small section on 'Style'), IOW things that you can do. (we don't really support much readl styling yet (other issues about that), though things like float_format could be included).

@@ -1390,7 +1390,8 @@ def to_csv(self, path_or_buf=None, sep=",", na_rep='', float_format=None,
def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='',
float_format=None, columns=None, header=True, index=True,
index_label=None, startrow=0, startcol=0, engine=None,
merge_cells=True, encoding=None, inf_rep='inf', verbose=True):
merge_cells=True, encoding=None, inf_rep='inf', verbose=True,
freeze_panes=None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add freeze_panes to the docstring here, which this function uses

_shared_docs['to_excel'] = """

@jeffcarey
Copy link
Contributor Author

@jreback @chris-b1 Requested changes made, please review.

Also, I can look at supporting autofilter as well, as was mentioned in the original issue. Shall I open a separate issue for that? Sounds cleaner to me.

@jreback
Copy link
Contributor

jreback commented Feb 4, 2017

@jeffcarey that's fine to open a new issue.

One thing to thing about is do we just keep adding kwargs to .to_excel? or a better API?

@chris-b1

@@ -1058,6 +1058,9 @@ def __setstate__(self, state):
inf_rep : string, default 'inf'
Representation for infinity (there is no native representation for
infinity in Excel)
freeze_panes : tuple of integer (length 2), default None
Specifies the bottommost row and rightmost column that
is to be frozen
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a versionadded tag here

@@ -1322,6 +1328,14 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0):
wks.title = sheet_name
self.sheets[sheet_name] = wks

if (
freeze_panes is not None and
Copy link
Contributor

@jreback jreback Feb 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe make this a validation function

freeze_panes = _validate_freeze_panes(freeze_panes)
if freeze_panes:
    ....

@jreback
Copy link
Contributor

jreback commented Feb 4, 2017

can you add a smoke test to write & then read back a simple frame.

@chris-b1
Copy link
Contributor

chris-b1 commented Feb 4, 2017

@jreback - not sure on the API, for now probably easiest as a kwarg.

I guess could see having some kind of template / styler like api?

df.to_excel('tmp.xlsx') # default, template=ExcelTemplate

my_template =  pd.ExcelTemplate.freeze_panes().autofilter()

df.to_excel('tmp2.xlsx', template=my_template)

@jreback
Copy link
Contributor

jreback commented Feb 4, 2017

@chris-b1 yeah, I guess if only a couple of other options then kwargs is the way to go.

@@ -2823,6 +2824,16 @@ argument to ``to_excel`` and to ``ExcelWriter``. The built-in engines are:

df.to_excel('path_to_file.xlsx', sheet_name='Sheet1')

Style and Formatting
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can add a ref-tag here: io.excel.style

all(isinstance(item, int) for item in freeze_panes)
):
return freeze_panes
else:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need the else

@@ -1837,6 +1837,15 @@ def test_true_and_false_value_options(self):
tm.assert_frame_equal(read_frame, expected)


# GH15160
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put the comment inside the function

@jreback jreback added this to the 0.20.0 milestone Feb 7, 2017
@jreback
Copy link
Contributor

jreback commented Feb 7, 2017

minor comments, some flake issues (use git diff master | flake8 --diff to see).

lgtm. ping on green.

@jeffcarey
Copy link
Contributor Author

@jreback Checks are green. Do you want me to fix the conflict that came up in the whatsnew or is that something you can do?

@jreback
Copy link
Contributor

jreback commented Feb 8, 2017

@jorisvandenbossche comments?

@jeffcarey can fix it on merge.

@jreback
Copy link
Contributor

jreback commented Feb 14, 2017

can you rebase

@jreback
Copy link
Contributor

jreback commented Feb 15, 2017

@jeffcarey can you rebase and push one more time. sorry had asome issues with the ci.

Cleaning up tests and whatsnew

Added additional validation, whats new entry, documentation entry

Clean up conflicts

Added 1) test 2) validate function for freeze_panes 3) versionadded tag

Clean up commits

Fixed flake differences, Added tag in docs
@jreback
Copy link
Contributor

jreback commented Feb 16, 2017

thanks!

keem em coming!

Copy link
Member

@jorisvandenbossche jorisvandenbossche left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeffcarey a bit late feedback for the PR, but if you would like to do a small follow-up PR for this, always welcome!


- ``float_format`` : Format string for floating point numbers (default None)
- ``freeze_panes`` : A tuple of two integers representing the bottommost row and rightmost column to freeze. Each of these parameters is one-based, so (1, 1) will
freeze the first row and first column (default None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line will not be formatted nicely in the html docs (it needs two spaces at the start to have it indented in the list)

@@ -1072,6 +1072,11 @@ def __setstate__(self, state):
inf_rep : string, default 'inf'
Representation for infinity (there is no native representation for
infinity in Excel)
freeze_panes : tuple of integer (length 2), default None
Specifies the bottommost row and rightmost column that
is to be frozen
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this start at zero or one?

@jreback
Copy link
Contributor

jreback commented Mar 4, 2017

@jeffcarey I just realized that https://github.com/pandas-dev/pandas/blame/master/pandas/core/frame.py#L1441 was defined in core/frame.py. This should only be in io/excel.py. We want to make code core/frame.py as simple as possible, and this is completely extraneous.

Can you do a PR to remove (and simply put it in .write_cells, where I think it is already validated anyhow).

AnkurDedania pushed a commit to AnkurDedania/pandas that referenced this pull request Mar 21, 2017
…dev#15160)

closes pandas-dev#15160

Author: Jeff Carey <[email protected]>

Closes pandas-dev#15291 from jeffcarey/enh-15160 and squashes the following commits:

cef8fce [Jeff Carey] ENH: Added ability to freeze panes from DataFrame.to_excel()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement IO Excel read_excel, to_excel
Projects
None yet
Development

Successfully merging this pull request may close these issues.

to_excel should (optionally) freeze panes
5 participants