mastodon-sc / mastodon

Mastodon – a large-scale tracking and track-editing framework for large, multi-view images.
BSD 2-Clause "Simplified" License
66 stars 20 forks source link

Exception when opening MaMuT file #272

Closed JoOkuma closed 5 months ago

JoOkuma commented 6 months ago

Hi, happy new years.

I'm trying to open a MaMuT file (shared at http://public.czbiohub.org/royerlab/ultrack/misc/tracks.xml) and I'm getting the error below. Do you know can I fix it?

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at org.mastodon.views.trackscheme.util.AlphanumCompare.compare(AlphanumCompare.java:104)
    at org.mastodon.app.ui.SearchVertexLabel$SearchIterator.lambda$new$0(SearchVertexLabel.java:503)
    at org.mastodon.collection.ref.RefArrayList.quicksort(RefArrayList.java:550)
    at org.mastodon.collection.ref.RefArrayList.sort(RefArrayList.java:538)
    at org.mastodon.app.ui.SearchVertexLabel$SearchIterator.<init>(SearchVertexLabel.java:503)
    at org.mastodon.app.ui.SearchVertexLabel$SearchAction.reinit(SearchVertexLabel.java:386)
    at org.mastodon.app.ui.SearchVertexLabel$SearchAction.<init>(SearchVertexLabel.java:308)
    at org.mastodon.app.ui.SearchVertexLabel.<init>(SearchVertexLabel.java:213)
    at org.mastodon.app.ui.SearchVertexLabel.install(SearchVertexLabel.java:136)
    at org.mastodon.mamut.MamutViewBdv.<init>(MamutViewBdv.java:253)
    at org.mastodon.mamut.WindowManager.createBigDataViewer(WindowManager.java:495)
    at org.mastodon.mamut.WindowManager.createBigDataViewer(WindowManager.java:488)
    at org.mastodon.util.RunnableActionPair.actionPerformed(RunnableActionPair.java:64)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
    at java.awt.Component.processMouseEvent(Component.java:6539)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
    at java.awt.Component.processEvent(Component.java:6304)
    at java.awt.Container.processEvent(Container.java:2239)
    at java.awt.Component.dispatchEventImpl(Component.java:4889)
    at java.awt.Container.dispatchEventImpl(Container.java:2297)
    at java.awt.Component.dispatchEvent(Component.java:4711)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4904)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4535)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4476)
    at java.awt.Container.dispatchEventImpl(Container.java:2283)
    at java.awt.Window.dispatchEventImpl(Window.java:2746)
    at java.awt.Component.dispatchEvent(Component.java:4711)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
    at java.awt.EventQueue.access$500(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:709)
    at java.awt.EventQueue$3.run(EventQueue.java:703)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
    at java.awt.EventQueue$4.run(EventQueue.java:733)
    at java.awt.EventQueue$4.run(EventQueue.java:731)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

I converted my tracks to this .xml using my own script, I'm assuming it's correct because MaMuT can open it, but I might be missing something.

The image is too big to share, I'm happy to have a quick call to debug this.

Thanks in advance.

tinevez commented 6 months ago

Hello @JoOkuma Thanks for your interest in Mastodon.

The file you link is not a BDV file. It is a TrackMate or a MaMuT file:

<?xml version="1.0" ?>
<TrackMate version="3.7.0">
    <Model>
        <AllTracks>
            <Track TRACK_ID="1" NUMBER_SPOTS="11" NUMBER_GAPS="0" TRACK_START="112" TRACK_STOP="122" name="Track_1">
                <Edge SPOT_SOURCE_ID="113001015" SPOT_TARGET_ID="114001213" EDGE_TIME="112.5"/>
                <Edge SPOT_SOURCE_ID="114001213" SPOT_TARGET_ID="115001100" EDGE_TIME="113.5"/>
                <Edge SPOT_SOURCE_ID="115001100" SPOT_TARGET_ID="116001183" EDGE_TIME="114.5"/>

MaMuT and Mastodon are two different software, and do not use the same file format.

tinevez commented 6 months ago

Totally forget @JoOkuma : Happy new year!!! Do you want to use MAstodon or MaMuT? Frankly, if you deal with very large amount a data items I would stick with Mastodon. I still maintain MaMuT but do not develop it further.

JoOkuma commented 6 months ago

Hi @tinevez ,

I'm using Mastodon, but I'm using the option to import a MaMuT file to start my Mastodon project. Is this a valid use case?

Thanks for the quick response.

tinevez commented 6 months ago

No it's totally valid. My bad! I could reproduce the error and am working on it. Sorry!

JoOkuma commented 6 months ago

Thanks @tinevez ,

I'm fine with adding any missing metadata to my tracks .XML file.

