Skip to content

BUG: Improve col_space in to_html to allow css length strings (#25941) #26012

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

Merged
merged 12 commits into from
Apr 29, 2019
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.25.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ I/O
- Bug in ``read_csv`` which would not raise ``ValueError`` if a column index in ``usecols`` was out of bounds (:issue:`25623`)
- Improved the explanation for the failure when value labels are repeated in Stata dta files and suggested work-arounds (:issue:`25772`)
- Improved :meth:`pandas.read_stata` and :class:`pandas.io.stata.StataReader` to read incorrectly formatted 118 format files saved by Stata (:issue:`25960`)
- Improved the ``col_space`` parameter in :meth:`DataFrame.to_html` to accept a string so CSS length values can be set correctly (:issue:`25941`)

Plotting
^^^^^^^^
Expand Down
11 changes: 9 additions & 2 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,9 @@ def _repr_html_(self):

@Substitution(header='Write out the column names. If a list of strings '
'is given, it is assumed to be aliases for the '
'column names')
'column names',
col_space_type='int',
col_space='The minimum width of each column')
@Substitution(shared_params=fmt.common_docstring,
returns=fmt.return_docstring)
def to_string(self, buf=None, columns=None, col_space=None, header=True,
Expand Down Expand Up @@ -2149,7 +2151,12 @@ def to_parquet(self, fname, engine='auto', compression='snappy',
compression=compression, index=index,
partition_cols=partition_cols, **kwargs)

@Substitution(header='Whether to print column labels, default True')
@Substitution(header='Whether to print column labels, default True',
col_space_type='str or int',
col_space='The minimum width of each column in CSS length '
'units. An int is assumed to be px units.\n\n'
' .. versionadded:: 0.25.0\n'
' Abillity to use str')
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you need a blank line here. does this render properly when this doc-page is built (meaning w/o warning)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Didn't need an extra blank line, but I did need to indent the line under versionadded a little more to remove warnings. Should be all set now. Here is what it looks like rendered:

image

@Substitution(shared_params=fmt.common_docstring,
returns=fmt.return_docstring)
def to_html(self, buf=None, columns=None, col_space=None, header=True,
Expand Down
4 changes: 2 additions & 2 deletions pandas/io/formats/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
Buffer to write to.
columns : sequence, optional, default None
The subset of columns to write. Writes all columns by default.
col_space : int, optional
The minimum width of each column.
col_space : %(col_space_type)s, optional
%(col_space)s.
header : bool, optional
%(header)s.
index : bool, optional, default True
Expand Down
11 changes: 8 additions & 3 deletions pandas/io/formats/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,13 @@ def write(self, s, indent=0):
rs = pprint_thing(s)
self.elements.append(' ' * indent + rs)

def write_th(self, s, indent=0, tags=None):
if self.fmt.col_space is not None and self.fmt.col_space > 0:
def write_th(self, s, header=False, indent=0, tags=None):
# header=False is for use of this function inside <tbody>
# header is set to True for use inside <thead>
if header and self.fmt.col_space is not None:
if isinstance(self.fmt.col_space, int):
self.fmt.col_space = ('{colspace}px'
Copy link
Contributor

Choose a reason for hiding this comment

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

instead of actually changing this parameter, can you just use it directly; I would do this check instead in the initializer step

Copy link
Contributor Author

Choose a reason for hiding this comment

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

moved to init as requested

.format(colspace=self.fmt.col_space))
tags = (tags or "")
tags += ('style="min-width: {colspace};"'
.format(colspace=self.fmt.col_space))
Expand Down Expand Up @@ -137,7 +142,7 @@ def write_tr(self, line, indent=0, indent_delta=0, header=False,
for i, s in enumerate(line):
val_tag = tags.get(i, None)
if header or (self.bold_rows and i < nindex_levels):
self.write_th(s, indent, tags=val_tag)
self.write_th(s, indent=indent, header=header, tags=val_tag)
else:
self.write_td(s, indent, tags=val_tag)

Expand Down
14 changes: 14 additions & 0 deletions pandas/tests/io/formats/test_to_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,3 +643,17 @@ def test_to_html_round_column_headers():
notebook = df.to_html(notebook=True)
assert "0.55555" in html
assert "0.556" in notebook


@pytest.mark.parametrize("unit", ['100px', '10%', '5em', 150])
Copy link
Member

Choose a reason for hiding this comment

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

Per @simonjayhawkins does it make sense to allow percentages here?

def test_to_html_with_col_space_units(unit):
# GH 25941
df = DataFrame(np.random.random(size=(1, 3)))
result = df.to_html(col_space=unit)
result = result.split('tbody')[0]
hdrs = [x for x in result.split("\n") if re.search(r"<th[>\s]", x)]
if isinstance(unit, int):
unit = str(unit) + 'px'
for h in hdrs:
expected = '<th style="min-width: {unit};">'.format(unit=unit)
assert expected in h