Skip to content
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

Add plugin to create tag set for the highlighting of cell divisions #54

Merged
merged 1 commit into from
Feb 20, 2024

Conversation

maarzt
Copy link
Contributor

@maarzt maarzt commented Feb 15, 2024

Adds a new entry to Mastodon's "Plugins" menu which is called:
"Tags > Add Tag Set to Highlight Cell Divisions"

When executed the plugin adds a new tag set to the model. The tag set has tags which are added to the spots before cell division and first spots after cell division.

The tag set is meant to be used for 3d visualization purposes. Changing the color of a cell shortly before cell division can attract the users attention and makes it easier for the user to focus on the cell divisions.

Screenshot: new menu entry*
image

Screenshot: the newly created tag set, shown in a trackscheme window
image

Adds a new entry to Mastodon's "Plugins" menu which is called:
 "Tags > Add Tag Set to Highlight Cell Divisions"
@maarzt maarzt force-pushed the cell-division-tag-set branch from 2162273 to 421eec2 Compare February 15, 2024 11:18
Copy link
Collaborator

@stefanhahmann stefanhahmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds a useful new functionality to Mastodon.

  • I have minor suggestions regarding the code style.
  • When testing I encountered 2 different types of exceptions.
  • I have some suggestions for improving the user experience.

@Override
public void cancel( String reason )
{

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could consider adding a comment, why this method is intentionally empty.

Cf.: https://rules.sonarsource.com/java/RSPEC-1186/

}

private TagSetStructure.Tag getTag( boolean dividesBefore,
boolean dividesAfter, int startOffset, int endOffset )
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be on the same line as the line above.


private static final String[] KEYS = { "not mapped" };

private static final Map< String, String > menuTexts = Collections.singletonMap( ID, "Add Tag Set to Highlight Cell Divisions ..." );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend to omit the "..." at the end. This would be more consistent with other function that can be called from the menu, which also do not have the "..."


private void run()
{
commandService.run( CellDivisionsTagSetCommand.class, true, "projectModel", projectModel );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When this is called, on my machine, I get this exception:

[ERROR] Malfunctioning plugin: org.scijava.ui.swing.widget.SwingObjectWidget
java.lang.NullPointerException
	at org.scijava.widget.WidgetModel.getChoices(WidgetModel.java:140)
	at org.scijava.ui.swing.widget.SwingObjectWidget.supports(SwingObjectWidget.java:101)
	at org.scijava.ui.swing.widget.SwingObjectWidget.supports(SwingObjectWidget.java:54)
	at org.scijava.plugin.TypedService.find(TypedService.java:70)
	at org.scijava.plugin.WrapperService.create(WrapperService.java:64)
	at org.scijava.widget.AbstractInputHarvester.addInput(AbstractInputHarvester.java:110)
	at org.scijava.widget.AbstractInputHarvester.buildPanel(AbstractInputHarvester.java:84)
	at org.scijava.widget.InputHarvester.harvest(InputHarvester.java:67)
	at org.scijava.ui.AbstractInputHarvesterPlugin.process(AbstractInputHarvesterPlugin.java:74)
	at org.scijava.module.ModuleRunner.preProcess(ModuleRunner.java:103)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:154)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)
	at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)
	at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)

However, the expected dialog still opens:
grafik

private ProjectModel projectModel;

@Parameter( label = "Tag set name" )
private String tagSetName = "cell divisions";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the users view, it is possible to have different tag set names for different settings. However, users may easily forget to do this.

If they do, they end up with this situation:

grafik

You could consider adding the timepoints setting to the tagset name automatically so that it is easier for the user afterwards to differentiate between different tagset.

E.g.: "highlight cell division (+/- 3 timepoints)"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I understand your point. But I would like to wait for user feedback. Having a predictable tag set name is also an advantage. There would also be the question if to include the colors in the tag set name and how, etc. Maybe overwriting existing tag sets is the best thing to do?

@Override
public void run()
{
projectModel.getBranchGraphSync().sync();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I run the the plugin on this dataset: https://github.com/mastodon-sc/mastodon-example-data/tree/master/tgmm-mini with these settings:
grafik
I get this exception:


Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index 8 out of bounds for length 0
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
	at java.base/java.util.Objects.checkIndex(Objects.java:372)
	at java.base/java.util.ArrayList.get(ArrayList.java:458)
	at org.mastodon.views.table.FeatureTagTablePanel$MyTableModel.getValueAt(FeatureTagTablePanel.java:635)
	at java.desktop/javax.swing.JTable.getValueAt(JTable.java:2706)
	at java.desktop/javax.swing.JTable.prepareRenderer(JTable.java:5721)
	at java.desktop/javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2185)
	at java.desktop/javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2087)
	at java.desktop/javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1883)
	at com.formdev.flatlaf.ui.FlatTableUI.paint(FlatTableUI.java:405)
	at java.desktop/javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
	at java.desktop/javax.swing.JComponent.paintComponent(JComponent.java:797)
	at java.desktop/javax.swing.JComponent.paint(JComponent.java:1074)
	at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5255)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedImpl(RepaintManager.java:1643)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1618)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1556)
	at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1323)
	at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5203)
	at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5013)
	at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:865)
	at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:848)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:848)
	at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:823)
	at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:772)
	at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1890)
	at java.desktop/java.awt.event.InvocationEvent.dispatch$$$capture(InvocationEvent.java:313)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
