open-ephys / plugin-GUI

Software for processing, recording, and visualizing multichannel electrophysiology data
https://open-ephys.org/gui
GNU General Public License v3.0
192 stars 684 forks source link

Plugin developement questions #564

Open MarineChap opened 1 year ago

MarineChap commented 1 year ago

Dear,

Can I create my own datatype (like spike, continuous, event) to be use in two open ephys plugins without modifying the plugin-GUI itself ?

Also do you have a way to make third party plugins easily accessible from the open-ephys store ?

Thanks. Have a good day.

jsiegle commented 1 year ago

Hi Marine – What is the datatype you'd like to create?

Without modifying the main application, there are a few options for this:

Would any of these options work?

jsiegle commented 1 year ago

To make plugins available via the Plugin Installer, we'd need to fork the code to the open-ephys-plugins account and set it up for automated building and deployment to JFrog Artifactory. This is what we did with for the Falcon Output, and the process is quite easy once the plugin is complete.

MarineChap commented 1 year ago

Hello Josh,

The metadata in the event sound promising ! I think i can work around that.

Does this mean that for the plugin installer, you will always have to include every developed plugin into your organization? Wouldn't it be interesting to have a second level of plugins from the community that you don't have to maintain yourself?

An example that comes to mind is the plugins in microk8s. There is a list of official plugins, and if you add a "community plugin," it unlocks the appearance of other plugins developed by external individuals to the organization. Because there is a second level, there are not the same expectations for it.

I would be curious to know your plan on the question.

(Happy to be back at work in this domain!)

jsiegle commented 1 year ago

We've definitely thought about this, but it didn't seem worth the effort given the rate at which community plugins are being developed. So far it has been easiest for us to fork plugins that are ready for wider distribution and ensure the appropriate metadata, documentation, and deployment features are in place. If it reaches a point where there is more demand for plugin distribution than the core support team can handle, then we can implement a system where anyone can register plugins with the Plugin Installer.

MarineChap commented 1 year ago

Make sense. I will inform JJ (I think you discussed with him about his project recently) and keep you posted when our plugins are ready that you can see if you want to integrate them or not.

Thank you for your help as always.

MarineChap commented 1 year ago

Hello, I am struggling with adding metadatas in a new event. Do you have an example on how to do it ?

I tried something like this


    MetadataValueArray metaDataArray;
    MetadataValue metaData(MetadataDescriptor(MetadataDescriptor::MetadataType::FLOAT, 4, "position", "", "metadata.pos"));
    metaData.setValue<float>(position.data());
    metaDataArray.add(&metaData);

    TTLEventPtr event = TTLEvent::createTTLEvent(eventChannels.getLast(),
                                                (int64) spike->getSampleNumber(),
                                                0, true, metaDataArray);
    // create events + metadata containing the position
    addEvent(event,spike->getSampleNumber());

This failed because the object pointed is not herited from ReferencedCounterObject.

I tried to wrap the position vector in a class inheriting from the ReferenceCounterObject but then there is linking errors when setting the value. So I am quite stuck here. Do you think you can help me please ?

Side note, once I make it work, I would be happy to do a PR with some documentations (maybe in tutorial section ?) if you are interested. Thank you, Have a good day

jsiegle commented 1 year ago

The only change that's needed is that metaData should be a pointer, e.g.:

MetadataValue* metaData = new MetadataValue(MetadataDescriptor(MetadataDescriptor::MetadataType::FLOAT, 4, "position", "", "metadata.pos"));

This allows it to be deleted after the event is added to the outgoing buffer, rather than when the metaData variable goes out of scope.

You should also make sure the MetadataDescriptor is added to the event channel info object in the updateSettings() method, so downstream processors can know what type of metadata to expect with these events:

MetadataDescriptor* desc = new MetadataDescriptor(MetadataDescriptor::MetadataType::FLOAT, 4, "position", "", "metadata.pos");
eventChannel->addEventMetadata(desc);

And it would be great to have a tutorial on this sort of thing, since it's not currently documented anywhere. Let us know what you're thinking in terms of content!

MarineChap commented 1 year ago

Thank that's work indeed ! For the tutorial, I will think about it. I am quite busy this summer but I will try to open a PR before September ! Thank you for your help all along this plugin development.

For reference, if someone want to do the same thing

    MetadataValueArray metaDataArray;
    MetadataValue* metaData = new MetadataValue(MetadataDescriptor(MetadataDescriptor::MetadataType::FLOAT, 4, "position", "triangulated position", "metadata.pos"));
    metaData->setValue<float>(spikePosition.data());
    metaDataArray.add(metaData);

    TTLEventPtr event = TTLEvent::createTTLEvent(eventChannels.getLast(),
                                                (int64) spike->getSampleNumber(),
                                                1, true, metaDataArray);

    addEvent(event,spike->getSampleNumber());