001/*
002 *                  BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 * Created on Aug 3, 2007
021 *
022 */
023
024package org.biojava.nbio.structure.gui;
025
026import org.biojava.nbio.structure.align.StrucAligParameters;
027import org.biojava.nbio.structure.align.pairwise.AlternativeAlignment;
028import org.biojava.nbio.structure.align.pairwise.FragmentPair;
029import org.biojava.nbio.structure.gui.util.color.ContinuousColorMapper;
030import org.biojava.nbio.structure.gui.util.color.DefaultMatrixMapper;
031import org.biojava.nbio.structure.jama.Matrix;
032
033import javax.swing.*;
034import java.awt.*;
035import java.awt.image.BufferedImage;
036import java.lang.reflect.Method;
037
038
039/** a JPanel that can display a difference of distance matrix and paths that have been
040 * taken for the alignment
041 *
042 * <p>Note: This panel displays the transpose of its underlying matrix.
043 * Thus its width will be the same as {@link Matrix#getRowDimension()} and its
044 * height the same as {@link Matrix#getColumnDimension()}. This stems from the
045 * unfortunate ordering of {@link Matrix#get(int, int)} parameters as (row, col),
046 * which is opposite from the normal (x,y) order used when displaying graphics.
047 *
048 * @author Andreas Prlic
049 *
050 */
051public class JMatrixPanel extends JPanel{
052
053        /**
054         *
055         */
056        private static final long serialVersionUID = -1720879395453257846L;
057        BufferedImage _bufImage;
058        Matrix matrix;
059        ContinuousColorMapper cellColor; //Maps matrix elements to a color
060        float scale;
061
062        FragmentPair[] fragmentPairs;
063        AlternativeAlignment[] aligs;
064        int selectedAlignmentPos;
065
066        final static BasicStroke stroke = new BasicStroke(2.0f);
067        StrucAligParameters params;
068
069        public JMatrixPanel(){
070                scale = 1;
071                cellColor = new DefaultMatrixMapper(10, 0.9f);
072                //saturation = 0.9f;
073                //scalevalue = 10;
074                selectedAlignmentPos = -1;
075                matrix = new Matrix(0,0);
076                params = new StrucAligParameters();
077        }
078
079        public int getSelectedAlignmentPos() {
080                return selectedAlignmentPos;
081        }
082
083        public void setSelectedAlignmentPos(int selectedAlignmentPos) {
084                this.selectedAlignmentPos = selectedAlignmentPos;
085        }
086
087        public AlternativeAlignment[] getAlternativeAligs() {
088                return aligs;
089        }
090
091        public void setAlternativeAligs(AlternativeAlignment[] aligs) {
092                this.aligs = aligs;
093        }
094
095
096
097        public FragmentPair[] getFragmentPairs() {
098                return fragmentPairs;
099        }
100
101        public void setFragmentPairs(FragmentPair[] fragmentPairs) {
102                this.fragmentPairs = fragmentPairs;
103        }
104
105        public float getScale() {
106                return scale;
107        }
108
109        public void setPreferredSize(){
110
111                int prefW = Math.round(matrix.getRowDimension() * scale);
112                int prefH = Math.round(matrix.getColumnDimension() * scale);
113
114                this.setPreferredSize(new Dimension(prefW,prefH));
115
116        }
117
118        public void setScale(float scale) {
119
120                if ( scale == this.scale)
121                        return;
122                //System.out.println("setting scale " + scale + "current width " + getWidth() + " " + getHeight());
123
124                this.scale = scale;
125
126                setPreferredSize();
127
128                this.repaint();
129
130        }
131
132        public Matrix getMatrix() {
133                return matrix;
134        }
135
136        /** sets the distance matrix to be displayed
137         *
138         * @param matrix
139         */
140        public void setMatrix(Matrix matrix) {
141                this.matrix = matrix;
142                setPreferredSize();
143        }
144
145        @Override
146        public void paintComponent(Graphics g){
147
148                //super.paintComponent(g);
149
150                Graphics2D g2 = (Graphics2D)g;
151                if ( _bufImage == null){
152
153                        int w = getWidth();
154                        int h = getHeight();
155                        _bufImage = (BufferedImage) createImage(w,h);
156                        //Graphics gc = _bufImage.createGraphics();
157                        //gc.setColor(Color.blue);
158                        //gc.fillRect(0,0,w,h);
159
160                }
161
162
163                g2.drawImage(_bufImage,null,0,0);
164                drawDistances(g);
165
166                drawPairs(g);
167
168                if ( scale >= 4) {
169                        drawBoxes(g);
170                }
171        }
172
173        /** draw alternative alignments
174         *
175         * @param g
176         */
177        public void drawPairs(Graphics g){
178
179                if ( aligs == null)
180                        return;
181
182                int nr = aligs.length;
183
184                Graphics2D g2D = (Graphics2D)g;
185                Stroke oldStroke = g2D.getStroke();
186                g2D.setStroke(stroke);
187
188                Color color;
189                float hue;
190
191                int width = Math.round(scale);
192                int w2 = width / 2 ;
193
194                for (int i = 0; i < aligs.length; i++) {
195                        AlternativeAlignment a = aligs[i];
196                        int[] idx1 = a.getIdx1();
197                        int[] idx2 = a.getIdx2();
198                        int xold = -1;
199                        int yold = -1;
200                        boolean start = true;
201
202                        if ( (selectedAlignmentPos != -1 ) &&
203                                        ( selectedAlignmentPos == i)){
204                                color = Color.white;
205                        } else {
206
207                                hue = i * (1/ (float)nr);
208                                color = Color.getHSBColor(hue,1.0f,1.0f);
209                        }
210                        g.setColor(color);
211
212                        for (int j = 0; j < idx1.length; j++) {
213                                int x1 = Math.round(idx1[j]*scale) ;
214                                int y1 = Math.round(idx2[j]*scale) ;
215                                if ( ! start){
216                                        //g.drawLine(xold+1,yold,x1+1,y1);
217
218                                        //g2D.draw(new Line2D.Double(xold,yold,x1,y1));
219                                        g.fillRect(xold,yold,2,2);
220                                } else {
221                                        g.fillRect(x1,y1, w2, w2);
222                                        start =false;
223                                }
224                                xold = x1;
225                                yold = y1;
226                        }
227
228                        if ( ! start)
229                                g.fillRect(xold,yold,w2,w2);
230
231
232                }
233
234                g2D.setStroke(oldStroke);
235        }
236
237
238        /** draw high scoring fragments that are used for the initial alignment seed
239         * selection
240         *
241         * @param g
242         */
243        public void drawBoxes(Graphics g){
244                if ( fragmentPairs == null )
245                        return;
246
247                g.setColor(Color.yellow);
248
249
250                for (int i = 0; i < fragmentPairs.length; i++) {
251                        FragmentPair fp =fragmentPairs[i];
252                        int xp = fp.getPos1();
253                        int yp = fp.getPos2();
254
255                        int width = Math.round(scale);
256
257                        g.drawRect(Math.round(xp*scale),Math.round(yp*scale),width, width);
258
259                }
260        }
261
262
263        /**
264         * For each element in matrix, draw it as a colored square or pixel.
265         *
266         * The color of a matrix element with value x is specified as
267         *   - H: 1-x/scalevalue
268         *   - S: saturation
269         *   - B: 1-x/scalevalue
270         * @param g1
271         */
272        public void drawDistances(Graphics g1){
273                Graphics2D g = (Graphics2D)g1;
274
275                int c = matrix.getRowDimension();
276                int d = matrix.getColumnDimension();
277
278                float scale = getScale();
279                int width = Math.round(scale);
280
281                for (int i = 0; i < c; i++) {
282                        int ipaint = Math.round(i*scale);
283
284                        for (int j = 0; j < d; j++) {
285                                double val = matrix.get(i,j);
286
287                                int jpaint = Math.round(j*scale);
288
289                                Color color = cellColor.getColor(val);
290                                g.setColor(color);
291
292                                g.fillRect(ipaint,jpaint,width,width);
293                        }
294
295                }
296
297        }
298
299
300        @Deprecated
301        public float getSaturation() {
302                try {
303                        Method getSaturation = cellColor.getClass().getMethod("getSaturation");
304                        Float saturation = (Float)getSaturation.invoke(cellColor);
305                        return saturation;
306                } catch (Exception e) {
307                        throw new IllegalStateException("Error calling getSaturation() for "+cellColor.getClass());
308                }
309        }
310
311        @Deprecated
312        public void setSaturation(float saturation) {
313                try {
314                        Method setSaturation = cellColor.getClass().getMethod("setSaturation",Float.TYPE);
315                        setSaturation.invoke(cellColor);
316                } catch (Exception e) {
317                        throw new IllegalStateException("Error calling setSaturation(float) for "+cellColor.getClass());
318                }
319        }
320
321        @Deprecated
322        public float getScalevalue() {
323                try {
324                        Method getScalevalue = cellColor.getClass().getMethod("getScalevalue");
325                        Float scalevalue = (Float)getScalevalue.invoke(cellColor);
326                        return scalevalue;
327                } catch (Exception e) {
328                        throw new IllegalStateException("Error calling getScalevalue() for "+cellColor.getClass());
329                }
330        }
331
332        @Deprecated
333        public void setScalevalue(float scalevalue) {
334                try{
335                        Method setScalevalue = cellColor.getClass().getMethod("setScalevalue",Float.TYPE);
336                        setScalevalue.invoke(cellColor);
337                } catch (Exception e) {
338                        throw new IllegalStateException("Error calling setScalevalue(float) for "+cellColor.getClass());
339                }
340        }
341
342        /**
343         * @return the color mapping of the JMatrixPanel
344         */
345        public ContinuousColorMapper getCellColor() {
346                return cellColor;
347        }
348
349        /**
350         * @param cellColor the color mapping of the JMatrixPanel to set
351         */
352        public void setCellColor(ContinuousColorMapper cellColor) {
353                this.cellColor = cellColor;
354        }
355
356
357
358}