Skip to content

Commit ca326da

Browse files
committed
Merge remote-tracking branch 'upstream/main' into load_data_in_thread
2 parents 7611861 + 803c35e commit ca326da

File tree

5 files changed

+59
-24
lines changed

5 files changed

+59
-24
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ and this project adheres to [Semantic Versioning][].
88
[keep a changelog]: https://keepachangelog.com/en/1.0.0/
99
[semantic versioning]: https://semver.org/spec/v2.0.0.html
1010

11-
## [0.x.x] - 2024-xx-xx
11+
## [0.5.3] - 2024-09-25
12+
13+
### Fixed
14+
15+
- Bug table was not reset after an element without table was added #317
16+
- Bug when changing channel for a multichannel image #301 #302
17+
- Bug when plotting catgorical annotations on points #304
1218

1319
## [0.5.2] - 2024-08-16
1420

src/napari_spatialdata/_view.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,13 @@ def _update_adata(self) -> None:
137137
)
138138
layer.metadata["adata"] = table
139139

140-
if layer is not None and "adata" in layer.metadata:
141-
with self.model.events.adata.blocker():
142-
self.model.adata = layer.metadata["adata"]
140+
if layer is not None:
141+
if "adata" in layer.metadata:
142+
with self.model.events.adata.blocker():
143+
self.model.adata = layer.metadata["adata"]
144+
else:
145+
with self.model.events.adata.blocker():
146+
self.model.adata = None
143147

144148
if self.model.adata.shape == (0, 0):
145149
return
@@ -186,8 +190,8 @@ def _select_layer(self) -> None:
186190
self.color_widget.clear()
187191
return
188192

189-
if layer is not None and "adata" in layer.metadata:
190-
self.model.adata = layer.metadata["adata"]
193+
if layer is not None:
194+
self.model.adata = layer.metadata.get("adata", None)
191195

192196
def screenshot(self) -> Any:
193197
return QImg2array(self.grab().toImage())
@@ -384,10 +388,11 @@ def _select_layer(self) -> None:
384388
if isinstance(layer, (Points, Shapes)) and (cols_df := layer.metadata.get("_columns_df")) is not None:
385389
self.dataframe_columns_widget.addItems(map(str, cols_df.columns))
386390
self.model.system_name = layer.metadata.get("name", None)
391+
self.model.adata = None
387392
return
388393

389-
if layer is not None and "adata" in layer.metadata:
390-
self.model.adata = layer.metadata["adata"]
394+
if layer is not None:
395+
self.model.adata = layer.metadata.get("adata", None)
391396

392397
if self.model.adata.shape == (0, 0):
393398
return
@@ -418,9 +423,13 @@ def _update_adata(self) -> None:
418423
)
419424
layer.metadata["adata"] = table
420425

421-
if layer is not None and "adata" in layer.metadata:
422-
with self.model.events.adata.blocker():
423-
self.model.adata = layer.metadata["adata"]
426+
if layer is not None:
427+
if "adata" in layer.metadata:
428+
with self.model.events.adata.blocker():
429+
self.model.adata = layer.metadata["adata"]
430+
else:
431+
with self.model.events.adata.blocker():
432+
self.model.adata = None
424433

425434
if self.model.adata.shape == (0, 0):
426435
return
@@ -440,10 +449,12 @@ def _update_adata(self) -> None:
440449
return
441450

442451
def _get_adata_layer(self) -> Sequence[str | None]:
452+
if self.model.adata is None:
453+
return [None]
443454
adata_layers = list(self.model.adata.layers.keys())
444-
if len(adata_layers):
445-
return adata_layers
446-
return [None]
455+
if len(adata_layers) == 0:
456+
return [None]
457+
return adata_layers
447458

448459
def _change_color_by(self) -> None:
449460
self.color_by.setText(f"Color by: {self.model.color_by}")

