Skip to content
Snippets Groups Projects
OpenBISScreeningML.java 93 KiB
Newer Older
  • Learn to ignore specific revisions
  •     /**
         * Uploads specified data set for specified plate. The data set code will be returned.
         * <p>
         * Matlab example:
         * 
         * <pre>
         * % Upload data set /path/to/my-data-set with properties DESCRIPTION and NUMBER for 
         * % plate P005 in space SPACE
         * % with data set  201007091122-928 as the parent
         * properties = {'DESCRIPTION' 'hello example'; 'NUMBER' 3.14}
         * parents = {'201007091122-928' }
         * datasetcode = OpenBISScreeningML.uploadDataSetForPlateAndParents('/SPACE/P005', parents, '/path/to/my-data-set', 'HCS_IMAGE', properties)
         * </pre>
         * 
         * @param augmentedPlateCode The augmented plate code.
         * @param parentDataSetCodeObjects The codes of the parents of this data set
         * @param dataSetFilePath Path to the data set file/folder to be uploaded.
         * @param dataSetType Data set type.
         * @param dataSetProperties A two dimensional array where the first column contains the property
         *            codes and the second column the corresponding property values.
         */
        public static Object uploadDataSetForPlateAndParents(String augmentedPlateCode,
                Object[] parentDataSetCodeObjects, String dataSetFilePath, String dataSetType,
                Object[][] dataSetProperties)
        {
            checkLoggedIn();
            Plate plateIdentifier = getPlate(augmentedPlateCode);
            List<String> dataSetCodes = createStringList(parentDataSetCodeObjects);
            File dataSetFile = new File(dataSetFilePath);
            if (dataSetFile.exists() == false)
            {
                throw new RuntimeException("Unknown data set file path '" + dataSetFilePath + "'.");
            }
            try
            {
                Map<String, String> map = createMap(dataSetProperties);
                IDataSetDss dataSet =
                        openbis.putDataSet(plateIdentifier, dataSetFile, new NewDataSetMetadataDTO(
                                dataSetType, map, dataSetCodes));
                return dataSet.getCode();
            } catch (Exception ex)
            {
                throw new RuntimeException("Couldn't upload data set for plate '" + augmentedPlateCode
                        + "'.", ex);
            }
        }
    
        /**
         * Uploads a data set to the specified experiment, setting the data set parents. The data set
         * code will be returned.
         * <p>
         * Matlab example:
         * 
         * <pre>
         * % Upload data set /path/to/my-data-set with property DESCRIPTION and N 
         * % to experiment E103 in project PROJECT and space SPACE 
         * % with data set  201007091122-928 as the parent
         * properties = {'DESCRIPTION' 'hello example' }
         * parents = {'201007091122-928' }
         * datasetcode = OpenBISScreeningML.uploadDataSetWithParents('/SPACE/PROJECT/E103', parents, '/path/to/my-data-set', 'HCS_IMAGE', properties)
         * </pre>
         * 
         * @param augmentedExperimentCode The augmented experiment code.
         * @param parentDataSetCodeObjects The codes of the parents of this data set
         * @param dataSetFilePath Path to the data set file/folder to be uploaded.
         * @param dataSetType Data set type.
         * @param dataSetProperties A two dimensional array where the first column contains the property
         *            codes and the second column the corresponding property values.
         */
        public static Object uploadDataSetForExperimentAndParents(String augmentedExperimentCode,
                Object[] parentDataSetCodeObjects, String dataSetFilePath, String dataSetType,
                Object[][] dataSetProperties)
        {
            checkLoggedIn();
            ExperimentIdentifier experimentIdentifier =
                    getExperimentIdentifierOrFail(augmentedExperimentCode);
            List<String> dataSetCodes = createStringList(parentDataSetCodeObjects);
            File dataSetFile = new File(dataSetFilePath);
            if (dataSetFile.exists() == false)
            {
                throw new RuntimeException("Unknown data set file path '" + dataSetFilePath + "'.");
            }
            try
            {
                Map<String, String> map = createMap(dataSetProperties);
                IDataSetDss dataSet =
                        openbis.putDataSet(experimentIdentifier, dataSetFile,
                                new NewDataSetMetadataDTO(dataSetType, map, dataSetCodes));
                return dataSet.getCode();
            } catch (Exception ex)
            {
                throw new RuntimeException("Couldn't upload data set for experiment '"
                        + augmentedExperimentCode + "' and parents '"
                        + Arrays.toString(parentDataSetCodeObjects) + "'.", ex);
            }
        }
    
    
        private static Map<String, String> createMap(Object[][] properties)
    
            Map<String, String> map = new HashMap<String, String>();
            for (Object[] objects : properties)
            {
                if (objects.length == 2)
                {
                    Object value = objects[1];
                    map.put(objects[0].toString(), value == null ? null : value.toString());
                }
            }
            return map;
    
        private static List<String> createStringList(Object[] identifiers)
        {
            List<String> list = new ArrayList<String>();
            for (Object identifier : identifiers)
            {
                list.add(identifier.toString());
            }
            return list;
        }
    
    
         * Loads the TIFF images for the given well location, all tiles and all channels and stores them
         * in temporary files. The temporary files will be removed automatically when the Java Virtual
    
         * Machine exits.
         * <p>
         * Matlab example:
         * 
         * <pre>
         * % Load the images for all channels of well B10 of plate P005 in space SPACE
    
         * imginfo = OpenBISScreeningML.loadImages('/SPACE/P005', 2, 10)
    
         * % Get the plate-well descriptions of all locations
         * imginfo(2,:,3)
         * % Show the third image (assuming there are at least three images)
         * imtool(imginfo(1,3))
         * </pre>
         * 
         * @param plate The augmented plate code
         * @param row The row in the plate to get the images for
         * @param col The column in the plate to get the images for
         * @return <code>{ names of TIFF files, image annotation }</code>
         *         <p>
         *         Each of <code>names of TIFF files</code> and <code>image annotation</code> is a
         *         vector of length of the number of images.
         *         <p>
         *         <code>image annotation</code> contains
         *         <code>{ channel name, tile number, plate well description, 
         *         plate augmented code, plate perm id, plate space code, plate code, row, column, 
         *         experiment augmented code, experiment perm id, experiment space code, 
         *         experiment project code, experiment code, data set code }</code>
         */
        public static Object[][][] loadImages(String plate, int row, int col)
        {
            return loadImages(plate, row, col, (String[]) null);
        }
    
        /**
    
         * Loads the TIFF images for the given well location, tile number, and all channels and stores
         * them in temporary files. The temporary files will be removed automatically when the Java
         * Virtual Machine exits.
         * <p>
         * Matlab example:
         * 
         * <pre>
         * % Load the images for all channels of well B10 and tile 3 of plate P005 in space SPACE
         * imginfo = OpenBISScreeningML.loadImages('/SPACE/P005', 2, 10, 3)
         * % Get the plate-well descriptions of all locations
         * imginfo(2,:,3)
         * % Show the third image (assuming there are at least three images)
         * imtool(imginfo(1,3))
         * </pre>
         * 
         * @param plate The augmented plate code
         * @param row The row in the plate to get the images for
         * @param col The column in the plate to get the images for
    
         * @param tile The tile number. Starts with 0.
    
         * @return <code>{ names of TIFF files, image annotation }</code>
         *         <p>
         *         Each of <code>names of TIFF files</code> and <code>image annotation</code> is a
         *         vector of length of the number of images.
         *         <p>
         *         <code>image annotation</code> contains
         *         <code>{ channel name, tile number, plate well description, 
         *         plate augmented code, plate perm id, plate space code, plate code, row, column, 
         *         experiment augmented code, experiment perm id, experiment space code, 
         *         experiment project code, experiment code, data set code }</code>
         */
        public static Object[][][] loadImages(String plate, int row, int col, int tile)
        {
            return loadImages(plate, row, col, tile, (String[]) null);
        }
    
        /**
         * Loads the TIFF images for the given well location, list of channels, and all tiles and stores
         * them in temporary files. The temporary files will be removed automatically when the Java
         * Virtual Machine exits.
    
         * <p>
         * Matlab example:
         * 
         * <pre>
         * % Load the images for channel DAPI of well H10 of plate P005 in space SPACE
    
         * imginfo=OpenBISScreeningML.loadImages('/SPACE/P005', 8, 10, 'DAPI')
    
         * % Get the channel names and tile numbers of all locations
         * imginfo(2,:,1:2)
         * % Show the second image (assuming there are at least two images)
         * imtool(imginfo(1,2))
         * </pre>
         * 
         * @param plate The augmented plate code
         * @param row The row in the plate to get the images for
         * @param col The column in the plate to get the images for
         * @param channels The names of the channels to get the images for
         * @return <code>{ names of TIFF files, image annotation }</code>
         *         <p>
         *         Each of <code>names of TIFF files</code> and <code>image annotation</code> is a
         *         vector of length of the number of images.
         *         <p>
         *         <code>image annotation</code> contains
         *         <code>{ channel name, tile number, plate well description, 
         *         plate augmented code, plate perm id, plate space code, plate code, row, column, 
         *         experiment augmented code, experiment perm id, experiment space code, 
         *         experiment project code, experiment code, data set code }</code>
         */
        public static Object[][][] loadImages(String plate, int row, int col, String[] channels)
    
            return loadRawImages(plate, row, col, channels, createAllTilesIterator());
        }
    
        /**
         * Has the same effect as {@link #loadImages(String, int, int, String[])}, but instead of
         * loading raw images loads their segmentation results if available.
    
    tpylak's avatar
    tpylak committed
         * 
    
         * @param objectNamesOrNull The names of the segmentation objects to get the images for. If
         *            <code>null</code> (or <code>[]</code> in MatLab) no restriction applies.
         * @param analysisProcedureOrNull The analysis procedure used to filter the result. That is, the
         *            result is restricted to feature vector data sets with a value of property
         *            <code>ANALYSIS_PROCEDURE</code> as specified. If <code>null</code> (or
         *            <code>[]</code> in MatLab) no restriction applies.
    
         */
        public static Object[][][] loadSegmentationImages(String plate, int row, int col,
    
                String[] objectNamesOrNull, String analysisProcedureOrNull)
    
            return loadSegmentationImages(plate, row, col, objectNamesOrNull, createAllTilesIterator(),
                    analysisProcedureOrNull);
    
        }
    
        private static ITileNumberIterable createAllTilesIterator()
        {
            return new ITileNumberIterable()
    
                {
                    private int maximumNumberOfTiles;
    
                    public void setMaximumNumberOfTiles(int numberOfTiles)
                    {
                        this.maximumNumberOfTiles = numberOfTiles;
                    }
    
                    public int getMaximumNumberOfTiles()
                    {
                        return maximumNumberOfTiles;
                    }
    
                    public Iterator<Integer> iterator()
                    {
                        return new Iterator<Integer>()
                            {
                                private int index;
    
                                public boolean hasNext()
                                {
                                    return index < maximumNumberOfTiles;
                                }
    
                                public Integer next()
                                {
                                    return index++;
                                }
    
                                public void remove()
                                {
                                    throw new UnsupportedOperationException();
                                }
                            };
                    }
    
        }
    
        /**
         * Loads the TIFF images for the given well location, tile number, and list of channels and
         * stores them in temporary files. The temporary files will be removed automatically when the
         * Java Virtual Machine exits.
         * <p>
         * Matlab example:
         * 
         * <pre>
         * % Load the images for channel DAPI of well H10 and tile 3 of plate P005 in space SPACE
         * imginfo=OpenBISScreeningML.loadImages('/SPACE/P005', 8, 10, 3, 'DAPI')
         * % Get the channel names of all locations
         * imginfo(2,:,1)
         * % Show the second image (assuming there are at least two images)
         * imtool(imginfo(1,2))
         * </pre>
         * 
         * @param plate The augmented plate code
         * @param row The row in the plate to get the images for
         * @param col The column in the plate to get the images for
    
         * @param tile The tile number. Starts with 0.
    
         * @param channels The names of the channels to get the images for
         * @return <code>{ names of TIFF files, image annotation }</code>
         *         <p>
         *         Each of <code>names of TIFF files</code> and <code>image annotation</code> is a
         *         vector of length of the number of images.
         *         <p>
         *         <code>image annotation</code> contains
         *         <code>{ channel name, tile number, plate well description, 
         *         plate augmented code, plate perm id, plate space code, plate code, row, column, 
         *         experiment augmented code, experiment perm id, experiment space code, 
         *         experiment project code, experiment code, data set code }</code>
         */
        public static Object[][][] loadImages(String plate, int row, int col, final int tile,
                String[] channels)
        {
    
            return loadRawImages(plate, row, col, channels, createSingleTileIterator(tile));
        }
    
        /**
         * Has the same effect as {@link #loadImages(String, int, int, int, String[])}, but instead of
         * loading raw images loads their segmentation results if available.
    
    tpylak's avatar
    tpylak committed
         * 
    
         * @param objectNamesOrNull The names of the segmentation objects to get the images for. If
         *            <code>null</code> (or <code>[]</code> in MatLab) no restriction applies.
         * @param analysisProcedureOrNull The analysis procedure used to filter the result. That is, the
         *            result is restricted to feature vector data sets with a value of property
         *            <code>ANALYSIS_PROCEDURE</code> as specified. If <code>null</code> (or
         *            <code>[]</code> in MatLab) no restriction applies.
    
         */
        public static Object[][][] loadSegmentationImages(String plate, int row, int col,
    
                final int tile, String[] objectNamesOrNull, String analysisProcedureOrNull)
    
            return loadSegmentationImages(plate, row, col, objectNamesOrNull,
                    createSingleTileIterator(tile), analysisProcedureOrNull);
    
        }
    
        private static ITileNumberIterable createSingleTileIterator(final int tile)
        {
            return new ITileNumberIterable()
    
                {
                    public void setMaximumNumberOfTiles(int numberOfTiles)
                    {
                        if (tile >= numberOfTiles)
                        {
                            throw new IllegalArgumentException("Tile number " + tile
                                    + " is not less than number of tiles " + numberOfTiles + ".");
                        }
                    }
    
                    public int getMaximumNumberOfTiles()
                    {
                        return 1;
                    }
    
                    public Iterator<Integer> iterator()
                    {
                        return new Iterator<Integer>()
                            {
                                private boolean delivered;
    
                                public boolean hasNext()
                                {
                                    return delivered == false;
                                }
    
                                public Integer next()
                                {
                                    delivered = true;
                                    return tile;
                                }
    
                                public void remove()
                                {
                                    throw new UnsupportedOperationException();
                                }
                            };
                    }
    
                };
        }
    
        /**
         * Lists all segmentation objects for the <var>plate</var>.
         * <p>
         * Matlab example:
         * 
         * <pre>
         * % Get the segmentation objects of plate P005 in space SPACE.
    
         * segmentationObjects = OpenBISScreeningML.listSegmentationObjects('/SPACE/P005', []);
         * % Get the segmentation objects of plate P005 in space SPACE for data sets calculated 
         * % with analysis procedure AP-42.
         * segmentationObjects = OpenBISScreeningML.listSegmentationObjects('/SPACE/P005', 'AP-42');
    
         * % How many segmentation objects do we have?
         * length(segmentationObjects)
         * % What is the name of segmentation objects 1?
         * segmentationObjects(1)
         * </pre>
         * 
         * @param plate augmented code of the plate
    
         * @param analysisProcedureOrNull The analysis procedure used to filter the result. That is, the
         *            result is restricted to feature vector data sets with a value of property
         *            <code>ANALYSIS_PROCEDURE</code> as specified. If <code>null</code> (or
         *            <code>[]</code> in MatLab) no restriction applies.
    
         * @return Each row contains information about one segmentation object. Currently the only
         *         information available is the segmentation object name.
         */
    
        public static Object[][] listSegmentationObjects(String plate, String analysisProcedureOrNull)
    
        {
            checkLoggedIn();
            Plate plateId = getPlate(plate);
    
            final List<ImageDatasetReference> imageDatasets =
                    listSegmentationImageDatasets(plateId, analysisProcedureOrNull);
    
            if (imageDatasets.isEmpty())
            {
                return new Object[0][];
            }
            return extractChannels(imageDatasets.get(0));
    
        private static Object[][] extractChannels(ImageDatasetReference imageDatasetReference)
        {
            final List<ImageDatasetMetadata> meta =
                    openbis.listImageMetadata(Arrays.asList(imageDatasetReference));
            if (meta.isEmpty())
            {
                return new Object[0][];
            }
            final List<String> channels = getChannelCodes(meta);
            Object[][] result = new Object[channels.size()][1];
            for (int i = 0; i < result.length; ++i)
            {
                result[i][0] = channels.get(i);
            }
            return result;
        }
    
        private static Object[][][] loadRawImages(String plate, int row, int col, String[] channels,
    
                ITileNumberIterable tileNumberIterable)
    
            final Plate plateId = getPlate(plate);
    
            final List<ImageDatasetReference> imageDatasets = listRawImageDatasets(plateId);
    
            return loadImages(plateId, imageDatasets, row, col, channels, tileNumberIterable);
        }
    
        private static Object[][][] loadSegmentationImages(String plate, int row, int col,
    
                String[] channelsOrNull, ITileNumberIterable tileNumberIterable,
                String analysisProcedureOrNull)
    
        {
            checkLoggedIn();
            final Plate plateId = getPlate(plate);
    
            final List<ImageDatasetReference> imageDatasets =
                    listSegmentationImageDatasets(plateId, analysisProcedureOrNull);
            return loadImages(plateId, imageDatasets, row, col, channelsOrNull, tileNumberIterable);
    
        }
    
        private static Object[][][] loadImages(Plate plate, List<ImageDatasetReference> imageDatasets,
    
                int row, int col, String[] channelsOrNull, ITileNumberIterable tileNumberIterable)
    
            final List<ImageDatasetMetadata> meta = openbis.listImageMetadata(imageDatasets);
            if (meta.isEmpty())
            {
                return new Object[][][]
                    { new Object[0][], new Object[0][] };
            }
    
            if (channelsOrNull == null || channelsOrNull.length == 0)
    
    tpylak's avatar
    tpylak committed
                imageChannels = getChannelCodes(meta);
    
                imageChannels = Arrays.asList(channelsOrNull);
    
            final List<ImageReferenceAndFile> imageReferencesAndFiles =
    
                    new ArrayList<ImageReferenceAndFile>(imageDatasets.size());
    
            final Object[][][] result = new Object[2][][];
    
            tileNumberIterable.setMaximumNumberOfTiles(meta.get(0).getNumberOfTiles());
            int numberOfTiles = tileNumberIterable.getMaximumNumberOfTiles();
            result[0] = new Object[imageDatasets.size() * imageChannels.size() * numberOfTiles][1];
            result[1] = new Object[imageDatasets.size() * imageChannels.size() * numberOfTiles][15];
    
            int dsIdx = 0;
            int resultIdx = 0;
            for (ImageDatasetReference ds : imageDatasets)
            {
                for (String channel : imageChannels)
                {
    
                    for (Integer tile : tileNumberIterable)
    
                    {
                        final PlateImageReference ref =
                                new PlateImageReference(row, col, tile, channel, ds);
    
                        final File imageFile = createImageFileName(plate, ref);
    
                        imageReferencesAndFiles.add(new ImageReferenceAndFile(ref, imageFile));
    
                        result[0][resultIdx][0] = imageFile.getPath();
    
                        PlateIdentifier plateIdentifier = ds.getPlate();
                        ExperimentIdentifier expIdentifier = ds.getExperimentIdentifier();
    
                        final Object[] annotations =
                                new Object[]
                                    { channel, tile,
    
                                            createPlateWellDescription(plateIdentifier, row, col),
                                            plateIdentifier.getAugmentedCode(),
                                            plateIdentifier.getPermId(),
                                            plateIdentifier.tryGetSpaceCode(),
                                            plateIdentifier.getPlateCode(), row, col,
                                            expIdentifier.getAugmentedCode(),
                                            expIdentifier.getPermId(), expIdentifier.getSpaceCode(),
                                            expIdentifier.getProjectCode(),
                                            expIdentifier.getExperimentCode(), ds.getPermId(), };
    
                        System.arraycopy(annotations, 0, result[1][resultIdx], 0, annotations.length);
                        resultIdx++;
                    }
                }
                dsIdx++;
            }
            try
            {
    
                loadImages(imageReferencesAndFiles);
    
            } catch (IOException ex)
            {
                throw new RuntimeException(ex);
            }
            return result;
        }
    
    
        private static List<ImageDatasetReference> listRawImageDatasets(final Plate plateId)
        {
            return openbis.listRawImageDatasets(Arrays.asList(plateId));
        }
    
    
        private static List<ImageDatasetReference> listSegmentationImageDatasets(final Plate plateId,
                String analysisProcedureOrNull)
    
            return openbis.listSegmentationImageDatasets(Arrays.asList(plateId),
                    analysisProcedureOrNull);
    
        /**
         * Saves images for a given list of image references (given by data set code, well position,
    
         * 
         * @throws IOException when reading images from the server or writing them to the files fails
         */
    
        private static void loadImages(List<ImageReferenceAndFile> imageReferencesAndFiles)
                throws IOException
    
            List<PlateImageReference> imageReferences = new ArrayList<PlateImageReference>();
            final Map<PlateImageReference, ImageReferenceAndFile> imageRefToFileMap =
                    new HashMap<PlateImageReference, ImageReferenceAndFile>();
            for (ImageReferenceAndFile imageReferenceAndFile : imageReferencesAndFiles)
            {
                PlateImageReference imageReference = imageReferenceAndFile.getImageReference();
                File file = loadedImages.get(imageReference);
                if (file == null)
                {
                    imageReferences.add(imageReference);
                    imageRefToFileMap.put(imageReference, imageReferenceAndFile);
                }
            }
    
            try
            {
                openbis.loadImages(imageReferences, new IImageOutputStreamProvider()
                    {
                        public OutputStream getOutputStream(PlateImageReference imageReference)
                                throws IOException
                        {
    
                            return imageRefToFileMap.get(imageReference).open();
    
                Collection<ImageReferenceAndFile> values = imageRefToFileMap.values();
                for (ImageReferenceAndFile imageReferenceAndFile : values)
                {
                    imageReferenceAndFile.close();
                    PlateImageReference imageReference = imageReferenceAndFile.getImageReference();
                    loadedImages.put(imageReference, imageReferenceAndFile.getImageFile());
                }
    
        private static File createImageFileName(Plate plate, PlateImageReference image)
        {
    
            final WellPosition well = image.getWellPosition();
            File imageDir = new File(temporarySessionDir, "images");
            imageDir.mkdirs();
            final File f =
    
                    new File(imageDir, "img_" + plate.getPlateCode() + "_" + image.getDatasetCode()
                            + "_row" + well.getWellRow() + "_col" + well.getWellColumn() + "_"
                            + image.getChannel() + "_tile" + image.getTile() + ".tiff");
    
        //
        // Feature matrix
        //
    
        /**
         * Returns the feature matrix of the specified features for all locations in
         * <var>experiment</var> (a location is one well position in one feature vector data set) in
         * <var>experiment</var> connected to <var>gene</var> in <code>[0]</code>, location annotations
         * in <code>[1]</code> and feature annotation in <code>[2]</code>.
         * <p>
         * Matlab example:
         * 
         * <pre>
    
         * % Get feature matrix for experiment /SPACE/PROJ/MYEXP for locations connected to GENENAME
         * fmatrix = OpenBISScreeningML.getFeatureMatrix('/SPACE/PROJ/MYEXP', 'GENENAME', [], []);
         * % Get feature matrix for features F1, F2 and F3 for 
    
         * % experiment /SPACE/PROJ/MYEXP for locations connected to GENENAME
    
         * fmatrix = OpenBISScreeningML.getFeatureMatrix('/SPACE/PROJ/MYEXP', 'GENENAME', [], {'F1' 'F2' 'F3'));
         * % Get feature matrix for features F1 and F2 for experiment /SPACE/PROJ/MYEXP for locations 
         * % connected to GENENAME calculated with analysis procedure AP-42.
         * fmatrix = OpenBISScreeningML.getFeatureMatrix('/SPACE/PROJ/MYEXP', 'GENENAME', 'AP-42', {'F1' 'F2'));
    
         * % Get the feature vector for the second location (assuming that there are at least two locations) 
         * % of third data set (assuming that there are at least three data sets)
         * fmatrix(1,:,2,3)
         * % Get the values of the fourth feature for all locations (assuming that there are at least 4 features) 
         * % of third data set (assuming that there are at least three data sets)
         * fmatrix(1,4,:,3)
         * % Get code of the fourth feature (assuming that there are at least 4 features)
         * fmatrix(3,4)
         * % Get the plate-well descriptions for the second location (assuming that there are at least two locations) 
         * % of third data set (assuming that there are at least three data sets)
         * fmatrix(2,2,3,:)
    
         * </pre>
         * 
         * @param experiment The augmented experiment code
    
         * @param gene The gene code (stored as material code in openBIS, usually it is gene id)
    
         * @param analysisProcedureOrNull The code of the analysis procedure used to calculate requested
         *            features. That is, the result is restricted to feature vector data sets with a
    
         *            value of property <code>ANALYSIS_PROCEDURE</code> as specified. If
         *            <code>null</code> (or <code>[]</code> in MatLab) no restriction applies.
    
         * @param featuresOrNull The codes of the features to contain the feature matrix. Unknown
         *            feature codes will be ignored. If <code>null</code> (or <code>[]</code> in MatLab)
         *            all features are returned.
    
         * @return a four dimensional matrix. The first dimension denotes the type in the following
         *         order: <code>{feature matrix, annotations per location, feature codes}</code>. The
         *         other dimensions depend on the value of the first dimension:
         *         <ol>
         *         <li>feature matrix: 2. dimension is feature vector, 3. dimension is location number,
         *         4. dimension is data set number. If for a particular location and a particular data
    
         *         set the corresponding feature value does not exists <code>NaN</code> will be
         *         returned. <li>annotations: 2. dimension is location number, 3. dimension is data set
         *         number, 4. dimension is location annotations in the following order: <code>{plate
         *         well description, plate augmented code, plate perm id, plate space code, plate code,
         *         row, column, experiment augmented code, experiment perm id, experiment space code,
         *         experiment project code, experiment code, data set code, data set type}</code> <li>
         *         feature codes: 2. dimension is feature codes in alphabetical order. 3. and 4.
         *         dimension are meaningless (i.e. they have length one)
    
        public static Object[][][][] getFeatureMatrix(String experiment, String gene,
                String analysisProcedureOrNull, String[] featuresOrNull)
    
        {
            checkLoggedIn();
            final ExperimentIdentifier experimentId = experimentCodeToExperimentMap.get(experiment);
            if (experimentId == null)
            {
                throw new RuntimeException("No experiment with that code found.");
            }
            final List<Plate> experimentPlates = experimentToPlateMap.get(experiment);
            if (experimentPlates == null || experimentPlates.isEmpty())
            {
    
                return new Object[][][][]
                    { new Object[0][][], new Object[0][][], new Object[0][][] };
    
            }
            final List<FeatureVectorWithDescription> featureVectors =
                    openbis.loadFeaturesForPlateWells(experimentId, new MaterialIdentifier(
    
                            MaterialTypeIdentifier.GENE, gene), analysisProcedureOrNull,
    
                            (featuresOrNull == null) ? null : Arrays.asList(featuresOrNull));
    
            return getFeatureMatrix(featureVectors);
    
        }
    
        /**
         * Returns the feature matrix of the specified features for all locations (a location is one
         * well position in one feature vector data set) in <var>experiment</var> connected to
         * <var>gene</var> in <code>[0]</code>, location annotations in <code>[1]</code> and feature
         * annotation in <code>[2]</code>.
         * <p>
         * Matlab example:
         * 
         * <pre>
    
         * % Get feature matrix for GENENAME
         * fmatrix = OpenBISScreeningML.getFeatureMatrix('GENENAME', [], []);
    
         * % Get feature matrix for features FEATURE1, FEATURE2 and FEATURE3 for GENENAME
    
         * fmatrix = OpenBISScreeningML.getFeatureMatrix('GENENAME', [], {'FEATURE1' 'FEATURE2' 'FEATURE3'});
         * % Get feature matrix for features FEATURE1 and FEATURE2 for GENENAME 
         * % computed with analysis procedure AP-42
         * fmatrix = OpenBISScreeningML.getFeatureMatrix('GENENAME', 'AP-42', {'FEATURE1' 'FEATURE2'});
    
         * % Get the feature vector for the second location (assuming that there are at least two locations) 
         * % of third data set (assuming that there are at least three data sets)
         * fmatrix(1,:,2,3)
         * % Get the values of the fourth feature for all locations (assuming that there are at least 4 features) 
         * % of third data set (assuming that there are at least three data sets)
         * fmatrix(1,4,:,3)
         * % Get code of the fourth feature (assuming that there are at least 4 features)
         * fmatrix(3,4)
         * % Get the plate-well descriptions for the second location (assuming that there are at least two locations) 
         * % of third data set (assuming that there are at least three data sets)
         * fmatrix(2,2,3,:)
    
         * @param gene The gene code (stored as material code in openBIS, usually it is gene id)
    
         * @param analysisProcedureOrNull The code of the analysis procedure used to calculate requested
         *            features. That is, the result is restricted to feature vector data sets with a
         *            value of property <code>ANALYSIS_PROCEDURE</code> as specified. If
         *            <code>null</code> (or <code>[]</code> in MatLab) no restriction applies.
         * @param featuresOrNull The codes of the features to contain the feature matrix. Unknown
         *            feature codes will be ignored. If <code>null</code> (or <code>[]</code> in MatLab)
         *            all features are returned.
    
         * @return a four dimensional matrix. The first dimension denotes the type in the following
         *         order: <code>{feature matrix, annotations per location, feature codes}</code>. The
         *         other dimensions depend on the value of the first dimension:
         *         <ol>
         *         <li>feature matrix: 2. dimension is feature vector, 3. dimension is location number,
         *         4. dimension is data set number. If for a particular location and a particular data
    
         *         set the corresponding feature value does not exists <code>NaN</code> will be
         *         returned. <li>annotations: 2. dimension is location number, 3. dimension is data set
         *         number, 4. dimension is location annotations in the following order: <code>{plate
         *         well description, plate augmented code, plate perm id, plate space code, plate code,
         *         row, column, experiment augmented code, experiment perm id, experiment space code,
         *         experiment project code, experiment code, data set code, data set type}</code> <li>
         *         feature codes: 2. dimension is feature codes in alphabetical order. 3. and 4.
         *         dimension are meaningless (i.e. they have length one)
    
        public static Object[][][][] getFeatureMatrix(String gene, String analysisProcedureOrNull,
                String[] featuresOrNull)
    
        {
            checkLoggedIn();
            final List<FeatureVectorWithDescription> featureVectors =
                    openbis.loadFeaturesForPlateWells(new MaterialIdentifier(
    
                            MaterialTypeIdentifier.GENE, gene), analysisProcedureOrNull,
                            (featuresOrNull == null) ? null : Arrays.asList(featuresOrNull));
    
            return getFeatureMatrix(featureVectors);
        }
    
        private static Object[][][][] getFeatureMatrix(
                final List<FeatureVectorWithDescription> featureVectors)
        {
            final Object[][][][] result = new Object[3][][][];
    
            List<String> featureCodes = getFeatureCodes(featureVectors);
            Map<String, Integer> featureCodeToIndexMap = new HashMap<String, Integer>();
            result[2] = new Object[featureCodes.size()][1][1];
            for (int i = 0; i < featureCodes.size(); ++i)
    
                String code = featureCodes.get(i);
                result[2][i][0][0] = code;
                featureCodeToIndexMap.put(code, i);
    
            IndexSet<String> dataSetCodes = new IndexSet<String>();
            IndexSet<WellPosition> wellPositions = new IndexSet<WellPosition>();
            for (FeatureVectorWithDescription featureVector : featureVectors)
    
                WellPosition wellPosition = featureVector.getWellPosition();
                wellPositions.add(wellPosition);
                dataSetCodes.add(featureVector.getDatasetWellReference().getDatasetCode());
    
            result[0] = new Object[featureCodes.size()][wellPositions.size()][dataSetCodes.size()];
    
            result[1] = new Object[wellPositions.size()][dataSetCodes.size()][14];
    
            for (FeatureVectorWithDescription vector : featureVectors)
            {
                WellPosition wellPosition = vector.getWellPosition();
                int wellIndex = wellPositions.getIndex(wellPosition);
                int[] featureIndexes = createFeatureIndexes(vector, featureCodeToIndexMap);
                FeatureVectorDatasetWellReference dataSetRef = vector.getDatasetWellReference();
                int dataSetIndex = dataSetCodes.getIndex(dataSetRef.getDatasetCode());
                copyFeatureValuesInto(result, wellIndex, dataSetIndex, featureIndexes, vector);
                copyAnnotationsInto(result, wellIndex, dataSetIndex, dataSetRef, vector);
            }
            return replaceFeatureNullValuesByNaN(result);
    
        /**
         * Returns the feature matrix of the specified features for all locations (a location is one
    
         * well position in one feature vector data set) of all feature vector data sets created by
         * specified analysis procedure of the given <var>plate</var> in <code>[0]</code>, location
         * annotations in <code>[1]</code> and feature annotation in <code>[2]</code>.
    
         * <p>
         * Matlab example:
    
         * <pre>
    
         * % Get feature matrix for PLATECODE
         * fmatrix = OpenBISScreeningML.getFeatureMatrixForPlate('PLATECODE', [], []);
         * % Get feature matrix for features FEATURE1, FEATURE2 and FEATURE3 for PLATECODE.
         * fmatrix = OpenBISScreeningML.getFeatureMatrixForPlate('PLATECODE', [], {'FEATURE1' 'FEATURE2' 'FEATURE3'});
         * % Get feature matrix for features FEATURE1 and FEATURE2 for PLATECODE calculated by analysis procedure AP-42.
         * fmatrix = OpenBISScreeningML.getFeatureMatrixForPlate('PLATECODE', 'AP-42', {'FEATURE1' 'FEATURE2'});
    
         * % Get the feature vector for the second location (assuming that there are at least two locations) 
         * % of third data set (assuming that there are at least three data sets)
         * fmatrix(1,:,2,3)
         * % Get the values of the fourth feature for all locations (assuming that there are at least 4 features) 
         * % of third data set (assuming that there are at least three data sets)
         * fmatrix(1,4,:,3)
         * % Get code of the fourth feature (assuming that there are at least 4 features)
         * fmatrix(3,4)
         * % Get the plate-well descriptions for the second location (assuming that there are at least two locations) 
         * % of third data set (assuming that there are at least three data sets)
         * fmatrix(2,2,3,:)
    
         * @param plate augmented code of the plate for which features should be loaded
    
         * @param analysisProcedureOrNull The code of the analysis procedure used to calculate requested
         *            features. That is, the result is restricted to feature vector data sets with a
    
         *            value of property <code>ANALYSIS_PROCEDURE</code> as specified. If
         *            <code>null</code> (or <code>[]</code> in MatLab) no restriction applies.
    
         * @param featuresOrNull The codes of the features to contain the feature matrix. Unknown
         *            feature codes will be ignored. If <code>null</code> (or <code>[]</code> in MatLab)
         *            all features are returned.
    
         * @return a four dimensional matrix. The first dimension denotes the type in the following
         *         order: <code>{feature matrix, annotations per location, feature codes}</code>. The
         *         other dimensions depend on the value of the first dimension:
         *         <ol>
         *         <li>feature matrix: 2. dimension is feature vector, 3. dimension is location number,
         *         4. dimension is data set number. If for a particular location and a particular data
    
         *         set the corresponding feature value does not exists <code>NaN</code> will be
         *         returned. <li>annotations: 2. dimension is location number, 3. dimension is data set
         *         number, 4. dimension is location annotations in the following order: <code>{plate
         *         well description, plate augmented code, plate perm id, plate space code, plate code,
         *         row, column, experiment augmented code, experiment perm id, experiment space code,
         *         experiment project code, experiment code, data set code, data set type}</code> <li>
         *         feature codes: 2. dimension is feature codes in alphabetical order. 3. and 4.
         *         dimension are meaningless (i.e. they have length one)
    
        public static Object[][][][] getFeatureMatrixForPlate(String plate,
                String analysisProcedureOrNull, String[] featuresOrNull)
    
        {
            checkLoggedIn();
    
            final List<FeatureVectorDataset> dataSets =
    
                    openbis.loadFeaturesForPlates(
                            Arrays.asList(PlateIdentifier.createFromAugmentedCode(plate)),
    
                            (featuresOrNull == null) ? null : Arrays.asList(featuresOrNull),
                            analysisProcedureOrNull);
    
            final Object[][][][] result = new Object[3][][][];
            if (dataSets.isEmpty())
    
            {
                return result;
            }
    
            List<String> featureCodes = getFeatureCodes(dataSets);
            Map<String, Integer> featureCodeToIndexMap = new HashMap<String, Integer>();
            result[2] = new Object[featureCodes.size()][1][1];
            for (int i = 0; i < featureCodes.size(); ++i)
    
                String code = featureCodes.get(i);
                result[2][i][0][0] = code;
                featureCodeToIndexMap.put(code, i);
    
            IndexSet<WellPosition> wellPositions = new IndexSet<WellPosition>();
            for (FeatureVectorDataset dataSet : dataSets)
    
                List<FeatureVector> featureVectors = dataSet.getFeatureVectors();
                for (FeatureVector featureVector : featureVectors)
    
                    WellPosition wellPosition = featureVector.getWellPosition();
                    wellPositions.add(wellPosition);
    
            int numberOfDataSets = dataSets.size();
    
            result[0] = new Object[featureCodes.size()][wellPositions.size()][numberOfDataSets];
    
            result[1] = new Object[wellPositions.size()][numberOfDataSets][14];
    
            for (int dataSetIndex = 0; dataSetIndex < numberOfDataSets; dataSetIndex++)
    
                FeatureVectorDataset dataSet = dataSets.get(dataSetIndex);
                FeatureVectorDatasetReference dataSetRef = dataSet.getDataset();
                int[] featureIndexes = createFeatureIndexes(dataSet, featureCodeToIndexMap);
                for (FeatureVector vector : dataSet.getFeatureVectors())
                {
                    WellPosition wellPosition = vector.getWellPosition();
                    int wellIndex = wellPositions.getIndex(wellPosition);
                    copyFeatureValuesInto(result, wellIndex, dataSetIndex, featureIndexes, vector);
                    copyAnnotationsInto(result, wellIndex, dataSetIndex, dataSetRef, vector);
                }
            }
            return replaceFeatureNullValuesByNaN(result);
        }
    
        private static Object[][][][] replaceFeatureNullValuesByNaN(final Object[][][][] result)
        {
            Double nan = Double.NaN;
            for (int i = 0; i < result[0].length; i++)
            {
                Object[][] r0i = result[0][i];
                for (int j = 0; j < r0i.length; j++)
                {
                    Object[] r0ij = r0i[j];
                    for (int k = 0; k < r0ij.length; k++)
                    {
                        if (r0ij[k] == null)
                        {
                            r0ij[k] = nan;
                        }
                    }
                }
    
        private static int[] createFeatureIndexes(IFeatureCodesProvider dataSet,
                Map<String, Integer> featureCodeToIndexMap)
    
    tpylak's avatar
    tpylak committed
        {
    
            List<String> codes = dataSet.getFeatureCodes();
            int[] featureIndexes = new int[codes.size()];
            for (int i = 0; i < featureIndexes.length; i++)
            {
                featureIndexes[i] = featureCodeToIndexMap.get(codes.get(i));
            }
            return featureIndexes;
        }
    
        private static void copyFeatureValuesInto(final Object[][][][] result, int wellIndex,
                int dataSetIndex, int[] featureIndexes, FeatureVector vector)
        {
            List<Object> valueObjects = vector.getValueObjects();
            for (int i = 0, n = valueObjects.size(); i < n; i++)
            {
                int featureIndex = featureIndexes[i];
                try
                {
                    Object[][] f = result[0][featureIndex];
                    Object[] d = f[wellIndex];
                    d[dataSetIndex] = valueObjects.get(i);
    
                    throw new RuntimeException(featureIndex + "." + wellIndex + "." + dataSetIndex, ex);
    
                }
            }
        }
    
        private static void copyAnnotationsInto(final Object[][][][] result, int wellIndex,
                int dataSetIndex, FeatureVectorDatasetReference dataSetRef, FeatureVector vector)
        {
            Object[] annotations =
                    new Object[]
                        { createPlateWellDescription(dataSetRef.getPlate(), vector),
                                dataSetRef.getPlate().getAugmentedCode(),
                                dataSetRef.getPlate().getPermId(),
                                dataSetRef.getPlate().tryGetSpaceCode(),
                                dataSetRef.getPlate().getPlateCode(),
                                vector.getWellPosition().getWellRow(),
                                vector.getWellPosition().getWellColumn(),
                                dataSetRef.getExperimentIdentifier().getAugmentedCode(),
                                dataSetRef.getExperimentIdentifier().getPermId(),
                                dataSetRef.getExperimentIdentifier().getSpaceCode(),
                                dataSetRef.getExperimentIdentifier().getProjectCode(),
                                dataSetRef.getExperimentIdentifier().getExperimentCode(),
    
                                dataSetRef.getDatasetCode(), dataSetRef.getDataSetType() };
    
            System.arraycopy(annotations, 0, result[1][wellIndex][dataSetIndex], 0, annotations.length);
        }
    
        private static List<String> getFeatureCodes(List<? extends IFeatureCodesProvider> dataSets)
        {
            Set<String> codes = new HashSet<String>();
            for (IFeatureCodesProvider featureVectorDataset : dataSets)
            {
                codes.addAll(featureVectorDataset.getFeatureCodes());
            }
            List<String> result = new ArrayList<String>(codes);
            Collections.sort(result);
            return result;
    
        /**
         * Returns the gene mapping for the given <var>plateCodes</var> in <code>[0]</code> and location
         * annotations in <code>[1]</code>.
         * <p>
         * One row in the matrix corresponds to one well.
         * <p>
         * Matlab example:
         * 
         * <pre>
         * % Get feature matrix for features FEATURE1, FEATURE2 and FEATURE for PLATECODE
         * genes = getGeneMappingForPlate('PLATECODE');
         * % Get the plate well location description of the 10th wells
         * loc2 = genes(2,10,1)
         * % Get the gene ids that are in the 10th well
         * geneIds = genes(1,10,:)
         * </pre>
         * 
         * @param platesCodes The augmented codes of the plates to get the mapping for
         * @return <code>{ gene ids, annotations per well }</code> where <code>gene ids</code> can be 0,
         *         1 or more gene ids. <code>annotations per location</code> contain: