diff idr_download_by_ids.py @ 0:57aa9597cd31 draft

"planemo upload for repository https://github.com/galaxyproject/tools-iuc/tree/master/tools/idr_download commit 253efabdfea3a1fecc4c0f2c54c0e97a7d7960ab"
author iuc
date Sat, 08 Feb 2020 13:24:39 -0500
parents
children 9340cbc7796c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/idr_download_by_ids.py	Sat Feb 08 13:24:39 2020 -0500
@@ -0,0 +1,271 @@
+import argparse
+import os
+import sys
+
+from matplotlib import pyplot as plt
+from omero.gateway import BlitzGateway  # noqa
+from omero.constants.namespaces import NSBULKANNOTATIONS  # noqa
+
+
+def warn(message, image_identifier):
+    print(
+        'ImageSpecWarning for {0}: {1}'
+        .format(image_identifier, message),
+        file=sys.stderr
+    )
+
+
+def find_channel_index(image, channel_name):
+    channel_name = channel_name.lower()
+    for n, channel in enumerate(image.getChannels()):
+        if channel_name == channel.getLabel().lower():
+            return n
+    # Check map annotation for information (this is necessary for some images)
+    for ann in image.listAnnotations(NSBULKANNOTATIONS):
+        pairs = ann.getValue()
+        for p in pairs:
+            if p[0] == "Channels":
+                channels = p[1].replace(" ", "").split(";")
+                for n, c in enumerate(channels):
+                    for value in c.split(':'):
+                        if channel_name == value.lower():
+                            return n
+    return -1
+
+
+def get_clipping_region(image, x, y, w, h):
+    # If the (x, y) coordinate falls outside the image boundaries, we
+    # cannot just shift it because that would render the meaning of
+    # w and h undefined (should width and height be decreased or the whole
+    # region be shifted to keep them fixed?).
+    # It may be better to abort in this situation.
+    if x < 0 or y < 0:
+        raise ValueError(
+            'Too small upper left coordinate ({0}, {1}) for clipping region.'
+            .format(x, y)
+        )
+    size_x = image.getSizeX()
+    size_y = image.getSizeY()
+    if x >= size_x or y >= size_y:
+        raise ValueError(
+            'Upper left coordinate ({0}, {1}) of clipping region lies '
+            'outside of image.'
+            .format(x, y)
+        )
+    # adjust width and height to the image dimensions
+    if w <= 0 or x + w > size_x:
+        w = size_x - x
+    if h <= 0 or y + h > size_y:
+        h = size_y - y
+    return [x, y, w, h]
+
+
+def confine_plane(image, z):
+    if z < 0:
+        z = 0
+    else:
+        max_z = image.getSizeZ() - 1
+        if z > max_z:
+            z = max_z
+    return z
+
+
+def confine_frame(image, t):
+    if t < 0:
+        t = 0
+    else:
+        max_t = image.getSizeT() - 1
+        if t > max_t:
+            t = max_t
+    return t
+
+
+def download_plane_as_tiff(image, tile, z, c, t, fname):
+    pixels = image.getPrimaryPixels()
+    selection = pixels.getTile(theZ=z, theT=t, theC=c, tile=tile)
+
+    if fname[-5:] != '.tiff':
+        fname += '.tiff'
+    plt.imsave(fname, selection)
+
+
+def download_image_data(
+    image_ids,
+    channel=None, z_stack=0, frame=0,
+    coord=(0, 0), width=0, height=0, region_spec='rectangle',
+    skip_failed=False
+):
+
+    # connect to idr
+    conn = BlitzGateway('public', 'public',
+                        host='idr.openmicroscopy.org',
+                        secure=True)
+    conn.connect()
+
+    try:
+        prefix = 'image-'
+        for image_id in image_ids:
+            if image_id[:len(prefix)] == prefix:
+                image_id = image_id[len(prefix):]
+            image_id = int(image_id)
+            image = conn.getObject("Image", image_id)
+
+            if image is None:
+                image_warning_id = 'Image-ID: {0}'.format(image_id)
+                if skip_failed:
+                    warn(
+                        'Unable to find an image with this ID in the '
+                        'database. Skipping download!',
+                        image_warning_id
+                    )
+                    continue
+                raise ValueError(
+                    '{0}: Unable to find an image with this ID in the '
+                    'database. Aborting!'
+                    .format(image_warning_id)
+                )
+
+            image_name = os.path.splitext(image.getName())[0]
+            image_warning_id = '{0} (ID: {1})'.format(
+                image_name, image_id
+            )
+
+            if region_spec == 'rectangle':
+                tile = get_clipping_region(image, *coord, width, height)
+            elif region_spec == 'center':
+                tile = get_clipping_region(
+                    image,
+                    *_center_to_ul(*coord, width, height)
+                )
+            else:
+                raise ValueError(
+                    'Got unknown value "{0}" as region_spec argument'
+                    .format(region_spec)
+                )
+            if tile[2] < width or tile[3] < height:
+                # The downloaded image region will have smaller dimensions
+                # than the specified width x height.
+                warn(
+                    'Downloaded image dimensions ({0} x {1}) will be smaller '
+                    'than the specified width and height ({2} x {3}).'
+                    .format(tile[2], tile[3], width, height),
+                    image_warning_id
+                )
+
+            ori_z, z_stack = z_stack, confine_plane(image, z_stack)
+            if z_stack != ori_z:
+                warn(
+                    'Specified image plane ({0}) is out of bounds. Using {1} '
+                    'instead.'
+                    .format(ori_z, z_stack),
+                    image_warning_id
+                )
+
+            ori_frame, frame = frame, confine_frame(image, frame)
+            if frame != ori_frame:
+                warn(
+                    'Specified image frame ({0}) is out of bounds. Using '
+                    'frame {1} instead.'
+                    .format(ori_frame, frame),
+                    image_warning_id
+                )
+            # Get the channel index. If the index is not valid, skip the image
+            if channel is None:
+                channel_index = 0
+                num_channels = image.getSizeC()
+                if num_channels > 1:
+                    warn(
+                        'No specific channel selected for multi-channel '
+                        'image. Using first of {0} channels.'
+                        .format(num_channels),
+                        image_warning_id
+                    )
+            else:
+                channel_index = find_channel_index(image, channel)
+                if channel_index == -1:
+                    raise ValueError(
+                        '"{0}" is not a known channel name for image {1}'
+                        .format(channel, image.getName())
+                    )
+
+            # download and save the region as TIFF
+            fname = '_'.join(
+                [image_name, str(image_id)] + [str(x) for x in tile]
+            )
+            download_plane_as_tiff(image, tile, z_stack, channel_index, frame, fname)
+    finally:
+        # Close the connection
+        conn.close()
+
+
+def _center_to_ul(center_x, center_y, width, height):
+    if width > 0:
+        ext_x = (width - 1) // 2
+        ul_x = max([center_x - ext_x, 0])
+        width = center_x + ext_x + 1 - ul_x
+    else:
+        ul_x = 0
+    if height > 0:
+        ext_y = (height - 1) // 2
+        ul_y = max([center_y - ext_y, 0])
+        height = center_y + ext_y + 1 - ul_y
+    else:
+        ul_y = 0
+    return ul_x, ul_y, width, height
+
+
+if __name__ == "__main__":
+    p = argparse.ArgumentParser()
+    p.add_argument(
+        'image_ids', nargs='*', default=[],
+        help='one or more IDR image ids for which to retrieve data (default: '
+             'read ids from stdin).'
+    )
+    p.add_argument(
+        '-c', '--channel',
+        help='name of the channel to retrieve data for '
+             '(note: the first channel of each image will be downloaded if '
+             'left unspecified)'
+    )
+    region = p.add_mutually_exclusive_group()
+    region.add_argument(
+        '--rectangle', nargs=4, type=int, default=argparse.SUPPRESS,
+        help='specify a clipping region for the image as x y width height, '
+             'where x and y give the upper left coordinate of the rectangle '
+             'to clip to. Set width and height to 0 to extend the rectangle '
+             'to the actual size of the image.'
+    )
+    region.add_argument(
+        '--center', nargs=4, type=int, default=argparse.SUPPRESS,
+        help='specify a clipping region for the image as x y width height, '
+             'where x and y define the center of a width x height rectangle. '
+             'Set either width or height to 0 to extend the region to the '
+             'actual size of the image along the x- or y-axis.\n'
+             'Note: Even values for width and height will be rounded down to '
+             'the nearest odd number.'
+    )
+    p.add_argument(
+        '-f', '--frame', type=int, default=0
+    )
+    p.add_argument(
+        '-z', '--z-stack', type=int, default=0
+    )
+    p.add_argument(
+        '--skip-failed', action='store_true'
+    )
+    args = p.parse_args()
+    if not args.image_ids:
+        args.image_ids = sys.stdin.read().split()
+    if 'center' in args:
+        args.coord, args.width, args.height = (
+            args.center[:2], args.center[2], args.center[3]
+        )
+        args.region_spec = 'center'
+        del args.center
+    elif 'rectangle' in args:
+        args.coord, args.width, args.height = (
+            args.rectangle[:2], args.rectangle[2], args.rectangle[3]
+        )
+        args.region_spec = 'rectangle'
+        del args.rectangle
+    download_image_data(**vars(args))