diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py index c4e3dd1c755cf..f691ab2119067 100644 --- a/pandas/io/formats/format.py +++ b/pandas/io/formats/format.py @@ -6,6 +6,7 @@ from functools import partial from io import StringIO from shutil import get_terminal_size +from typing import Optional, Type, Union from unicodedata import east_asian_width import numpy as np @@ -32,6 +33,7 @@ is_timedelta64_dtype, ) from pandas.core.dtypes.generic import ( + ABCDataFrame, ABCIndexClass, ABCMultiIndex, ABCSeries, @@ -402,6 +404,12 @@ class TableFormatter: is_truncated = False show_dimensions = None + tr_frame = None # type: ABCDataFrame + float_format = None + na_rep = None + col_space = None + decimal = None + max_colwidth = None @property def should_show_dimensions(self): @@ -420,6 +428,24 @@ def _get_formatter(self, i): i = self.columns[i] return self.formatters.get(i, None) + def _format_col(self, i: int): + """ + Calls `format_array` for column `i` of truncated DataFrame with + optional `formatter` + """ + frame = self.tr_frame + formatter = self._get_formatter(i) + values_to_format = frame.iloc[:, i]._formatting_values() + return format_array( + values_to_format, + formatter, + float_format=self.float_format, + na_rep=self.na_rep, + space=self.col_space, + decimal=self.decimal, + max_colwidth=self.max_colwidth, + ) + class DataFrameFormatter(TableFormatter): """ @@ -501,6 +527,7 @@ def __init__( self._chk_truncate() self.adj = _get_adjustment() + self.max_colwidth = None # use display.max_colwidth setting def _chk_truncate(self): """ @@ -804,19 +831,6 @@ def to_latex( else: raise TypeError("buf is not a file name and it has no write " "method") - def _format_col(self, i): - frame = self.tr_frame - formatter = self._get_formatter(i) - values_to_format = frame.iloc[:, i]._formatting_values() - return format_array( - values_to_format, - formatter, - float_format=self.float_format, - na_rep=self.na_rep, - space=self.col_space, - decimal=self.decimal, - ) - def to_html(self, classes=None, notebook=False, border=None): """ Render a DataFrame to a html table. @@ -966,6 +980,7 @@ def format_array( justify="right", decimal=".", leading_space=None, + max_colwidth: Optional[Union[bool, int]] = None, ): """ Format an array for printing. @@ -988,6 +1003,13 @@ def format_array( When formatting an Index subclass (e.g. IntervalIndex._format_native_types), we don't want the leading space since it should be left-aligned. + max_colwidth: False, int or None, optional, default None + Whether the array should be formatted with strings truncated. + * False: do not truncate strings + * int: the maximum width of strings + * None: use display.max_colwidth setting + + .. versionadded:: 1.0 Returns ------- @@ -995,7 +1017,7 @@ def format_array( """ if is_datetime64_dtype(values.dtype): - fmt_klass = Datetime64Formatter + fmt_klass = Datetime64Formatter # type: Type[GenericArrayFormatter] elif is_datetime64tz_dtype(values): fmt_klass = Datetime64TZFormatter elif is_timedelta64_dtype(values.dtype): @@ -1018,6 +1040,9 @@ def format_array( if digits is None: digits = get_option("display.precision") + if max_colwidth is None: + max_colwidth = get_option("display.max_colwidth") + fmt_obj = fmt_klass( values, digits=digits, @@ -1028,6 +1053,7 @@ def format_array( justify=justify, decimal=decimal, leading_space=leading_space, + max_colwidth=max_colwidth, ) return fmt_obj.get_result() @@ -1047,6 +1073,7 @@ def __init__( quoting=None, fixed_width=True, leading_space=None, + max_colwidth=None, ): self.values = values self.digits = digits @@ -1059,10 +1086,13 @@ def __init__( self.quoting = quoting self.fixed_width = fixed_width self.leading_space = leading_space + self.max_colwidth = max_colwidth def get_result(self): fmt_values = self._format_strings() - return _make_fixed_width(fmt_values, self.justify) + return _make_fixed_width( + fmt_values, self.justify, max_colwidth=self.max_colwidth + ) def _format_strings(self): if self.float_format is None: @@ -1552,7 +1582,9 @@ def _formatter(x): return _formatter -def _make_fixed_width(strings, justify="right", minimum=None, adj=None): +def _make_fixed_width( + strings, justify="right", minimum=None, adj=None, max_colwidth=None +): if len(strings) == 0 or justify == "all": return strings @@ -1565,13 +1597,12 @@ def _make_fixed_width(strings, justify="right", minimum=None, adj=None): if minimum is not None: max_len = max(minimum, max_len) - conf_max = get_option("display.max_colwidth") - if conf_max is not None and max_len > conf_max: - max_len = conf_max + if max_colwidth is not None and max_len > max_colwidth: + max_len = max_colwidth def just(x): - if conf_max is not None: - if (conf_max > 3) & (adj.len(x) > max_len): + if max_colwidth is not None: + if (max_colwidth > 3) & (adj.len(x) > max_len): x = x[: max_len - 3] + "..." return x diff --git a/pandas/io/formats/html.py b/pandas/io/formats/html.py index e6aae44baa69b..626002c38556f 100644 --- a/pandas/io/formats/html.py +++ b/pandas/io/formats/html.py @@ -9,8 +9,6 @@ from pandas.core.dtypes.generic import ABCMultiIndex -from pandas import option_context - from pandas.io.common import _is_url from pandas.io.formats.format import TableFormatter, get_level_lengths from pandas.io.formats.printing import pprint_thing @@ -43,8 +41,15 @@ def __init__(self, formatter, classes=None, border=None): self.border = border self.table_id = self.fmt.table_id self.render_links = self.fmt.render_links + self.max_colwidth = False # do not truncate strings + self.tr_frame = self.fmt.tr_frame + self.formatters = self.fmt.formatters + self.float_format = self.fmt.float_format + self.na_rep = self.fmt.na_rep + self.decimal = self.fmt.decimal if isinstance(self.fmt.col_space, int): self.fmt.col_space = "{colspace}px".format(colspace=self.fmt.col_space) + self.col_space = self.fmt.col_space @property def show_row_idx_names(self): @@ -356,9 +361,7 @@ def _write_header(self, indent): self.write("", indent) def _get_formatted_values(self): - with option_context("display.max_colwidth", 999999): - fmt_values = {i: self.fmt._format_col(i) for i in range(self.ncols)} - return fmt_values + return {i: self._format_col(i) for i in range(self.ncols)} def _write_body(self, indent): self.write("
", indent) @@ -546,8 +549,9 @@ class NotebookFormatter(HTMLFormatter): DataFrame._repr_html_() and DataFrame.to_html(notebook=True) """ - def _get_formatted_values(self): - return {i: self.fmt._format_col(i) for i in range(self.ncols)} + def __init__(self, formatter, classes=None, border=None): + super().__init__(formatter, classes, border) + self.max_colwidth = None # use display.max_colwidth setting def _get_columns_formatted_values(self): return self.columns.format()