Test Python plugins on OMERO

Hi everyone,

I am trying to implement a plugin to be used on omero. I will need to test it to debug it, so i don’t want it to be visible by the other users (yet).
After some research, i found this tutorial:https://docs.openmicroscopy.org/omero/5.6.1/developers/scripts/advanced.html

I followed the guideline, but after uploading, i can’t figure where the script is uploaded. Should it be on the server, or on the PC i am using to code?

In any case, i can’t access it with omero web, but when i click on the button “Display the available plugins” on OMERO.insight, i am getting this error:

java.lang.Exception: Abnormal termination due to an uncaught exception.
java.lang.StringIndexOutOfBoundsException: begin 1, end 0, length 0
at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3319)
at java.base/java.lang.String.substring(String.java:1874)
at org.openmicroscopy.shoola.agents.treeviewer.view.ToolBar.showAvailableScriptsMenu(ToolBar.java:1013)
at org.openmicroscopy.shoola.agents.treeviewer.view.TreeViewerWin.showMenu(TreeViewerWin.java:979)
at org.openmicroscopy.shoola.agents.treeviewer.view.TreeViewerComponent.setAvailableScripts(TreeViewerComponent.java:4303)
at org.openmicroscopy.shoola.agents.treeviewer.ScriptsLoader.handleResult(ScriptsLoader.java:118)
at org.openmicroscopy.shoola.env.data.events.DSCallAdapter.eventFired(DSCallAdapter.java:90)
at org.openmicroscopy.shoola.env.data.views.BatchCallMonitor$1.run(BatchCallMonitor.java:124)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
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)
Abnormal termination due to an uncaught exception.
java.lang.StringIndexOutOfBoundsException: begin 1, end 0, length 0
at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3319)
at java.base/java.lang.String.substring(String.java:1874)
at org.openmicroscopy.shoola.agents.treeviewer.view.ToolBar.showAvailableScriptsMenu(ToolBar.java:1013)
at org.openmicroscopy.shoola.agents.treeviewer.view.TreeViewerWin.showMenu(TreeViewerWin.java:979)
at org.openmicroscopy.shoola.agents.treeviewer.view.TreeViewerComponent.setAvailableScripts(TreeViewerComponent.java:4303)
at org.openmicroscopy.shoola.agents.treeviewer.ScriptsLoader.handleResult(ScriptsLoader.java:118)
at org.openmicroscopy.shoola.env.data.events.DSCallAdapter.eventFired(DSCallAdapter.java:90)
at org.openmicroscopy.shoola.env.data.views.BatchCallMonitor$1.run(BatchCallMonitor.java:124)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
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)
Exception in thread “AWT-EventQueue-0”

at org.openmicroscopy.shoola.env.ui.UserNotifierImpl.showErrorDialog(UserNotifierImpl.java:189)
at org.openmicroscopy.shoola.env.ui.UserNotifierImpl.notifyError(UserNotifierImpl.java:289)
at org.openmicroscopy.shoola.env.AbnormalExitHandler.doTermination(AbnormalExitHandler.java:147)
at org.openmicroscopy.shoola.env.AbnormalExitHandler.terminate(AbnormalExitHandler.java:85)
at org.openmicroscopy.shoola.env.RootThreadGroup.uncaughtException(RootThreadGroup.java:69)
at java.desktop/java.awt.EventDispatchThread.processException(EventDispatchThread.java:222)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:214)
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)

The error disappears after i delete the plugin with /opt/omero/server/venv3/bin/omero script delete number_of_script

Any clues? Thanks by advance, Marc.

Hi Marc,

I think you need to upload the scripts as admin user with --official flag. Then it should show up in Web and Insight. But the error in Insight is definitely not expected either way. I’ll open an issue for that.
And yes, scripts are uploaded and run on the server directly.

Regards,
Dominik

Hi Dominik,

Thanks for your answer, but after reading it and reading:

https://docs.openmicroscopy.org/omero/5.6.1/developers/scripts/user-guide.html
https://docs.openmicroscopy.org/omero/5.6.1/developers/scripts/advanced.html

It means the scripts (labeled as “official”) will be uploaded on the server, via a root account, and will be visible and potentially executable by other users.

