diff --git a/screening/etc/service.properties b/screening/etc/service.properties index 014b948454598501ac86f21a464671cb256e285b..36f93e28c1d2255367867a7c87f4d5ce15cb5dc3 100644 --- a/screening/etc/service.properties +++ b/screening/etc/service.properties @@ -79,7 +79,7 @@ quiet-period = 3 # --------------------------------------------------------------------------- # Comma separated names of reporting plugins. Each plugin should have configuration properties prefixed with its name. -reporting-plugins = plate-image-reporter, plate-image-params-reporter, plate-image-analysis-merger, demo-reporter +reporting-plugins = plate-image-reporter, plate-image-params-reporter, plate-image-analysis-merger, plate-image-analysis-graph, demo-reporter # Label of the plugin which will be shown for the users. demo-reporter.label = Show Dataset Size @@ -113,6 +113,12 @@ plate-image-analysis-merger.dataset-types = HCS_IMAGE_ANALYSIS_DATA plate-image-analysis-merger.class = ch.systemsx.cisd.openbis.dss.generic.server.plugins.ImageAnalysisMergedRowsReportingPlugin plate-image-analysis-merger.properties-file = +plate-image-analysis-graph.label = Show Image Analysis Graphs +plate-image-analysis-graph.dataset-types = HCS_IMAGE_ANALYSIS_DATA +plate-image-analysis-graph.class = ch.systemsx.cisd.openbis.dss.generic.server.plugins.ImageAnalysisGraphReportingPlugin +plate-image-analysis-graph.servlet-path = datastore_server_graph/ +plate-image-analysis-graph.properties-file = etc/tabular-data-graph.properties + # --------------------------------------------------------------------------- # Comma separated names of processing plugins. Each plugin should have configuration properties prefixed with its name. @@ -134,13 +140,18 @@ hierarchical-storage-updater.hierarchy-root-dir = targets/hierarchical-store # --------------------------------------------------------------------------- # list of additional web servlets which will be exposed -plugin-services = screening-image-download-servlet +plugin-services = screening-image-download-servlet, tabular-data-graph-servlet # class of the web servlet #screening-image-download-servlet.class = ch.systemsx.cisd.openbis.dss.generic.server.MergingImagesDownloadServlet screening-image-download-servlet.class = ch.systemsx.cisd.openbis.dss.generic.server.SplittingImagesDownloadServlet # URL which will be mapped to this servlet screening-image-download-servlet.path = /datastore_server_screening/* +tabular-data-graph-servlet.class = ch.systemsx.cisd.openbis.dss.generic.server.TabularDataGraphServlet +# URL which will be mapped to this servlet +tabular-data-graph-servlet.path = /datastore_server_graph/* +tabular-data-graph-servlet.properties-file = etc/tabular-data-graph.properties + # --------------------------------------------------------------------------- # Comma separated names of processing threads. Each thread should have configuration properties prefixed with its name. diff --git a/screening/etc/tabular-data-graph.properties b/screening/etc/tabular-data-graph.properties new file mode 100644 index 0000000000000000000000000000000000000000..9c3080b91851b38697b87b2c6134516d45d59781 --- /dev/null +++ b/screening/etc/tabular-data-graph.properties @@ -0,0 +1,3 @@ +# ------------------------------------------------------------------ +# Properties File For Generating Graphs From Tabular Data +# ------------------------------------------------------------------ diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/TabularDataGraphGeneratorServlet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/TabularDataGraphGeneratorServlet.java deleted file mode 100644 index 95c58d2db477225a563bd1f23cb04ea780350ffc..0000000000000000000000000000000000000000 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/TabularDataGraphGeneratorServlet.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * 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. - */ - -package ch.systemsx.cisd.openbis.dss.generic.server; - -import java.io.IOException; -import java.util.Enumeration; -import java.util.Properties; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import ch.systemsx.cisd.common.exceptions.UserFailureException; -import ch.systemsx.cisd.openbis.dss.generic.server.graph.TabularDataGraphGenerator; -import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.DatasetFileLines; - -/** - * @author Chandrasekhar Ramakrishnan - */ -public class TabularDataGraphGeneratorServlet extends AbstractDatasetDownloadServlet -{ - - private static final long serialVersionUID = 1L; - - // Required servlet parameters - - public final static String DATASET_CODE_PARAM = "dataset"; - - public final static String GRAPH_TYPE_CODE = "type"; - - // Optional, but recommended servlet parameters - - public final static String IMAGE_WIDTH_PARAM = "w"; - - public final static String IMAGE_HEIGHT_PARAM = "h"; - - // Default values for optional parameters - public final static int DEFAULT_WIDTH = 300; - - public final static int DEFAULT_HEIGHT = 200; - - /** - * A utility class for dealing with the parameters required to generate an image from a - * chromatogram. This class makes sure all the required parameters are in the request (it throws - * exceptions otherwise), and it defaults values for all optional parameters if they are not in - * the request. - * - * @author Chandrasekhar Ramakrishnan - */ - private static class RequestParams - { - private final String sessionId; - - private final String datasetCode; - - private final String graphTypeCode; - - private final int width; - - private final int height; - - public RequestParams(HttpServletRequest request) - { - sessionId = getParam(request, SESSION_ID_PARAM); - datasetCode = getParam(request, DATASET_CODE_PARAM); - graphTypeCode = getParam(request, GRAPH_TYPE_CODE); - width = getIntParam(request, IMAGE_WIDTH_PARAM, DEFAULT_WIDTH); - height = getIntParam(request, IMAGE_HEIGHT_PARAM, DEFAULT_HEIGHT); - } - - private static int getIntParam(HttpServletRequest request, String paramName, - int defaultValue) - { - String value = request.getParameter(paramName); - if (value == null) - return defaultValue; - - try - { - return Integer.valueOf(value); - } catch (NumberFormatException e) - { - throw new UserFailureException("parameter " + paramName - + " should be an integer, but is: " + value); - } - } - - private static String getParam(final HttpServletRequest request, String paramName) - { - String value = request.getParameter(paramName); - if (value == null) - { - throw new UserFailureException("no value for the parameter " + paramName - + " found in the URL"); - } - return value; - } - - public String getSessionId() - { - return sessionId; - } - - public String getDatasetCode() - { - return datasetCode; - } - - public String getGraphTypeCode() - { - return graphTypeCode; - } - - public int getWidth() - { - return width; - } - - public int getHeight() - { - return height; - } - } - - // The properties needed for connecting to the database - private Properties dbProperties; - - @Override - protected synchronized void doSpecificInitialization(Enumeration<String> parameterNames, - ServletConfig servletConfig) - { - // Only initialize the db properties once - if (dbProperties != null) - return; - - dbProperties = new Properties(); - String name; - while (parameterNames.hasMoreElements()) - { - name = parameterNames.nextElement(); - dbProperties.setProperty(name, servletConfig.getInitParameter(name)); - } - } - - @Override - protected final void doGet(final HttpServletRequest request, final HttpServletResponse response) - throws ServletException, IOException - { - try - { - // Get the parameters from the request - RequestParams params = new RequestParams(request); - String sessionId = params.getSessionId(); - String datasetCode = params.getDatasetCode(); - int height = params.getHeight(); - int width = params.getWidth(); - - // Get the session and user from the request - HttpSession session = tryGetOrCreateSession(request, sessionId); - if (session == null) - { - printSessionExpired(response); - return; - } - // Check that the user has view access to the chromatogram data - // NOTE: This throws an exception -- it may be nicer to return an image for a - // non-accessible chromatogram... - ensureDatasetAccessible(datasetCode, session, sessionId); - - // Get the chromatogram data - DatasetFileLines fileLines = tryDatasetLinesForParameters(params); - - // Generate a chromatogram image into the stream - TabularDataGraphGenerator generator = - new TabularDataGraphGenerator(fileLines, response.getOutputStream(), width, - height); - generator.generateImage(); - - } catch (Exception e) - { - printErrorResponse(response, "Invalid Request"); - e.printStackTrace(); - } - } - - private DatasetFileLines tryDatasetLinesForParameters(RequestParams params) - { - return null; - } -} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/TabularDataGraphServlet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/TabularDataGraphServlet.java new file mode 100644 index 0000000000000000000000000000000000000000..0c6b2da27aa827f0e3972be1a96423bf0f9646f4 --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/TabularDataGraphServlet.java @@ -0,0 +1,184 @@ +/* + * 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. + */ + +package ch.systemsx.cisd.openbis.dss.generic.server; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import com.csvreader.CsvReader; + +import ch.systemsx.cisd.common.exceptions.UserFailureException; +import ch.systemsx.cisd.openbis.dss.generic.server.graph.ITabularDataGraph; +import ch.systemsx.cisd.openbis.dss.generic.server.graph.TabularDataGraphCollectionConfiguration; +import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.DatasetFileLines; + +/** + * @author Chandrasekhar Ramakrishnan + */ +public class TabularDataGraphServlet extends AbstractDatasetDownloadServlet +{ + // Required servlet parameters + public final static String DATASET_CODE_PARAM = "dataset"; + + public final static String FILE_PATH_PARAM = "file"; + + public final static String GRAPH_TYPE_CODE = "type"; + + private static final long serialVersionUID = 1L; + + private TabularDataGraphCollectionConfiguration configuration; + + private final static String PROPERTIES_FILE_KEY = "properties-file"; + + /** + * A utility class for dealing with the URL parameters required to generate an image. This class + * makes sure all the required parameters are in the request (it throws exceptions otherwise), + * and it defaults values for all optional parameters if they are not in the request. + * + * @author Chandrasekhar Ramakrishnan + */ + private static class RequestParams + { + private final String sessionId; + + private final String datasetCode; + + private final String filePath; + + private final String graphTypeCode; + + public RequestParams(HttpServletRequest request) + { + sessionId = getRequiredParameter(request, SESSION_ID_PARAM); + datasetCode = getRequiredParameter(request, DATASET_CODE_PARAM); + filePath = getRequiredParameter(request, FILE_PATH_PARAM); + graphTypeCode = getRequiredParameter(request, GRAPH_TYPE_CODE); + } + + private static String getRequiredParameter(final HttpServletRequest request, + String paramName) + { + String value = request.getParameter(paramName); + if (value == null) + { + throw new UserFailureException("no value for the parameter " + paramName + + " found in the URL"); + } + return value; + } + } + + @Override + protected synchronized void doSpecificInitialization(Enumeration<String> parameterNames, + ServletConfig servletConfig) + { + // Only initialize the db properties once + if (configuration != null) + return; + + String propertiesFilePath = servletConfig.getInitParameter(PROPERTIES_FILE_KEY); + configuration = + TabularDataGraphCollectionConfiguration.getConfiguration(propertiesFilePath); + } + + @Override + protected final void doGet(final HttpServletRequest request, final HttpServletResponse response) + throws ServletException, IOException + { + try + { + // Get the parameters from the request + RequestParams params = new RequestParams(request); + String sessionId = params.sessionId; + String datasetCode = params.datasetCode; + String filePath = params.filePath; + + // Get the session and user from the request + HttpSession session = tryGetOrCreateSession(request, sessionId); + if (session == null) + { + printSessionExpired(response); + return; + } + // Check that the user has view access to the data + // NOTE: This throws an exception -- it may be nicer to return an image for a + // non-accessible dataset... + ensureDatasetAccessible(datasetCode, session, sessionId); + + // Get the tabular data + DatasetFileLines fileLines = getDatasetFileLines(filePath); + + // Generate an image image into the stream + ITabularDataGraph generator = + configuration.getGraph(params.graphTypeCode, fileLines, response + .getOutputStream()); + generator.generateImage(); + + } catch (Exception e) + { + printErrorResponse(response, "Invalid Request"); + e.printStackTrace(); + } + } + + /** + * Return the tabular data as a DatasetFileLines. + */ + private DatasetFileLines getDatasetFileLines(String path) throws IOException + { + File file = new File(path); + CsvReader reader = getCsvReader(file); + List<String[]> lines = new ArrayList<String[]>(); + while (reader.readRecord()) + { + lines.add(reader.getValues()); + } + + return new DatasetFileLines(file, path, lines); + } + + /** + * Get a CsvReader for parsing a tabular data file. + */ + private CsvReader getCsvReader(File file) throws IOException + { + if (file.isFile() == false) + { + throw new UserFailureException(file + " does not exist or is not a file."); + } + FileInputStream fileInputStream = new FileInputStream(file); + + CsvReader csvReader = new CsvReader(fileInputStream, Charset.defaultCharset()); + csvReader.setDelimiter(configuration.getColumnDelimiter()); + csvReader.setSkipEmptyRecords(true); + csvReader.setUseComments(configuration.isIgnoreComments()); + csvReader.setComment(configuration.getCommentDelimiter()); + + return csvReader; + } +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/AbstractTabularDataGraph.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/AbstractTabularDataGraph.java index 926a5bbc575b9b0f998c0488c0692181c964c0f6..202adf9e9a20d6eaa82886eae519c00c5933d6fc 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/AbstractTabularDataGraph.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/AbstractTabularDataGraph.java @@ -34,7 +34,8 @@ import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.DatasetFileLine * * @author Chandrasekhar Ramakrishnan */ -public abstract class AbstractTabularDataGraph<T extends TabularDataGraphConfiguration> +abstract class AbstractTabularDataGraph<T extends TabularDataGraphConfiguration> implements + ITabularDataGraph { protected final T configuration; diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/ITabularDataGraph.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/ITabularDataGraph.java new file mode 100644 index 0000000000000000000000000000000000000000..59c01edd3775176cdc932e0a14facc6ab441875e --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/ITabularDataGraph.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package ch.systemsx.cisd.openbis.dss.generic.server.graph; + +import java.io.IOException; + +/** + * @author Chandrasekhar Ramakrishnan + */ +public interface ITabularDataGraph +{ + + // Public API + /** + * Create an image from the file lines and write it to the output stream. + * + * @throws IOException + */ + public abstract void generateImage() throws IOException; + +} \ No newline at end of file diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataGraphCollectionConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataGraphCollectionConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..19bf44fa8b7628db2ec9ab3d207bf0559087b879 --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataGraphCollectionConfiguration.java @@ -0,0 +1,178 @@ +/* + * 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. + */ + +package ch.systemsx.cisd.openbis.dss.generic.server.graph; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Properties; + +import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; +import ch.systemsx.cisd.common.utilities.PropertyUtils; +import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.DatasetFileLines; + +/** + * @author Chandrasekhar Ramakrishnan + */ +public class TabularDataGraphCollectionConfiguration +{ + private static final String SEPARATOR_PROPERTY_KEY = "separator"; + + private static final String IGNORE_COMMENTS_PROPERTY_KEY = "ignore-comments"; + + // the seperator in the file + private final char separator; + + private final boolean ignoreComments; + + // the comment marker in the file + private final char comment; + + private final ArrayList<String> graphTypeCodes; + + private final HashMap<String, TabularDataGraphConfiguration> graphTypeMap; + + /** + * Create a configuration from the properties file located at path. + * + * @param path Path to the properties file. + */ + public static TabularDataGraphCollectionConfiguration getConfiguration(String path) + throws EnvironmentFailureException + { + Properties configurationProps = new Properties(); + try + { + configurationProps.load(new FileInputStream(path)); + } catch (FileNotFoundException ex) + { + throw new EnvironmentFailureException("Could not find the configuration file " + + new File(path).getAbsolutePath()); + } catch (IOException ex) + { + throw new EnvironmentFailureException("Could not read the configuration file " + path); + } + + return new TabularDataGraphCollectionConfiguration(configurationProps); + } + + /** + * Initialize the configuration based on the properties object. + */ + private TabularDataGraphCollectionConfiguration(Properties properties) + { + comment = '#'; + + this.separator = PropertyUtils.getChar(properties, SEPARATOR_PROPERTY_KEY, ';'); + this.ignoreComments = + PropertyUtils.getBoolean(properties, IGNORE_COMMENTS_PROPERTY_KEY, true); + graphTypeCodes = new ArrayList<String>(); + graphTypeMap = new HashMap<String, TabularDataGraphConfiguration>(); + initialzeGraphTypeMap(properties); + + } + + private void initialzeGraphTypeMap(Properties properties) + { + TabularDataGraphConfiguration config = + new TabularDataGraphConfiguration("Test", "TotalCells", "InfectedCells", 300, 200); + graphTypeMap.put("scatter", config); + graphTypeCodes.add("scatter"); + } + + /** + * Return the graph configuration associated with the graphTypeCode. + * + * @param graphTypeCode The name of the graph type + */ + public TabularDataGraphConfiguration getGraphConfiguration(String graphTypeCode) + { + TabularDataGraphConfiguration config = graphTypeMap.get(graphTypeCode); + if (null == config) + { + throw new IllegalArgumentException("No graph associated with code " + graphTypeCode); + } + return config; + } + + /** + * Return the graph generator associated with the graphTypeCode, initialized by the fileLines + * and out. + * + * @param graphTypeCode The name of the graph type + * @param fileLines The data to generate a graph from + * @param out The stream to write the graph to + */ + public ITabularDataGraph getGraph(String graphTypeCode, DatasetFileLines fileLines, + OutputStream out) + { + TabularDataGraphConfiguration config = graphTypeMap.get(graphTypeCode); + if (null == config) + { + throw new IllegalArgumentException("No graph associated with code " + graphTypeCode); + } + return new TabularDataScatterplot(config, fileLines, out); + } + + public char getColumnDelimiter() + { + return separator; + } + + /** + * Should comments be ignored? + */ + public boolean isIgnoreComments() + { + return ignoreComments; + } + + public char getCommentDelimiter() + { + return comment; + } + + public int getImageWidth() + { + return 800; + } + + public int getImageHeight() + { + return 600; + } + + public int getThumbnailWidth() + { + return 300; + } + + public int getThumbnailHeight() + { + return 200; + } + + public List<String> getGraphTypeCodes() + { + return graphTypeCodes; + } +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataGraphConfiguration.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataGraphConfiguration.java index b7cf659499c631bf04c36bcb441c2884d0593280..5a45d0bcde3111f58df452d3aaa777b3352a1465 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataGraphConfiguration.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataGraphConfiguration.java @@ -44,7 +44,7 @@ public class TabularDataGraphConfiguration * @param imageWidth The desired width of the resulting image * @param imageHeight The desired height of the resulting image */ - protected TabularDataGraphConfiguration(String title, String xAxisColumn, + public TabularDataGraphConfiguration(String title, String xAxisColumn, String yAxisColumn, int imageWidth, int imageHeight) { this.title = title; @@ -57,7 +57,7 @@ public class TabularDataGraphConfiguration /** * The title for the resulting image. */ - protected String getTitle() + public String getTitle() { return title; } diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataGraphGenerator.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataGraphGenerator.java deleted file mode 100644 index 0dd108990b3cef36612cc92096eeacf40d0c5d1f..0000000000000000000000000000000000000000 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataGraphGenerator.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * 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. - */ - -package ch.systemsx.cisd.openbis.dss.generic.server.graph; - -import java.awt.Color; -import java.awt.Font; -import java.io.IOException; -import java.io.OutputStream; -import java.util.List; - -import org.jfree.chart.ChartFactory; -import org.jfree.chart.ChartUtilities; -import org.jfree.chart.JFreeChart; -import org.jfree.chart.axis.Axis; -import org.jfree.chart.axis.ValueAxis; -import org.jfree.chart.plot.PlotOrientation; -import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.renderer.xy.XYBarRenderer; -import org.jfree.chart.renderer.xy.XYItemRenderer; -import org.jfree.chart.renderer.xy.XYSplineRenderer; -import org.jfree.data.xy.IntervalXYDataset; -import org.jfree.data.xy.XYSeries; -import org.jfree.data.xy.XYSeriesCollection; - -import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.DatasetFileLines; - -/** - * Generates a graph from tabular data. Both the graph type and the columns used for the graph can - * be configured. - * - * @author Chandrasekhar Ramakrishnan - */ -public class TabularDataGraphGenerator -{ - public static enum ChartType - { - AREA, BAR, LINE, SPLINE - } - - public final static ChartType DEFAULT_CHART_TYPE = ChartType.LINE; - - private final String title; - - private final String xAxisHeader; - - private final String yAxisHeader; - - private final DatasetFileLines fileLines; - - private final int imageWidth; - - private final int imageHeight; - - private final ChartType chartType; - - private final OutputStream out; - - /** - * Initialize a chromatogram generator. The chart type is defaulted to DEFAULT_CHART_TYPE. - * - * @param fileLines The data to generate a graph from. - * @param out The stream to write the image to - * @param imageWidth The width in pixels of the generated image - * @param imageHeight The height in pixels of the generated image - */ - public TabularDataGraphGenerator(DatasetFileLines fileLines, OutputStream out, - int imageWidth, int imageHeight) - { - this("Chart", "TotalCells", "InfectedCells", imageWidth, imageHeight, DEFAULT_CHART_TYPE, - fileLines, out); - } - - /** - * Initialize a chromatogram generator. - * - * @param title The title of the graph - * @param xAxisColumnHeader The header of the data column used to create the x-axis - * @param yAxisColumnHeader The header of the data column used to create the y-axis - * @param imageWidth The width in pixels of the generated image - * @param imageHeight The height in pixels of the generated image - * @param chartType One of AREA, BAR, LINE, or SPLINE - * @param fileLines The data to generate a graph from. - * @param out The stream to write the image to. - */ - public TabularDataGraphGenerator(String title, String xAxisColumnHeader, - String yAxisColumnHeader, int imageWidth, int imageHeight, ChartType chartType, - DatasetFileLines fileLines, OutputStream out) - { - this.title = title; - this.xAxisHeader = xAxisColumnHeader; - this.yAxisHeader = yAxisColumnHeader; - this.imageWidth = imageWidth; - this.imageHeight = imageHeight; - this.chartType = chartType; - this.fileLines = fileLines; - this.out = out; - } - - /** - * Create an image from the chromatogram and write it to the output stream. - * - * @throws IOException - */ - public void generateImage() throws IOException - { - JFreeChart chart = createChart(tryCreateDataset()); - ChartUtilities.writeChartAsPNG(out, chart, imageWidth, imageHeight); - } - - private JFreeChart createChart(IntervalXYDataset dataset) - { - JFreeChart chart = null; - switch (chartType) - { - case AREA: - chart = createAreaChart(dataset); - break; - case BAR: - chart = createBarChart(dataset); - break; - case LINE: - chart = createLineChart(dataset); - break; - case SPLINE: - chart = createSplineChart(dataset); - break; - } - - return chart; - } - - private JFreeChart createBarChart(IntervalXYDataset dataset) - { - JFreeChart chart = ChartFactory.createXYBarChart(title, // title - "Run Time", // x-axis label - false, // use date axis? - "Intensity", // y-axis label - dataset, // data - PlotOrientation.VERTICAL, // plot orientation - false, // create legend? - false, // generate tooltips? - false // generate URLs? - ); - - XYPlot plot = configureChart(chart); - - XYItemRenderer r = plot.getRenderer(); - if (r instanceof XYBarRenderer) - { - XYBarRenderer renderer = (XYBarRenderer) r; - renderer.setShadowVisible(false); - } - - return chart; - } - - private JFreeChart createLineChart(IntervalXYDataset dataset) - { - JFreeChart chart = ChartFactory.createXYLineChart(title, // title - "run time", // x-axis label - "intensity", // y-axis label - dataset, // data - PlotOrientation.VERTICAL, // plot orientation - false, // create legend? - false, // generate tooltips? - false // generate URLs? - ); - - configureChart(chart); - - return chart; - } - - private JFreeChart createSplineChart(IntervalXYDataset dataset) - { - JFreeChart chart = ChartFactory.createXYLineChart(title, // title - "run time", // x-axis label - "intensity", // y-axis label - dataset, // data - PlotOrientation.VERTICAL, // plot orientation - false, // create legend? - false, // generate tooltips? - false // generate URLs? - ); - - XYPlot plot = configureChart(chart); - - XYSplineRenderer renderer = new XYSplineRenderer(); - renderer.setSeriesShapesVisible(0, false); - plot.setRenderer(renderer); - - return chart; - } - - private JFreeChart createAreaChart(IntervalXYDataset dataset) - { - JFreeChart chart = ChartFactory.createXYAreaChart(title, // title - "run time", // x-axis label - "intensity", // y-axis label - dataset, // data - PlotOrientation.VERTICAL, // plot orientation - false, // create legend? - false, // generate tooltips? - false // generate URLs? - ); - - configureChart(chart); - - return chart; - } - - /** - * Create a JFreeChart dataset from the chromatogram data. - */ - private IntervalXYDataset tryCreateDataset() - { - XYSeries s1 = new XYSeries(title); - String[] headers = fileLines.getHeaderTokens(); - // figure out which indices are used for the x- and y-axes - int xIndex = -1, yIndex = -1, i = 0; - for (String header : headers) - { - if (xAxisHeader.equals(header)) - { - xIndex = i; - } else if (yAxisHeader.equals(header)) - { - yIndex = i; - } - ++i; - } - - // The data set did not contain the expected headers. - if (xIndex < 0 || yIndex < 0) - { - return null; - } - - List<String[]> lines = fileLines.getDataLines(); - for (String[] line : lines) - { - float x = Float.valueOf(line[xIndex]); - float y = Float.valueOf(line[yIndex]); - s1.add(x, y); - } - - XYSeriesCollection dataset = new XYSeriesCollection(); - dataset.addSeries(s1); - - return dataset; - } - - /** - * Apply the visual preferences to the chart. - */ - private XYPlot configureChart(JFreeChart chart) - { - Font font = JFreeChart.DEFAULT_TITLE_FONT; - chart.getTitle().setFont(cloneFontWithNewSize(font, Math.max(11, imageHeight / 30))); - chart.setBackgroundPaint(Color.WHITE); - - XYPlot plot = (XYPlot) chart.getPlot(); - setAxisLabelFontSize(plot.getDomainAxis()); - setAxisLabelFontSize(plot.getRangeAxis()); - plot.setBackgroundPaint(Color.WHITE); - plot.setDomainGridlinesVisible(false); - plot.setRangeGridlinesVisible(true); - plot.setRangeGridlinePaint(Color.LIGHT_GRAY); - plot.setDomainCrosshairVisible(false); - plot.setRangeCrosshairVisible(false); - - ValueAxis axis = plot.getDomainAxis(); - axis.setAutoRange(true); - - return plot; - } - - private void setAxisLabelFontSize(Axis axis) - { - Font labelFont = axis.getLabelFont(); - axis.setLabelFont(cloneFontWithNewSize(labelFont, Math.max(10, imageHeight / 40))); - } - - private Font cloneFontWithNewSize(Font font, int newSize) - { - return new Font(font.getName(), font.getStyle(), newSize); - } -} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataHeatmap.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataHeatmap.java index 4ec497952ef1af961e98e78fcc0f96c330324e03..ed8e3c3e07fb4321f1abb5fd823db68127c137ab 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataHeatmap.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataHeatmap.java @@ -25,6 +25,7 @@ import java.util.regex.Pattern; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.axis.NumberTickUnit; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.GrayPaintScale; @@ -46,6 +47,8 @@ import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.DatasetFileLine public class TabularDataHeatmap extends AbstractTabularDataGraph<TabularDataHeatmapConfiguration> { + private final Pattern xySplitterPattern; + /** * @param configuration */ @@ -53,6 +56,7 @@ public class TabularDataHeatmap extends AbstractTabularDataGraph<TabularDataHeat DatasetFileLines fileLines, OutputStream out) { super(configuration, fileLines, out); + xySplitterPattern = Pattern.compile("([A-Z])([0-9]*)"); } @Override @@ -103,6 +107,7 @@ public class TabularDataHeatmap extends AbstractTabularDataGraph<TabularDataHeat } NumberAxis xAxis = new NumberAxis(xAxisLabel); xAxis.setAutoRangeIncludesZero(false); + xAxis.setTickUnit(new NumberTickUnit(1.)); NumberAxis yAxis = new NumberAxis(yAxisLabel); XYBlockRenderer renderer = new XYBlockRenderer(); @@ -170,7 +175,7 @@ public class TabularDataHeatmap extends AbstractTabularDataGraph<TabularDataHeat private void splitColumnIntoXandY(String string, HeatmapElement element) { - Pattern p = Pattern.compile("([A-Z])([0-9]*)"); + Pattern p = xySplitterPattern; Matcher m = p.matcher(string); if (m.matches()) { diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/ImageAnalysisGraphReportingPlugin.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/ImageAnalysisGraphReportingPlugin.java new file mode 100644 index 0000000000000000000000000000000000000000..6431cae5d3132ffb055035549042bc74962a896c --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/ImageAnalysisGraphReportingPlugin.java @@ -0,0 +1,156 @@ +/* + * Copyright 2009 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. + */ + +package ch.systemsx.cisd.openbis.dss.generic.server.plugins; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; +import ch.systemsx.cisd.common.exceptions.UserFailureException; +import ch.systemsx.cisd.openbis.dss.generic.server.TabularDataGraphServlet; +import ch.systemsx.cisd.openbis.dss.generic.server.graph.TabularDataGraphCollectionConfiguration; +import ch.systemsx.cisd.openbis.dss.generic.server.graph.TabularDataGraphConfiguration; +import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.AbstractDataMergingReportingPlugin; +import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.SimpleTableModelBuilder; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GeneratedImageTableCell; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ISerializableComparable; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel; +import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; + +/** + * Reporting plugin that returns a table in which each column contains a graph. The number and + * format of the graphs can be configured in a properties file. + * + * @author Chandrasekhar Ramakrishnan + */ +public class ImageAnalysisGraphReportingPlugin extends AbstractDataMergingReportingPlugin +{ + private static final long serialVersionUID = 1L; + + private final String graphServletPath; + + private final TabularDataGraphCollectionConfiguration configuration; + + // Keys for the properties + private final String SERVLET_PATH_PROP = "servlet-path"; + + private final static String PROPERTIES_FILE_KEY = "properties-file"; + + public ImageAnalysisGraphReportingPlugin(Properties properties, File storeRoot) + { + super(properties, storeRoot, SEMICOLON_SEPARATOR); + graphServletPath = properties.getProperty(SERVLET_PATH_PROP, "datastore_server_graph/"); + String propertiesFilePath = properties.getProperty(PROPERTIES_FILE_KEY); + if (propertiesFilePath == null) + { + throw new EnvironmentFailureException( + "ImageAnalysisGraphReportingPlugin requires a properties file (specified with the " + + PROPERTIES_FILE_KEY + "key)."); + } + + configuration = + TabularDataGraphCollectionConfiguration.getConfiguration(propertiesFilePath); + } + + public TableModel createReport(List<DatasetDescription> datasets) + { + SimpleTableModelBuilder builder = new SimpleTableModelBuilder(); + addHeaders(builder); + if (datasets.isEmpty()) + { + return builder.getTableModel(); + } + for (DatasetDescription dataset : datasets) + { + final File dir = getDataSubDir(dataset); + List<File> matchingFiles = findMatchingFiles(dataset, dir); + if (matchingFiles.size() > 1) + { + throw UserFailureException.fromTemplate( + "Found multiple candidate files in the dataset %s ", dataset + .getDatasetCode()); + } + builder.addRow(createRow(dataset.getDatasetCode(), matchingFiles.get(0))); + } + return builder.getTableModel(); + } + + /** + * Add the headers to the table -- these depend on the configuration + */ + private void addHeaders(SimpleTableModelBuilder builder) + { + builder.addHeader("Data Set Code"); + int width = getThumbnailWidth(); + for (String graphTypeCode : getGraphTypeCodes()) + { + TabularDataGraphConfiguration graphConfig = + configuration.getGraphConfiguration(graphTypeCode); + builder.addHeader(graphConfig.getTitle(), width); + } + } + + private List<ISerializableComparable> createRow(String datasetCode, File file) + { + List<ISerializableComparable> row = new ArrayList<ISerializableComparable>(); + + // The data set code + row.add(SimpleTableModelBuilder.asText(datasetCode)); + + for (String graphTypeCode : getGraphTypeCodes()) + { + + GeneratedImageTableCell imageCell = + new GeneratedImageTableCell(graphServletPath, getImageWidth(), + getImageHeight(), getThumbnailWidth(), getThumbnailHeight()); + imageCell.addParameter(TabularDataGraphServlet.DATASET_CODE_PARAM, datasetCode); + imageCell.addParameter(TabularDataGraphServlet.FILE_PATH_PARAM, file.getAbsolutePath()); + imageCell.addParameter(TabularDataGraphServlet.GRAPH_TYPE_CODE, graphTypeCode); + + row.add(imageCell); + } + + return row; + } + + private List<String> getGraphTypeCodes() + { + return configuration.getGraphTypeCodes(); + } + + private int getImageWidth() + { + return configuration.getImageWidth(); + } + + private int getImageHeight() + { + return configuration.getImageHeight(); + } + + private int getThumbnailWidth() + { + return configuration.getThumbnailWidth(); + } + + private int getThumbnailHeight() + { + return configuration.getThumbnailHeight(); + } +} diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataHeatmapTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataHeatmapTest.java index 94f1bd136e5e48606f59a151b485a16b4eb9d06c..b8ca69d7222434c7c35339e52bca911b10585aa4 100644 --- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataHeatmapTest.java +++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/graph/TabularDataHeatmapTest.java @@ -29,7 +29,7 @@ public class TabularDataHeatmapTest extends AbstractTabularDataGraphTest @Test public void testHeatmap() throws IOException { - File outputFile = getTestImageOutputFile(); + File outputFile = getImageOutputFile(); TabularDataHeatmapConfiguration config = new TabularDataHeatmapConfiguration("Test", "WellName", "InfectionIndex", 300, 200);