From 011c92dbea927aa8ae693ae75bf1b42a1c564aef Mon Sep 17 00:00:00 2001 From: amwaterhouse Date: Fri, 24 Feb 2006 11:35:27 +0000 Subject: [PATCH] Features are an array, rendering is faster --- src/jalview/appletgui/FeatureRenderer.java | 330 ++++++++++++++++++---------- src/jalview/appletgui/FeatureSettings.java | 129 +++++++---- src/jalview/appletgui/OverviewPanel.java | 48 ++-- 3 files changed, 333 insertions(+), 174 deletions(-) diff --git a/src/jalview/appletgui/FeatureRenderer.java b/src/jalview/appletgui/FeatureRenderer.java index 4cb4f43..21c401a 100755 --- a/src/jalview/appletgui/FeatureRenderer.java +++ b/src/jalview/appletgui/FeatureRenderer.java @@ -33,19 +33,17 @@ import java.util.*; public class FeatureRenderer { AlignViewport av; - SequenceGroup currentSequenceGroup = null; - SequenceGroup[] allGroups = null; - Graphics graphics; - // The following vector holds the features which are - // to be added, in the correct order or rendering - Vector featuresDisplayed; // A higher level for grouping features of a // particular type Hashtable featureGroups = null; - Color currentColour = null; + // This is actually an Integer held in the hashtable, + // Retrieved using the key feature type + Object currentColour; + + String [] renderOrder; boolean drawText = true; FontMetrics fm; @@ -62,7 +60,70 @@ public class FeatureRenderer initColours(); } - //boolean highlightTransparent = true; + + public Color findFeatureColour(Color initialCol, SequenceI seq, int i) + { + if(!av.showSequenceFeatures) + return initialCol; + + lastSequence = seq; + sequenceFeatures = lastSequence.getSequenceFeatures(); + if(sequenceFeatures==null) + return initialCol; + + sfSize = sequenceFeatures.length; + + if(jalview.util.Comparison.isGap(lastSequence.getCharAt(i))) + return Color.white; + + currentColour = null; + + drawSequence(null, lastSequence, lastSequence.findPosition(i), -1,-1, -1, -1); + + if(currentColour==null) + return initialCol; + + return new Color( ((Integer)currentColour).intValue() ); + } + /** + * This is used by the Molecule Viewer to get the accurate colour + * of the rendered sequence + */ + + boolean overview = false; + + int white = Color.white.getRGB(); + public int findFeatureColour(int initialCol, int seqIndex, int column) + { + if(!av.showSequenceFeatures) + return initialCol; + + if(seqIndex!=lastSequenceIndex) + { + lastSequence = av.alignment.getSequenceAt(seqIndex); + lastSequenceIndex = seqIndex; + sequenceFeatures = lastSequence.getSequenceFeatures(); + if(sequenceFeatures==null) + return initialCol; + + sfSize = sequenceFeatures.length; + } + + + if(jalview.util.Comparison.isGap(lastSequence.getCharAt(column))) + return Color.white.getRGB(); + + currentColour = null; + + drawSequence(null, lastSequence, lastSequence.findPosition(column), -1,-1, -1, -1); + + if(currentColour==null) + return initialCol; + + return ((Integer)currentColour).intValue(); + } + + /** * DOCUMENT ME! * @@ -76,88 +137,117 @@ public class FeatureRenderer * @param width DOCUMENT ME! * @param height DOCUMENT ME! */ + // String type; + // SequenceFeature sf; + int lastSequenceIndex=-1; + SequenceI lastSequence; + SequenceFeature [] sequenceFeatures; + int sfSize, sfindex, spos, epos; + public void drawSequence(Graphics g, SequenceI seq, - int start, int end, int x1, int y1, int width, int height) + int start, int end, int y1, int width, int height) { - fm = g.getFontMetrics(); - - if(seq.getSequenceFeatures()==null) - return; + if ( seq.getSequenceFeatures() == null + || seq.getSequenceFeatures().length==0) + return; - Enumeration e = null, e2; - String type; - if(featuresDisplayed!=null) - e = featuresDisplayed.elements(); - else - e = seq.getSequenceFeatures().elements(); + if(g!=null) + fm = g.getFontMetrics(); - while (e.hasMoreElements()) + if (av.featuresDisplayed == null || renderOrder==null) + { + findAllFeatures(); + sequenceFeatures = seq.getSequenceFeatures(); + sfSize = sequenceFeatures.length; + } + if(lastSequence==null || seq!=lastSequence) + { + lastSequence = seq; + sequenceFeatures = seq.getSequenceFeatures(); + sfSize = sequenceFeatures.length; + } + if(!overview) + { + spos = lastSequence.findPosition(start); + epos = lastSequence.findPosition(end); + } + String type; + for(int renderIndex=0; renderIndex epos + || sequenceFeatures[sfindex].getEnd() < spos)) + continue; + if (overview) + { - if (sf.getBegin() > seq.getEnd()) + if (sequenceFeatures[sfindex].begin - 1 <= start && + sequenceFeatures[sfindex].end + 1 >= start) { - continue; + currentColour = av.featuresDisplayed.get(sequenceFeatures[sfindex]. + type); } - if (type.equals("disulfide bond")) - { + } + else if (sequenceFeatures[sfindex].type.equals("disulfide bond")) + { - renderFeature(g, seq, - seq.findIndex(sf.getBegin()) - 1, - seq.findIndex(sf.getBegin()) - 1, - type, start, end, x1, y1, width, height); - renderFeature(g, seq, - seq.findIndex(sf.getEnd()) - 1, - seq.findIndex(sf.getEnd()) - 1, - type, start, end, x1, y1, width, height); + renderFeature(g, seq, + seq.findIndex(sequenceFeatures[sfindex].begin) - 1, + seq.findIndex(sequenceFeatures[sfindex].begin) - 1, + new Color( ( (Integer) av.featuresDisplayed.get( + sequenceFeatures[sfindex].type)).intValue()), + start, end, y1, width, height); + renderFeature(g, seq, + seq.findIndex(sequenceFeatures[sfindex].end) - 1, + seq.findIndex(sequenceFeatures[sfindex].end) - 1, + new Color( ( (Integer) av.featuresDisplayed.get( + sequenceFeatures[sfindex].type)).intValue()), + start, end, y1, width, height); + + } + else + renderFeature(g, seq, + seq.findIndex(sequenceFeatures[sfindex].begin) - 1, + seq.findIndex(sequenceFeatures[sfindex].end) - 1, + getColour(sequenceFeatures[sfindex].type), + start, end, y1, width, height); - } - else - renderFeature(g, seq, - seq.findIndex(sf.getBegin()) - 1, - seq.findIndex(sf.getEnd()) - 1, - type, start, end, x1, y1, width, height); + + } } } + + char s; + int i; void renderFeature(Graphics g, SequenceI seq, - int fstart, int fend, String type, int start, int end, - int x1, int y1, int width, int height) + int fstart, int fend, Color featureColour, int start, int end, int y1, int width, int height) { - if ( ( (fstart <= end) && (fend >= start))) + + if (((fstart <= end) && (fend >= start))) { if (fstart < start) { // fix for if the feature we have starts before the sequence start, @@ -168,97 +258,105 @@ public class FeatureRenderer { fend = end; } - for (int i = fstart; i <= fend; i++) - { - char s = seq.getSequence().charAt(i); - if (jalview.util.Comparison.isGap(s)) + for (i = fstart; i <= fend; i++) { - continue; - } + s = seq.getSequence().charAt(i); - currentColour = getColour(type); + if (jalview.util.Comparison.isGap(s)) + { + continue; + } - g.setColor(currentColour); + g.setColor(featureColour); - g.fillRect( (i - start) * width, y1, width, height); + g.fillRect( (i - start) * width, y1, width, height); - if (drawText) - { g.setColor(Color.white); charOffset = (width - fm.charWidth(s)) / 2; g.drawString(String.valueOf(s), - charOffset + x1 + (width * (i - start)), - (y1 + height) - height / 5); + charOffset + (width * (i - start)), + (y1 + height) - height / 5); //pady = height / 5; + } - } } } - Image offscreen; - Frame nullframe; - public Color findFeatureColour(Color initialCol, SequenceI seq, int i) + void findAllFeatures() { - currentColour = initialCol; - if(offscreen == null) + av.featuresDisplayed = new Hashtable(); + for (int i = 0; i < av.alignment.getHeight(); i++) { - nullframe = new Frame(); - nullframe.addNotify(); - offscreen = nullframe.createImage(1, 1); - } + SequenceFeature [] features = av.alignment.getSequenceAt(i).getSequenceFeatures(); - drawSequence(offscreen.getGraphics(), seq, i, i, 0, 0, 1, 1); - return currentColour; - } + if (features == null) + continue; + int index = 0; + while (index < features.length) + { + if (!av.featuresDisplayed.containsKey(features[index].getType())) + { + av.featuresDisplayed.put(features[index].getType(), + new Integer( getColour(features[index].getType()).getRGB()) ); + } + index++; + } + } + renderOrder = new String[av.featuresDisplayed.size()]; + Enumeration en = av.featuresDisplayed.keys(); + int i = 0; + while(en.hasMoreElements()) + { + renderOrder[i] = en.nextElement().toString(); + i++; + } + } public Color getColour(String featureType) { return (Color)featureColours.get(featureType); } - public void setColour(String featureType, Color col) - { - featureColours.put(featureType, col); - } - public void addNewFeature(String name, Color col) { + setColour(name, col); - if (featuresDisplayed == null) - featuresDisplayed = new Vector(); - featuresDisplayed.insertElementAt(name, 0); - } + if(av.featuresDisplayed==null) + av.featuresDisplayed = new Hashtable(); - /* public void setTransparency(float value) - { - transparency = value; + av.featuresDisplayed.put(name, "NOGROUP"); } - public float getTransparency() + public void setColour(String featureType, Color col) { - return transparency; - }*/ + featureColours.put(featureType, col); + } public void setFeaturePriority(Object [][] data) { // The feature table will display high priority // features at the top, but theses are the ones // we need to render last, so invert the data - if(featuresDisplayed!=null) - featuresDisplayed.removeAllElements(); - else - featuresDisplayed = new Vector(); + av.featuresDisplayed.clear(); + + renderOrder = new String[data.length]; - for(int i=data.length-1; i>-1; i--) + if(data.length>0) + for(int i=0; i400) height = 400; - jalview.bin.JalviewLite.addFrame(frame, "Feature Settings", 200, + jalview.bin.JalviewLite.addFrame(frame, "Feature Settings", 250, height); } @@ -73,55 +73,98 @@ public class FeatureSettings extends Panel implements ItemListener, fr.featureGroups.clear(); Vector allFeatures = new Vector(); - Enumeration tmpfeatures; - SequenceFeature sf; + SequenceFeature[] tmpfeatures; for (int i = 0; i < av.alignment.getHeight(); i++) { if (av.alignment.getSequenceAt(i).getSequenceFeatures() == null) continue; - tmpfeatures = av.alignment.getSequenceAt(i).getSequenceFeatures().elements(); - while (tmpfeatures.hasMoreElements()) + tmpfeatures = av.alignment.getSequenceAt(i).getSequenceFeatures(); + int index = 0; + while (index < tmpfeatures.length) { - sf = (SequenceFeature) tmpfeatures.nextElement(); - if (!allFeatures.contains(sf.getType())) + if(tmpfeatures[index].getFeatureGroup()!=null + && tmpfeatures[index].getFeatureGroup().length()>0 + && !fr.featureGroups.containsKey(tmpfeatures[index].getFeatureGroup())) { - allFeatures.addElement(sf.getType()); - Color col = fr.getColour(sf.getType()); - boolean displayed = true; - if (fr.featuresDisplayed != null) - displayed = fr.featuresDisplayed.contains(sf.getType()); - - Checkbox check = new Checkbox(sf.getType(), displayed); - check.addMouseListener(this); - check.addMouseMotionListener(this); - check.setBackground(col); - check.addItemListener(this); - featurePanel.add(check); - } - if(sf.getFeatureGroup()!=null - && !fr.featureGroups.containsKey(sf.getFeatureGroup())) - { - fr.featureGroups.put(sf.getFeatureGroup(), new Boolean(true)); + fr.featureGroups.put(tmpfeatures[index].getFeatureGroup(), new Boolean(true)); if(groupPanel==null) + { groupPanel = new Panel(); + } - Checkbox check = new Checkbox(sf.getFeatureGroup(), true); + Checkbox check = new Checkbox(tmpfeatures[index].getFeatureGroup(), true); check.setFont(new Font("Serif", Font.BOLD, 12)); check.addItemListener(this); groupPanel.add(check); } + + if (!allFeatures.contains(tmpfeatures[index].getType())) + { + allFeatures.addElement(tmpfeatures[index].getType()); + } + + + index ++; } } + resetTable(); featurePanel.setLayout(new GridLayout(allFeatures.size(), 2, 10,5)); featurePanel.validate(); } + void resetTable() + { + featurePanel.removeAll(); + Enumeration groups = fr.featureGroups.keys(); + SequenceFeature [] tmpfeatures; + String group, type; + Vector checksAdded = new Vector(); + + while(groups.hasMoreElements()) + { + group = groups.nextElement().toString(); + if ( !( (Boolean) fr.featureGroups.get(group)).booleanValue()) + continue; + + for (int i = 0; i < av.alignment.getHeight(); i++) + { + if (av.alignment.getSequenceAt(i).getSequenceFeatures() == null) + continue; + + tmpfeatures = av.alignment.getSequenceAt(i).getSequenceFeatures(); + int index = 0; + while (index < tmpfeatures.length) + { + if (tmpfeatures[index].getFeatureGroup() != null && + tmpfeatures[index].getFeatureGroup().equals(group)) + { + type = tmpfeatures[index].getType(); + if(!checksAdded.contains(type)) + { + checksAdded.addElement(type); + Checkbox check = new Checkbox(type, true); + check.addMouseListener(this); + check.addMouseMotionListener(this); + check.setBackground(fr.getColour(type)); + check.addItemListener(this); + featurePanel.add(check); + } + } + index++; + } + } + } + featurePanel.validate(); + if(scrollPane!=null) + scrollPane.validate(); + } + public void itemStateChanged(ItemEvent evt) { - if(evt!=null) + if (evt != null) { //Is the source a top level featureGroup? Checkbox source = (Checkbox) evt.getSource(); @@ -132,6 +175,7 @@ public class FeatureSettings extends Panel implements ItemListener, if (ap.overviewPanel != null) ap.overviewPanel.updateOverviewImage(); + resetTable(); return; } } @@ -139,16 +183,23 @@ public class FeatureSettings extends Panel implements ItemListener, Component[] comps = featurePanel.getComponents(); int cSize = comps.length; - Object[][] data = new Object[cSize][3]; - + Object[][] tmp = new Object[cSize][3]; + int tmpSize = 0; for (int i = 0; i < cSize; i++) { Checkbox check = (Checkbox) comps[i]; - data[i][0] = check.getLabel(); - data[i][1] = fr.getColour(check.getLabel()); - data[i][2] = new Boolean(check.getState()); + if(!check.getState()) + continue; + + tmp[tmpSize][0] = check.getLabel(); + tmp[tmpSize][1] = fr.getColour(check.getLabel()); + tmp[tmpSize][2] = new Boolean(check.getState()); + tmpSize++; } + Object[][]data = new Object[tmpSize][3]; + System.arraycopy(tmp, 0, data,0, tmpSize); + fr.setFeaturePriority(data); ap.seqPanel.seqCanvas.repaint(); if (ap.overviewPanel != null) diff --git a/src/jalview/appletgui/OverviewPanel.java b/src/jalview/appletgui/OverviewPanel.java index 47c781b..8d8472e 100755 --- a/src/jalview/appletgui/OverviewPanel.java +++ b/src/jalview/appletgui/OverviewPanel.java @@ -57,8 +57,10 @@ public class OverviewPanel sr = new SequenceRenderer(av); sr.graphics = nullFrame.getGraphics(); sr.renderGaps( false ); + sr.forOverview = true; fr = new FeatureRenderer(av); fr.drawText = false; + fr.overview = true; @@ -185,10 +187,9 @@ public class OverviewPanel if (av.showSequenceFeatures) { - fr.featuresDisplayed = ap.seqPanel.seqCanvas.getFeatureRenderer(). - featuresDisplayed; fr.featureGroups = ap.seqPanel.seqCanvas.getFeatureRenderer().featureGroups; fr.featureColours = ap.seqPanel.seqCanvas.getFeatureRenderer().featureColours; + fr.sequenceFeatures = ap.seqPanel.seqCanvas.getFeatureRenderer().sequenceFeatures; } @@ -237,12 +238,14 @@ public class OverviewPanel float sampleCol = (float) alwidth / (float) width; float sampleRow = (float) alheight / (float) sequencesHeight; - int lastcol=-1, lastrow=-1; + int lastcol=-1, lastrow=0; Color color = Color.yellow; int row, col; - for (col = 0; col < width; col++) + jalview.datamodel.SequenceI sequence; + for (row = 0; row < sequencesHeight; row++) { - for (row = 0; row < sequencesHeight; row++) + sequence = av.getAlignment().getSequenceAt(lastrow); + for (col = 0; col < width; col++) { if((int)(col*sampleCol) == lastcol && (int)(row*sampleRow)==lastrow) { @@ -250,29 +253,18 @@ public class OverviewPanel continue; } - if (av.conservation != null) - { - mg.translate(col, sequencesHeight); - ap.annotationPanel.drawGraph(mg, av.conservation, - (int) (sampleCol) + 1, - graphHeight, - (int) (col * sampleCol), - (int) (col * sampleCol) + 1); - mg.translate( -col, -sequencesHeight); - } - lastrow = (int)(row*sampleRow); lastcol = (int)(col*sampleCol); if(av.alignment.getSequenceAt(lastrow).getLength()>lastcol) { - color = sr.findSequenceColour(av.alignment.getSequenceAt(lastrow), lastcol); + color = sr.findSequenceColour(sequence, lastcol); if (av.showSequenceFeatures) color = fr.findFeatureColour(color, - av.alignment.getSequenceAt(lastrow), - lastcol); + sequence, + lastcol); } mg.setColor(color); @@ -281,6 +273,24 @@ public class OverviewPanel } } + if (av.conservation != null) + { + for (col = 0; col < width; col++) + { + lastcol = (int) (col * sampleCol); + { + mg.translate(col, sequencesHeight); + ap.annotationPanel.drawGraph(mg, av.conservation, + (int) (sampleCol) + 1, + graphHeight, + (int) (col * sampleCol), + (int) (col * sampleCol) + 1); + mg.translate( -col, -sequencesHeight); + } + } + } + + System.gc(); -- 1.7.10.2