*/
package jalview.appletgui;
+import java.awt.CheckboxMenuItem;
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuItem;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.Vector;
+
import jalview.analysis.AAFrequency;
import jalview.analysis.AlignmentAnnotationUtils;
import jalview.analysis.AlignmentUtils;
import jalview.util.MessageManager;
import jalview.util.UrlLink;
-import java.awt.CheckboxMenuItem;
-import java.awt.Frame;
-import java.awt.Menu;
-import java.awt.MenuItem;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.Vector;
-
public class APopupMenu extends java.awt.PopupMenu
implements ActionListener, ItemListener
{
contents.append(MessageManager
.formatMessage("label.annotation_for_displayid", new Object[]
{ seq.getDisplayId(true) }));
- new SequenceAnnotationReport(null).createSequenceAnnotationReport(
+ new SequenceAnnotationReport(false).createSequenceAnnotationReport(
contents, seq, true, true, ap.seqPanel.seqCanvas.fr);
contents.append("</p>");
}
package jalview.datamodel;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
import jalview.io.gff.Gff3Helper;
import jalview.schemes.ResidueProperties;
+import jalview.util.MapList;
import jalview.util.MappingUtils;
import jalview.util.StringUtils;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
/**
* A data bean to hold a list of mapped sequence features (e.g. CDS features
* mapped from protein), and the mapping between the sequences. It also provides
*/
public class MappedFeatures
{
+ /*
+ * VEP CSQ:HGVSp (if present) is a short-cut to the protein variant consequence
+ */
private static final String HGV_SP = "HGVSp";
private static final String CSQ = "CSQ";
/*
- * the mapping from one sequence to another
+ * the sequence the mapped features are on
*/
- public final Mapping mapping;
+ private final SequenceI linkedSeq;
- /**
- * the sequence mapped from
+ /*
+ * the mapping between sequences;
+ * NB this could be in either sense
*/
- public final SequenceI fromSeq;
+ private final Mapping mapping;
/*
- * features on the sequence mapped to that overlap the mapped positions
+ * if true, mapping is from the linked sequence, else to the linked sequence
+ */
+ private boolean mappingIsFromLinkedSequence;
+
+ /*
+ * features on linkedSeq that overlap the mapped positions
*/
public final List<SequenceFeature> features;
char res, List<SequenceFeature> theFeatures)
{
mapping = theMapping;
- fromSeq = from;
+ linkedSeq = from;
+ mappingIsFromLinkedSequence = mapping.to != linkedSeq;
toPosition = pos;
toResidue = res;
features = theFeatures;
{
codonPos = codonPositions;
baseCodon = new char[3];
- int cdsStart = fromSeq.getStart();
+ int cdsStart = linkedSeq.getStart();
baseCodon[0] = Character
- .toUpperCase(fromSeq.getCharAt(codonPos[0] - cdsStart));
+ .toUpperCase(linkedSeq.getCharAt(codonPos[0] - cdsStart));
baseCodon[1] = Character
- .toUpperCase(fromSeq.getCharAt(codonPos[1] - cdsStart));
+ .toUpperCase(linkedSeq.getCharAt(codonPos[1] - cdsStart));
baseCodon[2] = Character
- .toUpperCase(fromSeq.getCharAt(codonPos[2] - cdsStart));
+ .toUpperCase(linkedSeq.getCharAt(codonPos[2] - cdsStart));
}
else
{
return vars.toString();
}
+
+ /**
+ * Answers the name of the linked sequence holding any mapped features
+ *
+ * @return
+ */
+ public String getLinkedSequenceName()
+ {
+ return linkedSeq == null ? null : linkedSeq.getName();
+ }
+
+ /**
+ * Answers the mapped ranges (as one or more [start, end] positions) which
+ * correspond to the given [begin, end] range of the linked sequence.
+ *
+ * <pre>
+ * Example: MappedFeatures with CDS features mapped to peptide
+ * CDS/200-220 gtc aac TGa acGt att AAC tta
+ * mapped to PEP/6-7 WN by mapping [206, 207, 210, 210, 215, 217] to [6, 7]
+ * getMappedPositions(206, 206) should return [6, 6]
+ * getMappedPositions(200, 214) should return [6, 6]
+ * getMappedPositions(210, 215) should return [6, 7]
+ * </pre>
+ *
+ * @param begin
+ * @param end
+ * @return
+ */
+ public int[] getMappedPositions(int begin, int end)
+ {
+ MapList map = mapping.getMap();
+ return mappingIsFromLinkedSequence ? map.locateInTo(begin, end)
+ : map.locateInFrom(begin, end);
+ }
+
+ public boolean isFromCds()
+ {
+ if (mapping.getMap().getFromRatio() == 3)
+ {
+ return mappingIsFromLinkedSequence;
+ }
+ return !mappingIsFromLinkedSequence;
+ }
}
*/
package jalview.datamodel;
-import jalview.datamodel.features.FeatureAttributeType;
-import jalview.datamodel.features.FeatureAttributes;
-import jalview.datamodel.features.FeatureLocationI;
-import jalview.datamodel.features.FeatureSourceI;
-import jalview.datamodel.features.FeatureSources;
-import jalview.util.StringUtils;
-
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.Vector;
+import jalview.datamodel.features.FeatureAttributeType;
+import jalview.datamodel.features.FeatureAttributes;
+import jalview.datamodel.features.FeatureLocationI;
+import jalview.datamodel.features.FeatureSourceI;
+import jalview.datamodel.features.FeatureSources;
+import jalview.util.StringUtils;
+
/**
* A class that models a single contiguous feature on a sequence. If flag
* 'contactFeature' is true, the start and end positions are interpreted instead
}
/**
- * Answers an html-formatted report of feature details
+ * Answers an html-formatted report of feature details. If parameter
+ * {@code mf} is not null, the feature is a virtual linked feature, and
+ * details included both the original location and the mapped location
+ * (CDS/peptide).
*
* @param seqName
+ * @param mf
*
* @return
*/
- public String getDetailsReport(String seqName)
+ public String getDetailsReport(String seqName, MappedFeatures mf)
{
FeatureSourceI metadata = FeatureSources.getInstance()
.getSource(source);
StringBuilder sb = new StringBuilder(128);
sb.append("<br>");
sb.append("<table>");
- sb.append(String.format(ROW_DATA, "Location", seqName,
+ String name = mf == null ? seqName : mf.getLinkedSequenceName();
+ sb.append(String.format(ROW_DATA, "Location", name,
begin == end ? begin
: begin + (isContactFeature() ? ":" : "-") + end));
+ if (mf != null)
+ {
+ int[] beginRange = mf.getMappedPositions(begin, begin);
+ int[] endRange = mf.getMappedPositions(end, end);
+ int from = beginRange[0];
+ int to = endRange[endRange.length - 1];
+ String s = mf.isFromCds() ? "Peptide Location" : "Coding location";
+ sb.append(String.format(ROW_DATA, s, seqName, from == to ? from
+ : from + (isContactFeature() ? ":" : "-") + to));
+ if (mf.isFromCds())
+ {
+ sb.append(String.format(ROW_DATA, "Consequence",
+ mf.findProteinVariants(this), ""));
+ }
+ }
sb.append(String.format(ROW_DATA, "Type", type, ""));
String desc = StringUtils.stripHtmlTags(description);
sb.append(String.format(ROW_DATA, "Description", desc, ""));
*/
package jalview.gui;
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.Sequence;
-import jalview.datamodel.SequenceGroup;
-import jalview.datamodel.SequenceI;
-import jalview.gui.SeqPanel.MousePos;
-import jalview.io.SequenceAnnotationReport;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-import jalview.viewmodel.AlignmentViewport;
-import jalview.viewmodel.ViewportRanges;
-
import java.awt.BorderLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.gui.SeqPanel.MousePos;
+import jalview.io.SequenceAnnotationReport;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
+
/**
* This panel hosts alignment sequence ids and responds to mouse clicks on them,
* as well as highlighting ids matched by a search from the Find menu.
ScrollThread scrollThread = null;
- String linkImageURL;
-
int offy;
// int width;
this.av = av;
alignPanel = parent;
setIdCanvas(new IdCanvas(av));
- linkImageURL = getClass().getResource("/images/link.gif").toString();
- seqAnnotReport = new SequenceAnnotationReport(linkImageURL);
+ seqAnnotReport = new SequenceAnnotationReport(true);
setLayout(new BorderLayout());
add(getIdCanvas(), BorderLayout.CENTER);
addMouseListener(this);
*/
package jalview.gui;
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.Vector;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JColorChooser;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.JRadioButtonMenuItem;
+
import jalview.analysis.AAFrequency;
import jalview.analysis.AlignmentAnnotationUtils;
import jalview.analysis.AlignmentUtils;
import jalview.util.UrlLink;
import jalview.viewmodel.seqfeatures.FeatureRendererModel;
-import java.awt.Color;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.BitSet;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Hashtable;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.Vector;
-
-import javax.swing.ButtonGroup;
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JColorChooser;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.JPopupMenu;
-import javax.swing.JRadioButtonMenuItem;
-
/**
* The popup menu that is displayed on right-click on a sequence id, or in the
* sequence alignment.
}
/**
- * Add a link to show feature details for each sequence feature
+ * Add a menu item to show feature details for each sequence feature. Any
+ * linked 'virtual' features (CDS/protein) are also optionally found and
+ * included.
*
* @param features
- * @param column
* @param seq
+ * @param column
*/
protected void addFeatureDetails(List<SequenceFeature> features,
- SequenceI seq, int column)
+ final SequenceI seq, final int column)
{
/*
* add features in CDS/protein complement at the corresponding
String name = seq.getName();
for (final SequenceFeature sf : features)
{
- addFeatureDetailsMenuItem(details, name, sf);
+ addFeatureDetailsMenuItem(details, name, sf, null);
}
if (mf != null)
{
- name = mf.fromSeq == seq ? mf.mapping.getTo().getName()
- : mf.fromSeq.getName();
for (final SequenceFeature sf : mf.features)
{
- addFeatureDetailsMenuItem(details, name, sf);
+ addFeatureDetailsMenuItem(details, name, sf, mf);
}
}
}
/**
- * A helper method to add one menu item whose action is to show details for one
- * feature. The menu text includes feature description, but this may be
+ * A helper method to add one menu item whose action is to show details for
+ * one feature. The menu text includes feature description, but this may be
* truncated.
*
* @param details
* @param seqName
* @param sf
+ * @param mf
*/
void addFeatureDetailsMenuItem(JMenu details, final String seqName,
- final SequenceFeature sf)
+ final SequenceFeature sf, MappedFeatures mf)
{
int start = sf.getBegin();
int end = sf.getEnd();
+ if (mf != null)
+ {
+ /*
+ * show local rather than linked feature coordinates
+ */
+ int[] beginRange = mf.getMappedPositions(start, start);
+ start = beginRange[0];
+ int[] endRange = mf.getMappedPositions(end, end);
+ end = endRange[endRange.length - 1];
+ }
StringBuilder desc = new StringBuilder();
desc.append(sf.getType()).append(" ").append(String.valueOf(start));
if (start != end)
{
- desc.append("-").append(String.valueOf(end));
+ desc.append(sf.isContactFeature() ? ":" : "-");
+ desc.append(String.valueOf(end));
}
String description = sf.getDescription();
if (description != null)
@Override
public void actionPerformed(ActionEvent e)
{
- showFeatureDetails(seqName, sf);
+ showFeatureDetails(sf, seqName, mf);
}
});
details.add(item);
}
/**
- * Opens a panel showing a text report of feature dteails
- *
- * @param seqName
+ * Opens a panel showing a text report of feature details
*
* @param sf
+ * @param seqName
+ * @param mf
*/
- protected void showFeatureDetails(String seqName, SequenceFeature sf)
+ protected void showFeatureDetails(SequenceFeature sf, String seqName,
+ MappedFeatures mf)
{
CutAndPasteHtmlTransfer cap = new CutAndPasteHtmlTransfer();
// it appears Java's CSS does not support border-collapse :-(
cap.addStylesheetRule("table { border-collapse: collapse;}");
cap.addStylesheetRule("table, td, th {border: 1px solid black;}");
- cap.setText(sf.getDetailsReport(seqName));
+ cap.setText(sf.getDetailsReport(seqName, mf));
Desktop.addInternalFrame(cap,
MessageManager.getString("label.feature_details"), 500, 500);
"label.create_sequence_details_report_annotation_for",
new Object[]
{ seq.getDisplayId(true) }) + "</h2></p><p>");
- new SequenceAnnotationReport(null).createSequenceAnnotationReport(
+ new SequenceAnnotationReport(false).createSequenceAnnotationReport(
contents, seq, true, true, ap.getSeqPanel().seqCanvas.fr);
contents.append("</p>");
}
StringBuffer keyboardNo2;
- java.net.URL linkImageURL;
-
private final SequenceAnnotationReport seqARep;
StringBuilder tooltipText = new StringBuilder();
*/
public SeqPanel(AlignViewport viewport, AlignmentPanel alignPanel)
{
- linkImageURL = getClass().getResource("/images/link.gif");
- seqARep = new SequenceAnnotationReport(linkImageURL.toString());
+ seqARep = new SequenceAnnotationReport(true);
ToolTipManager.sharedInstance().registerComponent(this);
ToolTipManager.sharedInstance().setInitialDelay(0);
ToolTipManager.sharedInstance().setDismissDelay(10000);
{
List<SequenceFeature> features = ap.getFeatureRenderer()
.findFeaturesAtColumn(sequence, column + 1);
- unshownFeatures = seqARep.appendFeaturesLengthLimit(tooltipText, pos,
- features,
- this.ap.getSeqPanel().seqCanvas.fr, MAX_TOOLTIP_LENGTH);
+ unshownFeatures = seqARep.appendFeatures(tooltipText, pos,
+ features, this.ap.getSeqPanel().seqCanvas.fr,
+ MAX_TOOLTIP_LENGTH);
/*
* add features in CDS/protein complement at the corresponding
pos);
if (mf != null)
{
- unshownFeatures = seqARep.appendFeaturesLengthLimit(
- tooltipText, pos, mf, fr2,
- MAX_TOOLTIP_LENGTH);
+ unshownFeatures = seqARep.appendFeatures(tooltipText,
+ pos, mf, fr2, MAX_TOOLTIP_LENGTH);
}
}
}
*/
package jalview.io;
+import java.awt.Color;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
import jalview.analysis.AlignmentUtils;
import jalview.analysis.SequenceIdMatcher;
import jalview.api.AlignViewportI;
import jalview.util.ParseHtmlBodyAndLinks;
import jalview.util.StringUtils;
-import java.awt.Color;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.TreeMap;
-
/**
* Parses and writes features files, which may be in Jalview, GFF2 or GFF3
* format. These are tab-delimited formats but with differences in the use of
if (mf != null)
{
- MapList mapping = mf.mapping.getMap();
for (SequenceFeature sf : mf.features)
{
/*
found.add(sf);
int begin = sf.getBegin();
int end = sf.getEnd();
- int[] range = mf.mapping.getTo() == seq.getDatasetSequence()
- ? mapping.locateInTo(begin, end)
- : mapping.locateInFrom(begin, end);
+ int[] range = mf.getMappedPositions(begin, end);
SequenceFeature sf2 = new SequenceFeature(sf, range[0],
range[1], group, sf.getScore());
complementary.add(sf2);
*/
package jalview.io;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
import jalview.api.FeatureColourI;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.DBRefSource;
import jalview.util.UrlLink;
import jalview.viewmodel.seqfeatures.FeatureRendererModel;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
/**
* generate HTML reports for a sequence
*
private static final int MAX_SOURCES = 40;
+ private static String linkImageURL;
+
private static final String[][] PRIMARY_SOURCES = new String[][] {
DBRefSource.CODINGDBS, DBRefSource.DNACODINGDBS,
DBRefSource.PROTEINDBS };
- final String linkImageURL;
-
/*
* Comparator to order DBRefEntry by Source + accession id (case-insensitive),
* with 'Primary' sources placed before others, and 'chromosome' first of all
}
};
- public SequenceAnnotationReport(String linkURL)
+ private boolean forTooltip;
+
+ /**
+ * Constructor given a flag which affects behaviour
+ * <ul>
+ * <li>if true, generates feature details suitable to show in a tooltip</li>
+ * <li>if false, generates feature details in a form suitable for the sequence
+ * details report</li>
+ * </ul>
+ *
+ * @param isForTooltip
+ */
+ public SequenceAnnotationReport(boolean isForTooltip)
{
- this.linkImageURL = linkURL;
+ this.forTooltip = isForTooltip;
+ if (linkImageURL == null)
+ {
+ linkImageURL = getClass().getResource("/images/link.gif").toString();
+ }
}
/**
- * Append text for the list of features to the tooltip Returns number of
- * features left if maxlength limit is (or would have been) reached
+ * Append text for the list of features to the tooltip. Returns the number of
+ * features not added if maxlength limit is (or would have been) reached.
*
* @param sb
* @param residuePos
* @param minmax
* @param maxlength
*/
- public int appendFeaturesLengthLimit(final StringBuilder sb,
+ public int appendFeatures(final StringBuilder sb,
int residuePos, List<SequenceFeature> features,
FeatureRendererModel fr, int maxlength)
{
return 0;
}
- public void appendFeatures(final StringBuilder sb, int residuePos,
- List<SequenceFeature> features, FeatureRendererModel fr)
- {
- appendFeaturesLengthLimit(sb, residuePos, features, fr, 0);
- }
-
/**
- * Appends text for mapped features (e.g. CDS feature for peptide or vice versa)
- * Returns number of features left if maxlength limit is (or would have been)
- * reached
+ * Appends text for mapped features (e.g. CDS feature for peptide or vice
+ * versa) Returns number of features left if maxlength limit is (or would have
+ * been) reached.
*
* @param sb
* @param residuePos
* @param fr
* @param maxlength
*/
- public int appendFeaturesLengthLimit(StringBuilder sb, int residuePos,
+ public int appendFeatures(StringBuilder sb, int residuePos,
MappedFeatures mf, FeatureRendererModel fr, int maxlength)
{
for (int i = 0; i < mf.features.size(); i++)
return 0;
}
- public void appendFeatures(StringBuilder sb, int residuePos,
- MappedFeatures mf, FeatureRendererModel fr)
- {
- appendFeaturesLengthLimit(sb, residuePos, mf, fr, 0);
- }
-
/**
* Appends the feature at rpos to the given buffer
*
FeatureRendererModel fr, SequenceFeature feature,
MappedFeatures mf, int maxlength)
{
+ int begin = feature.getBegin();
+ int end = feature.getEnd();
+
+ /*
+ * if this is a virtual features, convert begin/end to the
+ * coordinates of the sequence it is mapped to
+ */
+ int[] beginRange = null;
+ int[] endRange = null;
+ if (mf != null)
+ {
+ beginRange = mf.getMappedPositions(begin, begin);
+ endRange = mf.getMappedPositions(end, end);
+ begin = beginRange[0];
+ end = endRange[endRange.length - 1];
+ }
+
StringBuilder sb = new StringBuilder();
if (feature.isContactFeature())
{
- if (feature.getBegin() == rpos || feature.getEnd() == rpos)
+ /*
+ * include if rpos is at start or end position of [mapped] feature
+ */
+ boolean showContact = (mf == null) && (rpos == begin || rpos == end);
+ boolean showMappedContact = (mf != null) && ((rpos >= beginRange[0]
+ && rpos <= beginRange[beginRange.length - 1])
+ || (rpos >= endRange[0]
+ && rpos <= endRange[endRange.length - 1]));
+ if (showContact || showMappedContact)
{
if (sb0.length() > 6)
{
sb.append("<br/>");
}
- sb.append(feature.getType()).append(" ").append(feature.getBegin())
- .append(":").append(feature.getEnd());
+ sb.append(feature.getType()).append(" ").append(begin).append(":")
+ .append(end);
}
- return appendTextMaxLengthReached(sb0, sb, maxlength);
+ return appendText(sb0, sb, maxlength);
}
if (sb0.length() > 6)
if (rpos != 0)
{
// we are marking a positional feature
- sb.append(feature.begin);
- }
- if (feature.begin != feature.end)
- {
- sb.append(" ").append(feature.end);
+ sb.append(begin);
+ if (begin != end)
+ {
+ sb.append(" ").append(end);
+ }
}
String description = feature.getDescription();
}
}
}
- return appendTextMaxLengthReached(sb0, sb, maxlength);
+ return appendText(sb0, sb, maxlength);
}
- void appendFeature(final StringBuilder sb, int rpos,
- FeatureRendererModel fr, SequenceFeature feature,
- MappedFeatures mf)
- {
- appendFeature(sb, rpos, fr, feature, mf, 0);
- }
-
- private static boolean appendTextMaxLengthReached(StringBuilder sb0,
- StringBuilder sb, int maxlength)
+ /**
+ * Appends sb to sb0, and returns false, unless maxlength is not zero and
+ * appending would make the result longer than or equal to maxlength, in which
+ * case the append is not done and returns true
+ *
+ * @param sb0
+ * @param sb
+ * @param maxlength
+ * @return
+ */
+ private static boolean appendText(StringBuilder sb0, StringBuilder sb,
+ int maxlength)
{
- boolean ret = false;
if (maxlength == 0 || sb0.length() + sb.length() < maxlength)
{
sb0.append(sb);
return false;
- } else {
- return true;
}
+ return true;
}
/**
.getNonPositionalFeatures())
{
int sz = -sb.length();
- appendFeature(sb, 0, fr, sf, null);
+ appendFeature(sb, 0, fr, sf, null, 0);
sz += sb.length();
maxWidth = Math.max(maxWidth, sz);
}
*/
package jalview.viewmodel.seqfeatures;
+import java.awt.Color;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
import jalview.api.AlignViewportI;
import jalview.api.FeatureColourI;
import jalview.api.FeaturesDisplayedI;
import jalview.schemes.FeatureColour;
import jalview.util.ColorUtils;
-import java.awt.Color;
-import java.beans.PropertyChangeListener;
-import java.beans.PropertyChangeSupport;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
public abstract class FeatureRendererModel
implements jalview.api.FeatureRenderer
{
}
@Override
- public MappedFeatures findComplementFeaturesAtResidue(SequenceI sequence,
- int pos)
+ public MappedFeatures findComplementFeaturesAtResidue(
+ final SequenceI sequence, final int pos)
{
SequenceI ds = sequence.getDatasetSequence();
if (ds == null)
}
/*
- * sort by renderorder, inefficiently
+ * sort by renderorder (inefficiently but ok for small scale);
+ * NB this sorts 'on top' feature to end, for rendering
*/
List<SequenceFeature> result = new ArrayList<>();
+ final int toAdd = found.size();
+ int added = 0;
for (String type : renderOrder)
{
for (SequenceFeature sf : found)
if (type.equals(sf.getType()))
{
result.add(sf);
- if (result.size() == found.size())
- {
- return new MappedFeatures(mapping, mapFrom, pos, residue,
- result);
- }
+ added++;
+ }
+ if (added == toAdd)
+ {
+ break;
+ }
+ if (added == toAdd)
+ {
+ break;
}
}
}
import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertTrue;
-import jalview.gui.JvOptionPane;
-
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
+import jalview.gui.JvOptionPane;
+
public class SequenceFeatureTest
{
String expected = "<br><table><tr><td>Location</td><td>TestSeq</td><td>22</td></tr>"
+ "<tr><td>Type</td><td>variant</td><td></td></tr>"
+ "<tr><td>Description</td><td>G,C</td><td></td></tr></table>";
- assertEquals(expected, sf.getDetailsReport(seqName));
+ assertEquals(expected, sf.getDetailsReport(seqName, null));
// contact feature
sf = new SequenceFeature("Disulphide Bond", "a description", 28, 31,
expected = "<br><table><tr><td>Location</td><td>TestSeq</td><td>28:31</td></tr>"
+ "<tr><td>Type</td><td>Disulphide Bond</td><td></td></tr>"
+ "<tr><td>Description</td><td>a description</td><td></td></tr></table>";
- assertEquals(expected, sf.getDetailsReport(seqName));
+ assertEquals(expected, sf.getDetailsReport(seqName, null));
sf = new SequenceFeature("variant", "G,C", 22, 33,
12.5f, "group");
+ "<tr><td>Group</td><td>group</td><td></td></tr>"
+ "<tr><td>Child</td><td></td><td>ENSP002</td></tr>"
+ "<tr><td>Parent</td><td></td><td>ENSG001</td></tr></table>";
- assertEquals(expected, sf.getDetailsReport(seqName));
+ assertEquals(expected, sf.getDetailsReport(seqName, null));
/*
* feature with embedded html link in description
+ "<tr><td>Type</td><td>Pfam</td><td></td></tr>"
+ "<tr><td>Description</td><td>Fer2 Status: True Positive <a href=\"http://pfam.xfam.org/family/PF00111\">Pfam 8_8</a></td><td></td></tr>"
+ "<tr><td>Group</td><td>Uniprot</td><td></td></tr></table>";
- assertEquals(expected, sf.getDetailsReport(seqName));
+ assertEquals(expected, sf.getDetailsReport(seqName, null));
}
}
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
import jalview.api.FeatureColourI;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.Sequence;
import jalview.renderer.seqfeatures.FeatureRenderer;
import jalview.schemes.FeatureColour;
import jalview.viewmodel.seqfeatures.FeatureRendererModel;
-
-import java.awt.Color;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
import junit.extensions.PA;
public class SequenceAnnotationReportTest
@Test(groups = "Functional")
public void testAppendFeature_disulfideBond()
{
- SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+ SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
StringBuilder sb = new StringBuilder();
sb.append("123456");
SequenceFeature sf = new SequenceFeature("disulfide bond", "desc", 1,
3, 1.2f, "group");
// residuePos == 2 does not match start or end of feature, nothing done:
- sar.appendFeature(sb, 2, null, sf, null);
+ sar.appendFeature(sb, 2, null, sf, null, 0);
assertEquals("123456", sb.toString());
// residuePos == 1 matches start of feature, text appended (but no <br/>)
// feature score is not included
- sar.appendFeature(sb, 1, null, sf, null);
+ sar.appendFeature(sb, 1, null, sf, null, 0);
assertEquals("123456disulfide bond 1:3", sb.toString());
// residuePos == 3 matches end of feature, text appended
// <br/> is prefixed once sb.length() > 6
- sar.appendFeature(sb, 3, null, sf, null);
+ sar.appendFeature(sb, 3, null, sf, null, 0);
assertEquals("123456disulfide bond 1:3<br/>disulfide bond 1:3",
sb.toString());
}
@Test(groups = "Functional")
public void testAppendFeatures_longText()
{
- SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+ SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
StringBuilder sb = new StringBuilder();
String longString = "Abcd".repeat(50);
SequenceFeature sf = new SequenceFeature("sequence", longString, 1, 3,
"group");
- sar.appendFeature(sb, 1, null, sf, null);
+ sar.appendFeature(sb, 1, null, sf, null, 0);
assertTrue(sb.length() < 100);
List<SequenceFeature> sfl = new ArrayList<>();
sfl.add(sf);
sfl.add(sf);
sfl.add(sf);
- int n = sar.appendFeaturesLengthLimit(sb, 1, sfl,
+ int n = sar.appendFeatures(sb, 1, sfl,
new FeatureRenderer(null), 200); // text should terminate before 200 characters
String s = sb.toString();
assertTrue(s.length() < 200);
@Test(groups = "Functional")
public void testAppendFeature_status()
{
- SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+ SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
StringBuilder sb = new StringBuilder();
SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
Float.NaN, "group");
sf.setStatus("Confirmed");
- sar.appendFeature(sb, 1, null, sf, null);
+ sar.appendFeature(sb, 1, null, sf, null, 0);
assertEquals("METAL 1 3; Fe2-S; (Confirmed)", sb.toString());
}
@Test(groups = "Functional")
public void testAppendFeature_withScore()
{
- SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+ SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
StringBuilder sb = new StringBuilder();
SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
"group");
FeatureRendererModel fr = new FeatureRenderer(null);
Map<String, float[][]> minmax = fr.getMinMax();
- sar.appendFeature(sb, 1, fr, sf, null);
+ sar.appendFeature(sb, 1, fr, sf, null, 0);
/*
* map has no entry for this feature type - score is not shown:
*/
* map has entry for this feature type - score is shown:
*/
minmax.put("METAL", new float[][] { { 0f, 1f }, null });
- sar.appendFeature(sb, 1, fr, sf, null);
+ sar.appendFeature(sb, 1, fr, sf, null, 0);
// <br/> is appended to a buffer > 6 in length
assertEquals("METAL 1 3; Fe2-S<br/>METAL 1 3; Fe2-S Score=1.3",
sb.toString());
*/
minmax.put("METAL", new float[][] { { 2f, 2f }, null });
sb.setLength(0);
- sar.appendFeature(sb, 1, fr, sf, null);
+ sar.appendFeature(sb, 1, fr, sf, null, 0);
assertEquals("METAL 1 3; Fe2-S", sb.toString());
}
@Test(groups = "Functional")
public void testAppendFeature_noScore()
{
- SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+ SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
StringBuilder sb = new StringBuilder();
SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
Float.NaN, "group");
- sar.appendFeature(sb, 1, null, sf, null);
+ sar.appendFeature(sb, 1, null, sf, null, 0);
assertEquals("METAL 1 3; Fe2-S", sb.toString());
}
@Test(groups = "Functional")
public void testAppendFeature_colouredByAttribute()
{
- SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+ SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
StringBuilder sb = new StringBuilder();
SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
Float.NaN, "group");
* first with no colour by attribute
*/
FeatureRendererModel fr = new FeatureRenderer(null);
- sar.appendFeature(sb, 1, fr, sf, null);
+ sar.appendFeature(sb, 1, fr, sf, null, 0);
assertEquals("METAL 1 3; Fe2-S", sb.toString());
/*
fc.setAttributeName("Pfam");
fr.setColour("METAL", fc);
sb.setLength(0);
- sar.appendFeature(sb, 1, fr, sf, null);
+ sar.appendFeature(sb, 1, fr, sf, null, 0);
assertEquals("METAL 1 3; Fe2-S", sb.toString()); // no change
/*
*/
fc.setAttributeName("clinical_significance");
sb.setLength(0);
- sar.appendFeature(sb, 1, fr, sf, null);
+ sar.appendFeature(sb, 1, fr, sf, null, 0);
assertEquals("METAL 1 3; Fe2-S; clinical_significance=Benign",
sb.toString());
}
@Test(groups = "Functional")
public void testAppendFeature_withScoreStatusAttribute()
{
- SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+ SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
StringBuilder sb = new StringBuilder();
SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
"group");
fc.setAttributeName("clinical_significance");
fr.setColour("METAL", fc);
minmax.put("METAL", new float[][] { { 0f, 1f }, null });
- sar.appendFeature(sb, 1, fr, sf, null);
+ sar.appendFeature(sb, 1, fr, sf, null, 0);
assertEquals(
"METAL 1 3; Fe2-S Score=1.3; (Confirmed); clinical_significance=Benign",
@Test(groups = "Functional")
public void testAppendFeature_DescEqualsType()
{
- SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+ SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
StringBuilder sb = new StringBuilder();
SequenceFeature sf = new SequenceFeature("METAL", "METAL", 1, 3,
Float.NaN, "group");
// description is not included if it duplicates type:
- sar.appendFeature(sb, 1, null, sf, null);
+ sar.appendFeature(sb, 1, null, sf, null, 0);
assertEquals("METAL 1 3", sb.toString());
sb.setLength(0);
sf.setDescription("Metal");
// test is case-sensitive:
- sar.appendFeature(sb, 1, null, sf, null);
+ sar.appendFeature(sb, 1, null, sf, null, 0);
assertEquals("METAL 1 3; Metal", sb.toString());
}
@Test(groups = "Functional")
public void testAppendFeature_stripHtml()
{
- SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+ SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
StringBuilder sb = new StringBuilder();
SequenceFeature sf = new SequenceFeature("METAL",
"<html><body>hello<em>world</em></body></html>", 1, 3,
Float.NaN, "group");
- sar.appendFeature(sb, 1, null, sf, null);
+ sar.appendFeature(sb, 1, null, sf, null, 0);
// !! strips off </body> but not <body> ??
assertEquals("METAL 1 3; <body>hello<em>world</em>", sb.toString());
sb.setLength(0);
sf.setDescription("<br>&kHD>6");
- sar.appendFeature(sb, 1, null, sf, null);
+ sar.appendFeature(sb, 1, null, sf, null, 0);
// if no <html> tag, html-encodes > and < (only):
assertEquals("METAL 1 3; <br>&kHD>6", sb.toString());
}
@Test(groups = "Functional")
public void testCreateSequenceAnnotationReport()
{
- SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+ SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
StringBuilder sb = new StringBuilder();
SequenceI seq = new Sequence("s1", "MAKLKRFQSSTLL");
@Test(groups = "Functional")
public void testCreateSequenceAnnotationReport_withEllipsis()
{
- SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+ SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
StringBuilder sb = new StringBuilder();
SequenceI seq = new Sequence("s1", "ABC");