I wrote my own Python trackmate writer here. I'm open to any comments to improve or extend it to make it compatible with Mastodon directly.

tinevez commented 6 months ago

Ok found it. The importer has expectations for the XML file. The key for the name of the spot must be name, and not NAME.

For instance:

  <Spot ID="2138" name="ID2138" ... />

is good, but in the file you sent you have:

 <Spot ID="233000705" NAME="233000705" .../>

As a consequence, the spots imported in Mastodon all receive null as label, which causes the error you have seen. If I do a big batch replace in the XML file it works:

https://github.com/mastodon-sc/mastodon/assets/3583203/b9b86b07-a838-44ac-802d-0df903c47544

(Cool dataset btw).

I am seeing your python writer just now. If you are interested @lxenard in the team has built a full IO package for TrackMate in Python.

tinevez commented 6 months ago

The line to change in your writer is this one: https://github.com/royerlab/ultrack/blob/main/ultrack/core/export/trackmate.py#L150

JoOkuma commented 6 months ago

Thanks a lot, @tinevez!

I am seeing your python writer just now. If you are interested @lxenard in the team has built a full IO package for TrackMate in Python.

I would love to use it on my package, what's its name?

JoOkuma commented 6 months ago

I'm back 😅.

I have a similar issue when saving the previously loaded MaMuT file as a Mastodon project.

The error is

Exception in thread "Thread-115" java.lang.NullPointerException
    at java.io.ObjectOutputStream$BlockDataOutputStream.getUTFLength(ObjectOutputStream.java:2136)
    at java.io.ObjectOutputStream$BlockDataOutputStream.writeUTF(ObjectOutputStream.java:2007)
    at java.io.ObjectOutputStream.writeUTF(ObjectOutputStream.java:869)
    at org.mastodon.mamut.importer.trackmate.TrackMateImportedFeaturesSerializer.serialize(TrackMateImportedFeaturesSerializer.java:61)
    at org.mastodon.mamut.importer.trackmate.TrackMateImportedFeaturesSerializer.serialize(TrackMateImportedFeaturesSerializer.java:46)
    at org.mastodon.mamut.feature.MamutRawFeatureModelIO.write(MamutRawFeatureModelIO.java:238)
    at org.mastodon.mamut.feature.MamutRawFeatureModelIO.serialize(MamutRawFeatureModelIO.java:84)
    at org.mastodon.mamut.ProjectManager.saveProject(ProjectManager.java:556)
    at org.mastodon.mamut.ProjectManager$1$3.lambda$run$0(ProjectManager.java:504)
    at java.lang.Thread.run(Thread.java:748)

I changed some of the Spot Features to see if it would be fixed, but I'm unfamiliar with Java and the code base.

Do you know what it could be?

tinevez commented 6 months ago

I think I found it:

Your <Spot> elements miss the feature POSITION_T. The MaMuT importer kind of expects it, since it is declared in the <FeatureDeclaration> section.

Could you regenerate a tracks.xml file and add a POSITION_T to each spot? This feature is supposed to give the time in physical units.

        <Spot ID="2001" name="ID2001" POSITION_T="0.0" ... />
JoOkuma commented 5 months ago

Hi @tinevez , thanks for the help.

I fixed that, but I still get the same error. I updated the shared dataset to reflect these changes. It can be found here

Must every element have the features declared on their respective Feature Declaration section? This isn't the current case.

Which features are required, MaMuT and Mastodon?

I really appreciate your help. I'm happy to have a quick chat if that is easier for you.

tinevez commented 5 months ago

Most likely it is the same reason: some features are declared in the <FeatureDeclaration> part, but are not set in the <Spot> elements. Can you try this by either specifying all features are removing superfluous ones from the declaration? I think you already have all the required features in the <Spot> elements.

JoOkuma commented 5 months ago

Thanks for the help @tinevez.

The suggested fix didn't work.

What did the trick was adding this to the <Model> element

  <Model spatialunits="pixels" timeunits="frames">

I appreciate the help. It made debugging easier.

tinevez commented 5 months ago

Hey @JoOkuma

Well done. I was wondering: are you using the MaMuT (TrackMate) file format as a means to exchange data from ultrack to Mastodon? Is there a general tracking file format you would like to use instead? Does such a file format exist? If not, what should it contains?

JoOkuma commented 5 months ago

@tinevez Yes, that's my use case. We're using it to correct a few tracks.

I'm not aware of any general tracking file format. Unfortunately, there's no standardized graph library, even within the Python context :(

My current option is that it should be a graph in JSON so we can communicate between different languages. Each node should contain (ID, T, (Z), Y, X, PARENT_ID) and optional arbitrary features.

The adjacency could be formulated more generally than an index to a parent node to support non-forest graphs.

I'm happy to talk more about this.