001/*
002 * Copyright (c) 2004-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.sdm.spa.actors.piw.viz;
031
032import java.awt.Color;
033import java.util.Collections;
034import java.util.Comparator;
035import java.util.HashMap;
036import java.util.Iterator;
037import java.util.Map;
038import java.util.Vector;
039
040/**
041 * @author xiaowen
042 */
043public class SiteCollection {
044
045        private final SequenceCollection _sequenceCollection;
046        private Site[] _overallSites;
047        private Site[][] _individualSites;
048
049        public SiteCollection(SequenceCollection sequenceCollection) {
050                this._sequenceCollection = sequenceCollection;
051                calculateSites();
052        }
053
054        public int size() {
055                return _overallSites.length;
056        }
057
058        public Site getSite(int index) {
059                return _overallSites[index];
060        }
061
062        public Site getSite(String name) {
063                // TODO: Inefficient.
064                for (int i = 0; i < _overallSites.length; i++) {
065                        Site site = _overallSites[i];
066                        if (name.equals(site.name)) {
067                                return site;
068                        }
069                }
070                return null;
071        }
072
073        public double getMaxFrequencyOverall() {
074                double max = 0;
075                for (int i = 0; i < _overallSites.length; i++) {
076                        Site site = _overallSites[i];
077                        if (site.frequency > max) {
078                                max = site.frequency;
079                        }
080                }
081                return max;
082        }
083
084        public double getMaxFrequencyPerSequence() {
085                // FIXME: Slightly wrong, but will work for now.
086                double max = 0;
087                HashMap siteToMinFreq = this.getSiteToMinPerSeqFreq();
088                for (int i = 0; i < _overallSites.length; i++) {
089                        Site site = _overallSites[i];
090                        double freq = ((Double) siteToMinFreq.get(site.name)).doubleValue();
091                        if (freq > max) {
092                                max = freq;
093                        }
094                }
095                return max;
096        }
097
098        public void selectAll() {
099                for (int i = 0; i < _overallSites.length; i++) {
100                        Site site = _overallSites[i];
101                        site.selected = true;
102                }
103        }
104
105        public void deselectSitesWithOverallFrequencyUnder(double frequency) {
106                for (int i = 0; i < _overallSites.length; i++) {
107                        Site site = _overallSites[i];
108                        if (frequency > site.frequency) {
109                                site.selected = false;
110                        }
111                }
112        }
113
114        public void deselectSitesWithPerSequenceFrequencyUnder(double frequency) {
115                HashMap siteToMinFreq = this.getSiteToMinPerSeqFreq();
116                for (int i = 0; i < _overallSites.length; i++) {
117                        Site site = _overallSites[i];
118                        if (frequency > ((Double) siteToMinFreq.get(site.name))
119                                        .doubleValue()) {
120                                site.selected = false;
121                        }
122                }
123        }
124
125        private HashMap getSiteToMinPerSeqFreq() {
126                HashMap siteToMinFreq = new HashMap();
127                for (int i = 0; i < _individualSites.length; i++) {
128                        for (int j = 0; j < _individualSites[i].length; j++) {
129                                Site site = _individualSites[i][j];
130                                if (siteToMinFreq.containsKey(site.name)) {
131                                        Double freq = (Double) siteToMinFreq.get(site.name);
132                                        if (freq.intValue() > site.frequency) {
133                                                siteToMinFreq
134                                                                .put(site.name, new Double(site.frequency));
135                                        }
136                                } else {
137                                        siteToMinFreq.put(site.name, new Double(site.frequency));
138                                }
139                        }
140                }
141
142                return siteToMinFreq;
143        }
144
145        private void calculateSites() {
146                HashMap siteToFreqOverall = new HashMap();
147                int totalSitesOverall = 0;
148
149                this._individualSites = new Site[_sequenceCollection.size()][];
150
151                for (int i = 0; i < _sequenceCollection.size(); i++) {
152                        Sequence sequence = _sequenceCollection.getSequence(i);
153
154                        HashMap siteToFreq = new HashMap();
155                        int totalSites = 0;
156
157                        for (int j = 0; j < sequence.arrTFBSs.length; j++) {
158                                TranscriptionFactorBindingSite tfbs = sequence.arrTFBSs[j];
159                                addToHashMap(siteToFreq, tfbs.name);
160                                addToHashMap(siteToFreqOverall, tfbs.name);
161                                totalSites++;
162                                totalSitesOverall++;
163                        }
164
165                        _individualSites[i] = mapToSiteArray(siteToFreq, totalSites);
166                }
167
168                _overallSites = mapToSiteArray(siteToFreqOverall, totalSitesOverall);
169        }
170
171        private Site[] mapToSiteArray(HashMap map, int total) {
172                Vector vecEntries = new Vector(map.entrySet());
173
174                // Sort by frequency.
175                Collections.sort(vecEntries, new Comparator() {
176                        public int compare(Object o1, Object o2) {
177                                Map.Entry e1 = (Map.Entry) o1;
178                                Map.Entry e2 = (Map.Entry) o2;
179
180                                int f1 = ((Integer) e1.getValue()).intValue();
181                                int f2 = ((Integer) e2.getValue()).intValue();
182                                if (f1 != f2) {
183                                        return f2 - f1;
184                                }
185
186                                String s1 = (String) e1.getKey();
187                                String s2 = (String) e2.getKey();
188
189                                return (s1.compareTo(s2));
190                        }
191                });
192
193                Site[] sites = new Site[vecEntries.size()];
194                int step = (int) Math.ceil(255 / Math.ceil(Math.pow(vecEntries.size(),
195                                1f / 3f)));
196                int r = 0;
197                int g = 0;
198                int b = 0;
199                int i = 0;
200
201                Iterator it = vecEntries.iterator();
202                while (it.hasNext()) {
203                        Map.Entry entry = (Map.Entry) it.next();
204
205                        // Update color.
206                        r += step;
207                        if (255 < r) {
208                                r -= 255;
209                                g += step;
210                        }
211                        if (255 < g) {
212                                g -= 255;
213                                b += step;
214                        }
215
216                        sites[i] = new Site((String) entry.getKey(), new Color(r, g, b),
217                                        ((Integer) entry.getValue()).intValue() / (double) total,
218                                        true);
219                        i++;
220                }
221                return sites;
222        }
223
224        private void addToHashMap(HashMap map, String name) {
225                if (map.containsKey(name)) {
226                        Integer i = (Integer) map.get(name);
227                        map.put(name, new Integer(i.intValue() + 1));
228                } else {
229                        map.put(name, new Integer(1));
230                }
231        }
232
233        class Site {
234                public final String name;
235                public final Color color;
236                public final double frequency;
237                public boolean selected;
238
239                public Site(String name, Color color, double frequency, boolean selected) {
240
241                        this.name = name;
242                        this.color = color;
243                        this.frequency = frequency;
244                        this.selected = selected;
245                }
246        }
247}