Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions package/PartSeg/plugins/napari_io/loader.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import typing
from importlib.metadata import version

Expand All @@ -9,6 +10,7 @@
from PartSegCore.analysis import ProjectTuple
from PartSegCore.io_utils import LoadBase, WrongFileTypeException
from PartSegCore.mask.io_functions import MaskProjectTuple
from PartSegCore.universal_const import format_layer_name
from PartSegImage import Image


Expand Down Expand Up @@ -54,12 +56,20 @@ def add_color(image: Image, idx: int) -> dict: # noqa: ARG001


def _image_to_layers(project_info, scale, translate):
settings = get_settings()
filename = os.path.basename(project_info.file_path)
res_layers = []
if project_info.image.name == "ROI" and project_info.image.channels == 1:
res_layers.append(
(
project_info.image.get_channel(0),
{"scale": scale, "name": project_info.image.channel_names[0], "translate": translate},
{
"scale": scale,
"name": format_layer_name(
settings.layer_naming_format, filename, project_info.image.channel_names[0]
),
"translate": translate,
},
"labels",
)
)
Expand All @@ -69,7 +79,9 @@ def _image_to_layers(project_info, scale, translate):
project_info.image.get_channel(i),
{
"scale": scale,
"name": project_info.image.channel_names[i],
"name": format_layer_name(
settings.layer_naming_format, filename, project_info.image.channel_names[i]
),
"blending": "additive",
"translate": translate,
"metadata": project_info.image.metadata,
Expand Down
22 changes: 22 additions & 0 deletions package/PartSeg/plugins/napari_widgets/_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from PartSeg.common_backend import napari_get_settings
from PartSegCore import Units
from PartSegCore.json_hooks import PartSegEncoder
from PartSegCore.universal_const import LayerNamingFormat

_SETTINGS = None

Expand All @@ -29,6 +30,14 @@ def io_units(self) -> Units:
def io_units(self, value: Units):
self.set("io_units", value)

@property
def layer_naming_format(self) -> LayerNamingFormat:
return self.get("layer_naming_format", LayerNamingFormat.channel_only)

@layer_naming_format.setter
def layer_naming_format(self, value: LayerNamingFormat):
self.set("layer_naming_format", value)


def get_settings() -> PartSegNapariSettings:
global _SETTINGS # noqa: PLW0603 # pylint: disable=global-statement
Expand All @@ -51,10 +60,23 @@ def __init__(self):
self.units_select.changed.connect(self.units_selection_changed)
self.settings.connect_("io_units", self.units_changed)
self.append(self.units_select)
self.layer_naming_select = create_widget(
self.settings.layer_naming_format, annotation=LayerNamingFormat, label="Format for Layer Name"
)
self.layer_naming_select.changed.connect(self.layer_naming_format_selection_changed)
self.settings.connect_("layer_naming_format", self.layer_naming_format_changed)
self.append(self.layer_naming_select)

def units_selection_changed(self, value):
self.settings.io_units = value
self.settings.dump()

def units_changed(self):
self.units_select.value = self.settings.io_units

def layer_naming_format_selection_changed(self, value):
self.settings.layer_naming_format = value
self.settings.dump()

def layer_naming_format_changed(self):
self.layer_naming_select.value = self.settings.layer_naming_format
23 changes: 23 additions & 0 deletions package/PartSegCore/universal_const.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,26 @@ def __str__(self):

_UNITS_LIST = ["mm", "µm", "nm", "pm"]
UNIT_SCALE = [10**3, 10**6, 10**9, 10**12]


@register_class()
class LayerNamingFormat(Enum):
channel_only = 0
filename_only = 1
filename_channel = 2
channel_filename = 3

def __str__(self):
return self.name.replace("_", " ")


def format_layer_name(layer_format: LayerNamingFormat, file_name: str, channel_name: str) -> str:
if layer_format == LayerNamingFormat.channel_only:
return channel_name
if layer_format == LayerNamingFormat.filename_only:
return file_name
if layer_format == LayerNamingFormat.filename_channel:
return f"{file_name} | {channel_name}"
if layer_format == LayerNamingFormat.channel_filename:
return f"{channel_name} | {file_name}"
raise ValueError("Unknown format") # pragma: no cover
11 changes: 11 additions & 0 deletions package/tests/test_PartSeg/test_napari_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
from PartSegCore.segmentation.noise_filtering import NoiseFilterSelection
from PartSegCore.segmentation.threshold import DoubleThresholdSelection, ThresholdSelection
from PartSegCore.segmentation.watershed import WatershedSelection
from PartSegCore.universal_const import LayerNamingFormat

NAPARI_GE_5_0 = parse_version(version("napari")) >= parse_version("0.5.0a1")
NAPARI_GE_4_19 = parse_version(version("napari")) >= parse_version("0.4.19a1")
Expand Down Expand Up @@ -655,3 +656,13 @@ def test_change_units(self, qtbot):
assert s.io_units == Units.nm
s.io_units = Units.mm
assert w.units_select.value == Units.mm

def test_change_layer_name_format(self, qtbot):
s = _settings.get_settings()
s.layer_naming_format = LayerNamingFormat.channel_only
w = _settings.SettingsEditor()
qtbot.addWidget(w.native)
w.layer_naming_select.value = LayerNamingFormat.channel_filename
assert s.layer_naming_format == LayerNamingFormat.channel_filename
s.layer_naming_format = LayerNamingFormat.channel_only
assert w.layer_naming_select.value == LayerNamingFormat.channel_only
14 changes: 14 additions & 0 deletions package/tests/test_PartSegCore/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
from PartSegCore.segmentation.noise_filtering import DimensionType
from PartSegCore.segmentation.segmentation_algorithm import ThresholdAlgorithm
from PartSegCore.segmentation.threshold import RangeThresholdSelection
from PartSegCore.universal_const import LayerNamingFormat, format_layer_name
from PartSegCore.utils import ProfileDict, check_loaded_dict
from PartSegImage import Image

Expand Down Expand Up @@ -911,6 +912,19 @@ def test_load(self, tmp_path):
assert res.roi_info.roi.shape == (1, 1, 100, 100)


@pytest.mark.parametrize(
("value", "expected"),
[
(LayerNamingFormat.channel_only, "b"),
(LayerNamingFormat.filename_only, "a"),
(LayerNamingFormat.filename_channel, "a | b"),
(LayerNamingFormat.channel_filename, "b | a"),
],
)
def test_format_layer_name(value, expected):
assert format_layer_name(value, "a", "b") == expected


UPDATE_NAME_JSON = """
{"problematic set": {
"__MeasurementProfile__": true,
Expand Down