Skip to content

Commit 6f4c435

Browse files
committed
Merge branch 'develop' into feature/17-parameters
# Conflicts: # datalab/adapters_metadata/base_adapter.py
2 parents ac1e716 + e5800dc commit 6f4c435

8 files changed

Lines changed: 110 additions & 101 deletions

File tree

datalab/adapters_metadata/base_adapter.py

Lines changed: 72 additions & 16 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,7 +136,7 @@ def label_contents(self) -> tuple[tuple[int, str], ...]:
143136
"""
144137
return tuple(enumerate(self.headers))
145138

146-
def add_to(self, obj: Union[SignalObj, ImageObj]) -> None:
139+
def add_to(self, obj: SignalObj | ImageObj) -> None:
147140
"""Add result to object metadata.
148141
149142
Args:
@@ -153,7 +146,7 @@ def add_to(self, obj: Union[SignalObj, ImageObj]) -> None:
153146
metadata_key = f"{self.META_PREFIX}{self.title}{self.SUFFIX}"
154147
obj.metadata[metadata_key] = self.result.to_dict()
155148

156-
def remove_from(self, obj: Union[SignalObj, ImageObj]) -> None:
149+
def remove_from(self, obj: SignalObj | ImageObj) -> None:
157150
"""Remove result from object metadata.
158151
159152
Args:
@@ -164,7 +157,7 @@ def remove_from(self, obj: Union[SignalObj, ImageObj]) -> None:
164157
obj.metadata.pop(metadata_key, None)
165158

166159
@classmethod
167-
def remove_all_from(cls, obj: Union[SignalObj, ImageObj]) -> None:
160+
def remove_all_from(cls, obj: SignalObj | ImageObj) -> None:
168161
"""Remove all results of this type from object metadata.
169162
170163
Args:
@@ -189,7 +182,7 @@ def match(cls, key: str, _value: Any) -> bool:
189182

190183
@classmethod
191184
@abstractmethod
192-
def from_metadata_entry(cls, obj: Union[SignalObj, ImageObj], key: str):
185+
def from_metadata_entry(cls, obj: SignalObj | ImageObj, key: str):
193186
"""Create a result adapter from a metadata entry.
194187
195188
Args:
@@ -204,7 +197,9 @@ def from_metadata_entry(cls, obj: Union[SignalObj, ImageObj], key: str):
204197
"""
205198

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