Skip to content

Commit e5800dc

Browse files
committed
Refactor geometry and table adapters to use 'result' instead of specific geometry/table attributes; enhance HTML conversion and display preferences handling in adapters.
1 parent 04c6f09 commit e5800dc

8 files changed

Lines changed: 111 additions & 102 deletions

File tree

datalab/adapters_metadata/base_adapter.py

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99
from __future__ import annotations
1010

1111
from abc import ABC, abstractmethod
12-
from typing import TYPE_CHECKING, Any, ClassVar, Generator, Union
12+
from typing import TYPE_CHECKING, Any, ClassVar, Generator
1313

1414
from sigima.objects import ImageObj, SignalObj
1515

1616
if TYPE_CHECKING:
1717
import pandas as pd
18+
from sigima.objects.scalar import GeometryResult, TableResult
1819

1920

2021
class BaseResultAdapter(ABC):
@@ -31,7 +32,7 @@ class BaseResultAdapter(ABC):
3132
META_PREFIX: ClassVar[str] = ""
3233
SUFFIX: ClassVar[str] = ""
3334

34-
def __init__(self, result: Any) -> None:
35+
def __init__(self, result: TableResult | GeometryResult) -> None:
3536
self.result = result
3637

3738
def set_applicative_attr(self, key: str, value: Any) -> None:
@@ -58,22 +59,14 @@ def get_applicative_attr(self, key: str, default: Any = None) -> Any:
5859
self.result.attrs[key] = default
5960
return self.result.attrs.get(key, default)
6061

61-
@abstractmethod
62-
def to_dataframe(self) -> "pd.DataFrame":
63-
"""Convert the result to a pandas DataFrame.
64-
65-
Returns:
66-
DataFrame with columns as in self.headers, and optional 'roi_index' column.
67-
"""
68-
6962
@property
70-
@abstractmethod
7163
def title(self) -> str:
7264
"""Get the title.
7365
7466
Returns:
7567
Title
7668
"""
69+
return self.result.title
7770

7871
@property
7972
@abstractmethod
@@ -143,15 +136,15 @@ def label_contents(self) -> tuple[tuple[int, str], ...]:
143136
"""
144137
return tuple(enumerate(self.headers))
145138

146-
def set_obj_metadata(self, obj: Union[SignalObj, ImageObj]) -> None:
139+
def set_obj_metadata(self, obj: SignalObj | ImageObj) -> None:
147140
"""Set object metadata from result (alias for add_to).
148141
149142
Args:
150143
obj: Signal or image object
151144
"""
152145
self.add_to(obj)
153146

154-
def add_to(self, obj: Union[SignalObj, ImageObj]) -> None:
147+
def add_to(self, obj: SignalObj | ImageObj) -> None:
155148
"""Add result to object metadata.
156149
157150
Args:
@@ -161,7 +154,7 @@ def add_to(self, obj: Union[SignalObj, ImageObj]) -> None:
161154
metadata_key = f"{self.META_PREFIX}{self.title}{self.SUFFIX}"
162155
obj.metadata[metadata_key] = self.result.to_dict()
163156

164-
def remove_from(self, obj: Union[SignalObj, ImageObj]) -> None:
157+
def remove_from(self, obj: SignalObj | ImageObj) -> None:
165158
"""Remove result from object metadata.
166159
167160
Args:
@@ -172,7 +165,7 @@ def remove_from(self, obj: Union[SignalObj, ImageObj]) -> None:
172165
obj.metadata.pop(metadata_key, None)
173166

174167
@classmethod
175-
def remove_all_from(cls, obj: Union[SignalObj, ImageObj]) -> None:
168+
def remove_all_from(cls, obj: SignalObj | ImageObj) -> None:
176169
"""Remove all results of this type from object metadata.
177170
178171
Args:
@@ -197,7 +190,7 @@ def match(cls, key: str, _value: Any) -> bool:
197190

198191
@classmethod
199192
@abstractmethod
200-
def from_metadata_entry(cls, obj: Union[SignalObj, ImageObj], key: str):
193+
def from_metadata_entry(cls, obj: SignalObj | ImageObj, key: str):
201194
"""Create a result adapter from a metadata entry.
202195
203196
Args:
@@ -212,7 +205,9 @@ def from_metadata_entry(cls, obj: Union[SignalObj, ImageObj], key: str):
212205
"""
213206

