-
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
docs: Add docs for plugin create #795
base: develop
Are you sure you want to change the base?
Changes from all commits
663b761
e456d72
76b302b
caaf30b
45fb87d
4411e64
7af9c97
657c962
41373b8
33b4ff2
79230b5
c3280b4
d011273
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
tasks: | ||
- init: > | ||
pip install -e .[test,pyqt] | ||
pip install -r docs/requirements.txt | ||
- before: sudo apt-get update && sudo apt-get install -y herbstluftwm libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 x11-utils xvfb | ||
# command: Xvfb :99 -screen 0 640x480x8 -nolisten tcp & herbstluftwm | ||
init: pip install -e .[all,test,docs] && bash ./build_utils/download_data.sh |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,116 @@ | ||||||||||||||
Creating plugins for PartSeg | ||||||||||||||
============================ | ||||||||||||||
|
||||||||||||||
PartSeg has a plugin system, but because of a lack of documentation, it is not very popular. | ||||||||||||||
This document is an attempt to explain how to create plugins for PartSeg. The list of good plugins that could be inspirration | ||||||||||||||
is available at the :ref:`end of this document<Already existing plugins>`. | ||||||||||||||
Comment on lines
+4
to
+6
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor grammatical error. - This document is an attempt to explain how to create plugins for PartSeg. The list of good plugins that could be inspirration
+ This document is an attempt to explain how to create plugins for PartSeg. The list of good plugins that could be inspiration Committable suggestion
Suggested change
|
||||||||||||||
|
||||||||||||||
.. note:: | ||||||||||||||
|
||||||||||||||
This document needs to be completed and may need to be corrected. If you have any questions, please inform me by a GitHub issue. | ||||||||||||||
|
||||||||||||||
PartSeg plugin system was designed at the beginning of the project when PartSeg was a python 2.7 project, and still, not | ||||||||||||||
all possibilities given by recent python versions are used. For example, plugin methods are still class-based, | ||||||||||||||
but there is a plan to allow function-based plugins. | ||||||||||||||
|
||||||||||||||
Where plugin could contribute in PartSeg | ||||||||||||||
---------------------------------------- | ||||||||||||||
|
||||||||||||||
Here I describe nine areas where plugins could contribute: | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
* **Threshold algorithms** - algorithms for binarizing single channel data. | ||||||||||||||
|
||||||||||||||
* **Noise Filtering algorithms** - algorithms for filtering noise from a single channel of data. | ||||||||||||||
|
||||||||||||||
* **Flow algorithms** - Watershed-like algorithms for flow from core object to the whole region. | ||||||||||||||
Currently, they are used in "Lower Threshold with Watershed" and "Upper Threshold with Watershed" | ||||||||||||||
segmentation methods | ||||||||||||||
|
||||||||||||||
* **ROI Analysis algorithm** - algorithm available in *ROI Analysis* GUI for ROI extraction. | ||||||||||||||
|
||||||||||||||
* **ROI Analysis load method** - method to load data in *ROI Analysis* GUI. | ||||||||||||||
|
||||||||||||||
* **ROI Analysis save method** - method to save data in *ROI Analysis* GUI. | ||||||||||||||
|
||||||||||||||
* **ROI Mask algorithm** - algorithm available in *ROI Mask* GUI for ROI extraction. | ||||||||||||||
|
||||||||||||||
* **ROI Mask load method** - method to load data in *ROI Mask* GUI. | ||||||||||||||
|
||||||||||||||
* **ROI Mask save method** - method to save data in *ROI Mask* GUI. | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
A person interested in developing a plugin could wound the whole list in :py:mod:`PartSegCore.register` module. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possible typo or incorrect word usage. - A person interested in developing a plugin could wound the whole list in :py:mod:`PartSegCore.register` module.
+ A person interested in developing a plugin could find the whole list in :py:mod:`PartSegCore.register` module. Committable suggestion
Suggested change
|
||||||||||||||
|
||||||||||||||
Plugin detection | ||||||||||||||
---------------- | ||||||||||||||
|
||||||||||||||
PartSeg uses :py:func:`pkg_resources.iter_entry_points` module to detect plugins. | ||||||||||||||
To be detected, the plugin needs to provide one of ``partseg.plugins``, ``PartSeg.plugins``. | ||||||||||||||
``partsegcore.plugins`` or ``PartSegCore.plugins`` entry point in python package metadata. | ||||||||||||||
The example of ``setup.cfg`` configuration from a plugin could be found `here <https://github.com/Czaki/Trapalyzer/blob/fc5b84fde2fb1fe4bea75bdd1e4a483772115500/setup.cfg#L43>`_ | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
|
||||||||||||||
|
||||||||||||||
``--develop`` mode of PartSeg | ||||||||||||||
----------------------------- | ||||||||||||||
|
||||||||||||||
PartSeg allows to use of plugins in ``--develop`` mode. In this mode is a settings dialog the additional | ||||||||||||||
tab "Develop" is added. In this tab, there is Reload button. After the button press, PartSeg tries | ||||||||||||||
to reload all plugins. This feature allows the development of a plugin without the need of too often restarting of PartSeg. | ||||||||||||||
|
||||||||||||||
This approach is limited and reloads only entries pointed in entry points. | ||||||||||||||
It is the plugin creator's responsibility to reload all other modules required by the plugin. | ||||||||||||||
To detect if the file is during reload, the plugin author could use the following code: | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
.. code-block:: python | ||||||||||||||
|
||||||||||||||
try: | ||||||||||||||
|
||||||||||||||
reloading | ||||||||||||||
except NameError: | ||||||||||||||
reloading = False | ||||||||||||||
else: | ||||||||||||||
reloading = True | ||||||||||||||
|
||||||||||||||
The ``importlib.reload`` function could be used to reload required modules. | ||||||||||||||
|
||||||||||||||
.. code-block:: python | ||||||||||||||
|
||||||||||||||
import importlib | ||||||||||||||
importlib.reload(module) | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
Already existing plugins | ||||||||||||||
------------------------ | ||||||||||||||
Here we list already existing PartSeg plugins. All plugins are also available when using PartSeg as a napari plugin. | ||||||||||||||
New plugin creator may want to look at them to see how to create new plugins. | ||||||||||||||
|
||||||||||||||
PartSeg-smfish | ||||||||||||||
~~~~~~~~~~~~~~ | ||||||||||||||
This is plugin for processing smFISH data. It could be found under https://github.com/4DNucleome/PartSeg-smfish/ page. | ||||||||||||||
This plugin provides a custom segmentation algorithm for smfish data (inspired by bigFISH algorithm that does not work well for our data) | ||||||||||||||
and custom measurement methods. | ||||||||||||||
|
||||||||||||||
The plugin is available from pypi and conda. | ||||||||||||||
|
||||||||||||||
PartSeg-bioimageio | ||||||||||||||
~~~~~~~~~~~~~~~~~~ | ||||||||||||||
PartSeg plugin to run bioimage.io deep learning models. It could be found under https:/github.com/czaki/PartSeg-bioimageio/ page | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The URL provided seems to be missing a colon, which could lead to a broken link. - PartSeg plugin to run bioimage.io deep learning models. It could be found under https:/github.com/czaki/PartSeg-bioimageio/ page
+ PartSeg plugin to run bioimage.io deep learning models. It could be found under https://github.com/czaki/PartSeg-bioimageio/ page Committable suggestion
Suggested change
|
||||||||||||||
This plugin allows to selection model saved in bioimage.io format from the disc and runs it on selected data with the test this model in interactive mode. | ||||||||||||||
|
||||||||||||||
As it depends on deep learn libraries, it cannot be used in PartSeg binary distribution. | ||||||||||||||
|
||||||||||||||
In this plugin, plugin creator could see an example of using custom magicgui-based widget for selecting a model. | ||||||||||||||
|
||||||||||||||
The plugin is under active development and currently available only on GitHub. | ||||||||||||||
|
||||||||||||||
Trapalyzer | ||||||||||||||
~~~~~~~~~~ | ||||||||||||||
|
||||||||||||||
This is plugin developed for process neutrophile `data <https://zenodo.org/record/7335168>`_. | ||||||||||||||
It provides custom segmentation data to find multiple class of cells in one run and custom measurement methods. | ||||||||||||||
|
||||||||||||||
It could be found on github https://github.com/Czaki/Trapalyzer and pypi. |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -130,22 +130,32 @@ def __get__(self, obj, klass): | |||||||||||||||||||||||||||||||||||||||||||||||||||
return model | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
def _partial_abstractmethod(funcobj): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
funcobj.__is_partial_abstractmethod__ = True | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return funcobj | ||||||||||||||||||||||||||||||||||||||||||||||||||||
def _partial_abstractmethod(func_obj): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
func_obj.__is_partial_abstractmethod__ = True | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return func_obj | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
class AlgorithmDescribeBaseMeta(ABCMeta): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
def __new__(cls, name, bases, attrs, **kwargs): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
cls2 = super().__new__(cls, name, bases, attrs, **kwargs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
__argument_class__: typing.Optional[typing.Type[PydanticBaseModel]] = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
def get_fields(self) -> typing.List[typing.Union[AlgorithmProperty, str]]: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
This function return list of parameters needed by algorithm. It is used for generate form in User Interface | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
:return: list of algorithm parameters and comments | ||||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
raise NotImplementedError | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
def __new__(mcs, name, bases, attrs, **kwargs): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
cls = super().__new__(mcs, name, bases, attrs, **kwargs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
not inspect.isabstract(cls2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
and hasattr(cls2.get_fields, "__is_partial_abstractmethod__") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
and cls2.__argument_class__ is None | ||||||||||||||||||||||||||||||||||||||||||||||||||||
not inspect.isabstract(cls) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
and hasattr(cls.get_fields, "__is_partial_abstractmethod__") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
and cls.__argument_class__ is None | ||||||||||||||||||||||||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
raise RuntimeError("class need to have __argument_class__ set or get_fields functions defined") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
cls2.__new_style__ = getattr(cls2.get_fields, "__is_partial_abstractmethod__", False) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return cls2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
cls.__new_style__ = getattr(cls.get_fields, "__is_partial_abstractmethod__", False) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return cls | ||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+149
to
+158
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure correct attribute access in the - and hasattr(cls.get_fields, "__is_partial_abstractmethod__")
+ and hasattr(cls, 'get_fields') and hasattr(cls.get_fields, '__is_partial_abstractmethod__') Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
class AlgorithmDescribeBase(ABC, metaclass=AlgorithmDescribeBaseMeta): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -253,7 +263,7 @@ def __init__(self, *args: AlgorithmType, class_methods=None, methods=None, sugge | |||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
:param class_methods: list of method which should be class method | ||||||||||||||||||||||||||||||||||||||||||||||||||||
:param methods: list of method which should be instance method | ||||||||||||||||||||||||||||||||||||||||||||||||||||
:param kwargs: elements passed to OrderedDict constructor (may be initial elements). I suggest to not use this. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
:param kwargs: elements passed to OrderedDict constructor (maybe initial elements). I suggest to not use this. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||
super().__init__(**kwargs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
self.suggested_base_class = suggested_base_class | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -466,15 +476,15 @@ def __new__(cls, name, bases, attrs, **kwargs): | |||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
def allow_positional_args(func): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@wraps(func) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
def _wraps(self, *args, **kwargs): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
def _wraps(self, *args, **kwargs_): | ||||||||||||||||||||||||||||||||||||||||||||||||||||
if args: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
warnings.warn( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
"Positional arguments are deprecated, use keyword arguments instead", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
FutureWarning, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
stacklevel=2, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
kwargs.update(dict(zip(self.__fields__, args))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return func(self, **kwargs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
kwargs_.update(dict(zip(self.__fields__, args))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return func(self, **kwargs_) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
return _wraps | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,11 +44,19 @@ class RegisterEnum(Enum): | |
flow = 0 #: algorithm for calculation flow from core object to borders. For spiting touching objects, deprecated | ||
threshold = 1 #: threshold algorithms. From greyscale array to binary array | ||
noise_filtering = 2 #: filter noise from image | ||
analysis_algorithm = 3 #: algorithm for creating segmentation in analysis PartSeg part | ||
mask_algorithm = 4 #: algorithm for creating segmentation in mask PartSeg part | ||
analysis_algorithm = 3 | ||
""" | ||
algorithm for creating segmentation in analysis PartSeg part | ||
(deprecated in favour of roi_analysis_segmentation_algorithm) | ||
""" | ||
mask_algorithm = 4 | ||
""" | ||
algorithm for creating segmentation in mask PartSeg part | ||
(deprecated in favour of roi_mask_segmentation_algorithm) | ||
""" | ||
analysis_save = 5 #: save functions for analysis part | ||
analysis_load = 6 #: load functions for analysis part | ||
mask_load = 7 #: load functions for mask part | ||
mask_load = 7 #: load functions for mask part) | ||
image_transform = 8 #: transform image, like interpolation | ||
mask_save_parameters = 9 #: save metadata for mask part (currently creating json file) | ||
mask_save_components = 10 #: save each segmentation component in separate file. Save location is directory | ||
Comment on lines
44
to
62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The deprecation of
|
||
|
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.
The addition of "sphinx.ext.autosectionlabel" to the extensions list is correct and aligns with the PR objective of enhancing documentation. Ensure that if there are any documents with duplicate section names, the configuration option "autosectionlabel_prefix_document" is set to True to avoid conflicts.