From fe050267d09a6648dd52c3a7427e574cb6f55e15 Mon Sep 17 00:00:00 2001 From: Daniel Manson Date: Tue, 3 Mar 2015 15:15:38 +0000 Subject: [PATCH 1/7] format.py - escape info column specific (optionally) --- pandas/core/format.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pandas/core/format.py b/pandas/core/format.py index 29f1e1efe9f5d..854594003d3c5 100644 --- a/pandas/core/format.py +++ b/pandas/core/format.py @@ -840,16 +840,16 @@ def write_th(self, s, indent=0, tags=None): return self._write_cell(s, kind='th', indent=indent, tags=tags) - def write_td(self, s, indent=0, tags=None): - return self._write_cell(s, kind='td', indent=indent, tags=tags) + def write_td(self, s, indent=0, tags=None,column=None): + return self._write_cell(s, kind='td', indent=indent, tags=tags, column=column) - def _write_cell(self, s, kind='td', indent=0, tags=None): + def _write_cell(self, s, kind='td', indent=0, tags=None, column=None): if tags is not None: start_tag = '<%s %s>' % (kind, tags) else: start_tag = '<%s>' % kind - - if self.escape: + + if (self.escape if not isinstance(self.escape, (tuple,list,dict)) else self.escape.get(column,True)): # escape & first to prevent double escaping of & esc = OrderedDict( [('&', r'&'), ('<', r'<'), ('>', r'>')] @@ -861,7 +861,7 @@ def _write_cell(self, s, kind='td', indent=0, tags=None): '%s%s' % (start_tag, rs, kind), indent) def write_tr(self, line, indent=0, indent_delta=4, header=False, - align=None, tags=None, nindex_levels=0): + align=None, tags=None, nindex_levels=0, escape=None): if tags is None: tags = {} @@ -876,7 +876,7 @@ def write_tr(self, line, indent=0, indent_delta=4, header=False, if header or (self.bold_rows and i < nindex_levels): self.write_th(s, indent, tags=val_tag) else: - self.write_td(s, indent, tags=val_tag) + self.write_td(s, indent, tags=val_tag, column=i-nindex_levels) indent -= indent_delta self.write('', indent) From 5d8de3da3e1fd934eaadf5018743c6ec8e9e576d Mon Sep 17 00:00:00 2001 From: Daniel Manson Date: Tue, 3 Mar 2015 15:23:10 +0000 Subject: [PATCH 2/7] frame.py - repr_html - read _formatters_html attr --- pandas/core/frame.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index e81aaebe77807..a74146475db45 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -1476,6 +1476,11 @@ def to_html(self, buf=None, columns=None, col_space=None, colSpace=None, FutureWarning, stacklevel=2) col_space = colSpace + formatters = formatters or getattr(self,'_formatters_html',None) + escape = {list(self.columns).index(k): + getattr(formatters[k],'escape',escape) for k in formatters} \ + if formatters else escape + formatter = fmt.DataFrameFormatter(self, buf=buf, columns=columns, col_space=col_space, na_rep=na_rep, formatters=formatters, From 15f7ca26600dee38ef38547e1c86a71841647542 Mon Sep 17 00:00:00 2001 From: Daniel Manson Date: Tue, 3 Mar 2015 15:59:59 +0000 Subject: [PATCH 3/7] format.py - justify info column specific (optionally) --- pandas/core/format.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/core/format.py b/pandas/core/format.py index 854594003d3c5..e5b8aaf7a4b1b 100644 --- a/pandas/core/format.py +++ b/pandas/core/format.py @@ -684,7 +684,8 @@ def _format_col(self, i): return format_array( frame.iloc[:, i]._values, formatter, float_format=self.float_format, na_rep=self.na_rep, - space=self.col_space + space=self.col_space, + justify=getattr(formatter,'justify','right') ) def to_html(self, classes=None, notebook=False): From 0238a95f8b3936dfd610f0ee1daa2730d6f81aa8 Mon Sep 17 00:00:00 2001 From: Daniel Manson Date: Thu, 5 Mar 2015 13:21:52 +0000 Subject: [PATCH 4/7] format.py/frame.py - html formatters as arg ...rather than dataframe meta-data. Also tidied logic a little and added docstring. --- pandas/core/format.py | 5 +++-- pandas/core/frame.py | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/pandas/core/format.py b/pandas/core/format.py index e5b8aaf7a4b1b..40adb41e8554e 100644 --- a/pandas/core/format.py +++ b/pandas/core/format.py @@ -821,7 +821,8 @@ def __init__(self, formatter, classes=None, max_rows=None, max_cols=None, self.elements = [] self.bold_rows = self.fmt.kwds.get('bold_rows', False) self.escape = self.fmt.kwds.get('escape', True) - + if self.fmt.formatters is not None and len(self.fmt.formatters): + self.escape = tuple(getattr(f,'escape',self.escape) for f in self.fmt.formatters) self.max_rows = max_rows or len(self.fmt.frame) self.max_cols = max_cols or len(self.fmt.columns) self.show_dimensions = self.fmt.show_dimensions @@ -850,7 +851,7 @@ def _write_cell(self, s, kind='td', indent=0, tags=None, column=None): else: start_tag = '<%s>' % kind - if (self.escape if not isinstance(self.escape, (tuple,list,dict)) else self.escape.get(column,True)): + if (self.escape if column is None or not isinstance(self.escape, tuple) else self.escape[column]): # escape & first to prevent double escaping of & esc = OrderedDict( [('&', r'&'), ('<', r'<'), ('>', r'>')] diff --git a/pandas/core/frame.py b/pandas/core/frame.py index a74146475db45..81a1564ce258f 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -1468,7 +1468,14 @@ def to_html(self, buf=None, columns=None, col_space=None, colSpace=None, max_cols : int, optional Maximum number of columns to show before truncating. If None, show all. - + formatters : callabable or dict/list/tuple of callables, optional + The keys to the dict are the column names, any missing or additional + names will be given defaults or ignored respectively. If list/tuple + the length should match the columns exactly. + Each callable can have an optional boolean `escape` attribute, + and an optional string `justify` attribute. See `_make_fixed_width` + function in `format.py` for meaning of `justify`. If `escape` is + not provided the primary `escape` argument is used (see above). """ if colSpace is not None: # pragma: no cover @@ -1476,10 +1483,11 @@ def to_html(self, buf=None, columns=None, col_space=None, colSpace=None, FutureWarning, stacklevel=2) col_space = colSpace - formatters = formatters or getattr(self,'_formatters_html',None) - escape = {list(self.columns).index(k): - getattr(formatters[k],'escape',escape) for k in formatters} \ - if formatters else escape + # convert dict/single callable to list + if isinstance(formatters,dict): + formatters = tuple(formatters.get(cname,None) for cname in self.columns) + elif callable(formatters): + formatters = (formatters,)*len(self.columns) formatter = fmt.DataFrameFormatter(self, buf=buf, columns=columns, col_space=col_space, na_rep=na_rep, From dfb0e400019e5b4e23f17a0b932592876c83dd40 Mon Sep 17 00:00:00 2001 From: Daniel Manson Date: Tue, 10 Mar 2015 14:11:56 +0000 Subject: [PATCH 5/7] frame.py - html formatters with multiindex columns --- pandas/core/frame.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 81a1564ce258f..7588fc2c62860 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -1485,7 +1485,18 @@ def to_html(self, buf=None, columns=None, col_space=None, colSpace=None, # convert dict/single callable to list if isinstance(formatters,dict): - formatters = tuple(formatters.get(cname,None) for cname in self.columns) + formatters_list = [] + for cname in self.columns: + if cname in formatters: + formatters_list.append(formatters[cname]) + elif isinstance(cname,tuple): + # look through all the names in tuple and take the first + # matching name form the supplied formatters + formatters_list.append(next((formatters[n] for n in cname\ + if n in formatters),None)) + else: + formatters_list.append(None) + formatters = tuple(formatters_list) elif callable(formatters): formatters = (formatters,)*len(self.columns) From acdb295ec7bbb7d43f9a43db2459b586e67793e8 Mon Sep 17 00:00:00 2001 From: Daniel Manson Date: Tue, 10 Mar 2015 19:31:18 +0000 Subject: [PATCH 6/7] bugfix/hack - use numpy's __str__ instead of custom formatter --- pandas/core/format.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pandas/core/format.py b/pandas/core/format.py index 40adb41e8554e..db34c6da09fd8 100644 --- a/pandas/core/format.py +++ b/pandas/core/format.py @@ -1985,6 +1985,8 @@ def _format(x): return self.na_rep elif isinstance(x, PandasObject): return '%s' % x + elif isinstance(x,np.ndarray): + return str(x).replace('\n',',') else: # object dtype return '%s' % formatter(x) From 20ce7adaccc2f204fc4c9a411855f7113000867a Mon Sep 17 00:00:00 2001 From: Daniel Manson Date: Mon, 17 Aug 2015 12:52:09 +0100 Subject: [PATCH 7/7] bugfix newline to comma --- pandas/core/format.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandas/core/format.py b/pandas/core/format.py index db34c6da09fd8..40adb41e8554e 100644 --- a/pandas/core/format.py +++ b/pandas/core/format.py @@ -1985,8 +1985,6 @@ def _format(x): return self.na_rep elif isinstance(x, PandasObject): return '%s' % x - elif isinstance(x,np.ndarray): - return str(x).replace('\n',',') else: # object dtype return '%s' % formatter(x)