From 03a5b744c84d7e91ed04f80e4c806a2148d59bb7 Mon Sep 17 00:00:00 2001 From: brinn <brinn> Date: Mon, 2 Aug 2010 15:51:20 +0000 Subject: [PATCH] add: OpenBISML and a jar file for the client that contains all necessary classes in one file SVN: 17325 --- screening/build/build.xml | 6 + screening/source/java/OpenBISML.java | 950 +++++++++++++++++++++++++++ 2 files changed, 956 insertions(+) create mode 100644 screening/source/java/OpenBISML.java diff --git a/screening/build/build.xml b/screening/build/build.xml index 11b76993df2..6e2490c2386 100644 --- a/screening/build/build.xml +++ b/screening/build/build.xml @@ -11,6 +11,7 @@ <property name="dist.screening-api" value="${dist}/screening_api" /> <property name="dist.screening-api.lib" value="${dist.screening-api}" /> <property name="dist.screening-api.jar" value="${dist.screening-api.lib}/openbis_screening_api.jar" /> + <property name="dist.screening-api-batteries-included.jar" value="${dist.screening-api.lib}/openbis_screening_api-batteries_included.jar" /> <property name="dist.screening-api.src" value="${dist.screening-api}/openbis_screening_api_source.zip" /> <property name="dist.screening-api.javadoc" value="${dist.screening-api}/doc" /> <property name="dist.screening-api.javadoc.zip" value="${dist.screening-api}/openbis_screening_api_javadoc.zip" /> @@ -137,6 +138,7 @@ <echo file="${build.info.file}">${version.number}:${revision.number}:${clean.flag}</echo> <recursive-jar destfile="${dist.screening-api.jar}"> <fileset dir="${classes.screening}"> + <include name="OpenBISML*.class" /> <include name="ch/systemsx/cisd/common/api/**/*.class" /> <exclude name="ch/systemsx/cisd/common/api/server/**/*.class" /> <include name="ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/**/*.class" /> @@ -169,6 +171,10 @@ <zipfileset src="${lib}/commons-codec/commons-codec.jar" /> <zipfileset src="${lib}/log4j/log4j.jar" /> </recursive-jar> + <recursive-jar destfile="${dist.screening-api-batteries-included.jar}"> + <zipfileset src="${dist.screening-api.lib}/spring-ext.jar" /> + <zipfileset src="${dist.screening-api.jar}" /> + </recursive-jar> <copy todir="${dist.screening-api}"> <fileset dir="${original.dist}/api" /> </copy> diff --git a/screening/source/java/OpenBISML.java b/screening/source/java/OpenBISML.java new file mode 100644 index 00000000000..4da3088323e --- /dev/null +++ b/screening/source/java/OpenBISML.java @@ -0,0 +1,950 @@ +/* + * Copyright 2010 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.IScreeningOpenbisServiceFacade; +import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ScreeningOpenbisServiceFacadeFactory; +import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ScreeningOpenbisServiceFacade.IImageOutputStreamProvider; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ExperimentIdentifier; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetReference; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorWithDescription; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ImageDatasetMetadata; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ImageDatasetReference; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.MaterialIdentifier; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.MaterialTypeIdentifier; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Plate; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifier; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateImageReference; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellPosition; + +/** + * Simple Matlab interface for openBIS for Screening. It is meant to be used in one Matlab + * session at a time, i.e. it is <i>not</i> multi-threading safe. + * <p> + * While written in Java, the API is idiomatic for Matlab, i.e. values are returned as + * multi-dimensional arrays. For the <code>get...</code> and <code>load...</code> methods the first + * index will contain the actual data, while the second index will contain per-row annotations. For + * <code>getFeatureMatrix</code>, the third index contains per-column annotations. This allows + * simple access with Matlab's slicing operator, see doc of e.g. {@link #getFeatureMatrix(String)}. + * <p> + * A typical Matlab session looks like: + * + * <pre> + * % Add the API jar file to the classpath + * javaaddpath('/home/brinn/matlab/openbis_screening_api-batteries_included.jar') + * % Login to server + * OpenBISML.login('user', 'secret', 'https://www.infectome.org') + * + * % ...perform calls on the server... + * + * % Logout to close the session on the server + * OpenBISML.logout() + * </pre> + * + * @author Bernd Rinn + */ +public class OpenBISML +{ + private static IScreeningOpenbisServiceFacade openbis = null; + + private static List<ExperimentIdentifier> experiments = null; + + private static List<Plate> plates = null; + + private static Map<String, List<Plate>> experimentToPlateMap = + new HashMap<String, List<Plate>>(); + + private static Map<String, ExperimentIdentifier> experimentCodeToExperimentMap = + new HashMap<String, ExperimentIdentifier>(); + + private static Map<String, Plate> plateCodeToPlateMap = new HashMap<String, Plate>(); + + private OpenBISML() + { + // Not to be constructed. + } + + // + // Versioning + // + + /** + * The version of the API. + */ + public static final String VERSION = "1"; + + /** + * The required version ("major.minor") of the screening API on the openBIS application server. + */ + public static final String REQUIRES_OPENBIS_AS_API = "1.2"; + + /** + * The required version ("major.minor") of the screening API on the openBIS datastore server. + */ + public static final String REQUIRES_OPENBIS_DSS_API = "1.1"; + + // + // Authentication methods + // + + /** + * Login to the openBIS server given as <var>url</var>. + * <p> + * Matlab example: + * + * <pre> + * OpenBISML.login('user', 'secret', 'https://www.infectome.org') + * </pre> + * + * @param user The user id on the server + * @param password The password on the server + * @param url The URL, e.g. <code>https://www.infectome.org</var> + */ + public static void login(String user, String password, String url) + { + openbis = ScreeningOpenbisServiceFacadeFactory.tryCreate(user, password, url); + if (openbis == null) + { + throw new RuntimeException("Login failed."); + } + experiments = openbis.listExperiments(); + experimentCodeToExperimentMap.clear(); + for (ExperimentIdentifier e : experiments) + { + experimentCodeToExperimentMap.put(e.getAugmentedCode(), e); + } + plates = openbis.listPlates(); + plateCodeToPlateMap.clear(); + experimentToPlateMap.clear(); + for (Plate p : plates) + { + final String plateCode = p.getAugmentedCode(); + plateCodeToPlateMap.put(plateCode, p); + final String experimentCode = p.getExperimentIdentifier().getAugmentedCode(); + List<Plate> experimentPlates = experimentToPlateMap.get(experimentCode); + if (experimentPlates == null) + { + experimentPlates = new ArrayList<Plate>(); + experimentToPlateMap.put(experimentCode, experimentPlates); + } + experimentPlates.add(p); + } + } + + /** + * Logs out and closes the session on the server. + * <p> + * Matlab example: + * + * <pre> + * OpenBISML.logout() + * </pre> + */ + public static void logout() + { + if (openbis == null) + { + return; + } + openbis.logout(); + openbis = null; + } + + // + // Information methods + // + + /** + * Lists all experiment. + * <p> + * Matlab example: + * + * <pre> + * % Get the experiments + * exps = OpenBISML.listExperiments(); + * % How many experiments do we have? + * length(exps) + * % Get all information about experiment 3 + * exp3 = exps(3,:) + * % Get the perm ids for all experiments + * permids = exps(:,2) + * </pre> + * + * @return Each row contains information about one plate: + * <p> + * <code>{ experiment augmented code, experiment perm id, experiment space code, + * experiment project code, experiment code }</code> + */ + public static Object[][] listExperiments() + { + checkLoggedIn(); + final Object[][] result = new Object[experiments.size()][5]; + for (int i = 0; i < experiments.size(); ++i) + { + final Object[] annotations = + new Object[] + { experiments.get(i).getAugmentedCode(), experiments.get(i).getPermId(), + experiments.get(i).getSpaceCode(), + experiments.get(i).getProjectCode(), + experiments.get(i).getExperimentCode() }; + System.arraycopy(annotations, 0, result[i], 0, annotations.length); + } + return result; + } + + /** + * Lists all plates. + * <p> + * Matlab example: + * + * <pre> + * % Get the plates + * plates = OpenBISML.listPlates(); + * % How many plates do we have? + * length(plates) + * % Get all information about plate 2 + * plate2 = plates(2,:) + * % Get the simple plate codes for all plates + * codes = plates(:,4) + * </pre> + * + * @return Each row contains information about one plate: + * <p> + * <code>{ plate augmented code, plate perm id, plate space code, plate code, + * experiment augmented code, experiment perm id, experiment space code, + * experiment project code, experiment code }</code> + */ + public static Object[][] listPlates() + { + checkLoggedIn(); + final Object[][] result = new Object[plates.size()][9]; + for (int i = 0; i < plates.size(); ++i) + { + final Object[] annotations = + new Object[] + { plates.get(i).getAugmentedCode(), plates.get(i).getPermId(), + plates.get(i).tryGetSpaceCode(), plates.get(i).getPlateCode(), + plates.get(i).getExperimentIdentifier().getAugmentedCode(), + plates.get(i).getExperimentIdentifier().getPermId(), + plates.get(i).getExperimentIdentifier().getSpaceCode(), + plates.get(i).getExperimentIdentifier().getProjectCode(), + plates.get(i).getExperimentIdentifier().getExperimentCode(), }; + System.arraycopy(annotations, 0, result[i], 0, annotations.length); + } + return result; + } + + /** + * Lists the plates of <var>experiment</var>. + * <p> + * Matlab example: + * + * <pre> + * % Get the plates of experiment MYEXP in project PROJ of space SPACE + * plates = OpenBISML.listPlates('/SPACE/PROJ/MYEXP'); + * % How many plates do we have? + * length(plates) + * % Get all information about plate 2 + * plate2 = plates(2,:) + * % Get the augmented plate codes for all plates + * acodes = plates(:,1) + * </pre> + * + * @param experiment The augmented code of the experiment to list the plates for + * @return Each row contains information about one plate: + * <p> + * <code>{ plate augmented code, plate perm id, plate space code, plate code, + * experiment augmented code, experiment perm id, experiment space code, + * experiment project code, experiment code }</code> + */ + public static Object[][] listPlates(String experiment) + { + checkLoggedIn(); + final List<Plate> experimentPlates = experimentToPlateMap.get(experiment); + if (experimentPlates == null) + { + throw new RuntimeException("No experiment with that code found."); + } + final Object[][] result = new Object[experimentPlates.size()][9]; + for (int i = 0; i < experimentPlates.size(); ++i) + { + final Object[] annotations = + new Object[] + { + experimentPlates.get(i).getAugmentedCode(), + plates.get(i).getPermId(), + experimentPlates.get(i).tryGetSpaceCode(), + plates.get(i).getPlateCode(), + experimentPlates.get(i).getExperimentIdentifier() + .getAugmentedCode(), + experimentPlates.get(i).getExperimentIdentifier().getPermId(), + experimentPlates.get(i).getExperimentIdentifier().getSpaceCode(), + experimentPlates.get(i).getExperimentIdentifier().getProjectCode(), + experimentPlates.get(i).getExperimentIdentifier() + .getExperimentCode(), }; + System.arraycopy(annotations, 0, result[i], 0, annotations.length); + } + return result; + } + + /** + * Lists all channels measured in <var>experiment</var>. + * <p> + * Matlab example: + * + * <pre> + * % Get the channels of experiment MYEXP in project PROJ of space SPACE + * channels = OpenBISML.listChannels('/SPACE/PROJ/MYEXP'); + * % How many channels do we have? + * length(channels) + * % What is the name of channel 1? + * channels(1) + * </pre> + * + * @param experiment The augmented code of the experiment to list the channels for + * @return Each row contains information about one channel. Currently the only information + * available is the channel name. + */ + public static Object[][] listChannels(String experiment) + { + checkLoggedIn(); + final List<Plate> experimentPlates = experimentToPlateMap.get(experiment); + if (experimentPlates == null) + { + throw new RuntimeException("No experiment with that code found."); + } + if (experimentPlates.isEmpty()) + { + return new Object[0][]; + } + final List<ImageDatasetReference> imageDatasets = + openbis.listImageDatasets(experimentPlates); + if (imageDatasets.isEmpty()) + { + return new Object[0][]; + } + final List<ImageDatasetMetadata> meta = + openbis.listImageMetadata(Arrays.asList(imageDatasets.get(0))); + if (meta.isEmpty()) + { + return new Object[0][]; + } + final List<String> channels = meta.get(0).getChannelNames(); + Object[][] result = new Object[channels.size()][1]; + for (int i = 0; i < result.length; ++i) + { + result[i][0] = channels.get(i); + } + return result; + } + + /** + * Lists all features computed for <var>experiment</var>. + * <p> + * Matlab example: + * + * <pre> + * % Get the features of experiment MYEXP in project PROJ of space SPACE + * features = OpenBISML.listFeatures('/SPACE/PROJ/MYEXP'); + * % How many features do we have? + * length(features) + * % What is the name of features 1? + * features(1) + * </pre> + * + * @param experiment The augmented code of the experiment to list the features for + * @return Each row contains information about one feature. Currently the only information + * available is the feature name. + */ + public static Object[][] listFeatures(String experiment) + { + checkLoggedIn(); + final List<Plate> experimentPlates = experimentToPlateMap.get(experiment); + if (experimentPlates == null) + { + throw new RuntimeException("No experiment with that code found."); + } + if (experimentPlates.isEmpty()) + { + return new Object[0][]; + } + final List<FeatureVectorDatasetReference> featureDatasets = + openbis.listFeatureVectorDatasets(experimentPlates); + if (featureDatasets.isEmpty()) + { + return new Object[0][]; + } + final List<String> features = + openbis.listAvailableFeatureNames(Arrays.asList(featureDatasets.get(0))); + Object[][] result = new Object[features.size()][1]; + for (int i = 0; i < result.length; ++i) + { + result[i][0] = features.get(i); + } + return result; + } + + // + // Images + // + + /** + * Loads the TIFF images for the given well location 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 = OpenBISML.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 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 of plate P005 in space SPACE + * imginfo=OpenBISML.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) + { + checkLoggedIn(); + final Plate plateId = plateCodeToPlateMap.get(plate); + if (plateId == null) + { + throw new RuntimeException("No plate with that code found."); + } + final List<String> imageChannels; + if (channels == null || channels.length == 0) + { + final List<ImageDatasetReference> imageDatasets = + openbis.listImageDatasets(Arrays.asList(plateId)); + final List<ImageDatasetMetadata> meta = openbis.listImageMetadata(imageDatasets); + if (meta.isEmpty()) + { + return new Object[][][] + { new Object[0][], new Object[0][] }; + } + imageChannels = meta.get(0).getChannelNames(); + } else + { + imageChannels = Arrays.asList(channels); + } + final List<ImageDatasetReference> imageDatasets = + openbis.listImageDatasets(Arrays.asList(plateId)); + if (imageDatasets.isEmpty()) + { + return new Object[][][] + { new Object[0][], new Object[0][] }; + } + final List<PlateImageReference> imageReferences = + new ArrayList<PlateImageReference>(imageDatasets.size()); + final List<ImageDatasetMetadata> meta = openbis.listImageMetadata(imageDatasets); + if (meta.isEmpty()) + { + return new Object[][][] + { new Object[0][], new Object[0][] }; + } + final List<File> imageFiles = + new ArrayList<File>(imageDatasets.size() * imageChannels.size() + * meta.get(0).getNumberOfTiles()); + final Object[][][] result = new Object[2][][]; + result[0] = + new Object[imageDatasets.size() * imageChannels.size() + * meta.get(0).getNumberOfTiles()][1]; + result[1] = + new Object[imageDatasets.size() * imageChannels.size() + * meta.get(0).getNumberOfTiles()][15]; + int dsIdx = 0; + int resultIdx = 0; + for (ImageDatasetReference ds : imageDatasets) + { + final ImageDatasetMetadata m = meta.get(dsIdx); + for (String channel : imageChannels) + { + for (int tile = 0; tile < m.getNumberOfTiles(); ++tile) + { + final PlateImageReference ref = + new PlateImageReference(row, col, tile, channel, ds); + imageReferences.add(ref); + final File imageFile = createImageFileName(plateId, ref); + imageFiles.add(imageFile); + result[0][resultIdx][0] = imageFile.getPath(); + final Object[] annotations = + new Object[] + { channel, tile, + createPlateWellDescription(ds.getPlate(), row, col), + ds.getPlate().getAugmentedCode(), + ds.getPlate().getPermId(), ds.getPlate().tryGetSpaceCode(), + ds.getPlate().getPlateCode(), row, col, + ds.getExperimentIdentifier().getAugmentedCode(), + ds.getExperimentIdentifier().getPermId(), + ds.getExperimentIdentifier().getSpaceCode(), + ds.getExperimentIdentifier().getProjectCode(), + ds.getExperimentIdentifier().getExperimentCode(), + ds.getPermId(), }; + System.arraycopy(annotations, 0, result[1][resultIdx], 0, annotations.length); + resultIdx++; + } + } + dsIdx++; + } + try + { + loadImages(imageReferences, imageFiles); + } catch (IOException ex) + { + throw new RuntimeException(ex); + } + return result; + } + + /** + * Saves images for a given list of image references (given by data set code, well position, + * channel and tile) in the specified files.<br> + * The number of image references has to be the same as the number of files. + * + * @throws IOException when reading images from the server or writing them to the files fails + */ + private static void loadImages(List<PlateImageReference> imageReferences, + List<File> imageOutputFiles) throws IOException + { + final Map<PlateImageReference, OutputStream> imageRefToFileMap = + createImageToFileMap(imageReferences, imageOutputFiles); + try + { + openbis.loadImages(imageReferences, new IImageOutputStreamProvider() + { + public OutputStream getOutputStream(PlateImageReference imageReference) + throws IOException + { + return imageRefToFileMap.get(imageReference); + } + }); + } finally + { + closeOutputStreams(imageRefToFileMap.values()); + } + } + + private static void closeOutputStreams(Collection<OutputStream> streams) throws IOException + { + for (OutputStream stream : streams) + { + stream.close(); + } + } + + private static Map<PlateImageReference, OutputStream> createImageToFileMap( + List<PlateImageReference> imageReferences, List<File> imageOutputFiles) + throws FileNotFoundException + { + assert imageReferences.size() == imageOutputFiles.size() : "there should be one file specified for each image reference"; + final Map<PlateImageReference, OutputStream> map = + new HashMap<PlateImageReference, OutputStream>(); + for (int i = 0; i < imageReferences.size(); i++) + { + OutputStream out = + new BufferedOutputStream(new FileOutputStream(imageOutputFiles.get(i))); + map.put(imageReferences.get(i), out); + } + return map; + } + + private static File createImageFileName(Plate plate, PlateImageReference image) + { + try + { + final WellPosition well = image.getWellPosition(); + final File f = + File.createTempFile("img_", "_" + plate.getPlateCode() + "_" + + image.getDatasetCode() + "_row" + well.getWellRow() + "_col" + + well.getWellColumn() + "_channel" + image.getChannel() + "_tile" + + image.getTile() + ".tiff"); + f.deleteOnExit(); + return f; + } catch (IOException ex) + { + throw new RuntimeException(ex); + } + } + + // + // Feature matrix + // + + /** + * Returns the feature matrix of all features for all locations in <var>experiment</var> (a + * location is one well position in one feature vector data set) connected to <var>gene</var> in + * <code>[0]</code>, location annotations in <code>[1]</code> and feature annotation in + * <code>[2]</code>. + * <p> + * One row in the matrix corresponds to one location (i.e. one well and one feature vector + * dataset), one column corresponds to one feature. + * <p> + * Matlab example: + * + * <pre> + * % Get feature matrix for experiment /SPACE/PROJ/MYEXP for locations connected to GENENAME + * fmatrix = OpenBISML.getFeatureMatrix('/SPACE/PROJ/MYEXP', 'GENENAME'); + * % Get the feature vector for the second location (assuming there are at least two locations) + * loc2 = fmatrix(1,2,:) + * % Get the values of the fifth feature for all locations (assuming there are at least 5 features) + * feature5 = fmatrix(1,:,5) + * % What are the features? + * featureNames = fmatrix(3,:) + * % Get the plate-well descriptions of the locations + * locationDescriptions = fmatrix(2,:,1) + * </pre> + * + * @param experiment The augmented experiment code + * @param gene The gene name as stored as material code in openBIS + * @return <code>{ feature matrix, annotations per location, feature names }</code> where + * <code>annotations per location</code> contain: + * <p> + * <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 }</code> + */ + public static Object[][][] getFeatureMatrix(String experiment, String gene) + { + return getFeatureMatrix(experiment, gene, (String[]) null); + } + + /** + * 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> + * One row in the matrix corresponds to one location (i.e. one well and one feature vector + * dataset), one column corresponds to one feature. + * <p> + * Matlab example: + * + * <pre> + * % Get feature matrix for features FEATURE1, FEATURE2 and FEATURE for + * % experiment /SPACE/PROJ/MYEXP for locations connected to GENENAME + * fmatrix = OpenBISML.getFeatureMatrix('/SPACE/PROJ/MYEXP', 'GENENAME', ('FEATURE1','FEATURE2','FEATURE3')); + * % Get the feature vector for the second location (assuming there are at least two locations) + * loc2 = fmatrix(1,2,:) + * % Get the values of the fourth feature for all locations (assuming there are at least 4 features) + * feature5 = fmatrix(1,:,4) + * % What are the features? + * featureNames = fmatrix(3,:) + * % Get the plate-well descriptions of the locations + * locationDescriptions = fmatrix(2,:,1) + * </pre> + * + * @param experiment The augmented experiment code + * @param gene The gene name as stored as material code + * @param features The names of the features to contain the feature matrix + * @return <code>{ feature matrix, annotations per location, feature names }</code> where + * <code>annotations per location</code> contain: + * <p> + * <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 }</code> + */ + public static Object[][][] getFeatureMatrix(String experiment, String gene, String[] features) + { + 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), (features == null) ? null : Arrays + .asList(features)); + final List<String> featureNameList = + featureVectors.get(featureVectors.size() - 1).getFeatureNames(); + final Object[][][] result = new Object[3][][]; + if (featureVectors.isEmpty()) + { + return result; + } + result[0] = new Object[featureVectors.size()][featureNameList.size()]; + result[1] = new Object[featureVectors.size()][13]; + int resultIdx = 0; + for (FeatureVectorWithDescription f : featureVectors) + { + arraycopy(f.getValues(), result[0][resultIdx]); + final Object[] annotations = + new Object[] + { + createPlateWellDescription(f), + f.getDatasetWellReference().getPlate().getAugmentedCode(), + f.getDatasetWellReference().getPlate().getPermId(), + f.getDatasetWellReference().getPlate().tryGetSpaceCode(), + f.getDatasetWellReference().getPlate().getPlateCode(), + f.getWellPosition().getWellRow(), + f.getWellPosition().getWellColumn(), + f.getDatasetWellReference().getExperimentIdentifier() + .getAugmentedCode(), + f.getDatasetWellReference().getExperimentIdentifier().getPermId(), + f.getDatasetWellReference().getExperimentIdentifier() + .getSpaceCode(), + f.getDatasetWellReference().getExperimentIdentifier() + .getProjectCode(), + f.getDatasetWellReference().getExperimentIdentifier() + .getExperimentCode(), + f.getDatasetWellReference().getDatasetCode(), }; + System.arraycopy(annotations, 0, result[1][resultIdx], 0, annotations.length); + resultIdx++; + } + result[2] = new Object[featureNameList.size()][1]; + for (int i = 0; i < featureNameList.size(); ++i) + { + result[2][i][0] = featureNameList.get(i); + } + return result; + } + + /** + * Returns the feature matrix of all features for all locations (a location is one well position + * in one feature vector data set) connected to <var>gene</var> in <code>[0]</code>, location + * annotations in <code>[1]</code> and feature annotation in <code>[2]</code>. + * <p> + * One row in the matrix corresponds to one location (i.e. one well and one feature vector + * dataset), one column corresponds to one feature. + * <p> + * Matlab example: + * + * <pre> + * % Get feature matrix for GENENAME + * fmatrix = OpenBISML.getFeatureMatrix('GENENAME'); + * % Get the feature vector for the second location (assuming there are at least two locations) + * loc2 = fmatrix(1,2,:) + * % Get the values of the fifth feature for all locations (assuming there are at least 5 features) + * feature5 = fmatrix(1,:,5) + * % What are the features? + * featureNames = fmatrix(3,:) + * % Get the plate-well descriptions of the locations + * locationDescriptions = fmatrix(2,:,1) + * </pre> + * + * @param gene The gene name as stored as material code in openBIS + * @return <code>{ feature matrix, annotations per location, feature names }</code> where + * <code>annotations per location</code> contain: + * <p> + * <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 }</code> + */ + public static Object[][][] getFeatureMatrix(String gene) + { + return getFeatureMatrix(gene, (String[]) null); + } + + /** + * 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> + * One row in the matrix corresponds to one location (i.e. one well and one feature vector + * dataset), one column corresponds to one feature. + * <p> + * Matlab example: + * + * <pre> + * % Get feature matrix for features FEATURE1, FEATURE2 and FEATURE for GENENAME + * fmatrix = OpenBISML.getFeatureMatrix('GENENAME', ('FEATURE1','FEATURE2','FEATURE3')); + * % Get the feature vector for the second location (assuming there are at least two locations) + * loc2 = fmatrix(1,2,:) + * % Get the values of the fourth feature for all locations (assuming there are at least 4 features) + * feature5 = fmatrix(1,:,4) + * % What are the features? + * featureNames = fmatrix(3,:) + * % Get the plate-well descriptions of the locations + * locationDescriptions = fmatrix(2,:,1) + * </pre> + * + * @param gene The gene name as stored as material code + * @param features The names of the features to contain the feature matrix + * @return <code>{ feature matrix, annotations per location, feature names }</code> where + * <code>annotations per location</code> contain: + * <p> + * <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 }</code> + */ + public static Object[][][] getFeatureMatrix(String gene, String[] features) + { + checkLoggedIn(); + final List<FeatureVectorWithDescription> featureVectors = + openbis.loadFeaturesForPlateWells(new MaterialIdentifier( + MaterialTypeIdentifier.GENE, gene), (features == null) ? null : Arrays + .asList(features)); + final List<String> featureNameList = + featureVectors.get(featureVectors.size() - 1).getFeatureNames(); + final Object[][][] result = new Object[3][][]; + if (featureVectors.isEmpty()) + { + return result; + } + result[0] = new Object[featureVectors.size()][featureNameList.size()]; + result[1] = new Object[featureVectors.size()][13]; + int resultIdx = 0; + for (FeatureVectorWithDescription f : featureVectors) + { + arraycopy(f.getValues(), result[0][resultIdx]); + final Object[] annotations = + new Object[] + { + createPlateWellDescription(f), + f.getDatasetWellReference().getPlate().getAugmentedCode(), + f.getDatasetWellReference().getPlate().getPermId(), + f.getDatasetWellReference().getPlate().tryGetSpaceCode(), + f.getDatasetWellReference().getPlate().getPlateCode(), + f.getWellPosition().getWellRow(), + f.getWellPosition().getWellColumn(), + f.getDatasetWellReference().getExperimentIdentifier() + .getAugmentedCode(), + f.getDatasetWellReference().getExperimentIdentifier().getPermId(), + f.getDatasetWellReference().getExperimentIdentifier() + .getSpaceCode(), + f.getDatasetWellReference().getExperimentIdentifier() + .getProjectCode(), + f.getDatasetWellReference().getExperimentIdentifier() + .getExperimentCode(), + f.getDatasetWellReference().getDatasetCode(), }; + System.arraycopy(annotations, 0, result[1][resultIdx], 0, annotations.length); + resultIdx++; + } + result[2] = new Object[featureNameList.size()][1]; + for (int i = 0; i < featureNameList.size(); ++i) + { + result[2][i][0] = featureNameList.get(i); + } + return result; + } + + // + // Helper methods + // + + private static void arraycopy(double[] src, Object[] dest) + { + for (int i = 0; i < dest.length; ++i) + { + dest[i] = src[i]; + } + } + + private static String createPlateWellDescription(FeatureVectorWithDescription f) + { + return createPlateWellDescription(f.getDatasetWellReference().getPlate(), f + .getWellPosition().getWellRow(), f.getWellPosition().getWellColumn()); + } + + private static String createPlateWellDescription(PlateIdentifier p, int row, int col) + { + return p.getPlateCode() + ":" + translateRowNumberIntoLetterCode(row) + col; + } + + /** + * Translates a row number into letter code. Thus, 1 -> A, 2 -> B, 26 -> Z, 27 -> AA, 28 -> AB, + * etc. + */ + private static String translateRowNumberIntoLetterCode(int rowNumber) + { + int rowIndex = rowNumber - 1; + String code = ""; + while (rowIndex >= 0) + { + code = (char) (rowIndex % 26 + 'A') + code; + rowIndex = rowIndex / 26 - 1; + } + return code; + } + + private static void checkLoggedIn() + { + if (openbis == null) + { + throw new RuntimeException("Not logged in."); + } + } +} -- GitLab