org.fhcrc.cpl.viewer.ms2.Fractionation2DUtilities.java Source code

Java tutorial

Introduction

Here is the source code for org.fhcrc.cpl.viewer.ms2.Fractionation2DUtilities.java

Source

/*
 * Copyright (c) 2003-2012 Fred Hutchinson Cancer Research Center
 *
 * 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 org.fhcrc.cpl.viewer.ms2;

import org.apache.log4j.Logger;
import org.fhcrc.cpl.toolbox.commandline.arguments.ArgumentValidationException;
import org.fhcrc.cpl.toolbox.gui.chart.PanelWithHeatMap;
import org.fhcrc.cpl.toolbox.datastructure.Pair;
import org.fhcrc.cpl.toolbox.ApplicationContext;
import org.jfree.chart.renderer.PaintScale;
import org.jfree.chart.renderer.LookupPaintScale;

import javax.swing.*;
import java.util.List;
import java.util.ArrayList;
import java.awt.*;

/**
 * Utilities for working with 2D-fractionated MS/MS experiments
 */
public class Fractionation2DUtilities {
    protected static Logger _log = Logger.getLogger(Fractionation2DUtilities.class);

    public static final int BY_ROW = 0;
    public static final int BY_COLUMN = 1;

    public Fractionation2DUtilities() {

    }

    /**
     * Describes the structure of an AMT database containing one or more fractionated
     * experiments
     */
    public static class FractionatedAMTDatabaseStructure {
        protected List<FractionatedExperimentStructure> experimentStructures;
        protected List<Integer> beginningIndicesForExperiments;

        public FractionatedAMTDatabaseStructure() {
            experimentStructures = new ArrayList<FractionatedExperimentStructure>();
            beginningIndicesForExperiments = new ArrayList<Integer>();
        }

        public FractionatedAMTDatabaseStructure(List<FractionatedExperimentStructure> experimentStructures) {
            this();
            for (FractionatedExperimentStructure experimentStructure : experimentStructures)
                addExperimentStructure(experimentStructure);
        }

        public FractionatedAMTDatabaseStructure(FractionatedExperimentStructure experimentStructure,
                int numExperiments) {
            this();
            for (int i = 0; i < numExperiments; i++)
                addExperimentStructure(experimentStructure);
        }

        public String toString() {
            StringBuffer resultBuf = new StringBuffer("Experiments: " + getNumExperiments() + "\n");
            for (int i = 0; i < experimentStructures.size(); i++) {
                FractionatedExperimentStructure experimentStruct = experimentStructures.get(i);
                resultBuf.append("Experiment " + i + ": " + experimentStruct + "\n");
            }
            return resultBuf.toString();
        }

        public void addExperimentStructure(FractionatedExperimentStructure experimentStructure) {
            beginningIndicesForExperiments.add(getNumFractions());
            experimentStructures.add(experimentStructure);
        }

        public FractionatedExperimentStructure getExperimentStructure(int experimentNumber) {
            return experimentStructures.get(experimentNumber);
        }

        public int getNumFractions() {
            int numFractions = 0;
            for (FractionatedExperimentStructure experimentStructure : experimentStructures) {
                numFractions += experimentStructure.getNumFractions();
            }
            return numFractions;
        }

        /**
         * experiment number is zero-based
         * @param index
         * @return
         */
        public Pair<Integer, int[]> calculateExperimentAndPosition(int index) {
            int experimentNumber;
            for (experimentNumber = 0; experimentNumber < getNumExperiments(); experimentNumber++) {
                if ((experimentNumber >= getNumExperiments() - 1)
                        || beginningIndicesForExperiments.get(experimentNumber + 1) > index)
                    break;
            }

            int indexInExperiment = index - beginningIndicesForExperiments.get(experimentNumber);
            int[] positionInExperiment = experimentStructures.get(experimentNumber)
                    .convertIndexToPosition(indexInExperiment);
            return new Pair<Integer, int[]>(experimentNumber, positionInExperiment);
        }

