changeset 0:d507ce86f0d0 draft default tip

planemo upload for repository https://github.com/lldelisle/tools-lldelisle/tree/master/tools/upload_roi_and_measures_to_omero commit 68de74426a3f93a240d64cb416f608ba7caca6eb
author lldelisle
date Fri, 16 Dec 2022 21:02:41 +0000
parents
children
files uploadROIandMeasuresToOMERO.xml upload_omero_roi_results.py
diffstat 2 files changed, 480 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uploadROIandMeasuresToOMERO.xml	Fri Dec 16 21:02:41 2022 +0000
@@ -0,0 +1,92 @@
+<tool id="uploadROIandMeasuresToOMERO" name="uploadROIandMeasuresToOMERO" version="0.0.5">
+    <description>Designed to work after measureGastruloids</description>
+    <requirements>
+        <requirement type="package" version="5.10.1">omero-py</requirement>
+        <requirement type="package" version="1.3.4">pandas</requirement>
+    </requirements>
+    <command detect_errors="exit_code"><![CDATA[
+        #import re
+        #if $omero_instance_type.omero_instance == "priv":
+            ## the user wants to use a non-public OMERO instance
+            ## check if credentials are set in the user-preferences, if not warn the user and exit
+            #set $username = $__user__.extra_preferences.get('omero_account|username', "")
+            #set $password = $__user__.extra_preferences.get('omero_account|password', "")
+
+            #if $omero_instance_type.galaxy_test_param != 'true' and ($username == "" or $password ==""):
+                echo "OMERO connection credentials are empty. Set your credentials via: User -> Preferences -> Manage Information" 1>&2 &&
+                exit 1 &&
+            #end if
+        #end if
+        
+        mkdir rois &&
+        #for file in $rois
+            #set identifier = re.sub('[^\s\w\-]', '_', str($file.element_identifier))
+            ln -s '$file' rois/${identifier}.txt &&
+        #end for
+        python '$__tool_directory__/upload_omero_roi_results.py'
+        #if $omero_instance_type.omero_instance =='priv':
+            -oh '$omero_instance_type.omero_host'
+            $omero_instance_type.omero_secured
+            -cf '$credentials'
+        #end if
+        --rois rois
+        --summaryResults $summary_results
+        --verbose
+        > output.log
+        ]]>
+    </command>
+    <configfiles>
+        <configfile name="credentials"><![CDATA[
+#if $omero_instance_type.omero_instance =='priv' and $omero_instance_type.galaxy_test_param == 'true':
+    ## as a test for a private instance we actually use a public instance, but with credentials
+    #set $username = 'public'
+    #set $password = 'public'
+#else:
+    #set $username = $__user__.extra_preferences.get('omero_account|username', "")
+    #set $password = $__user__.extra_preferences.get('omero_account|password', "")
+#end if
+{
+    "username": "$username",
+    "password": "$password"
+}
+        ]]></configfile>
+    </configfiles>
+    <inputs>
+        <conditional name="omero_instance_type">
+            <param name="omero_instance" type="select" label="Which OMERO instance to connect?"
+                   help="By default, the tool will download a tarball containing individual images from IDR into your Galaxy history. If you 
+                   need to connect to your own instance, set your connection username and password from User->Preference->Manage Information" >
+                <option value="idr">IDR</option>
+                <option value="priv">other OMERO instance</option>
+            </param>
+            <when value="priv">
+                <param name="omero_host" type="text" label="OMERO host URL">
+                    <validator type="regex" message="Enter a valid host location, for example, your.omero.server">^[a-zA-Z0-9._-]*$</validator>
+                    <validator type="expression" message="No two dots (..) allowed">'..' not in value</validator>
+                </param>
+                <param name="omero_secured" type="boolean" label="Secured connection?" checked="true" truevalue="--omero-secured" falsevalue=""
+                        help="Select Yes if your OMERO instance is running with SSL, otherwise select No">
+                </param>
+                <param name="galaxy_test_param" type="hidden" value="false" />
+            </when>
+            <when value="idr" />
+        </conditional>
+        <param name="rois" type="data_collection" format="tabular" label="Select ROIs." collection_type="list"/>
+        <param name="summary_results" type="data" format="csv" label="Select the all results csv."/>
+    </inputs>
+
+    <outputs>
+        <data name="logfile" format="txt" from_work_dir="output.log" label="${tool.name} on ${on_string}: logfile">
+        </data>
+    </outputs>
+    <help>
+    <![CDATA[
+**Overview**
+
+This tool will upload to OMERO the ROIs and the Results as table.
+
+The expected workflow is: idr_download_by_ids > measureGastruloids > uploadROIandMeasuresToOMERO
+]]>
+    </help>
+</tool>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/upload_omero_roi_results.py	Fri Dec 16 21:02:41 2022 +0000
@@ -0,0 +1,388 @@
+import argparse
+import json
+import os
+import re
+import tempfile
+
+import numpy as np
+
+import omero
+from omero.gateway import BlitzGateway
+from omero.rtypes import rdouble, rstring
+
+import pandas as pd
+
+file_base_name_exportedTIFF = re.compile(r"^.*__(\d+)__0__0__\d+__\d+$")
+file_base_name_original = re.compile(r"^.*__(\d+)$")
+
+non_roi_value = -1
+
+non_numeric_columns = ["Label", "Date", "Version", "IlastikProject",
+                       "Preprocess"]
+
+
+def get_image_id(image_file_name):
+    # Check the file name
+    # corresponds to the expected:
+    match = \
+        file_base_name_exportedTIFF.findall(image_file_name.replace(".tiff",
+                                                                    ""))
+    if len(match) == 0:
+        match = \
+            file_base_name_original.findall(image_file_name.replace(".tiff",
+                                                                    ""))
+        if len(match) == 0:
+            raise Exception(f"{image_file_name} does not match"
+                            "the expected format")
+    # Get the image_id
+    image_id = int(match[0])
+    return image_id
+
+
+def get_omero_credentials(config_file):
+    if config_file is None:  # IDR connection
+        omero_username = "public"
+        omero_password = "public"
+    else:  # other omero instance
+        with open(config_file) as f:
+            cfg = json.load(f)
+            omero_username = cfg["username"]
+            omero_password = cfg["password"]
+
+            if omero_username == "" or omero_password == "":
+                omero_username = "public"
+                omero_password = "public"
+    return (omero_username, omero_password)
+
+
+def clean(image_id, omero_username, omero_password, omero_host, omero_secured,
+          verbose):
+    with BlitzGateway(
+        omero_username, omero_password, host=omero_host, secure=omero_secured
+    ) as conn:
+        roi_service = conn.getRoiService()
+        img = conn.getObject("Image", image_id)
+        rois = roi_service.findByImage(image_id, None, conn.SERVICE_OPTS).rois
+        # Delete existing rois
+        if len(rois) > 0:
+            if verbose:
+                print(f"Removing {len(rois)} existing ROIs.")
+            conn.deleteObjects("Roi", [roi.getId().val
+                                       for roi
+                                       in rois],
+                               wait=True)
+        # Delete existing table named Results_from_Fiji
+        for ann in img.listAnnotations():
+            if ann.OMERO_TYPE == omero.model.FileAnnotationI:
+                if ann.getFileName() == "Results_from_Fiji":
+                    if verbose:
+                        print("Removing the table Results_from_Fiji.")
+                    conn.deleteObjects("OriginalFile", [ann.getFile().id],
+                                       wait=True)
+
+
+def upload(
+    image_id,
+    df,
+    roi_files,
+    omero_username,
+    omero_password,
+    omero_host,
+    omero_secured,
+    verbose,
+):
+    with BlitzGateway(
+        omero_username, omero_password, host=omero_host, secure=omero_secured
+    ) as conn:
+        updateService = conn.getUpdateService()
+        img = conn.getObject("Image", image_id)
+        # Create ROIs:
+        roi_ids = []
+        # roi_big_circle_ids = []
+        # roi_spine_ids = []
+        for i, ro_file in enumerate(roi_files):
+            # Create a polygon
+            my_poly = omero.model.PolygonI()
+            # Add the coordinates
+            with open(ro_file, "r") as f:
+                coos = f.readlines()
+            coos_formatted = ", ".join([line.strip().replace("\t", ",")
+                                        for line in coos])
+            my_poly.setPoints(rstring(coos_formatted))
+            # Add a name
+            my_poly.setTextValue(rstring("ROI" + str(i)))
+            # Create a omero ROI
+            my_new_roi = omero.model.RoiI()
+            my_new_roi.addShape(my_poly)
+            # Attach it to the image
+            my_new_roi.setImage(img._obj)
+            my_new_roi = updateService.saveAndReturnObject(my_new_roi)
+            roi_ids.append(my_new_roi.getId().val)
+            if verbose:
+                print(f"Created ROI{i} {my_new_roi.getId().val}.")
+            # Check if there is an elongation ROI associated:
+            if os.path.exists(ro_file.replace("roi_coordinates",
+                                              "elongation_rois")):
+                # Get the coordinates
+                with open(
+                    ro_file.replace("roi_coordinates", "elongation_rois"),
+                    "r"
+                ) as f:
+                    all_coos = f.readlines()
+                # Get the circles coos
+                circles_coos = [line for line in all_coos
+                                if len(line.split("\t")) == 3]
+                for j, circle_coo in enumerate(circles_coos):
+                    # Create an ellipse
+                    my_ellipse = omero.model.EllipseI()
+                    # Get the characteristics from text file
+                    xleft, ytop, width = [
+                        float(v) for v in circle_coo.strip().split("\t")
+                    ]
+                    # Add it to the ellipse
+                    my_ellipse.setRadiusX(rdouble(width / 2.0))
+                    my_ellipse.setRadiusY(rdouble(width / 2.0))
+                    my_ellipse.setX(rdouble(xleft + width / 2))
+                    my_ellipse.setY(rdouble(ytop + width / 2))
+                    # Add a name
+                    my_ellipse.setTextValue(
+                        rstring("inscribedCircle" + str(i) + "_" + str(j))
+                    )
+                    # Create a omero ROI
+                    my_new_roi = omero.model.RoiI()
+                    my_new_roi.addShape(my_ellipse)
+                    # Attach it to the image
+                    my_new_roi.setImage(img._obj)
+                    my_new_roi = updateService.saveAndReturnObject(my_new_roi)
+                    if verbose:
+                        print(
+                            f"Created ROI inscribedCircle {i}_{j}:"
+                            f"{my_new_roi.getId().val}."
+                        )
+                    # I store the id of the first circle:
+                    # if j == 0:
+                    #     roi_big_circle_ids.append(my_new_roi.getId().val)
+                if len(all_coos) > len(circles_coos):
+                    # Create a polyline for the spine
+                    my_poly = omero.model.PolylineI()
+                    coos_formatted = ", ".join(
+                        [
+                            line.strip().replace("\t", ",")
+                            for line in all_coos[len(circles_coos):]
+                        ]
+                    )
+                    my_poly.setPoints(rstring(coos_formatted))
+                    # Add a name
+                    my_poly.setTextValue(rstring("spine" + str(i)))
+                    # Create a omero ROI
+                    my_new_roi = omero.model.RoiI()
+                    my_new_roi.addShape(my_poly)
+                    # Attach it to the image
+                    my_new_roi.setImage(img._obj)
+                    my_new_roi = updateService.saveAndReturnObject(my_new_roi)
+                    if verbose:
+                        print(f"Created ROI spine{i}:"
+                              f" {my_new_roi.getId().val}.")
+                    # roi_spine_ids.append(my_new_roi.getId().val)
+                else:
+                    if verbose:
+                        print("No spine found")
+                    # roi_spine_ids.append(non_roi_value)
+            # else:
+            #     roi_big_circle_ids.append(non_roi_value)
+            #     roi_spine_ids.append(non_roi_value)
+
+        # Create the table:
+        table_name = "Results_from_Fiji"
+        columns = []
+        for col_name in df.columns[1:]:
+            if col_name in non_numeric_columns:
+                columns.append(omero.grid.StringColumn(col_name, "", 256, []))
+            else:
+                columns.append(omero.grid.DoubleColumn(col_name, "", []))
+
+        # From Claire's groovy:
+        # table_columns[size] = new TableDataColumn("Roi", size, ROIData)
+        columns.append(omero.grid.RoiColumn("Roi", "", []))
+        # For the moment (20220729),
+        # the table support only one ROI column with link...
+        # if 'Elongation_index' in df.columns[1:]:
+        #     columns.append(omero.grid.RoiColumn('Roi_maxCircle', '', []))
+        #     columns.append(omero.grid.RoiColumn('Roi_Spine', '', []))
+        # columns.append(omero.grid.RoiColumn('Roi_main', '', []))
+
+        resources = conn.c.sf.sharedResources()
+        repository_id = \
+            resources.repositories().descriptions[0].getId().getValue()
+        table = resources.newTable(repository_id, table_name)
+        table.initialize(columns)
+
+        data = []
+        for col_name in df.columns[1:]:
+            if col_name in non_numeric_columns:
+                data.append(
+                    omero.grid.StringColumn(
+                        col_name, "", 256,
+                        df[col_name].astype("string").to_list()
+                    )
+                )
+            else:
+                data.append(
+                    omero.grid.DoubleColumn(col_name, "",
+                                            df[col_name].to_list())
+                )
+        data.append(omero.grid.RoiColumn("Roi", "", roi_ids))
+        # if verbose:
+        #     print("Columns are " + " ".join(df.columns[1:]))
+        # if 'Elongation_index' in df.columns[1:]:
+        #     if verbose:
+        #         print("Adding 2 rois columns")
+        #         print(roi_ids)
+        #         print(roi_big_circle_ids)
+        #     data.append(omero.grid.RoiColumn('Roi_maxCircle', '',
+        #                                      roi_big_circle_ids))
+        #     data.append(omero.grid.RoiColumn('Roi_Spine', '',
+        #                                      roi_spine_ids))
+        # data.append(omero.grid.RoiColumn('Roi_main', '', roi_ids))
+
+        table.addData(data)
+        orig_file = table.getOriginalFile()
+        table.close()
+        # when we are done, close.
+
+        # Load the table as an original file
+
+        orig_file_id = orig_file.id.val
+        # ...so you can attach this data to an object e.g. Image
+        file_ann = omero.model.FileAnnotationI()
+        # use unloaded OriginalFileI
+        file_ann.setFile(omero.model.OriginalFileI(orig_file_id, False))
+        file_ann = updateService.saveAndReturnObject(file_ann)
+        link = omero.model.ImageAnnotationLinkI()
+        link.setParent(omero.model.ImageI(image_id, False))
+        link.setChild(omero.model.FileAnnotationI(
+            file_ann.getId().getValue(), False
+            ))
+        updateService.saveAndReturnObject(link)
+        if verbose:
+            print("Successfully created a Table with results.")
+
+
+def scan_and_upload(
+    roi_directory,
+    summary_results,
+    omero_username,
+    omero_password,
+    omero_host="idr.openmicroscopy.org",
+    omero_secured=False,
+    verbose=False,
+):
+    # First get the summary results
+    full_df = pd.read_csv(summary_results)
+    # Loop over the image names
+    for image_file_name in np.unique(full_df["Label"]):
+        # Get the image_id
+        image_id = get_image_id(image_file_name)
+        if verbose:
+            print(f"Image:{image_id} is in the table."
+                  " Cleaning old results.")
+        clean(
+            image_id, omero_username, omero_password, omero_host,
+            omero_secured, verbose
+        )
+        # Subset the result to the current image
+        df = full_df[full_df["Label"] == image_file_name]
+        if np.isnan(df["Area"].to_list()[0]):
+            # No ROI has been detected
+            if verbose:
+                print("No ROI was found.")
+            continue
+        n_rois = df.shape[0]
+        if verbose:
+            print(f"I found {n_rois} measurements.")
+        # Check the corresponding rois exists
+        roi_files = [
+            os.path.join(
+                roi_directory,
+                image_file_name.replace(".tiff", "_tiff")
+                + "__"
+                + str(i)
+                + "_roi_coordinates.txt",
+            )
+            for i in range(n_rois)
+        ]
+        for ro_file in roi_files:
+            if not os.path.exists(ro_file):
+                raise Exception(f"Could not find {ro_file}")
+        upload(
+            image_id,
+            df,
+            roi_files,
+            omero_username,
+            omero_password,
+            omero_host,
+            omero_secured,
+            verbose,
+        )
+    # Update the full_df with image id:
+    full_df["id"] = [
+        get_image_id(image_file_name)
+        for image_file_name in full_df["Label"]
+    ]
+    # Attach it to the dataset:
+    with BlitzGateway(
+        omero_username, omero_password, host=omero_host,
+        secure=omero_secured
+    ) as conn:
+        full_df["dataset_id"] = [
+            a.id
+            for id in full_df["id"]
+            for a in conn.getObject("Image", id).getAncestry()
+            if a.OMERO_CLASS == "Dataset"
+        ]
+        dir = tempfile.mkdtemp()
+        for dataset_id in np.unique(full_df["dataset_id"]):
+            df = full_df[full_df["dataset_id"] == dataset_id]
+            first_date = df["Date"].to_list()[0]
+            file_to_upload = os.path.join(
+                dir, "Results_from_Fiji_" + first_date + ".csv"
+            )
+            df.to_csv(file_to_upload, index=False)
+            dataset = conn.getObject("Dataset", dataset_id)
+            # create the original file and file annotation
+            # (uploads the file etc.)
+            # namespace = "my.custom.demo.namespace"
+            file_ann = conn.createFileAnnfromLocalFile(
+                file_to_upload
+            )  # , mimetype="text/plain", ns=namespace, desc=None)
+            print(
+                "Attaching FileAnnotation to Dataset: ",
+                "File ID:",
+                file_ann.getId(),
+                ",",
+                file_ann.getFile().getName(),
+                "Size:",
+                file_ann.getFile().getSize(),
+            )
+            dataset.linkAnnotation(file_ann)  # link it to dataset.
+
+
+if __name__ == "__main__":
+    p = argparse.ArgumentParser()
+    p.add_argument("-oh", "--omero-host", type=str,
+                   default="idr.openmicroscopy.org")
+    p.add_argument("--omero-secured", action="store_true", default=True)
+    p.add_argument("-cf", "--config-file", dest="config_file",
+                   default=None)
+    p.add_argument("--rois", type=str, default=None)
+    p.add_argument("--summaryResults", type=str, default=None)
+    p.add_argument("--verbose", action="store_true")
+    args = p.parse_args()
+    scan_and_upload(
+        args.rois,
+        args.summaryResults,
+        *get_omero_credentials(args.config_file),
+        omero_host=args.omero_host,
+        omero_secured=args.omero_secured,
+        verbose=args.verbose,
+    )