src/napari_spatialdata/_viewer.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from shapely import Polygon
1818
from spatialdata import get_element_annotators, get_element_instances
1919
from spatialdata._core.query.relational_query import _left_join_spatialelement_table
20+
from spatialdata._types import ArrayLike
2021
from spatialdata.models import PointsModel, ShapesModel, TableModel, force_2d, get_channels
2122
from spatialdata.transformations import Affine, Identity
2223
from spatialdata.transformations._utils import scale_radii
@@ -162,13 +163,13 @@ def _write_element_to_disk(
162163
element: tuple[DaskDataFrame | GeoDataFrame | AnnData],
163164
overwrite: bool,
164165
) -> None:
165-
if sdata.is_backed:
166-
self._delete_from_disk(sdata, element_name, overwrite)
167-
sdata[element_name] = element
168-
sdata.write_element(element_name)
169-
else:
170-
sdata[element_name] = element
171-
logger.warning("Spatialdata object is not stored on disk, could only add element in memory.")
166+
# if sdata.is_backed:
167+
# self._delete_from_disk(sdata, element_name, overwrite)
168+
# sdata[element_name] = element
169+
# sdata.write_element(element_name)
170+
# else:
171+
sdata[element_name] = element
172+
logger.warning("Annotations only added in memory, please manually save to disk.")
172173

173174
def _save_points_to_sdata(
174175
self, layer_to_save: Points, spatial_element_name: str | None, overwrite: bool
@@ -188,6 +189,8 @@ def _save_points_to_sdata(
188189
swap_data = swap_data[:, :2]
189190
parsed = PointsModel.parse(swap_data, transformations=transformation)
190191

192+
# saving to disk of points temporarily disabled until the interface update that will unify the view widget,
193+
# annotation widget and scatterplot widget
191194
self._write_element_to_disk(sdata, spatial_element_name, parsed, overwrite)
192195

193196
return parsed, coordinate_system
@@ -248,7 +251,18 @@ def _save_shapes_to_sdata(
248251
if len(layer_to_save.data) == 0:
249252
raise ValueError("Cannot export a shapes element with no shapes")
250253

251-
polygons: list[Polygon] = [Polygon(i) for i in _transform_coordinates(layer_to_save.data, f=lambda x: x[::-1])]
254+
coords = [
255+
np.array([layer_to_save.data_to_world(xy) for xy in shape._data])
256+
for shape in layer_to_save._data_view.shapes
257+
]
258+
259+
def _fix_coords(coords: ArrayLike) -> ArrayLike:
260+
remove_z = coords.shape[1] == 3
261+
first_index = 1 if remove_z else 0
262+
coords = coords[:, first_index::]
263+
return np.fliplr(coords)
264+
265+
polygons: list[Polygon] = [Polygon(_fix_coords(p)) for p in coords]
252266
gdf = GeoDataFrame({"geometry": polygons})
253267

254268
force_2d(gdf)
@@ -600,6 +614,7 @@ def get_sdata_shapes(self, sdata: SpatialData, key: str, selected_cs: str, multi
600614
name=key,
601615
affine=affine,
602616
shape_type="polygon",
617+
face_color="#00000000",
603618
metadata={
604619
"sdata": sdata,
605620
"adata": adata,

src/napari_spatialdata/_widgets.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ def _onAction(self, items: Iterable[str]) -> None:
135135
self.model.layer.text = None # needed because of the text-feature order of updates
136136
# self.model.layer.features = properties.get("features", None)
137137
self.model.layer.face_color = properties["face_color"]
138+
# self.model.layer.edge_color = properties["face_color"]
138139
self.model.layer.text = properties["text"]
139140
elif isinstance(self.model.layer, Labels):
140141
version = get_napari_version()
@@ -226,7 +227,7 @@ def _(self, vec: pd.Series, **kwargs: Any) -> dict[str, Any]:
226227
f"The {vec_color_name} column must have unique values for the each {vec.name} level. Found:\n"
227228
f"{unique_colors}"
228229
)
229-
color_dict = unique_colors.to_dict()["genes_color"]
230+
color_dict = unique_colors.to_dict()[f"{vec.name}_color"]
230231

231232
if self.model.instance_key is not None and self.model.instance_key == vec.index.name:
232233
merge_df = pd.merge(

src/napari_spatialdata/utils/_utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ def get_itemindex_by_text(
419419
return widget_item
420420

421421

422-
def _get_init_table_list(layer: Layer) -> Sequence[str | None] | None:
422+
def _get_init_table_list(layer: Layer | None) -> Sequence[str | None] | None:
423423
"""
424424
Get the table names annotating the SpatialElement upon creating the napari layer.
425425
@@ -432,6 +432,8 @@ def _get_init_table_list(layer: Layer) -> Sequence[str | None] | None:
432432
------
433433
The list of table names annotating the SpatialElement if any.
434434
"""
435+
if layer is None:
436+
return None
435437
table_names: Sequence[str | None] | None
436438
if table_names := layer.metadata.get("table_names"):
437439
return table_names # type: ignore[no-any-return]

0 commit comments

Comments
 (0)