[ERROR] Malfunctioning plugin: org.scijava.ui.swing.widget.SwingObjectWidget
java.lang.NullPointerException
	at org.scijava.widget.WidgetModel.getChoices(WidgetModel.java:140)
	at org.scijava.ui.swing.widget.SwingObjectWidget.supports(SwingObjectWidget.java:101)
	at org.scijava.ui.swing.widget.SwingObjectWidget.supports(SwingObjectWidget.java:54)
	at org.scijava.plugin.TypedService.find(TypedService.java:70)
	at org.scijava.plugin.WrapperService.create(WrapperService.java:64)
	at org.scijava.widget.AbstractInputHarvester.addInput(AbstractInputHarvester.java:110)
	at org.scijava.widget.AbstractInputHarvester.buildPanel(AbstractInputHarvester.java:84)
	at org.scijava.widget.InputHarvester.harvest(InputHarvester.java:67)
	at org.scijava.ui.AbstractInputHarvesterPlugin.process(AbstractInputHarvesterPlugin.java:74)
	at org.scijava.module.ModuleRunner.preProcess(ModuleRunner.java:103)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:154)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)
	at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)
	at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)
[ERROR] Malfunctioning plugin: org.scijava.ui.swing.widget.SwingObjectWidget
java.lang.NullPointerException
	at org.scijava.widget.WidgetModel.getChoices(WidgetModel.java:140)
	at org.scijava.ui.swing.widget.SwingObjectWidget.supports(SwingObjectWidget.java:101)
	at org.scijava.ui.swing.widget.SwingObjectWidget.supports(SwingObjectWidget.java:54)
	at org.scijava.plugin.TypedService.find(TypedService.java:70)
	at org.scijava.plugin.WrapperService.create(WrapperService.java:64)
	at org.scijava.widget.AbstractInputHarvester.addInput(AbstractInputHarvester.java:110)
	at org.scijava.widget.AbstractInputHarvester.buildPanel(AbstractInputHarvester.java:84)
	at org.scijava.widget.InputHarvester.harvest(InputHarvester.java:67)
	at org.scijava.ui.AbstractInputHarvesterPlugin.process(AbstractInputHarvesterPlugin.java:74)
	at org.scijava.module.ModuleRunner.preProcess(ModuleRunner.java:103)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:154)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:125)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:64)
	at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:247)
	at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)

I am not sure, if this related to this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's related to this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exception does not appear if I execute the code inside a full Fiji installation. I guess this exception is specific to some version of some scijava artifact.

Copy link
Collaborator

@xulman xulman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's good, no? :-)
I like it


reminds me I have to finish #29 (very related)


public CellDivisionsTagSetPlugin()
{
action = new RunnableAction( ID, () -> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is nice, I like the defensive style of it, makes the SW more robust..
(always learning from ya ;-) )

private ColorRGB highlightColor = new ColorRGB( "pink" );

@Parameter( label = "Timepoints to highlight before and after cell division" )
private int n = 3;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this maybe could have got a little longer name... down in the code I realized I had to search what 'n' is... but the code is short, so easy :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I simply have no idea how to name the variable properly.

String label = "T-" + ( i + 1 );
tagColors.set( n - i, Pair.of( label, color ) );
}
for ( int i = 0; i < n; i++ )
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is maybe unnecessarily the same - symmetrical, but it makes no sense to optimize it either

unless you maybe want to offer a transition from mother-default, over division, to daughters-new-default colors
(I could imagine color encoding a generation number.. but that's for some different story)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the colors are very similar. But having different tags for before and after the cell division allows the user to manually assign a different color before the cell division. If they would want to.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's a good and very valid point... (to have explicit Tags for the colors before and after the division so that the user can later change them...)

@maarzt maarzt merged commit 421eec2 into master Feb 20, 2024
2 checks passed
@stefanhahmann stefanhahmann deleted the cell-division-tag-set branch December 3, 2024 12:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants