Coverage for install/scipp/visualization/formatting_datagroup_html.py: 71%
96 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-04-28 01:28 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-04-28 01:28 +0000
1# SPDX-License-Identifier: BSD-3-Clause
2# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
4import uuid
5from string import Template
6from typing import Optional, Union
8import numpy as np
10from ..core.cpp_classes import DataArray, Dataset, Variable
11from ..core.data_group import DataGroup
12from ..units import dimensionless
13from .formatting_html import escape, inline_variable_repr
14from .resources import (
15 load_atomic_row_tpl,
16 load_collapsible_row_tpl,
17 load_dg_detail_list_tpl,
18 load_dg_repr_tpl,
19 load_dg_style,
20)
23def _format_shape(var: Union[Variable, DataArray, Dataset, DataGroup], br_at=30) -> str:
24 """Return HTML Component that represents the shape of ``var``"""
25 shape_list = [f"{escape(str(dim))}: {size}" for dim, size in var.sizes.items()]
26 if sum([len(line) - line.count('\\') for line in shape_list]) < br_at:
27 return f"({', '.join(shape_list)})"
28 else:
29 return f"({', <br> '.join(shape_list)})"
32def _format_atomic_value(value, maxidx: int = 5) -> str:
33 """Inline preview of single value"""
34 value_repr = str(value)[:maxidx]
35 if len(value_repr) < len(str(value)):
36 value_repr += "..."
37 return value_repr
40def _format_dictionary_item(name_item: tuple, maxidx: int = 10) -> str:
41 """Inline preview of a dictionary"""
42 name, item = name_item
43 name = _format_atomic_value(name, maxidx=maxidx)
44 type_repr = _format_atomic_value(type(item).__name__, maxidx=maxidx)
45 return "(" + ": ".join((name, type_repr)) + ")"
48def _format_multi_dim_data(var: Union[Dataset, np.ndarray]) -> str:
49 """Inline preview of single or multi-dimensional data"""
50 if isinstance(var, Dataset):
51 view_iterable = list(var.items())
52 var_len = len(var)
53 first_idx, last_idx = 0, -1
54 format_item = _format_dictionary_item
55 elif isinstance(var, np.ndarray):
56 view_iterable = var
57 var_len = var.size
58 first_idx = tuple(np.zeros(var.ndim, dtype=int))
59 last_idx = tuple(np.array(var.shape, dtype=int) - np.ones(var.ndim, dtype=int))
60 format_item = _format_atomic_value
62 view_items = []
63 if var_len > 0:
64 view_items.append(format_item(view_iterable[first_idx]))
65 if var_len > 2:
66 view_items.append('... ')
67 if var_len > 1:
68 view_items.append(format_item(view_iterable[last_idx]))
70 return ', '.join(view_items)
73def _summarize_atomic_variable(var, name: str, depth: int = 0) -> str:
74 """Return HTML Component that contains summary of ``var``"""
75 shape_repr = escape("()")
76 unit = ''
77 dtype_str = ''
78 preview = ''
79 parent_obj_str = ''
80 objtype_str = type(var).__name__
81 if isinstance(var, (Dataset, DataArray, Variable)):
82 parent_obj_str = "scipp"
83 shape_repr = _format_shape(var)
84 if isinstance(var, (DataArray, Variable)):
85 preview = inline_variable_repr(var)
86 dtype_str = str(var.dtype)
87 if var.unit is not None:
88 unit = '𝟙' if var.unit == dimensionless else str(var.unit) # noqa: RUF001
89 elif isinstance(var, Dataset):
90 preview = escape(_format_multi_dim_data(var))
91 elif isinstance(var, np.ndarray):
92 parent_obj_str = "numpy"
93 preview = f"shape={var.shape}, dtype={var.dtype}, values="
94 preview += escape(_format_multi_dim_data(var))
96 elif preview == '' and hasattr(var, "__str__"):
97 preview = escape(_format_atomic_value(var, maxidx=80))
99 html_tpl = load_atomic_row_tpl()
100 return Template(html_tpl).substitute(
101 depth=depth,
102 name=escape(name),
103 parent=escape(parent_obj_str),
104 objtype=escape(objtype_str),
105 shape_repr=shape_repr,
106 dtype=escape(dtype_str),
107 unit=escape(unit),
108 preview=preview,
109 )
112def _collapsible_summary(var: DataGroup, name: str, name_spaces: list) -> str:
113 parent_type = "scipp"
114 objtype = type(var).__name__
115 shape_repr = _format_shape(var)
116 checkbox_id = escape("summary-" + str(uuid.uuid4()))
117 depth = len(name_spaces)
118 subsection = _datagroup_detail(var, [*name_spaces, name])
119 html_tpl = load_collapsible_row_tpl()
121 return Template(html_tpl).substitute(
122 name=escape(str(name)),
123 parent=escape(parent_type),
124 objtype=escape(objtype),
125 shape_repr=shape_repr,
126 summary_section_id=checkbox_id,
127 depth=depth,
128 checkbox_status='',
129 subsection=subsection,
130 )
133def _datagroup_detail(dg: DataGroup, name_spaces: Optional[list] = None) -> str:
134 if name_spaces is None:
135 name_spaces = []
136 summary_rows = []
137 for name, item in dg.items():
138 if isinstance(item, DataGroup):
139 collapsible_row = _collapsible_summary(item, name, name_spaces)
140 summary_rows.append(collapsible_row)
141 else:
142 summary_rows.append(
143 _summarize_atomic_variable(item, name, depth=len(name_spaces))
144 )
146 dg_detail_tpl = Template(load_dg_detail_list_tpl())
147 return dg_detail_tpl.substitute(summary_rows=''.join(summary_rows))
150def datagroup_repr(dg: DataGroup) -> str:
151 """Return HTML Component containing details of ``dg``"""
152 obj_type = "scipp.{} ".format(type(dg).__name__)
153 checkbox_status = "checked" if len(dg) < 15 else ''
154 header_id = "datagroup-view-" + str(uuid.uuid4())
155 details = _datagroup_detail(dg)
156 html = Template(load_dg_repr_tpl())
157 return html.substitute(
158 style_sheet=load_dg_style(),
159 header_id=header_id,
160 checkbox_status=checkbox_status,
161 obj_type=obj_type,
162 shape_repr=_format_shape(dg, br_at=200),
163 details=details,
164 )