214207
@classmethod
215-
def iterate_from_obj(cls, obj: Union[SignalObj, ImageObj]) -> Generator:
208+
def iterate_from_obj(
209+
cls, obj: SignalObj | ImageObj
210+
) -> Generator["BaseResultAdapter", None, None]:
216211
"""Iterate over results stored in an object's metadata.
217212
218213
Args:
@@ -228,3 +223,64 @@ def iterate_from_obj(cls, obj: Union[SignalObj, ImageObj]) -> Generator:
228223
except (ValueError, TypeError):
229224
# Skip invalid entries
230225
pass
226+
227+
def to_dataframe(self) -> "pd.DataFrame":
228+
"""Convert the geometry result to a pandas DataFrame.
229+
230+
Returns:
231+
DataFrame with columns as in self.headers, and optional 'roi_index' column.
232+
"""
233+
return self.result.to_dataframe()
234+
235+
def to_html(
236+
self,
237+
obj=None,
238+
visible_headers: list[str] = None,
239+
transpose_single_row: bool = True,
240+
**kwargs,
241+
) -> str:
242+
"""Convert the result to HTML format.
243+
244+
Args:
245+
obj: Optional SignalObj or ImageObj for ROI title extraction
246+
visible_headers: Optional list of headers to show (filters columns)
247+
transpose_single_row: If True, transpose the table when there's only one row
248+
**kwargs: Additional arguments passed to DataFrame.to_html()
249+
250+
Returns:
251+
HTML representation of the result
252+
"""
253+
# Use visible headers from display preferences if not specified
254+
if visible_headers is None:
255+
visible_headers = self.result.get_visible_headers()
256+
257+
return self.result.to_html(
258+
obj=obj,
259+
visible_headers=visible_headers,
260+
transpose_single_row=transpose_single_row,
261+
**kwargs,
262+
)
263+
264+
def get_display_preferences(self) -> dict[str, bool]:
265+
"""Get display preferences.
266+
267+
Returns:
268+
Dictionary mapping header names to visibility (True=visible, False=hidden)
269+
"""
270+
return self.result.get_display_preferences()
271+
272+
def set_display_preferences(self, preferences: dict[str, bool]) -> None:
273+
"""Set display preferences.
274+
275+
Args:
276+
preferences: Dictionary mapping header names to visibility
277+
"""
278+
self.result.set_display_preferences(preferences)
279+
280+
def get_visible_headers(self) -> list[str]:
281+
"""Get list of currently visible headers based on display preferences.
282+
283+
Returns:
284+
List of header names that should be displayed
285+
"""
286+
return self.result.get_visible_headers()

datalab/adapters_metadata/common.py

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
if TYPE_CHECKING:
2525
from qtpy.QtWidgets import QWidget
26-
from sigima.objects import TypeROI
2726

2827

2928
@dataclasses.dataclass
@@ -142,29 +141,25 @@ def show_resultdata(parent: QWidget, rdata: ResultData, object_name: str = "") -
142141
def resultadapter_to_html(
143142
adapter: BaseResultAdapter,
144143
obj: SignalObj | ImageObj,
144+
visible_headers: list[str] = None,
145+
transpose_single_row: bool = True,
146+
**kwargs,
145147
) -> str:
146148
"""Convert a result adapter to HTML format
147149
148150
Args:
149151
adapter: Adapter to convert
150152
obj: Object associated to the adapter
153+
visible_headers: Optional list of headers to show (filters columns)
154+
transpose_single_row: If True, transpose the table when there's only one row
155+
**kwargs: Additional arguments passed to DataFrame.to_html()
151156
152157
Returns:
153158
HTML representation of the adapter
154159
"""
155-
df = adapter.to_dataframe()
156-
if "roi_index" in df.columns:
157-
df = df.drop(columns=["roi_index"])
158-
text = f'<u><b style="color: blue">{adapter.title}</b></u>:'
159-
row_headers = []
160-
for i_row in range(df.shape[0]):
161-
i_roi = i_row - 1
162-
header = ""
163-
if i_roi >= 0:
164-
roi: TypeROI = obj.roi
165-
assert obj.roi is not None, "Expected ROI to be defined"
166-
header = roi.get_single_roi_title(i_roi)
167-
row_headers.append(header)
168-
df.set_index(pd.Index(row_headers), inplace=True)
169-
text += df.to_html(float_format="%.3g", border=0)
170-
return text
160+
return adapter.to_html(
161+
obj=obj,
162+
visible_headers=visible_headers,
163+
transpose_single_row=transpose_single_row,
164+
**kwargs,
165+
)

datalab/adapters_metadata/geometry_adapter.py

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,12 @@
88

99
from __future__ import annotations
1010

11-
from typing import TYPE_CHECKING, ClassVar
11+
from typing import ClassVar
1212

1313
from sigima.objects import GeometryResult, ImageObj, SignalObj
1414

1515
from datalab.adapters_metadata.base_adapter import BaseResultAdapter
1616

17-
if TYPE_CHECKING:
18-
import pandas as pd
19-
2017

2118
class GeometryAdapter(BaseResultAdapter):
2219
"""Adapter for GeometryResult objects.
@@ -34,7 +31,6 @@ class GeometryAdapter(BaseResultAdapter):
3431

