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;
031
032import java.awt.BorderLayout;
033import java.awt.Color;
034import java.awt.Dimension;
035import java.text.DecimalFormat;
036import java.text.NumberFormat;
037import java.util.Collections;
038import java.util.Comparator;
039import java.util.HashMap;
040import java.util.HashSet;
041import java.util.Iterator;
042import java.util.Map;
043import java.util.StringTokenizer;
044import java.util.Vector;
045
046import javax.swing.BoxLayout;
047import javax.swing.JFrame;
048import javax.swing.JLabel;
049import javax.swing.JPanel;
050import javax.swing.JScrollPane;
051import javax.swing.JTable;
052import javax.swing.SwingUtilities;
053import javax.swing.table.DefaultTableModel;
054
055import ptolemy.actor.TypedAtomicActor;
056import ptolemy.actor.TypedIOPort;
057import ptolemy.data.StringToken;
058import ptolemy.data.type.BaseType;
059import ptolemy.kernel.CompositeEntity;
060import ptolemy.kernel.util.IllegalActionException;
061import ptolemy.kernel.util.NameDuplicationException;
062
063//////////////////////////////////////////////////////////////////////////
064//// MatchDisplay
065/**
066 * Show the Match Results in a tabulated form.
067 * 
068 * @author Zhengang Cheng, Xiaowen Xin
069 * @version $Revision: 24234 $
070 */
071
072public class MatchDisplay extends TypedAtomicActor {
073        TfDisplay frame = null;
074
075        int m_intCount = 0;
076        HashMap m_mapFreq = new HashMap();
077
078        SequenceSet m_sequenceSet = new SequenceSet();
079
080        /**
081         * Construct an actor with the given container and name.
082         * 
083         * @param container
084         *            The container.
085         * @param name
086         *            The name of this actor.
087         * @exception IllegalActionException
088         *                If the actor cannot be contained by the proposed
089         *                container.
090         * @exception NameDuplicationException
091         *                If the container already has an actor with this name.
092         */
093        public MatchDisplay(CompositeEntity container, String name)
094                        throws NameDuplicationException, IllegalActionException {
095                super(container, name);
096
097                // default tokenConsumptionRate is 1.
098                input = new TypedIOPort(this, "GI", true, false);
099                input.setTypeEquals(BaseType.STRING);
100
101                context = new TypedIOPort(this, "Context", true, false);
102                context.setTypeEquals(BaseType.STRING);
103
104                // Set the icon.
105                _attachText("_iconDescription", "<svg>\n"
106                                + "<polygon points=\"-15,-15 15,15 15,-15 -15,15\" "
107                                + "style=\"fill:white\"/>\n" + "</svg>\n");
108        }
109
110        // -- Part of the Actor
111
112        public TypedIOPort input;
113        public TypedIOPort context;
114
115        // /////////////////////////////////////////////////////////////////
116        // // public methods ////
117
118        public void initialize() throws IllegalActionException {
119                super.initialize();
120                // if (frame == null)
121                frame = new TfDisplay();
122                m_intCount = 0;
123                m_mapFreq = new HashMap();
124        } // end of initialize
125
126        /**
127         * It receives GI number and the Match result in a string.
128         * 
129         * */
130        public void fire() throws IllegalActionException {
131                super.fire();
132
133                String in = ((StringToken) (input.get(0))).stringValue();
134                // Get the context of the result
135                final String ctx = ((StringToken) (context.get(0))).stringValue();
136                _debug("Process:" + in);
137
138                // The results are in several lines.
139                // Each field in a line is separated by \t
140                String temp;
141                StringTokenizer st1, st2;
142                final Vector mn, pom, cs, ms, seq, ln, tfm, lnt, freq;
143                mn = new Vector();
144                pom = new Vector();
145                cs = new Vector();
146                ms = new Vector();
147                seq = new Vector();
148                ln = new Vector();
149                tfm = new Vector();
150                lnt = new Vector();
151
152                st1 = new StringTokenizer(in, "\n");
153                while (st1.hasMoreTokens()) {
154                        String line = st1.nextToken();
155                        // Each line will look like:
156                        // M00108 V$NRF2_01 980 (+) 1.000 0.922 gacGGAAGtg NRF-2
157                        st2 = new StringTokenizer(line, "\t");
158                        temp = st2.nextToken();
159                        ln.add(temp); // Link
160                        mn.add(st2.nextToken());
161                        pom.add(st2.nextToken());
162                        cs.add(st2.nextToken());
163                        ms.add(st2.nextToken());
164                        seq.add(st2.nextToken());
165                        tfm.add(st2.nextToken());
166                }
167
168                freq = processTfbs(mn);
169
170                // Modify link vector to add information:
171                for (int i = 0; i < ln.size(); i++) {
172                        lnt
173                                        .addElement("http://www.gene-regulation.com/cgi-bin/pub/databases/transfac/getTF.cgi?AC="
174                                                        + (String) ln.elementAt(i));
175                }
176
177                final DefaultTableModel dtm = new DefaultTableModel();
178
179                // Create a new table instance
180                dtm.addColumn("matrixName", mn);
181                dtm.addColumn("link", lnt);
182                dtm.addColumn("positionOfMatrix", pom);
183                dtm.addColumn("coreSimilarity", cs);
184                dtm.addColumn("matrixSimilarity", ms);
185                dtm.addColumn("sequence", seq);
186                dtm.addColumn("frequencies", freq);
187
188                SwingUtilities.invokeLater(new Runnable() {
189                        public void run() {
190
191                                // add tables showing Transfac results and frequencies
192                                frame.addResult(ctx, dtm);
193                                frame.addResult("Frequencies", getFrequencyPerRun(mn));
194
195                                // update table showing overall frequencies
196                                frame.addOverallFreq("Overall", getFrequencyOverall(mn));
197
198                                // update table showing overall counts
199                                frame
200                                                .addOverallCounts("Counts", m_sequenceSet.addData(mn,
201                                                                ctx));
202
203                                // play with frame size--make sure it's not too big
204                                if (!frame.isShowing()) {
205                                        frame.pack();
206
207                                        double width = java.awt.Toolkit.getDefaultToolkit()
208                                                        .getScreenSize().getWidth();
209                                        double height = java.awt.Toolkit.getDefaultToolkit()
210                                                        .getScreenSize().getHeight();
211
212                                        if (frame.getWidth() < width) {
213                                                width = frame.getWidth();
214                                        }
215
216                                        if (frame.getHeight() < height) {
217                                                height = frame.getHeight();
218                                        }
219
220                                        frame.setSize(new Dimension((int) width, (int) height));
221                                }
222                                frame.show();
223
224                        }
225                });
226
227        }
228
229        class TfDisplay extends JFrame {
230                JPanel outpanel;
231
232                JPanel panelOverallFreq;
233
234                JPanel panelOverallCounts;
235
236                public JPanel addResult(String ctx, DefaultTableModel dtm) {
237                        JPanel cellpanel;
238                        JTable table;
239                        JScrollPane scrollPane;
240
241                        // Create a panel to hold all other components
242                        cellpanel = new JPanel();
243                        cellpanel.setLayout(new BorderLayout());
244                        table = new JTable(dtm);
245                        table.setCellSelectionEnabled(true);
246                        table.setAutoResizeMode(1);
247                        table.setColumnSelectionAllowed(true);
248                        table.setRowSelectionAllowed(true);
249                        JScrollPane cellsp = new JScrollPane(table);
250                        cellpanel.setLayout(new BorderLayout());
251                        cellpanel.add(new JLabel("Context:" + ctx), BorderLayout.NORTH);
252                        cellpanel.add(cellsp, BorderLayout.CENTER);
253                        outpanel.add(cellpanel);
254
255                        return cellpanel;
256                }
257
258                public void addOverallFreq(String ctx, DefaultTableModel dtm) {
259                        if (null != panelOverallFreq) {
260                                outpanel.remove(panelOverallFreq);
261                        }
262                        panelOverallFreq = addResult(ctx, dtm);
263                }
264
265                public void addOverallCounts(String ctx, DefaultTableModel dtm) {
266                        if (null != panelOverallCounts) {
267                                outpanel.remove(panelOverallCounts);
268                        }
269                        panelOverallCounts = addResult(ctx, dtm);
270                }
271
272                TfDisplay() {
273                        setTitle("Match(Transfac) Result Display");
274                        setBackground(Color.gray);
275                        outpanel = new JPanel();
276                        outpanel.setLayout(new BoxLayout(outpanel, BoxLayout.Y_AXIS));
277                        JScrollPane outsp = new JScrollPane(outpanel);
278                        getContentPane().add(outsp);
279
280                }
281        }
282
283        private Vector processTfbs(Vector mn) {
284                String str, str1;
285                double tfCount;
286                double mnCount = mn.size();
287                double frequency;
288                Vector uniqueTF = new Vector();
289                Vector tfFrequency = new Vector();
290                Vector frequencies = new Vector();
291                for (int i = 0; i < mn.size(); i++) {
292                        int index = ((String) mn.elementAt(i)).indexOf("_");
293                        str = ((String) mn.elementAt(i)).substring(0, index);
294                        if (uniqueTF.contains(str)) {
295                        } else {
296                                uniqueTF.addElement(str);
297                        }
298                }
299
300                NumberFormat formatter = new DecimalFormat("0.000");
301
302                for (int i = 0; i < uniqueTF.size(); i++) {
303                        tfCount = 0;
304                        for (int j = 0; j < mn.size(); j++) {
305                                if (((String) mn.elementAt(j)).startsWith(((String) uniqueTF
306                                                .elementAt(i))
307                                                + "_")) {
308                                        tfCount++;
309                                }
310                        }
311                        // We allow only 3 digits
312                        frequency = (tfCount / mnCount) * 100;
313
314                        tfFrequency.add(i, formatter.format(frequency));
315
316                }
317
318                for (int i = 0; i < mn.size(); i++) {
319                        int index = ((String) mn.elementAt(i)).indexOf("_");
320                        str = ((String) mn.elementAt(i)).substring(0, index);
321                        int freqIndex = uniqueTF.indexOf(str);
322                        frequencies.addElement(tfFrequency.elementAt(freqIndex) + "%");
323                }
324
325                return frequencies;
326        }
327
328        private DefaultTableModel getFrequencyPerRun(Vector tfSites) {
329                // create hashmap mapping from tf binding site to frequency
330                HashMap mapFrequencies = new HashMap();
331
332                Iterator itFreq = tfSites.iterator();
333                while (itFreq.hasNext()) {
334                        String strSite = (String) itFreq.next();
335                        strSite = strSite.split("_")[0];
336
337                        if (mapFrequencies.containsKey(strSite)) {
338                                Integer count = (Integer) mapFrequencies.get(strSite);
339                                mapFrequencies.put(strSite, new Integer(count.intValue() + 1));
340                        } else {
341                                mapFrequencies.put(strSite, new Integer(1));
342                        }
343                }
344                return createTableModel(mapFrequencies, tfSites.size());
345        }
346
347        private DefaultTableModel getFrequencyOverall(Vector tfSites) {
348                // create a set with only unique tf binding sites
349                HashSet setSites = new HashSet();
350                Iterator itSites = tfSites.iterator();
351                while (itSites.hasNext()) {
352                        String strSite = (String) itSites.next();
353                        setSites.add(strSite.split("_")[0]);
354                }
355
356                // update m_mapFreq
357                itSites = setSites.iterator();
358                while (itSites.hasNext()) {
359                        String strSite = (String) itSites.next();
360
361                        if (m_mapFreq.containsKey(strSite)) {
362                                Integer count = (Integer) m_mapFreq.get(strSite);
363                                m_mapFreq.put(strSite, new Integer(count.intValue() + 1));
364                        } else {
365                                m_mapFreq.put(strSite, new Integer(1));
366                        }
367                }
368
369                // update m_intCount
370                m_intCount++;
371
372                return createTableModel(m_mapFreq, m_intCount);
373        }
374
375        /**
376         * Create a DefaultTableModel representing the HashMap
377         * 
378         * @param map
379         *            a map from transcription factor binding sites to the number of
380         *            times they appear
381         * @param count
382         *            total number of transcription factor binding sites
383         * @return an object fit to be displayed sorted by frequency
384         */
385        private DefaultTableModel createTableModel(HashMap map, int count) {
386                // put the entries of the HashMap in a vector
387                Vector vec = new Vector(map.entrySet());
388
389                // sort the vector by frequency
390                Collections.sort(vec, new Comparator() {
391                        public int compare(Object o1, Object o2) {
392                                if (!((o1 instanceof Map.Entry && o2 instanceof Map.Entry))) {
393                                        throw new ClassCastException(
394                                                        "Comparator called with arguments not of Map.Entry type.");
395                                }
396
397                                Map.Entry entry1 = (Map.Entry) o1;
398                                Map.Entry entry2 = (Map.Entry) o2;
399
400                                if (!((entry1.getKey() instanceof String) && (entry2.getKey() instanceof String))) {
401                                        throw new ClassCastException(
402                                                        "Inputs to Comparator don't have keys of String type.");
403                                }
404                                if (!((entry1.getValue() instanceof Integer) && (entry2
405                                                .getValue() instanceof Integer))) {
406                                        throw new ClassCastException(
407                                                        "Inputs to Comparator don't have values of Integer type.");
408                                }
409
410                                String key1 = (String) entry1.getKey();
411                                String key2 = (String) entry2.getKey();
412
413                                Integer value1 = (Integer) entry1.getValue();
414                                Integer value2 = (Integer) entry2.getValue();
415
416                                int comp = value1.compareTo(value2);
417                                if (0 != comp) {
418                                        return -comp;
419                                } else {
420                                        return key1.compareTo(key2);
421                                }
422                        }
423                });
424
425                // populate table model
426                DefaultTableModel tableModel = new DefaultTableModel();
427                tableModel.addColumn("MatrixName");
428                tableModel.addColumn("Frequency");
429                tableModel.addColumn("MatrixName");
430                tableModel.addColumn("Frequency");
431                tableModel.addColumn("MatrixName");
432                tableModel.addColumn("Frequency");
433
434                NumberFormat formatter = new DecimalFormat("0.000");
435                int size = vec.size();
436                Vector vecRow = new Vector();
437                for (int i = 0; i < size; i++) {
438                        Map.Entry entry = (Map.Entry) vec.elementAt(i);
439                        String strSite = (String) entry.getKey();
440                        String strFreq = formatter.format(((Integer) entry.getValue())
441                                        .intValue()
442                                        * 100.0 / count);
443
444                        vecRow.add(strSite);
445                        vecRow.add(strFreq + "% (" + entry.getValue() + "/" + count + ")");
446
447                        if (i % 3 == 2) {
448                                tableModel.addRow(vecRow);
449                                vecRow = new Vector();
450                        }
451                }
452                if (vecRow.size() > 0) {
453                        tableModel.addRow(vecRow);
454                }
455
456                return tableModel;
457        }
458
459        /**
460         * Class to keep track of counts This class remembers the counts of tfbs'
461         * for all sequences it has processed so far.
462         */
463        class SequenceSet {
464                // set of strings representing transcription factor binding sites
465                HashSet setTfs = new HashSet();
466
467                // vector of Sequence objects
468                Vector vecSequences = new Vector();
469
470                /**
471                 * Class to store data related to one specific sequence
472                 */
473                class Sequence {
474                        // name of the sequence
475                        String strName;
476
477                        // maps name of tfbs to number of times it occurred
478                        HashMap mapCount;
479                }
480
481                /**
482                 * Create a DefaultTableModel representing all data so far
483                 * 
484                 * @param vecTfs
485                 *            vector of tfbs'
486                 * @param name
487                 *            name of the sequence
488                 * @return an object fit to be displayed sorted by tfbs name
489                 */
490                public DefaultTableModel addData(Vector vecTfs, String name) {
491                        // create sequence
492                        Sequence sequence = createSequence(vecTfs, name);
493
494                        // update member variables of this class
495                        vecSequences.add(sequence);
496                        setTfs.addAll(sequence.mapCount.keySet());
497
498                        // initialize the DefaultTableModel to be returned
499                        DefaultTableModel dtm = new DefaultTableModel();
500
501                        // create the left-most column
502                        vecTfs = new Vector(setTfs);
503                        Collections.sort(vecTfs);
504                        dtm.addColumn("TFBS", vecTfs);
505
506                        // loop over sequences
507                        Iterator it = vecSequences.iterator();
508                        while (it.hasNext()) {
509                                sequence = (Sequence) it.next();
510
511                                Vector vecCounts = new Vector();
512
513                                // loop over each TF
514                                Iterator itTf = vecTfs.iterator();
515                                while (itTf.hasNext()) {
516                                        String strTf = (String) itTf.next();
517
518                                        if (sequence.mapCount.containsKey(strTf)) {
519                                                vecCounts.add(sequence.mapCount.get(strTf));
520                                        } else {
521                                                vecCounts.add(new Integer(0));
522                                        }
523                                }
524
525                                // add a column corresponding to this sequence to dtm
526                                dtm.addColumn(sequence.strName, vecCounts);
527                        }
528
529                        return dtm;
530                }
531
532                /**
533                 * Create a Sequence object
534                 * 
535                 * @param vecTfs
536                 *            vector of tfbs'
537                 * @param name
538                 *            name of the sequence
539                 * @return Sequence object containing representing input data
540                 */
541                public Sequence createSequence(Vector vecTfs, String name) {
542                        // create hashmap mapping from tf binding site to frequency
543                        HashMap mapFrequencies = new HashMap();
544
545                        // loop over tfbs'
546                        Iterator itFreq = vecTfs.iterator();
547                        while (itFreq.hasNext()) {
548                                String strSite = (String) itFreq.next();
549                                strSite = strSite.split("_")[0];
550
551                                if (mapFrequencies.containsKey(strSite)) {
552                                        Integer count = (Integer) mapFrequencies.get(strSite);
553                                        mapFrequencies.put(strSite, new Integer(
554                                                        count.intValue() + 1));
555                                } else {
556                                        mapFrequencies.put(strSite, new Integer(1));
557                                }
558                        }
559
560                        // create sequence object and return it
561                        Sequence sequence = new Sequence();
562                        sequence.strName = name;
563                        sequence.mapCount = mapFrequencies;
564
565                        return sequence;
566                }
567
568        }
569
570}
571
572// vim: noet ts=4 sw=4