Skip to content

Commit c56b4a7

Browse files
ianthomas23martinRenou
authored andcommitted
Use sensible defaults for BarRenderer.bar_value
Signed-off-by: Ian Thomas <[email protected]>
1 parent 353128f commit c56b4a7

File tree

9 files changed

+99
-9
lines changed

9 files changed

+99
-9
lines changed

examples/ConditionalFormatting.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@
340340
"renderers = {\n",
341341
" \"Value 1\": text_renderer,\n",
342342
" \"Dates\": BarRenderer(\n",
343-
" bar_value=DateScale(min=df[\"Dates\"][0], max=df[\"Dates\"][n - 1]),\n",
343+
" bar_value=DateScale(),\n",
344344
" bar_color=Expr(bar_color),\n",
345345
" format=\"%Y/%m/%d\",\n",
346346
" format_type=\"time\",\n",

examples/Pandas.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
" \"Value 1\": text_renderer,\n",
4848
" \"Value 2\": text_renderer,\n",
4949
" \"Dates\": BarRenderer(\n",
50-
" bar_value=DateScale(min=df[\"Dates\"][0], max=df[\"Dates\"][n - 1]),\n",
50+
" bar_value=DateScale(),\n",
5151
" bar_color=Expr(bar_color),\n",
5252
" format=\"%Y/%m/%d\",\n",
5353
" format_type=\"time\",\n",

ipydatagrid/cellrenderer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ class BarRenderer(TextRenderer):
120120
_view_name = Unicode("BarRendererView").tag(sync=True)
121121

122122
bar_value = Union(
123-
(Float(), Instance(VegaExpr), Instance(Scale)), default_value=0.0
123+
(Float(allow_none=True), Instance(VegaExpr), Instance(Scale)),
124+
default_value=0.0,
124125
).tag(sync=True, **widget_serialization)
125126
bar_color = Union(
126127
(Color(), Instance(VegaExpr), Instance(ColorScale)),

ipydatagrid/datagrid.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
)
2424

2525
from ._frontend import module_name, module_version
26-
from .cellrenderer import CellRenderer, TextRenderer
26+
from .cellrenderer import BarRenderer, CellRenderer, TextRenderer
2727

2828

2929
class SelectionIterator(Iterator):
@@ -378,6 +378,7 @@ def __init__(self, dataframe, index_name=None, **kwargs):
378378
self._cell_click_handlers = CallbackDispatcher()
379379
self._cell_change_handlers = CallbackDispatcher()
380380
self.on_msg(self.__handle_custom_msg)
381+
self._set_renderer_defaults()
381382

382383
def __handle_custom_msg(self, _, content, buffers): # noqa: U101,U100
383384
if content["event_type"] == "cell-changed":
@@ -865,3 +866,47 @@ def _get_cell_value_by_numerical_index(data, column_index, row_index):
865866
if column is None:
866867
return None
867868
return data["data"][row_index][column]
869+
870+
def _set_renderer_defaults(self):
871+
# Set sensible default values for renderers that are not completely
872+
# specified, such as missing a min or max value.
873+
874+
data = None # Only read data once, and only if necessary.
875+
876+
for name, renderer in self.renderers.items():
877+
if isinstance(renderer, BarRenderer):
878+
from bqplot import DateScale, LinearScale, Scale
879+
880+
if renderer.bar_value is None:
881+
# If BarRenderer.bar_value is not specified, create an
882+
# appropriate Scale based on the column data type.
883+
col_schema = next(
884+
filter(
885+
lambda x: x["name"] == name,
886+
self._data["schema"]["fields"],
887+
)
888+
)
889+
is_date = col_schema["type"] in ("date", "time", "datetime")
890+
if is_date:
891+
renderer.bar_value = DateScale()
892+
else:
893+
renderer.bar_value = LinearScale()
894+
895+
scale = renderer.bar_value
896+
if (
897+
isinstance(scale, Scale)
898+
and scale.has_trait("min")
899+
and scale.has_trait("max")
900+
and (scale.min is None or scale.max is None)
901+
):
902+
# Set min and/or max from column data.
903+
if data is None:
904+
data = self.data # Only want to get the data once
905+
column_data = data[name]
906+
is_date = isinstance(scale, DateScale)
907+
if scale.min is None:
908+
min = column_data.min()
909+
scale.min = min if is_date else float(min)
910+
if scale.max is None:
911+
max = column_data.max()
912+
scale.max = max if is_date else float(max)