It wasn’t my plan: my current objective was to use them “privately” from my client PC to test them only on my images, like it was mentioned in https://docs.openmicroscopy.org/omero/5.6.1/developers/scripts/advanced.html

So i assume the only way to test them is to upload them on the server and to let them potentially be executable by any user, is that correct?

Thanks by advance, Marc.

Yes, an ‘official’ script has to be uploaded as an OMERO user with the respective permissions (or the OMERO root user) and is executable by everyone. Tbh, I don’t know how/who can run a non-‘official’ script, as they are not listed in the clients, as you noticed.
But I’m not sure, if the OMERO.script workflow is actually what you want. Wouldn’t a local Python script using the https://docs.openmicroscopy.org/omero/5.6.1/developers/Python.html API do the job?
Kind Regards,
Dominik

Hi Dominik,

Thanks for the link. I looked the examples a bit, it may be useful. But it leads to another question:

How can i decide when is it relevant either to use the Python API locally, or to import the Python script on the server?

To give you an idea, the plugin i will try to implement should:

  • Be able to make a montage image of selected channels of a picture and the addition of the channels.
  • Be able to tune separately the brightness/contrast of each channel selected.
  • Be able to be used on any image format (shouldn’t be too problematic with the Bio-Formats library, however some 12 bits images coded in 16 bit depth might be problematic for their contrast range. The LIF/LIFEXT images might be challenging too), and take into account the stacks of images.
  • And be able to be used on a full dataset on images, with the same tunings.
  • Maybe be able to make Z-projects of the montages.

I also assume that my plugin should be able to create another dataset, filled with the montage images.

The main finality of this plugin is to create montages dedicated for publication. You will probably tell me to use OMERO.figure, and i concede it is a good tool for that, but the main point is to use the same tunings of contrast/brightness on a whole dataset, so it make me think that OMERO.figure is not the best solution for that.

I hope to have given you enough details. If you know fellows who had similar problems (and maybe have developed more relevant solutions, or met problems i haven’t foresought - after all, i’m still a beginner), feel free to let me know.

However, thanks for the advice, Marc.

A non-official script requires there to be a user-mode processor started to answer any requests by the server. This can be done with omero script serve. Another option would be to use omero script run locally without the need to upload the scripts either way.

@will-moore gave an introduction to scripting OMERO.figure during OME2020. That can be done either via the JS in the browser or also via a script. It might be interesting as a comparison. (Looking for a reference then I’ll add it here)

~Josh

Hi @mmongy

You can script the creation of OMERO.figure files in Python as described at https://omero-guides.readthedocs.io/en/latest/figure/docs/omero_figure_scripting.html#figure-creation-in-python

You can write a script that will create a figure with all the Images from a Dataset, applying your chosen rendering settings to them all.
Then you can open the figure in the OMERO.figure app (apply any other edits if needed) and export it to create a new Image in OMERO. This new Image will be in the same Dataset as the source Images, but it’s easy enough to move it to it’s own Dataset.

How would you like users of the script to choose rendering settings for the Images?
In OMERO.figure you can also select all the Images in the figure and apply the same rendering settings to them all.

How many Images do you typically have in your Datasets?

Will.

Hi Will, Hi Josh,

Sorry to have not answered earlier, i was on holidays for 2 weeks. Now, i’m back.
@will-moore I read your documentation about OMERO.figure, and i figured my best bet would be to start with the script “Split_View_Figure.py”, because it can already take into input a dataset, split the channels, and display them on a figure.