        public int getNumExperiments() {
            return experimentStructures.size();
        }
    }

    public static class FractionatedExperimentStructure {
        public int rows;
        public int columns;
        public int organization;

        public FractionatedExperimentStructure(int columns, int rows, int organization) {
            this.rows = rows;
            this.columns = columns;
            this.organization = organization;
        }

        public String toString() {
            return "cols=" + columns + ", rows=" + rows + ", organization="
                    + (organization == BY_ROW ? "row" : "col");
        }

        public int getNumFractions() {
            return rows * columns;
        }

        /**
         * Takes a single index in a 1D array representing the experiment and returns the
         * equivalent 2D location
         * @param index
         * @return a position in two coordinates.  First column, then row
         */
        public int[] convertIndexToPosition(int index) {
            int[] result = new int[2];
            switch (organization) {
            case BY_ROW:
                result[0] = index % columns;
                result[1] = index / columns;
                break;
            case BY_COLUMN:
                result[0] = index / rows;
                result[1] = index % rows;
                break;
            default:
                throw new IllegalArgumentException(
                        "Illegal organization argument to convertIndexToPosition: " + organization);
            }
            return result;
        }

        /**
         * Takes data representing a value for each index in a 1D array representing the experiment
         * and converts it into a 2D array.
         * @param values
         * @return
         */
        public double[][] convertIndicesToPositions(double[] values) {
            double[][] result = new double[columns][rows];
            switch (organization) {
            case BY_ROW:
                for (int i = 0; i < rows; i++)
                    for (int j = 0; j < columns; j++)
                        result[j][i] = values[(columns * i) + j];
                break;
            case BY_COLUMN:

                for (int i = 0; i < rows; i++)
                    for (int j = 0; j < columns; j++)
                        result[i][j] = values[(columns * i) + j];
                break;
            default:
                throw new IllegalArgumentException(
                        "Illegal organization argument to convertIndexToPosition: " + organization);
            }
            return result;
        }
    }

    /**
     * num rows, num columns, fraction order, number of experiments
     * @param structureArgument
     * @return
     */
    public static FractionatedAMTDatabaseStructure digestAmtStructureArgument(String structureArgument)
            throws ArgumentValidationException {
        String[] chunks = structureArgument.split(",");
        if (chunks.length != 4)
            throw new ArgumentValidationException(
                    "argument amtdbdimensions must have four comma-separated parts (rows, columns, organization, # experiments)."
                            + "  Specified argument has " + chunks.length);
        int lastCommaIndex = structureArgument.lastIndexOf(",");
        FractionatedExperimentStructure experimentStructure = digestDimensionArgument(
                structureArgument.substring(0, lastCommaIndex));

        try {
            int numExperiments = Integer.parseInt(chunks[3]);
            return new FractionatedAMTDatabaseStructure(experimentStructure, numExperiments);
        } catch (Exception e) {
            throw new ArgumentValidationException(e);
        }
    }

    /**
     * Takes a String argument defining the structure of an MS/MS experiment
     * (number of rows, number of columns, and whether the runs appear in the order
     * of rows or columns) and parses it
     * @param dimensionArgument
     * @return
     * @throws ArgumentValidationException
     */
    public static FractionatedExperimentStructure digestDimensionArgument(String dimensionArgument)
            throws ArgumentValidationException {
        int dbRows, dbCols, organization;

        String[] chunks = dimensionArgument.split(",");
        if (chunks.length != 3)
            throw new ArgumentValidationException(
                    "argument amtdbdimensions must have three comma-separated parts (rows, columns, organization)."
                            + "  Specified argument has " + chunks.length);

        try {
            dbRows = Integer.parseInt(chunks[0]);
            dbCols = Integer.parseInt(chunks[1]);
        } catch (NumberFormatException e) {
            throw new ArgumentValidationException(
                    "Could not understand the number of rows and columns passed in argument amtdbdimensions");
        }

        if (chunks[2].equalsIgnoreCase("row"))
            organization = BY_ROW;
        else if (chunks[2].equalsIgnoreCase("col"))
            organization = BY_COLUMN;
        else
            throw new ArgumentValidationException(
                    "Please specify 'row' or 'col' (without quotes) for the organization of database rows");

        return new FractionatedExperimentStructure(dbCols, dbRows, organization);
    }

