Test Python plugins on OMERO

It’s done. Now, you should be able to see it.

OK, I had a go at this and I think this should help you: https://github.com/mmongy/my_channel_viewer/pull/1

Hi Will,

Thanks for the help. I dissected your code and it helped me to understand how to work directly with the parameters listed in the JSON associated to each image.

After reading and trying it, i guess the idea behind your code is to:

  • Extract the original parameters from the JSON
  • Store them into variables, modify them through the web interface
  • Add the modified parameters to the rendered image URL ("/webclient/render_image/")

Correct me if i’m fooled. I’m not an expert in JavaScript.

But i have some other questions:

  • Is there a way to display separately the channels of the input image?

    • When i tried to use the getChannels function, all i had was a list of ChannelWrappers, and the ChannelWrapper class doesn’t propose any way to display the image associated to the channel (according to the doc: https://downloads.openmicroscopy.org/omero/5.5.0/api/python/omero/omero.gateway.html#omero.gateway._ChannelWrapper).
    • At least, it seems possible to display the channels independently by create on the web page other rendered images of the original image, and to neutralize or to suppress directly from the URL the unwanted channels for each image.
    • There seems also to be a way to play a bit with the pseudo colors by tuning them directly in the URL (ex: turning $FF0000 to $FF00FF, to go from red to magenta), or to play with the shades (ex: turning $FF00FF to $FF005F). I guess it is even possible to add a color chooser for each channel like in https://ourcodeworld.com/articles/read/81/top-5-best-javascript-and-jquery-color-picker-plugins
    • It seems also possible to create a resulting image by “cheating” a bit, by taking the parameters used in the rendered channels URLs, and concatenate them in a resulting image URL.
  • Is there a way to interact directly with the pixels of each channel, then to sum up the channels, to display a resulting image?

    • If i want to implement other things like the possibility to add a gamma correction for each channel, or to apply custom LUTs (the polychrome ones, like a hot-metal palette) for each channel, for visualization purposes… It doesn’t seem to be possible via the URL.

Sorry for the questions, but i am curious about the ChannelWrappers (and maybe more widely about the concept of “wrappers”).

Best regards, Marc.

Hi Marc,

See more code and answers at https://github.com/mmongy/my_channel_viewer/pull/1#issuecomment-695368406

I’m not using the image.getChannels() python code at-all in this example since we get everything we need from the imgData JSON in JavaScript.
I’m working mostly in JavaScript since that gives a more interactive experience for web users. You can do more in Python, like some of the webtest examples I mentioned above.

If you want to do get more info from the ChannelsWrapper, the best place to look is the code at https://github.com/ome/omero-py/blob/0546d34066a42aaf3db07de0f6a8557a78892dfc/src/omero/gateway/init.py#L7553

You can read more about Wrappers at https://docs.openmicroscopy.org/omero/5.6.2/developers/PythonBlitzGateway.html#model-object-wrappers

Hope that helps,
Will.

Hi Will,

Thanks for the help last time. Your code was nice enough for me to read (it took a bit of time though). The only thing that bugged me was the way you created functions inside the main function.

I was also stuck with the asynchronous functioning of the “.getJSON()” and:".map()" functions, especially the way they “return” data. So, for testing purposes, i tried to find synchronous (classic) ways to set and return data, at least to learn how to modify the data JSON by functions. Now it works well with “.getJSON()”.

Also, the CSS for the sliders were a bit faulty (you can’t modify the bottom value of the slider, it was even mentioned in the comments of Stackoverflow), so i stuck with my JQuery sliders. It works quite well.

I tried to implement a function to swap the display of the channels/result images by a click on a button. But this solution was too problematic to implement (notably the way the “onclick” parameter is used when using a function with multiple parameters, one of the parameters was the data JSON associated with the image), so i used JQuery to make thumbnails. It renders nice.

I also added sliders to tune the Z-depth and T-time, checkboxes to enable/disable the channels, and a dropdown list to choose the maximum dynamic range of the images.

It works, but there are also some problems. The display is a bit glitchy: the grey background of the sliders is displayed outside the sliders (it is strange, because it rendered nicely before, and i didn’t altered the CSS before the problems). Also i can’t figure a way to take into account the changes after tuning the colors, the LUT, the checkboxes, the dynamic range dropdown list: every change is registered ONLY after acting on the sliders handles (min max pixels of the channels, Z-Depth, T-time).

Also, i have questions for some remaining steps:

  • Is there a documented way to export the generated channels/result images to OMERO.figure (a bit like in Split View)?
    • I tried to explore “ome.split_view_figure.js”, but i think it will be a hard time for me to retrace its functioning.
  • I noticed (in https://docs.openmicroscopy.org/omero/5.6.1/developers/Web/WebGateway.html) that there is a way to extract histogram data in JSON format. Is there a way to display it on a graphical histogram on my GUI (maybe with the curve of the brightness/contrast on surimpression)? I just want to know if there an easy, documented way to make it, before tackling with d3js (ouch!) to make it…

I put my code on GitHub yesterday, in the same place as the last time. Feel free to have a glance.

Best regards and thanks for your help, Marc.

1 Like

Hi Marc,

I fixed some issues at https://github.com/mmongy/my_channel_viewer/pull/2

You need to understand the use of https://api.jquery.com/on/
This is really useful to setup events on the top-level elements when the page loads, instead of having to do it each time you update the UI (when you choose a different image). I used this approach to fix the LUT chooser. You might need to do the same for other controls.

You don’t need lots of $(document).ready() calls everywhere. I removed some of these but all of these should be removed from inside other functions. This is only needed to make sure the main function doesn’t run before the html page is ready.

The css issue for the slider ‘grey’ area was due to your #TuningItems div style applying to ALL the divs in that container.
I found that by using the dev tools to inspect the grey box, see that it had a margin of 80px and then found where that was coming from (see screenshot).

You need to clean up a lot of code that’s not being used. E.g. in your views.py context['image_channels'] = images_channels is never used, so you don’t need to create it.

I’ll come back to the other questions…

Will.

I added some code to that PR to show how to handle the form submission.
I only included some of the fields, but you should be able to handle the other ones.
For the slider values you could use your of minmaxPixelValues.

If you look at https://omero-guides.readthedocs.io/en/latest/figure/docs/omero_figure_scripting.html#figure-creation-in-python this describes how to create an OMERO.figure file in python - See the Split_View_Figure.py script linked from there.
Having created the figure, you could return a link to it or even redirect your users to the new figure page.

For the histogram, I’m afraid you’ll have to do this yourself with d3.
The code we use in webcient to do this is at https://github.com/ome/omero-web/blob/4b88d6adf10bcbd2916f34cd346c08ed29a9b824/omeroweb/webgateway/static/webgateway/js/ome.histogram.js

Regards,
Will

Hi Will,

I’m still advancing on my plugin.

About the histogram, i found a quick solution just after sending my last message: the canvas API (https://canvasjs.com/javascript-charts/json-data-api-ajax-chart/). I adapted the provided code to suit my needs. It’s probably not the best solution (it sometimes doesn’t display in the page), so i’ll try your D3JS alternative later. I had looked inside a bit anyway, and i don’t understand the “window.OME” thing.

I also examined a bit the way to export the parameters to a django form. After reading the python code (urls.py and views.py) you provided me, the OMEROweb “url.py” and “views.py”, and the code of the “Split_View_Figure.py” script, i figured how to do it. I copy-pasted a lot of functions from “Split_View_Figure.py”, to experiment, and after some tweaks, it worked, at least for the loaded image, but it’s still crude. I’ll tackle with it later, because i have another problem.

One of the main points behind my code is to tune the channel parameters of an image, but also to apply them to the other selected images.

After some thinking, i figured i had to load all the images (without displaying them, hence the “display:none”) on the webpage to obtain their respective URL links, then to get their JSONs in a list. After applying modifications, the listed JSONs are modified, and the images are updated from these listed JSONs. It works, but it’s quite slow (and maybe very memory-consuming, but if i want to apply tunings to the images, i have to load them first). And i guess it will get even slower with the number of selected images. Do you think there is a way to reduce the waiting time between each parameter refreshing? Maybe by using thumbnails instead of subdimensioned images?

I put my code on GitHub just now, in the same place as the last time. You know the trick…

Best regards, and thanks for your help, Marc.

Hi Marc,

I’m not sure I really understand what you’re trying to do here, which makes it harder to point you in the right direction.
I’m assuming that you select a bunch of images that have the same number of channels (acquired with the same settings on the microscope) and that you want to apply the same rendering settings to them all.
This is something you can already do in OMERO.figure directly. But I guess you don’t have a histogram, or is it something else that is missing?

It’s hard to tell what of your plugin is not working because I’m testing with different images, or going through different steps etc. Or what you need help with.

If you assume that all the images are comparable (same number of channels etc) you can just apply the same settings to all the images. You shouldn’t need to load the JSON for all of them, or load a rendered image unless you want to view it.

Previously, we were just loading the JSON for the 1 image when it was chosen by the select chooser, instead of loading JSON for all the images that were on the page.
You only need to POST the rendering settings for the selected image, and the list of all the other image IDs. Then you can generate all the JSON you need for these images in the figure creation code, adjusting each one to match the submitted settings.

I’m seeing a few bugs - If I choose any image other than the first image from the select list, I get an error.
Also, all the images are rendering black because you have ‘-’ before all the channels in the rendering query string.
I noticed that for a 3-channel image you’re loading histogram for channels “1”, “2” and “3” when it should be “0”, “1” & “2”, which might explain why it’s not working sometimes.

You need to fix those and make sure there’s only 1 thing failing that you need me to help with.

Also the code I added for setting up event listeners…

  // setup listeners on any <select class='lut'> choosers that we may create later
  // We bind ONE event listener to the #TuningItems element when the page loads.
  // This will capture any events coming from LUT choosers
  $("#TuningItems").on("change", "select.lut", function () {
    console.log('select LUT...', currentImageDataJSON);
    updateAllChannelsAndResultImage(currentImageDataJSON)
  });

This only needs to run once when the page loads. It doesn’t need to happen after the LUTs JSON loads and not every time the user chooses an Image.

Try to remove all non-essential features until we have the workflow working from start to finish and no bugs. Otherwise we’re trying to debug more complex code than necessary.

Will.

Hi Marc,

I thought I’d try the figure-creation python code, but I wanted to avoid some of the current JS bugs I mentioned above, so I went back to an older version (after you merged my last PR). But I found that this also had a bunch of bugs (images not rendering etc).
So I have spend over an hour trying to fix those (see my commits at https://github.com/will-moore/my_channel_viewer/commits/revert_3_commits).

Various issues… I think using the channel label in the IDs of the html elements you create is a bad idea, since you don’t know what’s in the label - e.g. could contain " etc.
Much better to use the index of the channel instead. Also, you need to use the channel index in the name of each input, so that you have this in the POST data.

Anyway, after more than an hour, I found there’s still problems when you choose a 2nd image from the select menu - This destroys the jQuery-UI tabs. They work for the first image you choose, but for some reason, when you choose a 2nd image, they break. This but might be there from when you first added jquery-UI tabs?

So I think you need to spend a bit of time to go back and fix these bugs. Maybe revert all the way back until you can be sure that everything works.
Whenever you add a new feature, you need to give everything a really good test to make sure you don’t break anything.
I think a lot of problems are coming from the jQuery UI tabs and sliders. My code without them from https://github.com/mmongy/my_channel_viewer/pull/1 is quite a bit simpler. So, don’t add them unless you need them, then test them well.

Also, it would help with going back over older code if you name your commits with a meaningful commit message.

Once you have something working, I think it would be best to open up github issues on your repository for any other issues you have, instead of adding to this tread. You can cc me on the issues.

Regards,
Will