Skip to content

feat: DH-21375: Integrate databars with UI table format#1289

Open
gzh2003 wants to merge 14 commits intomainfrom
DH-21375-databars-need-to-be-integrated-with-ui-table-format
Open

feat: DH-21375: Integrate databars with UI table format#1289
gzh2003 wants to merge 14 commits intomainfrom
DH-21375-databars-need-to-be-integrated-with-ui-table-format

Conversation

@gzh2003
Copy link
Contributor

@gzh2003 gzh2003 commented Feb 4, 2026

Part of DH-21375. Adds support for databars in ui.TableFormat via mode parameter. The legacy databars parameter is still supported but will show a deprecation warning.

Changes:

  • Added mode parameter to TableFormat, along with validation, and deprecation warning for databars
  • Updated UITableModel to extract and render databars from format rules
  • Updated docs to reference new api

There are some validation rules/warnings to be aware of while we maintain backwards compatibility with the old API

  1. databars prop and mode=TableDatabar() cant be used together
  2. databars and format_ cannot be used together with mode=TableDatabar()
  3. cols is required when mode is set in TableFormat
  4. columns can't be specified using the new api (should come from TableFormat.cols)
  5. legacy databars shows a deprecation warning

Most of these rules exist to support the old api, so we will have to clean them up once it's fully deprecated.

@gzh2003 gzh2003 self-assigned this Feb 4, 2026
@gzh2003 gzh2003 removed the request for review from margaretkennedy February 4, 2026 21:19
@mattrunyon
Copy link
Collaborator

@copilot Can you check how this PR compares to the plan at https://github.com/deephaven/deephaven-plugins/pull/1282/changes#diff-4b3243a5e436df978a8e62a555524a2fd6f899e8f65248f3879f74611bc0947d and comment if you think there are any discrepancies between the plan the this implementation?

Do not open a new pull request, just let me know if there are any discrepancies

Copy link
Contributor

Copilot AI commented Feb 4, 2026

@mattrunyon I've opened a new pull request, #1290, to work on those changes. Once the pull request is ready, I'll request review from you.

@gzh2003 gzh2003 requested review from mattrunyon and removed request for margaretkennedy February 4, 2026 22:00
@gzh2003 gzh2003 removed the request for review from margaretkennedy February 5, 2026 14:57
@gzh2003 gzh2003 marked this pull request as draft February 5, 2026 19:11
@gzh2003 gzh2003 force-pushed the DH-21375-databars-need-to-be-integrated-with-ui-table-format branch from 413b901 to dbeccb8 Compare February 6, 2026 15:20
@gzh2003 gzh2003 marked this pull request as ready for review February 9, 2026 13:57
> [!WARNING]
> Migrating from the `databars` parameter
>
> The legacy `databars` parameter is deprecated and will be removed in a future version. Use `format_` with `mode=ui.TableDatabar()` instead.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if gplus, maybe specific next version; if not, future version it is!

@mofojed
Copy link
Member

mofojed commented Feb 12, 2026

@gzh2003 you need to merge the latest main to fix the docs build issue, Joe fixed it with #1300

@gzh2003 gzh2003 force-pushed the DH-21375-databars-need-to-be-integrated-with-ui-table-format branch from abaf673 to b8b6dad Compare February 12, 2026 15:35
@github-actions
Copy link

ui docs preview (Available for 14 days)

Comment on lines +180 to +182
k: convert_dataclasses_to_dicts(v)
for k, v in asdict(obj).items()
if v is not None
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like asdict is already recursive, so when you have a dataclass you can just return asdict(dataclass). The rest of the recursive might be required if the top level is an array or dict though as asdict only works on dataclasses.

https://docs.python.org/3/library/dataclasses.html#dataclasses.asdict

I tried this in a Python console

from dataclasses import dataclass
@dataclass
class Point:
  x: int
  y: int
@dataclass
class A:
  val: dict
a = A({ 'abc': [Point(0, 0)], "xyz": Point(1, 1)})
asdict(a)
# {'val': {'abc': [{'x': 0, 'y': 0}], 'xyz': {'x': 1, 'y': 1}}}

Comment on lines +865 to +873
if isinstance(date, DTypeInstant.j_type): # type: ignore
return _convert_instant_to_nanos(date)

if isinstance(date, DTypeZonedDateTime.j_type):
if isinstance(date, DTypeZonedDateTime.j_type): # type: ignore
tz = date.getZone() # type: ignore
instant = date.toInstant() # type: ignore
return (_convert_instant_to_nanos(instant), str(tz) if tz else None)

if isinstance(date, DTypeLocalDate.j_type):
if isinstance(date, DTypeLocalDate.j_type): # type: ignore
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why # type: ignore? Is there not a valid type for us to use?

return convert_dict_keys(dict, to_camel_case)


def convert_dataclasses_to_dicts(obj: Any) -> Any:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is needed. We already do some recursive logic that converts dataclasses in arrays/dicts/props in Renderer.py


if databars is not None and format_ is not None:
format_list = format_ if isinstance(format_, list) else [format_]
has_format_databars = any(f.mode is not None for f in format_list)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be something like f.mode is not None and f.mode.type == 'databar'? I guess it doesn't really matter since we only have 1 render mode (for now) and the deprecated databars will probably go away soon anyway

def render(self, context: RenderContext) -> dict[str, Any]:
logger.debug("Returning props %s", self._props)
return dict_to_react_props(self._props)
converted_props = convert_dataclasses_to_dicts(self._props)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure this isn't necessary as the render call should convert the props already

Comment on lines +278 to +279
if (mode?.type === 'databar') {
return 'dataBar';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just standardize the mode name. If it's dataBar in Grid then make it dataBar in Python

Comment on lines +257 to +258
const databars = useMemo(() => {
const formatDatabars = extractDatabarsFromFormatRules(format);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might make more sense in the heatmap PR, but I'm thinking we should remove the databars prop from UITableModel and make it more generic on mode.

I think the color map resolution would be the only thing that depends on finding all the databars and we could instead parse mode for colors?

Comment on lines +256 to +257
if (mode != null && cols != null) {
const columns: ColumnName[] = Array.isArray(cols) ? cols : [cols];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes an assumption the only mode is dataBar which will not always be true

Comment on lines +241 to +250
t_databar_conditional = ui.table(
_stocks,
format_=[
ui.TableFormat(
cols="Size",
if_="Size > 50",
mode=ui.TableDatabar(color="positive", max=1000),
),
],
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The image for this doesn't seem to be correct

  • It is rendering as a databar for all values of size
  • It also is incorrectly overlapping the databar and the text . And I think the max isn't being applied properly? There is a 1090 value which loses its 1 and then the values with 3000 have the text completely overlapped

The 2nd seems to be a problem on the current version as well though. I think there might be a problem in Grid handling this. Could you check if it's an issue with UITable or Grid and file a ticket? Basically any value over max is not getting capped at max when it should be

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants