Skip to content
This repository was archived by the owner on Oct 24, 2024. It is now read-only.

Commit 42aa869

Browse files
html repr (#78)
* html repr displays data in root group * displays under name 'xarray.DataTree' * creates a html repr for each sub-group, but it looks messed up * correctly indents sub-groups * show names of groups * refactoring * dodge type hinting bug * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix failing test in merg * fix bug caused by merge * whatsnew Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 3ca4111 commit 42aa869

File tree

5 files changed

+85
-9
lines changed

5 files changed

+85
-9
lines changed

datatree/datatree.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
from collections import OrderedDict
4+
from html import escape
45
from typing import (
56
TYPE_CHECKING,
67
Any,
@@ -16,9 +17,10 @@
1617

1718
from xarray import DataArray, Dataset
1819
from xarray.core import utils
20+
from xarray.core.options import OPTIONS as XR_OPTS
1921
from xarray.core.variable import Variable
2022

21-
from .formatting import tree_repr
23+
from . import formatting, formatting_html
2224
from .mapping import TreeIsomorphismError, check_isomorphic, map_over_subtree
2325
from .ops import (
2426
DataTreeArithmeticMixin,
@@ -189,11 +191,17 @@ def _pre_attach(self: DataTree, parent: DataTree) -> None:
189191
f"parent {parent.name} already contains a data variable named {self.name}"
190192
)
191193

192-
def __repr__(self):
193-
return tree_repr(self)
194+
def __repr__(self) -> str:
195+
return formatting.datatree_repr(self)
194196

195-
def __str__(self):
196-
return tree_repr(self)
197+
def __str__(self) -> str:
198+
return formatting.datatree_repr(self)
199+
200+
def _repr_html_(self):
201+
"""Make html representation of datatree object"""
202+
if XR_OPTS["display_style"] == "text":
203+
return f"<pre>{escape(repr(self))}</pre>"
204+
return formatting_html.datatree_repr(self)
197205

198206
def get(
199207
self: DataTree, key: str, default: Optional[DataTree | DataArray] = None
@@ -227,8 +235,10 @@ def __getitem__(self: DataTree, key: str) -> DataTree | DataArray:
227235
key : str
228236
Name of variable / node, or unix-like path to variable / node.
229237
"""
238+
230239
# Either:
231240
if utils.is_dict_like(key):
241+
232242
# dict-like indexing
233243
raise NotImplementedError("Should this index over whole tree?")
234244
elif isinstance(key, str):
@@ -243,7 +253,7 @@ def __getitem__(self: DataTree, key: str) -> DataTree | DataArray:
243253
"implemented via .subset"
244254
)
245255
else:
246-
raise ValueError("Invalid format for key")
256+
raise ValueError(f"Invalid format for key: {key}")
247257

248258
def _set(self, key: str, val: DataTree | CoercibleValue) -> None:
249259
"""
@@ -352,6 +362,13 @@ def from_dict(
352362
def nbytes(self) -> int:
353363
return sum(node.ds.nbytes if node.has_data else 0 for node in self.subtree)
354364

365+
def __len__(self) -> int:
366+
if self.children:
367+
n_children = len(self.children)
368+
else:
369+
n_children = 0
370+
return n_children + len(self.ds)
371+
355372
def isomorphic(
356373
self,
357374
other: DataTree,

datatree/formatting.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def diff_tree_repr(a, b, compat):
5252
return "\n".join(summary)
5353

5454

55-
def tree_repr(dt):
55+
def datatree_repr(dt):
5656
"""A printable representation of the structure of this entire tree."""
5757
renderer = RenderTree(dt)
5858

datatree/formatting_html.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from functools import partial
2+
from html import escape
3+
from typing import Any, Mapping
4+
5+
from xarray.core.formatting_html import (
6+
_mapping_section,
7+
_obj_repr,
8+
attr_section,
9+
coord_section,
10+
datavar_section,
11+
dim_section,
12+
)
13+
from xarray.core.options import OPTIONS
14+
15+
OPTIONS["display_expand_groups"] = "default"
16+
17+
18+
def summarize_children(children: Mapping[str, Any]) -> str:
19+
children_li = "".join(
20+
f"<ul class='xr-sections'>{node_repr(n, c)}</ul>" for n, c in children.items()
21+
)
22+
23+
return (
24+
"<ul class='xr-sections'>"
25+
f"<div style='padding-left:2rem;'>{children_li}<br></div>"
26+
"</ul>"
27+
)
28+
29+
30+
children_section = partial(
31+
_mapping_section,
32+
name="Groups",
33+
details_func=summarize_children,
34+
max_items_collapse=1,
35+
expand_option_name="display_expand_groups",
36+
)
37+
38+
39+
def node_repr(group_title: str, dt: Any) -> str:
40+
header_components = [f"<div class='xr-obj-type'>{escape(group_title)}</div>"]
41+
42+
ds = dt.ds
43+
44+
sections = [
45+
children_section(dt.children),
46+
dim_section(ds),
47+
coord_section(ds.coords),
48+
datavar_section(ds.data_vars),
49+
attr_section(ds.attrs),
50+
]
51+
52+
return _obj_repr(ds, header_components, sections)
53+
54+
55+
def datatree_repr(dt: Any) -> str:
56+
obj_type = f"datatree.{type(dt).__name__}"
57+
return node_repr(obj_type, dt)

datatree/treenode.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def _detach(self, parent: Tree | None) -> None:
134134
def _attach(self, parent: Tree | None, child_name: str = None) -> None:
135135
if parent is not None:
136136
if child_name is None:
137-
raise ValueError()
137+
raise ValueError("Cannot directly assign a parent to an unnamed node")
138138

139139
self._pre_attach(parent)
140140
parentchildren = parent._children

docs/source/whats-new.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ New Features
3232
root node via ``"/"``, and the current node via ``"."``. (Internally it actually uses ``pathlib`` now.)
3333
By `Tom Nicholas <https://github.com/TomNicholas>`_.
3434
- New path-like API methods, such as ``.relative_to``, ``.find_common_ancestor``, and ``.same_tree``.
35-
- Some new diction-like methods, such as ``DataTree.get`` and ``DataTree.update``. (:pull:`76`)
35+
- Some new dictionary-like methods, such as ``DataTree.get`` and ``DataTree.update``. (:pull:`76`)
36+
By `Tom Nicholas <https://github.com/TomNicholas>`_.
37+
- New HTML repr, which will automatically display in a jupyter notebook. (:pull:`78`)
3638
By `Tom Nicholas <https://github.com/TomNicholas>`_.
3739

3840
Breaking changes

0 commit comments

Comments
 (0)