Skip to content

Commit 33b49be

Browse files
committed
Create a basic array data table viewer for 1 and 3 dimensional arrays stored in an ArrayData node.
1 parent c2a83b8 commit 33b49be

2 files changed

Lines changed: 78 additions & 2 deletions

File tree

src/alc_aiidalab_widgets/viewers.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
from alc_aiidalab_widgets.widgets.file_viewer import SinglefileDataViewer
44
from alc_aiidalab_widgets.widgets.process_node_view import ProcessNodeViewerWidget
55
from alc_aiidalab_widgets.widgets.structure import StructureViewWidget
6-
from alc_aiidalab_widgets.widgets.tables import XYZArrayDataTableWidget
6+
from alc_aiidalab_widgets.widgets.tables import (
7+
GenericArrayDataTableWidget,
8+
XYZArrayDataTableWidget,
9+
)
710

811
ALC_AIIDA_VIEWER_MAPPING = {
912
# Process node type labels
@@ -14,6 +17,7 @@
1417
# AiiDA data type labels
1518
"data.core.structure.StructureData.": StructureViewWidget,
1619
"data.core.singlefile.SinglefileData.": SinglefileDataViewer,
20+
"data.core.array.ArrayData.": GenericArrayDataTableWidget,
1721
# Custom redirections
1822
"xyz_table": XYZArrayDataTableWidget,
1923
}

src/alc_aiidalab_widgets/widgets/tables.py

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22

33
from aiida.orm import ArrayData
44
from ipywidgets import HTML, Dropdown, VBox
5+
from numpy import floating as npfloat
56

67

78
class XYZArrayDataTableWidget(VBox):
89
"""
9-
Custom widget to display array data produced from ChemShell jobs.
10+
Custom widget to display array data associated with XYZ coordinates.
1011
1112
Create a table based widget for displaying different arrays within
1213
an ArrayData object assuming that all the data is XYZ based i.e
@@ -58,3 +59,74 @@ def _render_array(self, change) -> None:
5859

5960
self.children = [self.array_selector, HTML(html)]
6061
return
62+
63+
64+
class GenericArrayDataTableWidget(VBox):
65+
"""Custom widget to display generic array data as a table."""
66+
67+
def __init__(self, array: ArrayData, **kwargs):
68+
"""GenericArrayDataTableWidget Constructor."""
69+
super().__init__(**kwargs)
70+
self.array = array
71+
self.array_selector = Dropdown(
72+
options=self.array.get_arraynames(),
73+
description="Array Labels:",
74+
layout={"width": "50%"},
75+
**kwargs,
76+
)
77+
self._render_array({"new": self.array_selector.index, "old": -1})
78+
self.array_selector.observe(self._render_array, "index")
79+
return
80+
81+
def _render_array(self, change: dict) -> None:
82+
"""Create a HTML table based on the currently selected array."""
83+
index = change["new"]
84+
if index == change["old"]:
85+
return
86+
values = self.array.get_array(self.array.get_arraynames()[index])
87+
if len(values.shape) > 2:
88+
self.children = [
89+
self.array_selector,
90+
HTML("<p>To many dimension to create 2D table from array.</p>"),
91+
]
92+
return
93+
if len(values.shape) == 1:
94+
nrows = values.shape[0]
95+
ncols = 1
96+
else:
97+
ncols, nrows = values.shape # type: ignore
98+
values = values.reshape(1, -1)
99+
100+
# Unique styling prefix to prevent CSS bleeding into other Jupyter elements
101+
102+
# Build Table Header (Column Indices)
103+
html = "<table style='width:100%; border: 1px solid #ddd; text-align: left; "
104+
html += "border-collapse: collapse;'>"
105+
html += "<tr style='background-color: #2196F3; color: white;'>"
106+
html += "<th>Index</th>"
107+
if ncols > 1:
108+
for c in range(ncols):
109+
html += f"<th>{c}</th>"
110+
else:
111+
col_header = (
112+
self.array.get_arraynames()[index].replace("_", " ").capitalize()
113+
)
114+
html += f"<th>{col_header}</th>"
115+
html += "</tr></thead><tbody>"
116+
117+
# Build Table Body (Row Index + Cell Data)
118+
for r in range(nrows):
119+
html += "<tr>"
120+
html += f'<th class="row-idx">{r}</th>'
121+
for c in range(ncols):
122+
val = values[c, r]
123+
# Format floats to 6 decimals, leave ints/strings as they are
124+
formatted_val = (
125+
f"{val:.6f}" if isinstance(val, float | npfloat) else str(val)
126+
)
127+
html += f"<td>{formatted_val}</td>"
128+
html += "</tr>"
129+
130+
html += "</tbody></table></div>"
131+
self.children = [self.array_selector, HTML(html)]
132+
return

0 commit comments

Comments
 (0)