    public static void showHeatMapChart(FractionatedAMTDatabaseStructure amtDatabaseStructure,
            double[] dataForChart, String chartName, boolean showLegend) {
        int chartWidth = 1000;
        int chartHeight = 1000;

        double globalMinValue = Double.MAX_VALUE;
        double globalMaxValue = Double.MIN_VALUE;

        for (double value : dataForChart) {
            if (value < globalMinValue)
                globalMinValue = value;
            if (value > globalMaxValue)
                globalMaxValue = value;
        }

        _log.debug("showHeatMapChart: experiment structures:");
        List<double[][]> amtPeptidesInExperiments = new ArrayList<double[][]>();
        for (int i = 0; i < amtDatabaseStructure.getNumExperiments(); i++) {
            int experimentWidth = amtDatabaseStructure.getExperimentStructure(i).columns;
            int experimentHeight = amtDatabaseStructure.getExperimentStructure(i).rows;
            _log.debug("\t" + amtDatabaseStructure.getExperimentStructure(i));
            amtPeptidesInExperiments.add(new double[experimentWidth][experimentHeight]);
        }
        for (int i = 0; i < dataForChart.length; i++) {
            Pair<Integer, int[]> positionInExperiments = amtDatabaseStructure.calculateExperimentAndPosition(i);
            int xpos = positionInExperiments.second[0];
            int ypos = positionInExperiments.second[1];
            int experimentIndex = positionInExperiments.first;
            //System.err.println("i, xpos, ypos: " + i + ", " + xpos + ", " + ypos);            
            amtPeptidesInExperiments.get(experimentIndex)[xpos][ypos] = dataForChart[i];

        }

        JDialog cd = new JDialog(ApplicationContext.getFrame(), "Heat Map(s)");
        cd.setSize(chartWidth, chartHeight);
        cd.setPreferredSize(new Dimension(chartWidth, chartHeight));
        cd.setLayout(new FlowLayout());

        int nextPerfectSquareRoot = 0;
        while (true) {
            nextPerfectSquareRoot++;
            if ((nextPerfectSquareRoot * nextPerfectSquareRoot) >= amtPeptidesInExperiments.size()) {
                break;
            }
        }

        int plotWidth = (int) ((double) (chartWidth - 20) / (double) nextPerfectSquareRoot);
        int plotHeight = (int) ((double) (chartHeight - 20) / (double) nextPerfectSquareRoot);

        _log.debug("Rescaled chart dimensions: " + plotWidth + "x" + plotHeight);

        LookupPaintScale paintScale = PanelWithHeatMap.createPaintScale(globalMinValue, globalMaxValue, Color.BLUE,
                Color.RED);

        for (int i = 0; i < amtPeptidesInExperiments.size(); i++) {
            PanelWithHeatMap pwhm = new PanelWithHeatMap(amtPeptidesInExperiments.get(i), "Experiment " + (i + 1));
            //            pwhm.setPalette(PanelWithHeatMap.PALETTE_BLUE_RED);
            pwhm.setPaintScale(paintScale);
            pwhm.setPreferredSize(new Dimension(plotWidth, plotHeight));
            pwhm.setAxisLabels("AX Fraction", "RP Fraction");
            if (!showLegend)
                pwhm.getChart().removeLegend();
            cd.add(pwhm);
        }
        cd.setTitle(chartName);
        cd.setVisible(true);
    }

}