Skip to content
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

Add text_align to existing formatter #5866

Merged
merged 6 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions examples/reference/widgets/Tabulator.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,12 @@
"source": [
"The list of valid Bokeh formatters includes:\n",
" \n",
"* [BooleanFormatter](https://docs.bokeh.org/en/latest/docs/reference/models/widgets.tables.html#bokeh.models.widgets.tables.BooleanFormatter)\n",
"* [DateFormatter](https://docs.bokeh.org/en/latest/docs/reference/models/widgets.tables.html#bokeh.models.widgets.tables.DateFormatter)\n",
"* [NumberFormatter](https://docs.bokeh.org/en/latest/docs/reference/models/widgets.tables.html#bokeh.models.widgets.tables.NumberFormatter)\n",
"* [HTMLTemplateFormatter](https://docs.bokeh.org/en/latest/docs/reference/models/widgets.tables.html#bokeh.models.widgets.tables.HTMLTemplateFormatter)\n",
"* [StringFormatter](https://docs.bokeh.org/en/latest/docs/reference/models/widgets.tables.html#bokeh.models.widgets.tables.StringFormatter)\n",
"* [ScientificFormatter](https://docs.bokeh.org/en/latest/docs/reference/models/widgets.tables.html#bokeh.models.widgets.tables.ScientificFormatter)\n",
"* [BooleanFormatter](https://docs.bokeh.org/en/latest/docs/reference/models/widgets/tables.html#bokeh.models.BooleanFormatter)\n",
"* [DateFormatter](https://docs.bokeh.org/en/latest/docs/reference/models/widgets/tables.html#bokeh.models.DateFormatter)\n",
"* [NumberFormatter](https://docs.bokeh.org/en/latest/docs/reference/models/widgets/tables.html#bokeh.models.NumberFormatter)\n",
"* [HTMLTemplateFormatter](https://docs.bokeh.org/en/latest/docs/reference/models/widgets/tables.html#bokeh.models.HTMLTemplateFormatter)\n",
"* [StringFormatter](https://docs.bokeh.org/en/latest/docs/reference/models/widgets/tables.html#bokeh.models.StringFormatter)\n",
"* [ScientificFormatter](https://docs.bokeh.org/en/latest/docs/reference/models/widgets/tables.html#bokeh.models.ScientificFormatter)\n",
"\n",
"However in addition to the formatters exposed by Bokeh it is also possible to provide valid formatters built into the *Tabulator* library. These may be defined either as a string or as a dictionary declaring the `type` and other arguments, which are passed to *Tabulator* as the `formatterParams`:"
]
Expand Down
23 changes: 23 additions & 0 deletions panel/tests/widgets/test_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -2113,3 +2113,26 @@ def test_tabulator_hidden_columns_fix():
table = Tabulator(pd.DataFrame(), show_index=False)
table.hidden_columns = ["a", "b", "c"]
assert table.hidden_columns == ["a", "b", "c"]

@pytest.mark.parametrize('align', [{"x": "right"}, "right"], ids=["dict", "str"])
def test_bokeh_formatter_with_text_align(align):
# https://github.com/holoviz/panel/issues/5807
data = pd.DataFrame({"x": [1.1, 2.0, 3.47]})
formatters = {"x": NumberFormatter(format="0.0")}
assert formatters["x"].text_align == "left" # default
model = Tabulator(data, formatters=formatters, text_align=align)
columns = model._get_column_definitions("x", data)
output = columns[0].formatter.text_align
assert output == "right"

@pytest.mark.parametrize('align', [{"x": "right"}, "right"], ids=["dict", "str"])
def test_bokeh_formatter_with_text_align_conflict(align):
# https://github.com/holoviz/panel/issues/5807
data = pd.DataFrame({"x": [1.1, 2.0, 3.47]})
formatters = {"x": NumberFormatter(format="0.0", text_align="center")}
model = Tabulator(data, formatters=formatters, text_align=align)
msg = r"text_align in formatters\['x'\] is overridden by text_align"
with pytest.warns(RuntimeWarning, match=msg):
columns = model._get_column_definitions("x", data)
output = columns[0].formatter.text_align
assert output == "right"
56 changes: 37 additions & 19 deletions panel/widgets/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
BOKEH_JS_NAT, clone_model, datetime_as_utctimestamp, isdatetime, lazy_load,
styler_update, updating,
)
from ..util.warnings import warn
from .base import Widget
from .button import Button
from .input import TextInput
Expand Down Expand Up @@ -176,34 +177,18 @@ def _get_column_definitions(self, col_names: List[str], df: pd.DataFrame) -> Lis
col_kwargs = {}
kind = data.dtype.kind
editor: CellEditor
formatter: CellFormatter
formatter: CellFormatter | None = self.formatters.get(col)
if kind == 'i':
formatter = NumberFormatter(text_align='right')
editor = IntEditor()
elif kind == 'b':
formatter = StringFormatter(text_align='center')
editor = CheckboxEditor()
elif kind == 'f':
formatter = NumberFormatter(format='0,0.0[00000]', text_align='right')
editor = NumberEditor()
elif isdatetime(data) or kind == 'M':
if len(data) and isinstance(data.values[0], dt.date):
date_format = '%Y-%m-%d'
else:
date_format = '%Y-%m-%d %H:%M:%S'
formatter = DateFormatter(format=date_format, text_align='right')
editor = DateEditor()
else:
formatter = StringFormatter()
editor = StringEditor()

if isinstance(self.text_align, str):
formatter.text_align = self.text_align
elif col in self.text_align:
formatter.text_align = self.text_align[col]
elif col in self.indexes:
formatter.text_align = 'left'

if col in self.editors and not isinstance(self.editors[col], (dict, str)):
editor = self.editors[col]
if isinstance(editor, CellEditor):
Expand All @@ -212,10 +197,43 @@ def _get_column_definitions(self, col_names: List[str], df: pd.DataFrame) -> Lis
if col in indexes or editor is None:
editor = CellEditor()

if col in self.formatters and not isinstance(self.formatters[col], (dict, str)):
formatter = self.formatters[col]
if formatter is None or isinstance(formatter, (dict, str)):
if kind == 'i':
formatter = NumberFormatter(text_align='right')
elif kind == 'b':
formatter = StringFormatter(text_align='center')
elif kind == 'f':
formatter = NumberFormatter(format='0,0.0[00000]', text_align='right')
elif isdatetime(data) or kind == 'M':
if len(data) and isinstance(data.values[0], dt.date):
date_format = '%Y-%m-%d'
else:
date_format = '%Y-%m-%d %H:%M:%S'
formatter = DateFormatter(format=date_format, text_align='right')
else:
formatter = StringFormatter()

default_text_align = True
else:
if isinstance(formatter, CellFormatter):
formatter = clone_model(formatter)
if hasattr(formatter, 'text_align'):
default_text_align = type(formatter).text_align.class_default(formatter) == formatter.text_align
else:
default_text_align = True

if isinstance(self.text_align, str):
formatter.text_align = self.text_align
if not default_text_align:
msg = f"The 'text_align' in Tabulator.formatters[{col!r}] is overridden by Tabulator.text_align"
warn(msg, RuntimeWarning)
elif col in self.text_align:
formatter.text_align = self.text_align[col]
if not default_text_align:
msg = f'text_align in formatters[{col!r}] is overridden by text_align[{col!r}]'
warn(msg, RuntimeWarning)
elif col in self.indexes:
formatter.text_align = 'left'

if isinstance(self.widths, int):
col_kwargs['width'] = self.widths
Expand Down