/*
* add a mapping from CDS to the (unchanged) mapped to range
*/
- List<int[]> cdsRange = Collections.singletonList(new int[] { 1,
- cdsSeq.getLength() });
+ List<int[]> cdsRange = Collections
+ .singletonList(new int[]
+ { cdsSeq.getStart(),
+ cdsSeq.getLength() + cdsSeq.getStart() - 1 });
MapList cdsToProteinMap = new MapList(cdsRange,
mapList.getToRanges(), mapList.getFromRatio(),
mapList.getToRatio());
static SequenceI makeCdsSequence(SequenceI seq, Mapping mapping,
AlignmentI dataset)
{
- char[] seqChars = seq.getSequence();
- List<int[]> fromRanges = mapping.getMap().getFromRanges();
- int cdsWidth = MappingUtils.getLength(fromRanges);
- char[] newSeqChars = new char[cdsWidth];
+ /*
+ * construct CDS sequence name as "CDS|" with 'from id' held in the mapping
+ * if set (e.g. EMBL protein_id), else sequence name appended
+ */
+ String mapFromId = mapping.getMappedFromId();
+ final String seqId = "CDS|"
+ + (mapFromId != null ? mapFromId : seq.getName());
- int newPos = 0;
- for (int[] range : fromRanges)
+ SequenceI newSeq = null;
+
+ final MapList maplist = mapping.getMap();
+ if (maplist.isContiguous() && maplist.isFromForwardStrand())
{
- if (range[0] <= range[1])
- {
- // forward strand mapping - just copy the range
- int length = range[1] - range[0] + 1;
- System.arraycopy(seqChars, range[0] - 1, newSeqChars, newPos,
- length);
- newPos += length;
- }
- else
+ /*
+ * just a subsequence, keep same dataset sequence
+ */
+ int start = maplist.getFromLowest();
+ int end = maplist.getFromHighest();
+ newSeq = seq.getSubSequence(start - 1, end);
+ newSeq.setName(seqId);
+ }
+ else
+ {
+ /*
+ * construct by splicing mapped from ranges
+ */
+ char[] seqChars = seq.getSequence();
+ List<int[]> fromRanges = maplist.getFromRanges();
+ int cdsWidth = MappingUtils.getLength(fromRanges);
+ char[] newSeqChars = new char[cdsWidth];
+
+ int newPos = 0;
+ for (int[] range : fromRanges)
{
- // reverse strand mapping - copy and complement one by one
- for (int i = range[0]; i >= range[1]; i--)
+ if (range[0] <= range[1])
+ {
+ // forward strand mapping - just copy the range
+ int length = range[1] - range[0] + 1;
+ System.arraycopy(seqChars, range[0] - 1, newSeqChars, newPos,
+ length);
+ newPos += length;
+ }
+ else
{
- newSeqChars[newPos++] = Dna.getComplement(seqChars[i - 1]);
+ // reverse strand mapping - copy and complement one by one
+ for (int i = range[0]; i >= range[1]; i--)
+ {
+ newSeqChars[newPos++] = Dna.getComplement(seqChars[i - 1]);
+ }
}
}
+
+ newSeq = new Sequence(seqId, newSeqChars, 1, newPos);
}
- /*
- * assign 'from id' held in the mapping if set (e.g. EMBL protein_id),
- * else generate a sequence name
- */
- String mapFromId = mapping.getMappedFromId();
- String seqId = "CDS|" + (mapFromId != null ? mapFromId : seq.getName());
- SequenceI newSeq = new Sequence(seqId, newSeqChars, 1, newPos);
if (dataset != null)
{
SequenceI[] matches = dataset.findSequenceMatch(newSeq.getName());
{
copyTo = copyTo.getDatasetSequence();
}
+ if (fromSeq == copyTo || fromSeq.getDatasetSequence() == copyTo)
+ {
+ return 0; // shared dataset sequence
+ }
/*
* get features, optionally restricted by an ontology term
static int computePeptideVariants(SequenceI peptide, int peptidePos,
List<DnaVariant>[] codonVariants)
{
- String residue = String.valueOf(peptide.getCharAt(peptidePos - 1));
+ String residue = String
+ .valueOf(peptide.getCharAt(peptidePos - peptide.getStart()));
int count = 0;
String base1 = codonVariants[0].get(0).base;
String base2 = codonVariants[1].get(0).base;
*/
public static int alignAs(AlignmentI unaligned, AlignmentI aligned)
{
- /*
- * easy case - aligning a copy of aligned sequences
- */
- if (alignAsSameSequences(unaligned, aligned))
- {
- return unaligned.getHeight();
- }
-
- /*
- * fancy case - aligning via mappings between sequences
- */
List<SequenceI> unmapped = new ArrayList<>();
Map<Integer, Map<SequenceI, Character>> columnMap = buildMappedColumnsMap(
unaligned, aligned, unmapped);
* true; else returns false
*
* @param unaligned
- * - sequences to be aligned based on aligned
+ * - sequences to be aligned based on aligned
* @param aligned
- * - 'guide' alignment containing sequences derived from same dataset
- * as unaligned
+ * - 'guide' alignment containing sequences derived from same
+ * dataset as unaligned
* @return
+ * @deprecated probably obsolete and incomplete
*/
+ @Deprecated
static boolean alignAsSameSequences(AlignmentI unaligned,
AlignmentI aligned)
{
}
/*
- * first pass - check whether all sequences to be aligned share a dataset
- * sequence with an aligned sequence
+ * first pass - check whether all sequences to be aligned share a
+ * dataset sequence with an aligned sequence; also note the leftmost
+ * ungapped column from which to copy
*/
+ int leftmost = Integer.MAX_VALUE;
for (SequenceI seq : unaligned.getSequences())
{
- if (!alignedDatasets.containsKey(seq.getDatasetSequence()))
+ final SequenceI ds = seq.getDatasetSequence();
+ if (!alignedDatasets.containsKey(ds))
{
return false;
}
+ SequenceI alignedSeq = alignedDatasets.get(ds)
+ .get(0);
+ int startCol = alignedSeq.findIndex(seq.getStart()); // 1..
+ leftmost = Math.min(leftmost, startCol);
}
/*
* heuristic rule: pair off sequences in order for the case where
* more than one shares the same dataset sequence
*/
+ final char gapCharacter = aligned.getGapCharacter();
for (SequenceI seq : unaligned.getSequences())
{
List<SequenceI> alignedSequences = alignedDatasets
.get(seq.getDatasetSequence());
- // TODO: getSequenceAsString() will be deprecated in the future
- // TODO: need to leave to SequenceI implementor to update gaps
- seq.setSequence(alignedSequences.get(0).getSequenceAsString());
+ SequenceI alignedSeq = alignedSequences.get(0);
+
+ /*
+ * gap fill for leading (5') UTR if any
+ */
+ // TODO this copies intron columns - wrong!
+ int startCol = alignedSeq.findIndex(seq.getStart()); // 1..
+ int endCol = alignedSeq.findIndex(seq.getEnd());
+ char[] seqchars = new char[endCol - leftmost + 1];
+ Arrays.fill(seqchars, gapCharacter);
+ char[] toCopy = alignedSeq.getSequence(startCol - 1, endCol);
+ System.arraycopy(toCopy, 0, seqchars, startCol - leftmost,
+ toCopy.length);
+ seq.setSequence(String.valueOf(seqchars));
if (alignedSequences.size() > 0)
{
// pop off aligned sequences (except the last one)
*/
Set<String> types = new HashSet<>();
List<SequenceFeature> sfs = fr.findFeaturesAtResidue(
- seq.getRefSeq(), spos);
+ seq.getRefSeq(), spos, spos);
for (SequenceFeature sf : sfs)
{
types.add(sf.getType());
List<SequenceFeature> findFeaturesAtColumn(SequenceI sequence, int column);
/**
- * Returns features at the specified residue position on the given sequence.
- * Non-positional features are not included.
+ * Returns features at the specified residue positions on the given sequence.
+ * Non-positional features are not included. Features are returned in render
+ * order of their feature type (last is on top). Within feature type, ordering
+ * is undefined.
*
* @param sequence
- * @param resNo
- * residue position (start..)
+ * @param fromResNo
+ * @param toResNo
* @return
*/
- List<SequenceFeature> findFeaturesAtResidue(SequenceI sequence, int resNo);
+ List<SequenceFeature> findFeaturesAtResidue(SequenceI sequence,
+ int fromResNo, int toResNo);
/**
* get current displayed types, in ordering of rendering (on top last)
public interface ViewStyleI
{
+ void setShowComplementFeatures(boolean b);
+
+ boolean isShowComplementFeatures();
+
+ void setShowComplementFeaturesOnTop(boolean b);
+
+ boolean isShowComplementFeaturesOnTop();
void setColourAppliesToAllGroups(boolean b);
}
@Override
- public void highlightSequence(SearchResultsI results)
+ public String highlightSequence(SearchResultsI results)
{
if (av.isFollowHighlight())
{
}
setStatusMessage(results);
seqCanvas.highlightSearchResults(results);
-
+ return null;
}
@Override
*/
public AlignedCodonFrame()
{
- mappings = new ArrayList<SequenceToSequenceMapping>();
+ mappings = new ArrayList<>();
}
/**
{
// TODO return a list instead?
// return dnaSeqs;
- List<SequenceI> seqs = new ArrayList<SequenceI>();
+ List<SequenceI> seqs = new ArrayList<>();
for (SequenceToSequenceMapping ssm : mappings)
{
seqs.add(ssm.fromSeq);
public SequenceI[] getAaSeqs()
{
// TODO not used - remove?
- List<SequenceI> seqs = new ArrayList<SequenceI>();
+ List<SequenceI> seqs = new ArrayList<>();
for (SequenceToSequenceMapping ssm : mappings)
{
seqs.add(ssm.mapping.to);
public MapList[] getdnaToProt()
{
- List<MapList> maps = new ArrayList<MapList>();
+ List<MapList> maps = new ArrayList<>();
for (SequenceToSequenceMapping ssm : mappings)
{
maps.add(ssm.mapping.map);
public Mapping[] getProtMappings()
{
- List<Mapping> maps = new ArrayList<Mapping>();
+ List<Mapping> maps = new ArrayList<>();
for (SequenceToSequenceMapping ssm : mappings)
{
maps.add(ssm.mapping);
/**
* Returns the first mapping found which is to or from the given sequence, or
- * null.
+ * null if none is found
*
* @param seq
* @return
{
MapList ml = null;
SequenceI dnaSeq = null;
- List<char[]> result = new ArrayList<char[]>();
+ List<char[]> result = new ArrayList<>();
for (SequenceToSequenceMapping ssm : mappings)
{
*/
public List<Mapping> getMappingsFromSequence(SequenceI seq)
{
- List<Mapping> result = new ArrayList<Mapping>();
- List<SequenceI> related = new ArrayList<SequenceI>();
+ List<Mapping> result = new ArrayList<>();
+ List<SequenceI> related = new ArrayList<>();
SequenceI seqDs = seq.getDatasetSequence();
seqDs = seqDs != null ? seqDs : seq;
--- /dev/null
+package jalview.datamodel;
+
+import jalview.io.gff.Gff3Helper;
+import jalview.schemes.ResidueProperties;
+import jalview.util.MappingUtils;
+import jalview.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A data bean to hold a list of mapped sequence features (e.g. CDS features
+ * mapped from protein), and the mapping between the sequences
+ *
+ * @author gmcarstairs
+ */
+public class MappedFeatures
+{
+ /*
+ * the mapping from CDS to peptide
+ */
+ public final Mapping mapping;
+
+ /**
+ * the CDS sequence mapped to
+ */
+ public final SequenceI fromSeq;
+
+ /*
+ * the residue position in the peptide sequence
+ */
+ public final int fromPosition;
+
+ /*
+ * the peptide residue at the position
+ */
+ public final char fromResidue;
+
+ /*
+ * features on CDS that overlap the codon positions
+ */
+ public final List<SequenceFeature> features;
+
+ /**
+ * Constructor
+ *
+ * @param theMapping
+ * @param pos
+ * @param res
+ * @param theFeatures
+ */
+ public MappedFeatures(Mapping theMapping, SequenceI from, int pos,
+ char res,
+ List<SequenceFeature> theFeatures)
+ {
+ mapping = theMapping;
+ fromSeq = from;
+ fromPosition = pos;
+ fromResidue = res;
+ features = theFeatures;
+ }
+
+ /**
+ * Computes and returns a (possibly empty) list of HGVS notation peptide
+ * variants derived from codon allele variants
+ *
+ * @return
+ */
+ public List<String> findProteinVariants()
+ {
+ List<String> vars = new ArrayList<>();
+ if (features.isEmpty())
+ {
+ return vars;
+ }
+
+ /*
+ * determine canonical codon
+ */
+ int[] codonPos = MappingUtils.flattenRanges(
+ mapping.getMap().locateInFrom(fromPosition, fromPosition));
+ if (codonPos.length != 3)
+ {
+ // error
+ return vars;
+ }
+ final char[] baseCodon = new char[3];
+ int cdsStart = fromSeq.getStart();
+ baseCodon[0] = fromSeq.getCharAt(codonPos[0] - cdsStart);
+ baseCodon[1] = fromSeq.getCharAt(codonPos[1] - cdsStart);
+ baseCodon[2] = fromSeq.getCharAt(codonPos[2] - cdsStart);
+
+ for (SequenceFeature sf : features)
+ {
+ /*
+ * VCF data may already contain the protein consequence
+ */
+ String hgvsp = sf.getValueAsString("CSQ", "HGVSp");
+ if (hgvsp != null)
+ {
+ int colonPos = hgvsp.indexOf(':');
+ if (colonPos >= 0)
+ {
+ String var = hgvsp.substring(colonPos + 1);
+ if (!vars.contains(var))
+ {
+ vars.add(var);
+ }
+ continue;
+ }
+ }
+
+ /*
+ * otherwise, compute codon and peptide variant
+ */
+ // todo avoid duplication of code in AlignmentUtils.buildDnaVariantsMap
+ int cdsPos = sf.getBegin();
+ if (cdsPos != sf.getEnd())
+ {
+ // not handling multi-locus variant features
+ continue;
+ }
+ if (cdsPos != codonPos[0] && cdsPos != codonPos[1]
+ && cdsPos != codonPos[2])
+ {
+ // e.g. feature on intron within spliced codon!
+ continue;
+ }
+
+ String alls = (String) sf.getValue(Gff3Helper.ALLELES);
+ if (alls == null)
+ {
+ continue;
+ }
+ String from3 = StringUtils.toSentenceCase(
+ ResidueProperties.aa2Triplet
+ .get(String.valueOf(fromResidue)));
+
+ /*
+ * make a peptide variant for each SNP allele
+ * e.g. C,G,T gives variants G and T for base C
+ */
+ String[] alleles = alls.toUpperCase().split(",");
+ for (String allele : alleles)
+ {
+ allele = allele.trim().toUpperCase();
+ if (allele.length() > 1)
+ {
+ continue; // multi-locus variant
+ }
+ char[] variantCodon = new char[3];
+ variantCodon[0] = baseCodon[0];
+ variantCodon[1] = baseCodon[1];
+ variantCodon[2] = baseCodon[2];
+
+ /*
+ * poke variant base into canonical codon
+ */
+ int i = cdsPos == codonPos[0] ? 0 : (cdsPos == codonPos[1] ? 1 : 2);
+ variantCodon[i] = allele.toUpperCase().charAt(0);
+ String codon = new String(variantCodon);
+ String peptide = ResidueProperties.codonTranslate(codon);
+ if (fromResidue != peptide.charAt(0))
+ {
+ String to3 = ResidueProperties.STOP.equals(peptide) ? "STOP"
+ : StringUtils.toSentenceCase(
+ ResidueProperties.aa2Triplet.get(peptide));
+ String var = "p." + from3 + fromPosition + to3;
+ if (!vars.contains(var))
+ {
+ vars.add(var);
+ }
+ }
+ }
+ }
+
+ return vars;
+ }
+}
import jalview.io.gff.SequenceOntologyI;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
* A convenience method that converts a vararg for feature types to an
- * Iterable over matched feature sets in key order
+ * Iterable over matched feature sets. If no types are specified, all feature
+ * sets are returned. If one or more types are specified, feature sets for
+ * those types are returned, preserving the order of the types.
*
* @param type
* @return
}
List<FeatureStore> types = new ArrayList<>();
- List<String> args = Arrays.asList(type);
- for (Entry<String, FeatureStore> featureType : featureStore.entrySet())
+ for (String theType : type)
{
- if (args.contains(featureType.getKey()))
+ if (theType != null && featureStore.containsKey(theType))
{
- types.add(featureType.getValue());
+ types.add(featureStore.get(theType));
}
}
return types;
/**
* Returns a (possibly empty) list of features, optionally restricted to
* specified types, which overlap the given (inclusive) sequence position
- * range
+ * range. If types are specified, features are returned in the order of the
+ * types given.
*
* @param from
* @param to
* copy exon features to protein, compute peptide variants from dna
* variants and add as features on the protein sequence ta-da
*/
- AlignmentUtils.computeProteinFeatures(querySeq, proteinSeq,
- mapList);
+ // JAL-3187 render on the fly instead
+ // AlignmentUtils.computeProteinFeatures(querySeq, proteinSeq, mapList);
}
} catch (Exception e)
{
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
+import java.util.StringTokenizer;
import java.util.Vector;
import org.jmol.adapter.smarter.SmarterJmolAdapter;
implements JmolStatusListener, JmolSelectionListener,
ComponentListener
{
+ private String lastMessage;
+
boolean allChainsSelected = false;
/*
String lastCommand;
- String lastMessage;
-
boolean loadedInline;
StringBuffer resetLastRes = new StringBuffer();
viewer.openStringInline(string);
}
- public void mouseOverStructure(int atomIndex, String strInfo)
+ protected void mouseOverStructure(int atomIndex, final String strInfo)
{
int pdbResNum;
int alocsep = strInfo.indexOf("^");
} catch (Exception e)
{
}
- ;
}
- if (lastMessage == null || !lastMessage.equals(strInfo))
+
+ /*
+ * highlight position on alignment(s); if some text is returned,
+ * show this as a second line on the structure hover tooltip
+ */
+ String label = getSsm().mouseOverStructure(pdbResNum, chainId,
+ pdbfilename);
+ if (label != null)
{
- getSsm().mouseOverStructure(pdbResNum, chainId, pdbfilename);
+ StringTokenizer toks = new StringTokenizer(strInfo, " ");
+ StringBuilder sb = new StringBuilder();
+ sb.append("select ").append(String.valueOf(pdbResNum)).append(":")
+ .append(chainId).append("/1");
+ sb.append(";set hoverLabel \"").append(toks.nextToken()).append(" ")
+ .append(toks.nextToken());
+ sb.append("|").append(label).append("\"");
+ evalStateCommand(sb.toString());
}
-
- lastMessage = strInfo;
}
public void notifyAtomHovered(int atomIndex, String strInfo, String data)
{
+ if (strInfo.equals(lastMessage))
+ {
+ return;
+ }
+ lastMessage = strInfo;
if (data != null)
{
System.err.println("Ignoring additional hover info: " + data
import jalview.util.MapList;
import jalview.util.MappingUtils;
import jalview.util.MessageManager;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import jalview.ws.SequenceFetcher;
import java.util.ArrayList;
.isShowSequenceFeatures();
newFrame.setShowSeqFeatures(showSequenceFeatures);
copyThis.setShowSeqFeatures(showSequenceFeatures);
- FeatureRenderer myFeatureStyling = alignFrame.alignPanel
+ FeatureRendererModel myFeatureStyling = alignFrame.alignPanel
.getSeqPanel().seqCanvas.getFeatureRenderer();
/*
* copy feature rendering settings to split frame
*/
- FeatureRenderer fr1 = newFrame.alignPanel.getSeqPanel().seqCanvas
+ FeatureRendererModel fr1 = newFrame.alignPanel.getSeqPanel().seqCanvas
.getFeatureRenderer();
fr1.transferSettings(myFeatureStyling);
fr1.findAllFeatures(true);
- FeatureRenderer fr2 = copyThis.alignPanel.getSeqPanel().seqCanvas
+ FeatureRendererModel fr2 = copyThis.alignPanel.getSeqPanel().seqCanvas
.getFeatureRenderer();
fr2.transferSettings(myFeatureStyling);
fr2.findAllFeatures(true);
*/
package jalview.gui;
+import jalview.api.AlignViewportI;
import jalview.api.FeatureColourI;
import jalview.api.FeatureSettingsControllerI;
+import jalview.api.ViewStyleI;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.SequenceI;
import jalview.datamodel.features.FeatureMatcher;
import jalview.util.MessageManager;
import jalview.util.Platform;
import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
+import jalview.viewmodel.styles.ViewStyle;
import jalview.xml.binding.jalview.JalviewUserColours;
import jalview.xml.binding.jalview.JalviewUserColours.Colour;
import jalview.xml.binding.jalview.JalviewUserColours.Filter;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
+import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
private float originalTransparency;
+ private ViewStyleI originalViewStyle;
+
private Map<String, FeatureMatcherSetI> originalFilters;
final JInternalFrame frame;
transparency.setMaximum(100 - originalTransparencyAsPercent);
originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
+ originalViewStyle = new ViewStyle(af.viewport.getViewStyle());
try
{
final Object typeCol, final Map<String, float[][]> minmax, int x,
int y)
{
- final FeatureColourI featureColour = (FeatureColourI) typeCol;
-
JPopupMenu men = new JPopupMenu(MessageManager
.formatMessage("label.settings_for_param", new String[]
{ type }));
{
fr.setGroupVisibility(check.getText(), check.isSelected());
resetTable(new String[] { grp });
- af.alignPanel.paintAlignment(true, true);
+ refreshDisplay();
}
});
groupPanel.add(check);
if (fr.setFeaturePriority(rowData, visibleNew))
{
- af.alignPanel.paintAlignment(true, true);
+ refreshDisplay();
}
}
fr.setTransparency(originalTransparency);
fr.setFeatureFilters(originalFilters);
updateFeatureRenderer(originalData);
+ af.getViewport().setViewStyle(originalViewStyle);
close();
}
});
if (!inConstruction)
{
fr.setTransparency((100 - transparency.getValue()) / 100f);
- af.alignPanel.paintAlignment(true, true);
+ refreshDisplay();
}
}
});
transparency.setToolTipText(
MessageManager.getString("label.transparency_tip"));
- JPanel transPanel = new JPanel(new GridLayout(1, 2));
- bigPanel.add(transPanel, BorderLayout.SOUTH);
+ boolean nucleotide = af.getViewport().getAlignment().isNucleotide();
+ JCheckBox showComplement = new JCheckBox(
+ "Show " + (nucleotide ? "protein" : "CDS") + " features");
+ showComplement.setSelected(af.getViewport().isShowComplementFeatures());
+ showComplement.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ af.getViewport()
+ .setShowComplementFeatures(showComplement.isSelected());
+ refreshDisplay();
+ }
+ });
+
+ JCheckBox showComplementOnTop = new JCheckBox("on top");
+ showComplementOnTop
+ .setSelected(af.getViewport().isShowComplementFeaturesOnTop());
+ showComplementOnTop.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ af.getViewport().setShowComplementFeaturesOnTop(
+ showComplementOnTop.isSelected());
+ refreshDisplay();
+ }
+ });
+
+ JPanel lowerPanel = new JPanel(new GridLayout(1, 2));
+ bigPanel.add(lowerPanel, BorderLayout.SOUTH);
JPanel transbuttons = new JPanel(new GridLayout(5, 1));
transbuttons.add(optimizeOrder);
transbuttons.add(sortByScore);
transbuttons.add(sortByDens);
transbuttons.add(help);
- transPanel.add(transparency);
- transPanel.add(transbuttons);
+
+ boolean hasComplement = af.getViewport().getCodingComplement() != null;
+ JPanel transPanelLeft = new JPanel(
+ new GridLayout(hasComplement ? 3 : 2, 1));
+ transPanelLeft.add(new JLabel(" Colour transparency" + ":"));
+ transPanelLeft.add(transparency);
+ if (hasComplement)
+ {
+ JPanel cp = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ cp.add(showComplement);
+ cp.add(showComplementOnTop);
+ transPanelLeft.add(cp);
+ }
+ lowerPanel.add(transPanelLeft);
+ lowerPanel.add(transbuttons);
JPanel buttonPanel = new JPanel();
buttonPanel.add(ok);
}
/**
+ * Repaints alignment, structure and overview (if shown). If there is a
+ * complementary view which is showing this view's features, then also
+ * repaints that.
+ */
+ void refreshDisplay()
+ {
+ af.alignPanel.paintAlignment(true, true);
+ AlignViewportI complement = af.getViewport().getCodingComplement();
+ if (complement != null && complement.isShowComplementFeatures())
+ {
+ AlignFrame af2 = Desktop.getAlignFrameFor(complement);
+ af2.alignPanel.paintAlignment(true, true);
+ }
+ }
+
+ /**
* Answers a suitable tooltip to show on the colour cell of the table
*
* @param fcol
* @param withHint
- * if true include 'click to edit' and similar text
+ * if true include 'click to edit' and similar text
* @return
*/
public static String getColorTooltip(FeatureColourI fcol,
}
/**
- * Answers the class of the object in column c of the first row of the table
+ * Answers the class of column c of the table
*/
@Override
public Class<?> getColumnClass(int c)
{
- Object v = getValueAt(0, c);
- return v == null ? null : v.getClass();
+ switch (c)
+ {
+ case TYPE_COLUMN:
+ return String.class;
+ case COLOUR_COLUMN:
+ return FeatureColour.class;
+ case FILTER_COLUMN:
+ return FeatureMatcherSet.class;
+ default:
+ return Boolean.class;
+ }
}
@Override
*/
package jalview.gui;
+import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
import jalview.api.FeatureColourI;
import jalview.bin.Cache;
*/
if (ap != null)
{
- ap.paintAlignment(true, true);
+ refreshDisplay(true);
}
}
});
* save the colour, and repaint stuff
*/
fr.setColour(featureType, acg);
- ap.paintAlignment(updateStructsAndOverview, updateStructsAndOverview);
+ refreshDisplay(updateStructsAndOverview);
updateColoursTab();
}
{
fr.setColour(featureType, originalColour);
fr.setFeatureFilter(featureType, originalFilter);
- ap.paintAlignment(true, true);
+ refreshDisplay(true);
}
/**
* (note this might now be an empty filter with no conditions)
*/
fr.setFeatureFilter(featureType, combined.isEmpty() ? null : combined);
- ap.paintAlignment(true, true);
+ refreshDisplay(true);
updateFiltersTab();
}
+
+ /**
+ * Repaints alignment, structure and overview (if shown). If there is a
+ * complementary view which is showing this view's features, then also
+ * repaints that.
+ *
+ * @param updateStructsAndOverview
+ */
+ void refreshDisplay(boolean updateStructsAndOverview)
+ {
+ ap.paintAlignment(true, updateStructsAndOverview);
+ AlignViewportI complement = ap.getAlignViewport().getCodingComplement();
+ if (complement != null && complement.isShowComplementFeatures())
+ {
+ AlignFrame af2 = Desktop.getAlignFrameFor(complement);
+ af2.alignPanel.paintAlignment(true, updateStructsAndOverview);
+ }
+ }
}
import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
import jalview.io.DataSourceType;
import jalview.structure.StructureSelectionManager;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import javax.swing.SwingUtilities;
}
@Override
- public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
+ public FeatureRendererModel getFeatureRenderer(AlignmentViewPanel alignment)
{
AlignmentPanel ap = (alignment == null) ? cvf.getAlignmentPanel()
: (AlignmentPanel) alignment;
import jalview.renderer.OverviewRenderer;
import jalview.renderer.OverviewResColourFinder;
import jalview.viewmodel.OverviewDimensions;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import java.awt.Color;
import java.awt.Dimension;
* the renderer to transfer feature colouring from
*/
public void draw(boolean showSequenceFeatures, boolean showAnnotation,
- FeatureRenderer transferRenderer)
+ FeatureRendererModel transferRenderer)
{
miniMe = null;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.MappedFeatures;
import jalview.datamodel.SearchResultMatchI;
import jalview.datamodel.SearchResults;
import jalview.datamodel.SearchResultsI;
import jalview.util.Platform;
import jalview.viewmodel.AlignmentViewport;
import jalview.viewmodel.ViewportRanges;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
* the start of the highlighted region.
*/
@Override
- public void highlightSequence(SearchResultsI results)
+ public String highlightSequence(SearchResultsI results)
{
if (results == null || results.equals(lastSearchResults))
{
- return;
+ return null;
}
lastSearchResults = results;
{
setStatusMessage(results);
}
+ return results.isEmpty() ? null : getHighlightInfo(results);
+ }
+
+ /**
+ * temporary hack: answers a message suitable to show on structure hover
+ * label. This is normally null. It is a peptide variation description if
+ * <ul>
+ * <li>results are a single residue in a protein alignment</li>
+ * <li>there is a mapping to a coding sequence (codon)</li>
+ * <li>there are one or more SNP variant features on the codon</li>
+ * </ul>
+ * in which case the answer is of the format (e.g.) "p.Glu388Asp"
+ *
+ * @param results
+ * @return
+ */
+ private String getHighlightInfo(SearchResultsI results)
+ {
+ /*
+ * ideally, just find mapped CDS (as we don't care about render style here);
+ * for now, go via split frame complement's FeatureRenderer
+ */
+ AlignViewportI complement = ap.getAlignViewport().getCodingComplement();
+ if (complement == null)
+ {
+ return null;
+ }
+ AlignFrame af = Desktop.getAlignFrameFor(complement);
+ FeatureRendererModel fr2 = af.getFeatureRenderer();
+
+ int j = results.getSize();
+ List<String> infos = new ArrayList<>();
+ for (int i = 0; i < j; i++)
+ {
+ SearchResultMatchI match = results.getResults().get(i);
+ int pos = match.getStart();
+ if (pos == match.getEnd())
+ {
+ SequenceI seq = match.getSequence();
+ SequenceI ds = seq.getDatasetSequence() == null ? seq
+ : seq.getDatasetSequence();
+ MappedFeatures mf = fr2
+ .findComplementFeaturesAtResidue(ds, pos);
+ if (mf != null)
+ {
+ List<String> pv = mf.findProteinVariants();
+ for (String s : pv)
+ {
+ if (!infos.contains(s))
+ {
+ infos.addAll(pv);
+ }
+ }
+ }
+ }
+ }
+
+ if (infos.isEmpty())
+ {
+ return null;
+ }
+ StringBuilder sb = new StringBuilder();
+ for (String info : infos)
+ {
+ if (sb.length() > 0)
+ {
+ sb.append("|");
+ }
+ sb.append(info);
+ }
+ return sb.toString();
}
@Override
.findFeaturesAtColumn(sequence, column + 1);
seqARep.appendFeatures(tooltipText, pos, features,
this.ap.getSeqPanel().seqCanvas.fr);
+
+ /*
+ * add features in CDS/protein complement at the corresponding
+ * position if configured to do so
+ */
+ if (av.isShowComplementFeatures())
+ {
+ if (!Comparison.isGap(sequence.getCharAt(column)))
+ {
+ AlignViewportI complement = ap.getAlignViewport()
+ .getCodingComplement();
+ AlignFrame af = Desktop.getAlignFrameFor(complement);
+ FeatureRendererModel fr2 = af.getFeatureRenderer();
+ MappedFeatures mf = fr2.findComplementFeaturesAtResidue(sequence,
+ pos);
+ if (mf != null)
+ {
+ seqARep.appendFeatures(tooltipText, pos, mf.features, fr2);
+ }
+ }
+ }
}
if (tooltipText.length() == 6) // <html>
{
package jalview.io.vcf;
-import jalview.analysis.AlignmentUtils;
import jalview.analysis.Dna;
import jalview.api.AlignViewControllerGuiI;
import jalview.bin.Cache;
/*
* dna-to-peptide product mapping
*/
- AlignmentUtils.computeProteinFeatures(seq, mapTo, map);
+ // JAL-3187 render on the fly instead
+ // AlignmentUtils.computeProteinFeatures(seq, mapTo, map);
}
else
{
import jalview.gui.AppVarna;
import jalview.gui.ChimeraViewFrame;
import jalview.gui.Desktop;
-import jalview.gui.FeatureRenderer;
import jalview.gui.JvOptionPane;
import jalview.gui.OOMWarning;
import jalview.gui.PCAPanel;
import jalview.viewmodel.AlignmentViewport;
import jalview.viewmodel.PCAModel;
import jalview.viewmodel.ViewportRanges;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
import jalview.ws.jws2.Jws2Discoverer;
view.setFollowHighlight(av.isFollowHighlight());
view.setFollowSelection(av.followSelection);
view.setIgnoreGapsinConsensus(av.isIgnoreGapsConsensus());
+ view.setShowComplementFeatures(av.isShowComplementFeatures());
+ view.setShowComplementFeaturesOnTop(
+ av.isShowComplementFeaturesOnTop());
if (av.getFeaturesDisplayed() != null)
{
FeatureSettings fs = new FeatureSettings();
- FeatureRenderer fr = ap.getSeqPanel().seqCanvas
+ FeatureRendererModel fr = ap.getSeqPanel().seqCanvas
.getFeatureRenderer();
String[] renderOrder = fr.getRenderOrder().toArray(new String[0]);
viewport.setShowNPFeats(safeBoolean(view.isShowNPfeatureTooltip()));
viewport.setShowGroupConsensus(view.isShowGroupConsensus());
viewport.setShowGroupConservation(view.isShowGroupConservation());
+ viewport.setShowComplementFeatures(view.isShowComplementFeatures());
+ viewport.setShowComplementFeaturesOnTop(
+ view.isShowComplementFeaturesOnTop());
// recover feature settings
if (jm.getFeatureSettings() != null)
{
- FeatureRenderer fr = af.alignPanel.getSeqPanel().seqCanvas
+ FeatureRendererModel fr = af.alignPanel.getSeqPanel().seqCanvas
.getFeatureRenderer();
FeaturesDisplayed fdi;
viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
*/
package jalview.renderer.seqfeatures;
+import jalview.api.AlignViewportI;
import jalview.api.FeatureRenderer;
import jalview.api.FeaturesDisplayedI;
import jalview.datamodel.SequenceI;
*/
boolean noFeaturesDisplayed()
{
- if (featureRenderer == null
- || !featureRenderer.getViewport().isShowSequenceFeatures())
+ if (featureRenderer == null)
+ {
+ return true;
+ }
+ AlignViewportI av = featureRenderer.getViewport();
+ if (av.isShowComplementFeatures())
+ {
+ return false;
+ }
+ if (!av.isShowSequenceFeatures())
{
return true;
}
import jalview.api.AlignViewportI;
import jalview.api.FeatureColourI;
import jalview.datamodel.ContiguousI;
+import jalview.datamodel.MappedFeatures;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
import jalview.util.Comparison;
+import jalview.util.ReverseListIterator;
import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import java.awt.AlphaComposite;
* if columns are all gapped, or sequence has no features, nothing to do
*/
ContiguousI visiblePositions = seq.findPositions(start + 1, end + 1);
- if (visiblePositions == null || !seq.getFeatures().hasFeatures())
+ if (visiblePositions == null || !seq.getFeatures().hasFeatures()
+ && !av.isShowComplementFeatures())
{
return null;
}
Color drawnColour = null;
/*
+ * draw 'complement' features below ours if configured to do so
+ */
+ if (av.isShowComplementFeatures()
+ && !av.isShowComplementFeaturesOnTop())
+ {
+ drawnColour = drawComplementFeatures(g, seq, start, end, y1,
+ colourOnly, visiblePositions, drawnColour);
+ }
+
+ /*
* iterate over features in ordering of their rendering (last is on top)
*/
for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++)
if (featureColour == null)
{
/*
- * feature excluded by visibility settings, filters, or colour threshold
+ * feature excluded by filters, or colour threshold
*/
continue;
}
}
}
+ /*
+ * draw 'complement' features above ours if configured to do so
+ */
+ if (av.isShowComplementFeatures() && av.isShowComplementFeaturesOnTop())
+ {
+ drawnColour = drawComplementFeatures(g, seq, start, end, y1,
+ colourOnly, visiblePositions, drawnColour);
+ }
+
if (transparency != 1.0f && g != null)
{
/*
}
/**
+ * Find any features on the CDS/protein complement of the sequence region and
+ * draw them, with visibility and colouring as configured in the complementary
+ * viewport
+ *
+ * @param g
+ * @param seq
+ * @param start
+ * @param end
+ * @param y1
+ * @param colourOnly
+ * @param visiblePositions
+ * @param drawnColour
+ * @return
+ */
+ Color drawComplementFeatures(final Graphics g, final SequenceI seq,
+ int start, int end, int y1, boolean colourOnly,
+ ContiguousI visiblePositions, Color drawnColour)
+ {
+ AlignViewportI comp = av.getCodingComplement();
+ FeatureRenderer fr2 = Desktop.getAlignFrameFor(comp)
+ .getFeatureRenderer();
+
+ final int visibleStart = visiblePositions.getBegin();
+ final int visibleEnd = visiblePositions.getEnd();
+
+ for (int pos = visibleStart; pos <= visibleEnd; pos++)
+ {
+ int column = seq.findIndex(pos);
+ MappedFeatures mf = fr2
+ .findComplementFeaturesAtResidue(seq, pos);
+ if (mf != null)
+ {
+ for (SequenceFeature sf : mf.features)
+ {
+ FeatureColourI fc = fr2.getFeatureStyle(sf.getType());
+ Color featureColour = fr2.getColor(sf, fc);
+ renderFeature(g, seq, column - 1, column - 1, featureColour,
+ start, end, y1, colourOnly);
+ drawnColour = featureColour;
+ }
+ }
+ }
+ return drawnColour;
+ }
+
+ /**
* Called when alignment in associated view has new/modified features to
* discover and display.
*
updateFeatures();
/*
+ * show complement features on top (if configured to show them)
+ */
+ if (av.isShowComplementFeatures() && av.isShowComplementFeaturesOnTop())
+ {
+ Color col = findComplementFeatureColour(seq, column);
+ if (col != null)
+ {
+ return col;
+ }
+ }
+
+ /*
* inspect features in reverse renderOrder (the last in the array is
* displayed on top) until we find one that is rendered at the position
*/
}
/*
- * no displayed feature found at position
+ * show complement features underneath (if configured to show them)
*/
+ Color col = null;
+ if (av.isShowComplementFeatures()
+ && !av.isShowComplementFeaturesOnTop())
+ {
+ col = findComplementFeatureColour(seq, column);
+ }
+
+ return col;
+ }
+
+ Color findComplementFeatureColour(SequenceI seq, int column)
+ {
+ AlignViewportI complement = av.getCodingComplement();
+ AlignFrame af = Desktop.getAlignFrameFor(complement);
+ FeatureRendererModel fr2 = af.getFeatureRenderer();
+ MappedFeatures mf = fr2.findComplementFeaturesAtResidue(
+ seq, seq.findPosition(column - 1));
+ if (mf == null)
+ {
+ return null;
+ }
+ ReverseListIterator<SequenceFeature> it = new ReverseListIterator<>(
+ mf.features);
+ while (it.hasNext())
+ {
+ SequenceFeature sf = it.next();
+ if (!fr2.featureGroupNotShown(sf))
+ {
+ Color col = fr2.getColour(sf);
+ if (col != null)
+ {
+ return col;
+ }
+ }
+ }
return null;
}
}
// TODO remove this? never called on SequenceListener type
public void mouseOverSequence(SequenceI sequence, int index, int pos);
- public void highlightSequence(SearchResultsI results);
+ /**
+ * Highlights any position(s) represented by the search results and
+ * (optionally) returns an informative message about the position(s)
+ * higlighted
+ *
+ * @param results
+ * @return
+ */
+ public String highlightSequence(SearchResultsI results);
// TODO remove this? never called
public void updateColours(SequenceI sequence, int index);
* @param pdbResNum
* @param chain
* @param pdbfile
+ * @return
*/
- public void mouseOverStructure(int pdbResNum, String chain,
+ public String mouseOverStructure(int pdbResNum, String chain,
String pdbfile)
{
AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
List<AtomSpec> atoms = Collections.singletonList(atomSpec);
- mouseOverStructure(atoms);
+ return mouseOverStructure(atoms);
}
/**
*
* @param atoms
*/
- public void mouseOverStructure(List<AtomSpec> atoms)
+ public String mouseOverStructure(List<AtomSpec> atoms)
{
if (listeners == null)
{
// old or prematurely sent event
- return;
+ return null;
}
boolean hasSequenceListener = false;
for (int i = 0; i < listeners.size(); i++)
}
if (!hasSequenceListener)
{
- return;
+ return null;
}
SearchResultsI results = findAlignmentPositionsForStructurePositions(
atoms);
+ String result = null;
for (Object li : listeners)
{
if (li instanceof SequenceListener)
{
- ((SequenceListener) li).highlightSequence(results);
+ String s = ((SequenceListener) li).highlightSequence(results);
+ if (s != null)
+ {
+ result = s;
+ }
}
}
+ return result;
}
/**
return new MapList(getFromRanges(), toRanges, outFromRatio, outToRatio);
}
+ /**
+ * Answers true if the mapping is from one contiguous range to another, else
+ * false
+ *
+ * @return
+ */
+ public boolean isContiguous()
+ {
+ return fromShifts.size() == 1 && toShifts.size() == 1;
+ }
}
viewStyle.setProteinFontAsCdna(b);
}
+ @Override
+ public void setShowComplementFeatures(boolean b)
+ {
+ viewStyle.setShowComplementFeatures(b);
+ }
+
+ @Override
+ public boolean isShowComplementFeatures()
+ {
+ return viewStyle.isShowComplementFeatures();
+ }
+
+ @Override
+ public void setShowComplementFeaturesOnTop(boolean b)
+ {
+ viewStyle.setShowComplementFeaturesOnTop(b);
+ }
+
+ @Override
+ public boolean isShowComplementFeaturesOnTop()
+ {
+ return viewStyle.isShowComplementFeaturesOnTop();
+ }
+
/**
* @return true if view should scroll to show the highlighted region of a
* sequence
import jalview.api.AlignViewportI;
import jalview.api.FeatureColourI;
import jalview.api.FeaturesDisplayedI;
+import jalview.datamodel.AlignedCodonFrame;
import jalview.datamodel.AlignmentI;
+import jalview.datamodel.MappedFeatures;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.SearchResultMatchI;
+import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.datamodel.features.FeatureMatcherSetI;
visibleTypes);
/*
- * include features unless their feature group is not displayed, or
- * they are hidden (have no colour) based on a filter or colour threshold
+ * include features unless they are hidden (have no colour), based on
+ * feature group visibility, or a filter or colour threshold
*/
for (SequenceFeature sf : features)
{
- if (!featureGroupNotShown(sf) && getColour(sf) != null)
+ if (getColour(sf) != null)
{
result.add(sf);
}
* @param sequenceFeature
* @return
*/
- protected boolean featureGroupNotShown(final SequenceFeature sequenceFeature)
+ public boolean featureGroupNotShown(final SequenceFeature sequenceFeature)
{
return featureGroups != null
&& sequenceFeature.featureGroup != null
*/
@Override
public List<SequenceFeature> findFeaturesAtResidue(SequenceI sequence,
- int resNo)
+ int fromResNo, int toResNo)
{
List<SequenceFeature> result = new ArrayList<>();
if (!av.areFeaturesDisplayed() || getFeaturesDisplayed() == null)
* displayed, and feature group is null or the empty string
* or marked for display
*/
- Set<String> visibleFeatures = getFeaturesDisplayed()
- .getVisibleFeatures();
+ List<String> visibleFeatures = getDisplayedFeatureTypes();
String[] visibleTypes = visibleFeatures
.toArray(new String[visibleFeatures.size()]);
List<SequenceFeature> features = sequence.getFeatures().findFeatures(
- resNo, resNo, visibleTypes);
+ fromResNo, toResNo, visibleTypes);
for (SequenceFeature sf : features)
{
return filter == null ? true : filter.matches(sf);
}
+ /**
+ * Answers a bean containing a mapping, and a list of features in this
+ * alignment at a position (or range) which is mappable from the given
+ * sequence residue position in a mapped alignment. Features are returned in
+ * render order of feature type (on top last), with order within feature type
+ * undefined. If no features or mapping are found, answers null.
+ *
+ * @param sequence
+ * @param pos
+ * @return
+ */
+ public MappedFeatures findComplementFeaturesAtResidue(SequenceI sequence,
+ int pos)
+ {
+ SequenceI ds = sequence.getDatasetSequence();
+ if (ds == null)
+ {
+ ds = sequence;
+ }
+ final char residue = ds.getCharAt(pos - ds.getStart());
+
+ List<SequenceFeature> found = new ArrayList<>();
+ List<AlignedCodonFrame> mappings = this.av.getAlignment()
+ .getCodonFrame(sequence);
+
+ /*
+ * todo: direct lookup of CDS for peptide and vice-versa; for now,
+ * have to search through an unordered list of mappings for a candidate
+ */
+ Mapping mapping = null;
+ SequenceI mapFrom = null;
+
+ for (AlignedCodonFrame acf : mappings)
+ {
+ mapping = acf.getMappingForSequence(sequence);
+ if (mapping == null || !mapping.getMap().isTripletMap())
+ {
+ continue; // we are only looking for 3:1 or 1:3 mappings
+ }
+ SearchResultsI sr = new SearchResults();
+ acf.markMappedRegion(ds, pos, sr);
+ for (SearchResultMatchI match : sr.getResults())
+ {
+ int fromRes = match.getStart();
+ int toRes = match.getEnd();
+ mapFrom = match.getSequence();
+ List<SequenceFeature> fs = findFeaturesAtResidue(
+ match.getSequence(), fromRes, toRes);
+ for (SequenceFeature sf : fs)
+ {
+ if (!found.contains(sf))
+ {
+ found.add(sf);
+ }
+ }
+ }
+
+ /*
+ * just take the first mapped features we find
+ */
+ if (!found.isEmpty())
+ {
+ break;
+ }
+ }
+ if (found.isEmpty())
+ {
+ return null;
+ }
+
+ /*
+ * sort by renderorder, inefficiently
+ */
+ List<SequenceFeature> result = new ArrayList<>();
+ 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);
+ }
+ }
+ }
+ }
+
+ return new MappedFeatures(mapping, mapFrom, pos, residue, result);
+ }
+
@Override
public boolean isVisible(SequenceFeature feature)
{
setShowNPFeats(vs.isShowNPFeats());
setShowSequenceFeaturesHeight(vs.isShowSequenceFeaturesHeight());
setShowSequenceFeatures(vs.isShowSequenceFeatures());
+ setShowComplementFeatures(vs.isShowComplementFeatures());
+ setShowComplementFeaturesOnTop(vs.isShowComplementFeaturesOnTop());
setShowText(vs.getShowText());
setShowUnconserved(vs.getShowUnconserved());
setTextColour(vs.getTextColour());
&& isShowSequenceFeaturesHeight() == vs
.isShowSequenceFeaturesHeight()
&& isShowSequenceFeatures() == vs.isShowSequenceFeatures()
+ && isShowComplementFeatures() == vs.isShowComplementFeatures()
+ && isShowComplementFeaturesOnTop() == vs
+ .isShowComplementFeaturesOnTop()
&& getShowText() == vs.getShowText()
&& getShowUnconserved() == vs.getShowUnconserved()
&& getThreshold() == vs.getThreshold()
private int fontStyle;
+ private boolean showComplementFeatures;
+
+ private boolean showComplementFeaturesOnTop;
+
/**
* GUI state
*
{
proteinFontAsCdna = b;
}
+
+ @Override
+ public void setShowComplementFeatures(boolean b)
+ {
+ showComplementFeatures = b;
+ }
+
+ @Override
+ public boolean isShowComplementFeatures()
+ {
+ return showComplementFeatures;
+ }
+
+ @Override
+ public void setShowComplementFeaturesOnTop(boolean b)
+ {
+ showComplementFeaturesOnTop = b;
+ }
+
+ @Override
+ public boolean isShowComplementFeaturesOnTop()
+ {
+ return showComplementFeaturesOnTop;
+ }
}
assertFalse(iterator.hasNext());
/*
- * two types specified - get sorted alphabetically
+ * two types specified - order is preserved
*/
types = sf.varargToTypes("Metal", "Cath");
iterator = types.iterator();
assertTrue(iterator.hasNext());
- assertSame(iterator.next(), featureStores.get("Cath"));
- assertTrue(iterator.hasNext());
assertSame(iterator.next(), featureStores.get("Metal"));
+ assertTrue(iterator.hasNext());
+ assertSame(iterator.next(), featureStores.get("Cath"));
assertFalse(iterator.hasNext());
/*
import jalview.schemes.FeatureColour;
import jalview.schemes.FeatureColourTest;
import jalview.util.matcher.Condition;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import java.awt.Color;
import java.io.File;
/*
* set colour schemes for features
*/
- FeatureRenderer fr = af.getFeatureRenderer();
+ FeatureRendererModel fr = af.getFeatureRenderer();
// type1: red
fr.setColour("type1", new FeatureColour(Color.red));
expected = "METAL\tcc9900\n"
+ "GAMMA-TURN\tscore|ff0000|00ffff|noValueMin|20.0|95.0|below|66.0\n"
+ "\nSTARTGROUP\tuniprot\n"
- + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
+ "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n"
+ + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
+ "ENDGROUP\tuniprot\n";
assertEquals(expected, exported);
+ "Pfam\tff0000\n"
+ "GAMMA-TURN\tscore|ff0000|00ffff|noValueMin|20.0|95.0|below|66.0\n"
+ "\nSTARTGROUP\tuniprot\n"
- + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
+ "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n"
+ "<html>Pfam domain<a href=\"http://pfam.xfam.org/family/PF00111\">Pfam_3_4</a></html>\tFER_CAPAA\t-1\t20\t20\tPfam\t0.0\n"
+ + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
+ "ENDGROUP\tuniprot\n"
// null / empty group features are output after named groups
+ "\ndesc2\tFER_CAPAN\t-1\t4\t9\tPfam\n"
// Pfam feature columns include strand(+), phase(2), attributes
expected = gffHeader
+ "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n"
- + "FER_CAPAN\ts3dm\tGAMMA-TURN\t36\t38\t2.1\t.\t.\n"
- + "FER_CAPAN\tUniprot\tPfam\t20\t20\t0.0\t+\t2\tx=y;black=white\n";
+ + "FER_CAPAN\tUniprot\tPfam\t20\t20\t0.0\t+\t2\tx=y;black=white\n"
+ + "FER_CAPAN\ts3dm\tGAMMA-TURN\t36\t38\t2.1\t.\t.\n";
assertEquals(expected, exported);
}
import jalview.gui.AlignViewport;
import jalview.gui.AlignmentPanel;
import jalview.gui.Desktop;
-import jalview.gui.FeatureRenderer;
import jalview.gui.JvOptionPane;
import jalview.gui.PCAPanel;
import jalview.gui.PopupMenu;
import jalview.util.MapList;
import jalview.util.matcher.Condition;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import java.awt.Color;
import java.io.File;
/*
* set colour schemes for features
*/
- FeatureRenderer fr = af.getFeatureRenderer();
+ FeatureRendererModel fr = af.getFeatureRenderer();
fr.findAllFeatures(true);
// type1: red
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
import jalview.gui.AlignViewport;
-import jalview.gui.FeatureRenderer;
import jalview.io.DataSourceType;
import jalview.io.FileLoader;
import jalview.schemes.FeatureColour;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
import java.awt.Color;
private AlignFrame af;
- private FeatureRenderer fr;
+ private FeatureRendererModel fr;
@BeforeTest(alwaysRun = true)
public void setUp()