Skip to content

Commit f198721

Browse files
committed
BUG: let formatters be list in DataFrame.to_string, too. close #2520
1 parent baf54ed commit f198721

File tree

3 files changed

+35
-14
lines changed

3 files changed

+35
-14
lines changed

RELEASE.rst

+2
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ pandas 0.10.0
230230
- Union of empty DataFrames now return empty with concatenated index (GH2307_)
231231
- DataFrame.sort_index raises more helpful exception if sorting by column
232232
with duplicates (GH2488_)
233+
- DataFrame.to_string formatters can be list, too (GH2520_)
233234

234235
.. _GH407: https://github.com/pydata/pandas/issues/407
235236
.. _GH821: https://github.com/pydata/pandas/issues/821
@@ -343,6 +344,7 @@ pandas 0.10.0
343344
.. _GH2133: https://github.com/pydata/pandas/issues/2133
344345
.. _GH2307: https://github.com/pydata/pandas/issues/2307
345346
.. _GH2488: https://github.com/pydata/pandas/issues/2488
347+
.. _GH2520: https://github.com/pydata/pandas/issues/2520
346348

347349

348350
pandas 0.9.1

pandas/core/format.py

+27-11
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
string representation of NAN to use, default 'NaN'
4141
formatters : list or dict of one-parameter functions, optional
4242
formatter functions to apply to columns' elements by position or name,
43-
default None, if the result is a string , it must be a unicode string.
43+
default None, if the result is a string , it must be a unicode
44+
string. List must be of length equal to the number of columns.
4445
float_format : one-parameter function, optional
4546
formatter function to apply to columns' elements if they are floats
4647
default None
@@ -170,8 +171,22 @@ def _strlen(x):
170171

171172
return _strlen
172173

174+
class TableFormatter(object):
173175

174-
class DataFrameFormatter(object):
176+
177+
def _get_formatter(self, i):
178+
if isinstance(self.formatters, (list, tuple)):
179+
if com.is_integer(i):
180+
return self.formatters[i]
181+
else:
182+
return None
183+
else:
184+
if com.is_integer(i) and i not in self.columns:
185+
i = self.columns[i]
186+
return self.formatters.get(i, None)
187+
188+
189+
class DataFrameFormatter(TableFormatter):
175190
"""
176191
Render a DataFrame
177192
@@ -361,8 +376,7 @@ def to_latex(self, force_unicode=None, column_format=None):
361376
self.buf.write('\\end{tabular}\n')
362377

363378
def _format_col(self, i):
364-
col = self.columns[i]
365-
formatter = self.formatters.get(col)
379+
formatter = self._get_formatter(i)
366380
return format_array(self.frame.icol(i).values, formatter,
367381
float_format=self.float_format,
368382
na_rep=self.na_rep,
@@ -399,9 +413,10 @@ def is_numeric_dtype(dtype):
399413
dtypes = self.frame.dtypes
400414
need_leadsp = dict(zip(fmt_columns, map(is_numeric_dtype, dtypes)))
401415
str_columns = [[' ' + x
402-
if col not in self.formatters and need_leadsp[x]
416+
if not self._get_formatter(i) and need_leadsp[x]
403417
else x]
404-
for col, x in zip(self.columns, fmt_columns)]
418+
for i, (col, x) in
419+
enumerate(zip(self.columns, fmt_columns))]
405420

406421
if self.show_index_names and self.has_index_names:
407422
for x in str_columns:
@@ -425,7 +440,8 @@ def _get_formatted_index(self):
425440
show_index_names = self.show_index_names and self.has_index_names
426441
show_col_names = (self.show_index_names and self.has_column_names)
427442

428-
fmt = self.formatters.get('__index__', None)
443+
fmt = self._get_formatter('__index__')
444+
429445
if isinstance(index, MultiIndex):
430446
fmt_index = index.format(sparsify=self.sparsify, adjoin=False,
431447
names=show_index_names,
@@ -457,7 +473,7 @@ def _get_column_name_list(self):
457473
return names
458474

459475

460-
class HTMLFormatter(object):
476+
class HTMLFormatter(TableFormatter):
461477

462478
indent_delta = 2
463479

@@ -656,9 +672,9 @@ def _write_body(self, indent):
656672
def _write_regular_rows(self, fmt_values, indent):
657673
ncols = len(self.columns)
658674

659-
if '__index__' in self.fmt.formatters:
660-
f = self.fmt.formatters['__index__']
661-
index_values = self.frame.index.map(f)
675+
fmt = self.fmt._get_formatter('__index__')
676+
if fmt is not None:
677+
index_values = self.frame.index.map(fmt)
662678
else:
663679
index_values = self.frame.index.format()
664680

pandas/tests/test_format.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,16 @@ def test_to_string_with_formatters(self):
174174
'object': [(1,2), True, False]},
175175
columns=['int', 'float', 'object'])
176176

177-
result = df.to_string(formatters={'int': lambda x: '0x%x' % x,
178-
'float': lambda x: '[% 4.1f]' % x,
179-
'object': lambda x: '-%s-' % str(x)})
177+
formatters = [('int', lambda x: '0x%x' % x),
178+
('float', lambda x: '[% 4.1f]' % x),
179+
('object', lambda x: '-%s-' % str(x))]
180+
result = df.to_string(formatters=dict(formatters))
181+
result2 = df.to_string(formatters=zip(*formatters)[1])
180182
self.assertEqual(result, (' int float object\n'
181183
'0 0x1 [ 1.0] -(1, 2)-\n'
182184
'1 0x2 [ 2.0] -True-\n'
183185
'2 0x3 [ 3.0] -False-'))
186+
self.assertEqual(result, result2)
184187

185188
def test_to_string_with_formatters_unicode(self):
186189
df = DataFrame({u'c/\u03c3':[1,2,3]})

0 commit comments

Comments
 (0)