feat: DH-21375: Integrate databars with UI table format#1289
feat: DH-21375: Integrate databars with UI table format#1289
Conversation
|
@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 |
|
@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. |
413b901 to
dbeccb8
Compare
| > [!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. |
There was a problem hiding this comment.
if gplus, maybe specific next version; if not, future version it is!
abaf673 to
b8b6dad
Compare
|
ui docs preview (Available for 14 days) |
| k: convert_dataclasses_to_dicts(v) | ||
| for k, v in asdict(obj).items() | ||
| if v is not None |
There was a problem hiding this comment.
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}}}| 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 |
There was a problem hiding this comment.
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: |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
I'm pretty sure this isn't necessary as the render call should convert the props already
| if (mode?.type === 'databar') { | ||
| return 'dataBar'; |
There was a problem hiding this comment.
We should just standardize the mode name. If it's dataBar in Grid then make it dataBar in Python
| const databars = useMemo(() => { | ||
| const formatDatabars = extractDatabarsFromFormatRules(format); |
There was a problem hiding this comment.
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?
| if (mode != null && cols != null) { | ||
| const columns: ColumnName[] = Array.isArray(cols) ? cols : [cols]; |
There was a problem hiding this comment.
This makes an assumption the only mode is dataBar which will not always be true
| t_databar_conditional = ui.table( | ||
| _stocks, | ||
| format_=[ | ||
| ui.TableFormat( | ||
| cols="Size", | ||
| if_="Size > 50", | ||
| mode=ui.TableDatabar(color="positive", max=1000), | ||
| ), | ||
| ], | ||
| ) |
There was a problem hiding this comment.
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
1and then the values with3000have 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
Part of DH-21375. Adds support for databars in
ui.TableFormatviamodeparameter. The legacydatabarsparameter is still supported but will show a deprecation warning.Changes:
There are some validation rules/warnings to be aware of while we maintain backwards compatibility with the old API
databarsprop andmode=TableDatabar()cant be used togethercolumnscan't be specified using the new api (should come fromTableFormat.cols)Most of these rules exist to support the old api, so we will have to clean them up once it's fully deprecated.