After reading the doc (https://downloads.openmicroscopy.org/omero/5.5.0/api/python/omero/omero.gateway.html) and spelunking into the python files of omero server, i figured a bit how works the objects. I even (probably) found a way to get the min /max values of each channels and to modify them.

But at this point, things become hairy. After entering the ID of the dataset, i would like OMERO.web to display a popup where the pictures of the channels are displayed, with underneath a way to tune them (a bit like in OMERO.iviewer), and a way to choose the Z-depth.

For now, i can’t figure how to display this kind of popup, and i don’t really know where to start. Are there any script examples that displays a secondary popup, after the one generated by the command “client()” in omero.scripts?

Thanks by advance, Marc.

The script runs server-side so there’s no way to make it interactive with the clients (web or Insight).

Instead, you need to create a client UI to gather the parameters you want from your users, then pass all of these to the script. This is what we’ve done with the “figure scripts” (https://github.com/ome/omero-scripts/tree/develop/omero/figure_scripts)

The code for that dialog is in https://github.com/ome/omero-web/blob/ba645162d7e93ee0f16551037e9d05df6165dc15/omeroweb/webclient/templates/webclient/scripts/split_view_figure.html,
https://github.com/ome/omero-web/blob/ba645162d7e93ee0f16551037e9d05df6165dc15/omeroweb/webclient/static/webclient/javascript/ome.split_view_figure.js
and views.py for that script is https://github.com/ome/omero-web/blob/ba645162d7e93ee0f16551037e9d05df6165dc15/omeroweb/webclient/views.py#L3912

The easiest way to do the same thing yourself is to create your own OMERO.web app (see below) but first is to decide what are the extra parameters you need and add them to your script.

Once you’ve got your script working, you can use the auto-generated script UI in the webclient as a basis for creating your customised script UI.
Just grab the html from the script dialog. This will contain all the form fields with the correct names etc for passing parameters to the script.
You’ll want to add this as a new page in your own OMERO.web app.

Start by copying this directory and it’s contents and renaming minimal-webapp and minimal_webapp to your-app and your_app everywhere.


Then dev install it with:
$ cd your-app
$ pip install -e .

Now you can put the html you copied from the auto-generated form above and place this in the index.html (need to keep the static links to the JavaScript & CSS).
In the views.py def index() you want to use any Dataset ID from the query string and use it to find the Images. Then pass them to your html page:

dataset_id = request.GET.get('dataset', None)
dataset = conn.getObject('Dataset', dataset_id)
images = []
for img in dataset.listChildren():
    images.append({'id': img.id, 'name': img.name})
context['images'] = images

Then you could show the images in your script UI (index.html):

{% for image in images %}
    <img src="{% url 'web_render_image' image.id %}" />
{% endfor %}

Then you’d have to customise the form, using hidden fields if you didn’t want the user to see them, or provide alternative controls such as sliders and possibly updating the rendering levels of the images using JavaScript when you adjust the inputs (I could show you how to do this).

Finally, you’d want to configure “Open with” (see https://docs.openmicroscopy.org/omero/5.6.2/developers/Web/LinkingFromWebclient.html#open-with) e.g. with the ‘script_ui’ naming above, this could be:

omero config append omero.web.open_with '["script_ui", "script_ui_index", {"supported_objects": ["dataset"], "label": "Create Split View Figure"}]'

Now your users will be able to select a Dataset, right-click (in the left-panel tree) > Open with… > ‘Create Split View Figure’ and this would open your app page in a new tab.

The ‘Submit’ of your form should run your script just as it did for the auto-generated script UI.

Sorry if that seems a lot of work and there’s not an “out of the box” way of providing interactive UIs, but it shouldn’t be too much work and it gives you complete freedom to design your script UI. And I’m happy to help with any pointers. If you could put your code on GitHub that would be much easier.

Hope that helps,
Will.

1 Like

Hi Will,

I have other questions, but more about the interfacing of OMERO with the Django app.

I tried to install the “minimal_webapp”, from the examples. I used pip install -e ., like in the README.

I explored a bit the files to see what were the modifications: i noticed a file called
“minimal-webapp.egg-link” has been created in /opt/omero/web/venv3/lib/python3.6/site-packages/. After opening it, i saw the directory wher i unzipped the content of the app (/home/omero-web/downloads/omero-web-apps-examples-master/minimal-webapp), so i guess the “minimal-webapp.egg-link” file acts as a symbolic link. OK.

After restarting the omero-web interface, i accessed the minimal web-app. I have this page:

So, i guessed the app worked well.

Then, i tried to apply some modifications on the contents of the app.
First, i tried to modify the python code, especially the file “views.py”, by adding inside the lines you suggested me. After replacing the file in the installation directory of the app, i didn’t saw any modification.
So i tried to apply some changes in the javascript code (“app.js”), by adding some console.log() lines to see if the modified file was correctly loaded (after clearing the cache files). After some tries, i acknowledged the fact that the static files (“app.js” and “app.css”) have been duplicated in “/opt/omero/web/omero-web/var/static/minimal_webapp” and loaded from there. Why not…
Then, i tried to modify the contents of the HTML page (“index.html”). I tried to modify the title (“Welcome to OMERO”), by modifying the “index.html” located in /home/omero-web/downloads/omero-web-apps-examples-master/minimal-webapp (i haven’t found any other relevant path, even with the “find” command), but without success. I tried to locate an eventual duplication of “index.html” (like the case of “app.js”) with grep, but without success.

So, i want to ask you if there is a practical way to test an OMERO/Django app without too much crude, messy (and often trial/error) repeated manipulations.
Also, if i missed something about the locations of the files (the ones that are really loaded on OMERO), feel free to tell me.

Thanks by advance, and thanks for your previous advice,
Marc.

Hi Marc,
Sorry for the pain. Good to hear you’ve at least got your app running.
There are some docs at https://docs.openmicroscopy.org/omero/5.6.1/developers/Web/Deployment.html#using-the-lightweight-development-server about using the Django development server, which should refresh when you make edits.
But I tend to take a more low-level approach and do run the Django dev server directly from in the omero-web repo:

$ cd omero-web
$ python omeroweb/manage.py runserver 4080

Then access web at http://localhost:4080
This will run in the foreground and you should see the dev server restart when you save a change to any python files or Django templates. It should also update with any changes to static .js files too.

Eventually you’ll want to rename all the minimal-webapp and minimal_webapp to your app name, but not essential at this stage.

Hope that helps,
Will.

Hi Will,

Thanks for the answer. I located the script “manage.py” (in: /opt/omero/web/venv3/lib/python3.6/site-packages/omeroweb)

But when i try the runserver command, it tells me that the port 4080 is already used.

After trying the command sudo lsof -i:4080, i can read:

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
gunicorn 10273 omero-web 5u IPv4 1867616 0t0 TCP localhost:4080 (LISTEN)
gunicorn 10277 omero-web 5u IPv4 1867616 0t0 TCP localhost:4080 (LISTEN)
gunicorn 10278 omero-web 5u IPv4 1867616 0t0 TCP localhost:4080 (LISTEN)
gunicorn 10279 omero-web 5u IPv4 1867616 0t0 TCP localhost:4080 (LISTEN)
gunicorn 10282 omero-web 5u IPv4 1867616 0t0 TCP localhost:4080 (LISTEN)
gunicorn 10284 omero-web 5u IPv4 1867616 0t0 TCP localhost:4080 (LISTEN)

Hi Will,

I successfully applied the testing modification of the html page. I followed the advice in " Using the lightweight development server" of https://docs.openmicroscopy.org/omero/5.6.1/developers/Web/Deployment.html#using-the-lightweight-development-server. But i deactivated the debug mode (turned to “False”). All i had with it was a huuuuge Java-like error message.

Also, how can i have the python features? I tried basic debugging commands (print()), and i’m sure they are scanned, because the java-like huge error message shown python code extracts, but where can i visualize the output of print() commands? They don’t show in the Firefox console…

Thanks anyway,
Marc.

Never mind… I just saw the output of the prints on the teminal connected by ssh to the server (with the Django invite).

UPDATE:

In fact, i have to kill the Django instance and restart it with omero web start to reload the modified python code… OK…

Now my minimal_webapp shows a 500 error, with the Python error message…Still OK… i guess…

If you want us to look at any Errors or other issues, it would be handy if you could push your code to github.

I remembered I made a youtube video of getting started with omero-web dev setup which you might find useful: https://www.youtube.com/watch?v=r9UM1Sol60g
You can use the python debugging tools in VS Code with this setup. I don’t run it like this routinely but it can be helpful sometimes.

Cheers,
Will.

Hi Will, hi everyone,

It’s been a long time from my last message. I’m still on my project to make an OMERO app to select one or more images, to visualize channels of one selected image, tune them, apply the values to the other images, and make figures of the channels for all the images.

After your last message, i finally succeded to setup an installation of an custom OMERO.web interface on my PC, to be able to test things without breaking the server or the interface.

Next, i tried to find a good starting point, so i tried to implement dual-handle sliders, to define the minimal/maximal pixel values.

I have taken the “minimal_webapp” as a basis, and i first tried to display images. The code lines you gave me worked, at least when you enter the dataset identifiers manually in the views.py file.

After some research, it became clear i had to use JQuery to implement the sliders the way i wanted. Struggling both with Django and Javascript/JQuery/HTML seemed tricky to me, so i tried to implement them on local (non-connected) HTML/JS files (Codename: “mock_up_channels”), and on a simple image. For that, i used the HTML/JS Canvas API.
The result is a bit buggy (especially for the result image), but the sliders work as intended.

Then, i came back to Django. After some thinking, my idea was to allow the user to select one or more images on the OMERO.web interface to send them to a custom viewer (mentioned in: https://docs.openmicroscopy.org/omero/5.6.1/developers/Web/LinkingFromWebclient.html). To add the option in the menu “Open with”, i have followed the installation tutorials of OMERO.figure (https://pypi.org/project/omero-figure/) and OMERO.iviewer (https://pypi.org/project/omero-iviewer/)

I succeeded to display selectioned images with my application, but it stops here. I’m still stuck with the concept of wrappers of OMERO (ImageWrapper, ChannelWrapper…), and i begin to think about some practical questions:

The displayed image (JPEG, RGB, 3 channels, 8bit each, one Z-depth, one T-time…) on the web navigator cannot be assimilated as the real image, stored on the server (proprietary formats, multiple channels, 8bit/16bit/32bit each, multiple Z-depths and T-times), so, i have to find a way to retrieve the informations of original pixel values, Z-depth… for each channel, apply them on the sliders, retrieve the new values selected on the sliders, apply them to a clone of the original image, and render the new tunings on the web-displayed image.

Also, i’m still struggling with Django: passing values between javascript code and django code is problematic, and on a more global view, juggling between JQuery, Javascript, HTML, Python (sometimes on the same file) looks tricky and counter-intuitive (maybe it’s just for me… but honestly, i hope not).

I prepared a private branch (Name: my_channel_viewer) on my github account (ID: mmongy). But i prefer to warn you, it’s very sketchy, there is a lot of commented lines of old code, commented URLs where i took some ideas, and comments in French.

Thanks for your previous advice, Marc.

P.S.: I don’t know if it’s still relevant to use this thread, or to start a new one. The original topic becomes a bit old…

1 Like

You can get a lot of the image metadata (channels, pixel-types, current rendering settings etc) using the ‘imgData’ URL:

This is what OMERO.figure & OMERO.iviewer use.

You can use that data to construct a UI (sliders etc) and apply the chosen settings to render an image (see https://docs.openmicroscopy.org/omero/5.6.2/developers/Web/WebGateway.html#rendering-settings).

E.g. for this image http://idr.openmicroscopy.org/webclient/img_detail/9844369/
ImgData is http://idr.openmicroscopy.org/webgateway/imgData/9844369/
and rendered image is http://idr.openmicroscopy.org/webgateway/render_image/9844369/0/0/?c=1|7:4095$00FFFF,2|11:4095$00FF00,3|12:2156$0000FF
You can try adjusting the rendering levels in that URL, e.g. to make the first channel brighter, replace the “7:4095” with “0:1000”.

If you can make your code public then I can take a look and it would be easier to discuss specific issues. Don’t worry about the code being “sketchy”. All code starts like that!

Please feel free to open a new thread, even if it’s just “Help with OMERO.web app” to cover a range of issues.
Regards,
Will.

You may find some useful examples in the https://github.com/ome/omero-webtest repo.
This is easy to install and then browse to your-server/webtest/ to see a handful of very basic examples.
And there’s a /webtest/examples/IMAGE_ID/embed_viewer.html example as mentioned in the README.

These simple examples might be easier to understand than figure/iviewer etc.

Which case is better, shall i make it public, or shall i send you an invitation?

I would certainly prefer if it was public. Then it will be useful for others and also others will be able to help or contribute.
Will.