tests/test_datagrid.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
import numpy as np
44
import pandas as pd
55
import pytest
6+
from bqplot import DateScale, LinearScale, LogScale
67

7-
from ipydatagrid import DataGrid, TextRenderer
8+
from ipydatagrid import BarRenderer, DataGrid, TextRenderer
89
from ipydatagrid.datagrid import _widgets_dict_serialization
910

1011

@@ -15,6 +16,13 @@ def dataframe() -> pd.DataFrame:
1516
)
1617

1718

19+
@pytest.fixture()
20+
def dataframe_with_datetime(dataframe) -> pd.DataFrame:
21+
return dataframe.assign(
22+
dates=pd.to_datetime(["2024-03-05", "2024-03-06", "2024-03-07"])
23+
)
24+
25+
1826
@pytest.fixture()
1927
def datagrid(dataframe) -> DataGrid:
2028
return DataGrid(dataframe)
@@ -307,3 +315,39 @@ def test_serialization():
307315
dg = DataGrid(df)
308316

309317
assert dg.data.to_json() == df.to_json()
318+
319+
320+
@pytest.mark.parametrize(
321+
("column", "bar_value", "expected_min", "expected_max"),
322+
[
323+
("B", None, 4.0, 6.0),
324+
("B", LinearScale(), 4.0, 6.0),
325+
("B", LinearScale(min=2.2), 2.2, 6.0),
326+
("B", LinearScale(max=4.4), 4.0, 4.4),
327+
("B", LogScale(), 4.0, 6.0),
328+
(
329+
"dates",
330+
DateScale(),
331+
pd.Timestamp("2024-03-05"),
332+
pd.Timestamp("2024-03-07"),
333+
),
334+
],
335+
)
336+
def test_bar_renderer_defaults(
337+
dataframe_with_datetime,
338+
column,
339+
bar_value,
340+
expected_min,
341+
expected_max,
342+
):
343+
expected_type = type(bar_value) if bar_value else LinearScale
344+
345+
grid = DataGrid(
346+
dataframe_with_datetime,
347+
renderers={column: BarRenderer(bar_value=bar_value)},
348+
)
349+
350+
actual_bar_value = grid.renderers[column].bar_value
351+
assert isinstance(actual_bar_value, expected_type)
352+
assert actual_bar_value.min == expected_min
353+
assert actual_bar_value.max == expected_max

ui-tests-ipw7/tests/notebooks/conditional_formatting.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@
291291
"renderers = {\n",
292292
" \"Value 1\": text_renderer,\n",
293293
" \"Dates\": BarRenderer(\n",
294-
" bar_value=DateScale(min=df[\"Dates\"][0], max=df[\"Dates\"][n - 1]),\n",
294+
" bar_value=DateScale(),\n",
295295
" bar_color=Expr(bar_color),\n",
296296
" format=\"%Y/%m/%d\",\n",
297297
" format_type=\"time\",\n",

ui-tests-ipw7/tests/notebooks/datagrid.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
" \"Value 1\": text_renderer,\n",
4343
" \"Value 2\": text_renderer,\n",
4444
" \"Dates\": BarRenderer(\n",
45-
" bar_value=DateScale(min=df[\"Dates\"][0], max=df[\"Dates\"][n - 1]),\n",
45+
" bar_value=DateScale(),\n",
4646
" bar_color=Expr(bar_color),\n",
4747
" format=\"%Y/%m/%d\",\n",
4848
" format_type=\"time\",\n",

ui-tests-ipw8/tests/notebooks/conditional_formatting.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@
291291
"renderers = {\n",
292292
" \"Value 1\": text_renderer,\n",
293293
" \"Dates\": BarRenderer(\n",
294-
" bar_value=DateScale(min=df[\"Dates\"][0], max=df[\"Dates\"][n - 1]),\n",
294+
" bar_value=DateScale(),\n",
295295
" bar_color=Expr(bar_color),\n",
296296
" format=\"%Y/%m/%d\",\n",
297297
" format_type=\"time\",\n",

ui-tests-ipw8/tests/notebooks/datagrid.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
" \"Value 1\": text_renderer,\n",
4343
" \"Value 2\": text_renderer,\n",
4444
" \"Dates\": BarRenderer(\n",
45-
" bar_value=DateScale(min=df[\"Dates\"][0], max=df[\"Dates\"][n - 1]),\n",
45+
" bar_value=DateScale(),\n",
4646
" bar_color=Expr(bar_color),\n",
4747
" format=\"%Y/%m/%d\",\n",
4848
" format_type=\"time\",\n",

0 commit comments

Comments
 (0)