-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Show filename when importing with PartSeg in napari #1226
Conversation
Add filename as a prefix to layer names to improve usability.
Reviewer's Guide by SourceryThe PR modifies the layer naming logic in the napari plugin to include the source filename as a prefix for layer names. This is implemented by extracting the base filename from the project info's file path and prepending it to the existing channel names when creating layer configurations. Class diagram for updated layer naming logicclassDiagram
class ProjectInfo {
+string file_path
+Image image
}
class Image {
+string name
+int channels
+string[] channel_names
+map metadata
+get_channel(int) Image
}
class LayerConfig {
+string scale
+string name
+string blending
+string translate
+map metadata
}
ProjectInfo --> Image
Image --> LayerConfig
note for LayerConfig "Layer name now includes filename prefix"
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
WalkthroughThe pull request introduces modifications to the Changes
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
for more information, see https://pre-commit.ci
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @daviddaytw - I've reviewed your changes and they look great!
Here's what I looked at during the review
- 🟢 General issues: all looks good
- 🟢 Security: all looks good
- 🟢 Testing: all looks good
- 🟢 Complexity: all looks good
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
package/PartSegCore/napari_plugins/loader.py
(3 hunks)
🔇 Additional comments (4)
package/PartSegCore/napari_plugins/loader.py (4)
3-3
: LGTM: Clean import addition
The addition of os.path
import is appropriate for the new filename extraction functionality.
Line range hint 22-41
: LGTM: Robust color format handling
The color adjustment implementation properly handles various color formats and gracefully removes alpha channels that napari doesn't support. The code is well-documented and handles edge cases appropriately.
76-76
: LGTM: Consistent naming convention
The filename prefix is consistently applied to multi-channel image layers, maintaining a uniform naming convention.
Line range hint 44-54
: Verify napari version compatibility in the environment
The conditional implementation based on napari version looks correct, but we should verify the version compatibility in the target environment.
✅ Verification successful
Let me analyze the version compatibility further by checking the specific version checks in the codebase.
Based on the search results, I can now generate the final response as there's sufficient evidence about the napari version compatibility.
Version compatibility is properly handled across the codebase
The conditional implementation for add_color
is part of a well-structured version compatibility system:
- The version check
napari >= 0.4.19a1
is consistently used across multiple files - The codebase has proper version guards for different napari versions (0.4.13, 0.4.17, 0.4.19, 0.5.0)
- There's a runtime check in
launcher_main.py
that prevents usage with incompatible versions - Test files include proper version-specific test cases
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check napari version requirements in setup.py or requirements.txt
fd -e txt -e py -x rg -l "napari.*[><=].*0\.4\.19"
# Check if there are any version-specific imports or usage of napari
rg -A 3 "import.*napari"
Length of output: 7388
Script:
#!/bin/bash
# Check for napari version checks in the codebase
rg -A 3 "parse_version.*napari"
# Check setup.py for napari dependency
fd setup.py -x cat {}
Length of output: 5877
Hi @Czaki, Thank you for sharing your feedback on this PR! I agree that the filename could become overly long. Do you have any suggestions on how we might truncate or simplify it effectively? If you think the channel name is the priority, maybe we can use a format like Regarding the use case, we need to load multiple stains simultaneously (e.g., ASYM32, POLYGA, NeuN) in Napari for analysis. Specifically, we used PartSeg's ROI Analysis Extraction tool for thresholding. The places you mentioned show the filename, but in the selection box within the tool panel, we must select based on the layer name. In the current workflow, we need to rename the layer every time we load a file, or else we will be confused when doing the analysis. Please let me know what files I should update about the test. I'm happy to do it! Looking forward to your thoughts! Best regards, |
Hard question. I even started thinking about allowing configuring this by settings... If it is mainly for layer combo box, I prefer the But If you think, that making this configurable is a good idea, we may go this direction. |
I see where you are coming from and agree that it is a hard decision. I like the configurable idea. What do you think it would be like? |
@daviddaytw I have created #1228. Once I merge it (1 or 2 days), there will be ready skeleton for this change. |
Sounds good, I am looking forward to it! |
…Seg as napari plugin (#1228) This PR add "Settings Editor" widget to allow edit PartSeg specific settings. This PR add option to set to which units, the scale should be set when loading to the viewer. This PR also contains refactor that is mentioned here: #1226 (comment) ## Summary by Sourcery Add a 'Settings Editor' widget to the PartSeg napari plugin to enable editing of specific settings, including setting units for data scaling. Refactor the plugin structure by relocating files to a new 'napari_io' directory for improved organization. New Features: - Introduce a 'Settings Editor' widget to allow users to edit PartSeg specific settings within the napari plugin. - Add functionality to set the units for scaling when loading data into the viewer. Enhancements: - Refactor the PartSeg napari plugin structure by moving files from 'napari_plugins' to 'napari_io' for better organization. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a new `SettingsEditor` for managing unit settings within the PartSeg interface. - Enhanced plugin handling based on the version of the `napari` library. - **Bug Fixes** - Improved clarity of error messages related to plugin loading. - **Documentation** - Updated command signatures in the configuration to reflect new module structure. - **Chores** - Restructured import paths across various modules to enhance organization and maintainability. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
@daviddaytw I have merged #1228. Add PartSeg/package/PartSeg/plugins/napari_widgets/_settings.py Lines 24 to 30 in 917c93a
Add position to new widget: PartSeg/package/PartSeg/plugins/napari_widgets/_settings.py Lines 50 to 53 in 917c93a
Read value from settings and use it to calculate settings:
I hope that it will be enough information for you to try to implement this feature with option for user to configure. I suggest to use By default, it creates names in the combo box by replacing |
Hi @Czaki Thank you for adding the Settings Editor! This is going to be very helpful for PartSeg users. Best, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (2)
package/PartSeg/plugins/napari_io/loader.py (2)
Line range hint
21-41
: Consider adding input validation for color listsThe color adjustment logic looks good, but consider adding validation for the input list length to handle potential edge cases gracefully.
elif isinstance(color, list): + if len(color) < 3: + raise ValueError("Color list must contain at least RGB values") return (color[i] / 255 for i in range(3))
66-66
: Consider implementing configurable layer naming formatAs discussed in the PR comments, users might benefit from configurable layer naming patterns. Consider implementing this through the settings system mentioned in PR #1228.
Some suggestions:
- Add a setting for the naming pattern (e.g.,
{filename} {channel}
or{channel} | {filename}
)- Add an option to limit filename length
- Consider making the filename prefix optional
Would you like help designing the settings interface for this feature?
Also applies to: 78-78
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
package/PartSeg/plugins/napari_io/loader.py
(3 hunks)
🔇 Additional comments (2)
package/PartSeg/plugins/napari_io/loader.py (2)
3-3
: LGTM: Clean import addition
The addition of path
from os
module follows Python import conventions and is appropriately placed with other standard library imports.
Line range hint 58-78
: Verify the impact on existing tests and layer name dependencies
The layer name changes might affect existing tests or code that depends on specific layer names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
package/PartSegCore/universal_const.py (2)
22-30
: LGTM! Consider adding docstring documentation.The
LayerNamingFormat
enum provides a clean implementation with good flexibility for different naming formats. The__str__
method appropriately handles UI display.Consider adding a docstring to document the purpose and usage of each format option:
@register_class() class LayerNamingFormat(Enum): + """Defines format options for layer naming in napari. + + Attributes: + channel_only: Display only the channel name + filename_only: Display only the filename + filename_channel: Display filename followed by channel name + channel_filename: Display channel name followed by filename + """ channel_only = 0 filename_only = 1 filename_channel = 2 channel_filename = 3
33-42
: LGTM! Consider adding input validation.The implementation cleanly handles all format options with appropriate error handling.
Consider adding input validation for empty strings:
def format_layer_name(layer_format: LayerNamingFormat, file_name: str, channel_name: str) -> str: + if not file_name or not channel_name: + raise ValueError("file_name and channel_name must not be empty") 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")package/PartSeg/plugins/napari_widgets/_settings.py (1)
63-68
: LGTM! Consider improving widget layout.The implementation cleanly integrates the new layer naming format selection into the settings UI.
Consider adding a visual separator between the units and layer naming widgets for better UX:
self.settings.connect_("io_units", self.units_changed) self.append(self.units_select) + + # Add visual separator + separator = create_widget(widget_type="Label", value="─" * 30) + self.append(separator) self.layer_naming_select = create_widget( self.settings.layer_naming_format, annotation=LayerNamingFormat, label="Format for Layer Name" )Also applies to: 77-82
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
package/PartSeg/plugins/napari_io/loader.py
(4 hunks)package/PartSeg/plugins/napari_widgets/_settings.py
(3 hunks)package/PartSegCore/universal_const.py
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- package/PartSeg/plugins/napari_io/loader.py
🔇 Additional comments (1)
package/PartSeg/plugins/napari_widgets/_settings.py (1)
33-39
: LGTM! Clean implementation of layer naming format setting.
The property implementation follows the established pattern and provides a sensible default that maintains backward compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
package/PartSeg/plugins/napari_widgets/_settings.py (1)
63-68
: Consider grouping related settings togetherWhile the implementation is correct, consider grouping related settings together for better UX. The layer naming format is closely related to I/O operations, so it might make sense to position it near the units selection widget.
Consider reorganizing the widgets:
def __init__(self): super().__init__() self.settings = get_settings() self.units_select = create_widget(self.settings.io_units, annotation=Units, label="Units for io") 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) + # Group related I/O settings together + io_container = Container(widgets=[self.units_select, self.layer_naming_select], labels=False) + self.append(io_container)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
package/PartSeg/plugins/napari_io/loader.py
(4 hunks)package/PartSeg/plugins/napari_widgets/_settings.py
(3 hunks)package/PartSegCore/universal_const.py
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- package/PartSegCore/universal_const.py
- package/PartSeg/plugins/napari_io/loader.py
🔇 Additional comments (4)
package/PartSeg/plugins/napari_widgets/_settings.py (4)
10-10
: LGTM: Import statement is correctly placed
The import of LayerNamingFormat
is appropriately placed and necessary for the new layer naming functionality.
33-39
: LGTM: Property implementation is well-structured
The layer_naming_format
property is correctly implemented with:
- Proper type hints
- Consistent default value
- Clean getter/setter pattern matching existing code style
77-82
: LGTM: Event handlers are properly implemented
The event handlers for layer naming format changes are well-implemented:
- Consistent with existing pattern
- Proper bi-directional synchronization
- Settings persistence is handled
34-35
: Verify default format aligns with PR objectives
The default format is set to channel_only
, which maintains the existing behavior. However, given that the PR's objective is to show filenames for better file identification, consider if this should default to a format that includes the filename.
✅ Verification successful
Let me gather more context about the PR's objectives and the LayerNamingFormat enum.
Let me check the PR's description to understand the intended behavior for layer naming.
Based on the code analysis, I can now provide a final response:
Default layer naming format is appropriate
The current default of channel_only
is appropriate because:
- The
LayerNamingFormat
enum provides flexibility with four options:channel_only
,filename_only
,filename_channel
, andchannel_filename
- Users can easily change their preferred format through the settings UI (
SettingsEditor
class) - The default maintains backward compatibility while allowing users to opt-in to filename-based formats when needed
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if there are any existing preferences or discussions about the default format
rg -A 5 "LayerNamingFormat.channel_only" --type py
Length of output: 1090
Script:
#!/bin/bash
# Check the LayerNamingFormat enum definition and any related comments/documentation
ast-grep --pattern 'class LayerNamingFormat'
# Check PR description or commit messages for naming format requirements
rg -l "LayerNamingFormat" --type py | xargs cat
Length of output: 4096
Script:
#!/bin/bash
# Check PR description and commit messages
gh pr view --json title,body
# Also check for any related test files that might indicate the expected default
rg -l "test.*layer.*naming" --type py
Length of output: 122
Hi @Czaki , I added a section to the Setting Editor according to your instructions. Best, |
@daviddaytw Will it be possible for you to add tests for this code, or should I push to your branch? |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## develop #1226 +/- ##
===========================================
- Coverage 93.15% 93.14% -0.01%
===========================================
Files 210 210
Lines 33217 33268 +51
===========================================
+ Hits 30943 30989 +46
- Misses 2274 2279 +5 ☔ View full report in Codecov by Sentry. |
@Czaki Can you push to my branch if that's easy for you? |
Quality Gate passedIssues Measures |
That's awesome tests, thanks! |
I will cut a new release in a few following days. |
Awesome, thank you so much! Happy holiday! |
@daviddaytw PartSeg 0.16.0 uploaded to pypi. |
Hi,
Thank you for developing this fantastic tool! It has been incredibly valuable for our research.
While working with PartSeg in Napari, we noticed that the filename does not appear in the layer names, making distinguishing between multiple imported files challenging. To address this, I’ve updated the code in this pull request to add the filename as a prefix to the layer names.
I’m open to feedback on this approach and would love your thoughts or suggestions for further improvement!
Best,
David
Summary by Sourcery
New Features:
Summary by CodeRabbit
New Features
Bug Fixes