3532
def __init__(self, geometry: GeometryResult) -> None:
3633
super().__init__(geometry)
37-
self.geometry = geometry # Keep for backwards compatibility
3834

3935
@classmethod
4036
def from_geometry_result(cls, geometry: GeometryResult) -> GeometryAdapter:
@@ -48,13 +44,17 @@ def from_geometry_result(cls, geometry: GeometryResult) -> GeometryAdapter:
4844
"""
4945
return cls(geometry)
5046

51-
def to_dataframe(self) -> "pd.DataFrame":
52-
"""Convert the geometry result to a pandas DataFrame.
47+
@property
48+
def headers(self) -> list[str]:
49+
"""Get column headers for the coordinates.
5350
5451
Returns:
55-
DataFrame with columns as in self.headers, and optional 'roi_index' column.
52+
List of column headers
5653
"""
57-
return self.geometry.to_dataframe()
54+
# Get headers directly from the DataFrame
55+
df = self.result.to_dataframe()
56+
# Return coordinate columns (exclude 'roi_index' if present)
57+
return [col for col in df.columns if col != "roi_index"]
5858

5959
@property
6060
def category(self) -> str:
@@ -63,28 +63,7 @@ def category(self) -> str:
6363
Returns:
6464
Category
6565
"""
66-
return f"shape_{self.geometry.kind.value}"
67-
68-
@property
69-
def title(self) -> str:
70-
"""Get the title.
71-
72-
Returns:
73-
Title
74-
"""
75-
return self.geometry.title
76-
77-
@property
78-
def headers(self) -> list[str]:
79-
"""Get column headers for the coordinates.
80-
81-
Returns:
82-
List of column headers
83-
"""
84-
# Get headers directly from the DataFrame
85-
df = self.geometry.to_dataframe()
86-
# Return coordinate columns (exclude 'roi_index' if present)
87-
return [col for col in df.columns if col != "roi_index"]
66+
return f"shape_{self.result.kind.value}"
8867

8968
@staticmethod
9069
def add_geometry_result_to_obj(

datalab/adapters_metadata/table_adapter.py

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@
88

99
from __future__ import annotations
1010

11-
from typing import TYPE_CHECKING, ClassVar, Union
11+
from typing import ClassVar, Union
1212

1313
from sigima.objects import ImageObj, SignalObj
1414
from sigima.objects.scalar import NO_ROI, TableResult
1515

1616
from datalab.adapters_metadata.base_adapter import BaseResultAdapter
1717

18-
if TYPE_CHECKING:
19-
import pandas as pd
20-
2118

2219
class TableAdapter(BaseResultAdapter):
2320
"""Adapter for TableResult objects.
@@ -35,7 +32,6 @@ class TableAdapter(BaseResultAdapter):
3532

3633
def __init__(self, table: TableResult) -> None:
3734
super().__init__(table)
38-
self.table = table # Keep for backwards compatibility
3935

4036
@classmethod
4137
def from_table_result(cls, table: TableResult) -> TableAdapter:
@@ -49,31 +45,14 @@ def from_table_result(cls, table: TableResult) -> TableAdapter:
4945
"""
5046
return cls(table)
5147

52-
def to_dataframe(self) -> "pd.DataFrame":
53-
"""Convert the table result to a pandas DataFrame.
54-
55-
Returns:
56-
DataFrame with columns as in self.headers, and optional 'roi_index' column.
57-
"""
58-
return self.table.to_dataframe()
59-
60-
@property
61-
def title(self) -> str:
62-
"""Get the title.
63-
64-
Returns:
65-
Title
66-
"""
67-
return self.table.title
68-
6948
@property
7049
def headers(self) -> list[str]:
7150
"""Get the column headers.
7251
7352
Returns:
7453
Column headers
7554
"""
76-
return list(self.table.headers)
55+
return list(self.result.headers)
7756

7857
@property
7958
def category(self) -> str:
@@ -82,7 +61,7 @@ def category(self) -> str:
8261
Returns:
8362
Category (uses the title for backward compatibility)
8463
"""
85-
return self.table.title
64+
return self.result.title
8665

8766
@property
8867
def labels(self) -> list[str]:
@@ -91,7 +70,7 @@ def labels(self) -> list[str]:
9170
Returns:
9271
Column labels
9372
"""
94-
return list(self.table.labels)
73+
return list(self.result.labels)
9574

9675
def get_unique_roi_indices(self) -> list[int]:
9776
"""Get unique ROI indices present in the data.

0 commit comments

Comments
 (0)