--- /dev/null
+import java.awt.Color;
+import jalview.schemes.ResidueColourScheme;
+import jalview.schemes.ColourSchemes;
+import jalview.datamodel.AnnotatedCollectionI;
+import java.util.Map;
+import jalview.datamodel.SequenceI;
+
+/*
+ * Example script that registers two new alignment colour schemes
+ */
+
+/*
+ * Class that defines a colour scheme where odd columns are red,
+ * even numbered columns are blue, and gaps are yellow
+ */
+class Stripy extends ResidueColourScheme {
+ Stripy() { }
+ String getSchemeName() { "stripy" }
+ Stripy getInstance(AnnotatedCollectionI coll, Map map) { new Stripy() }
+ Color findColour(char res, int col, SequenceI seq) {
+ // determine the colour
+ Color colour = findColour(res, col)
+ // let Jalview apply conservation or consensus shading
+ adjustColour(res, col, colour);
+ }
+ Color findColour(char res, int col) {
+ if (res == ' ' || res == '-' || res == '.')
+ {
+ Color.yellow
+ } else if (col % 2 == 0)
+ {
+ Color.blue
+ } else
+ {
+ Color.red
+ }
+ }
+}
+
+/*
+ * Class that defines a colour scheme graduated
+ * (approximately) by amino acid weight
+ */
+class ByWeight extends ResidueColourScheme {
+ int min = 75
+ int max = 204
+ ByWeight() { }
+ boolean isPeptideSpecific() {true}
+ String getSchemeName() { "By Weight" }
+ ByWeight getInstance(AnnotatedCollectionI coll, Map map) { new ByWeight() }
+ Color makeColour(int weight) {
+ int i = 255 * (weight - min) / (max - min);
+ new Color(i, 0, i);
+ }
+ Color findColour(char res, int col, SequenceI seq) {
+ // determine the colour
+ Color colour = findColour(res, col)
+ // let Jalview apply any conservation or consensus shading
+ adjustColour(res, col, colour);
+ }
+ Color findColour(char res, int col) {
+ switch (res) {
+ case ' ':
+ case '-':
+ case '.':
+ Color.white
+ break
+ case 'A':
+ makeColour(89)
+ break
+ case 'R':
+ makeColour(174)
+ break
+ case 'N':
+ case 'D':
+ case 'B':
+ case 'I':
+ case 'L':
+ makeColour(132)
+ break
+ case 'C':
+ makeColour(121)
+ break
+ case 'Q':
+ case 'E':
+ case 'Z':
+ case 'K':
+ case 'M':
+ makeColour(146)
+ break
+ case 'G':
+ makeColour(75)
+ break
+ case 'H':
+ makeColour(155)
+ break
+ case 'F':
+ makeColour(165)
+ break
+ case 'P':
+ makeColour(115)
+ break
+ case 'S':
+ makeColour(105)
+ break
+ case 'T':
+ makeColour(119)
+ break
+ case 'W':
+ makeColour(204)
+ break
+ case 'Y':
+ makeColour(181)
+ break
+ case 'V':
+ makeColour(117)
+ break
+ default:
+ makeColour(150)
+ }
+ }
+}
+
+ColourSchemes.instance.registerColourScheme(new Stripy())
+ColourSchemes.instance.registerColourScheme(new ByWeight())
if (oldColourScheme instanceof UserColourScheme)
{
- schemeName.setText(((UserColourScheme) oldColourScheme).getSchemeName());
+ schemeName.setText(oldColourScheme.getSchemeName());
if (((UserColourScheme) oldColourScheme).getLowerCaseColours() != null)
{
caseSensitive.setSelected(true);
}
}
- void resetButtonPanel(boolean caseSensitive)
+ /**
+ * Rebuilds the panel with coloured buttons for residues. If not case
+ * sensitive colours, show 3-letter amino acid code as button text. If case
+ * sensitive, just show the single letter code, in order to make space for the
+ * additional buttons.
+ *
+ * @param isCaseSensitive
+ */
+ void resetButtonPanel(boolean isCaseSensitive)
{
buttonPanel.removeAll();
upperCaseButtons = new ArrayList<JButton>();
}
- JButton button;
- String label;
for (int i = 0; i < 20; i++)
{
- if (caseSensitive)
- {
- label = ResidueProperties.aa[i];
- }
- else
- {
- label = ResidueProperties.aa2Triplet.get(ResidueProperties.aa[i])
- .toString();
- }
-
- button = makeButton(label, ResidueProperties.aa[i], upperCaseButtons,
- i);
-
+ String label = isCaseSensitive ? ResidueProperties.aa[i]
+ : ResidueProperties.aa2Triplet.get(ResidueProperties.aa[i])
+ .toString();
+ JButton button = makeButton(label, ResidueProperties.aa[i],
+ upperCaseButtons, i);
buttonPanel.add(button);
}
buttonPanel.add(makeButton("X", "X", upperCaseButtons, 22));
buttonPanel.add(makeButton("Gap", "-", upperCaseButtons, 23));
- if (!caseSensitive)
+ if (!isCaseSensitive)
{
gridLayout.setRows(6);
gridLayout.setColumns(4);
{
int row = i / cols + 1;
int index = (row * cols) + i;
- button = makeButton(ResidueProperties.aa[i].toLowerCase(),
+ JButton button = makeButton(ResidueProperties.aa[i].toLowerCase(),
ResidueProperties.aa[i].toLowerCase(), lowerCaseButtons, i);
buttonPanel.add(button, index);
}
}
- if (caseSensitive)
+ if (isCaseSensitive)
{
buttonPanel.add(makeButton("b", "b", lowerCaseButtons, 20));
buttonPanel.add(makeButton("z", "z", lowerCaseButtons, 21));
// codes
if (this.frame != null)
{
- int newWidth = caseSensitive ? MY_FRAME_WIDTH_CASE_SENSITIVE
+ int newWidth = isCaseSensitive ? MY_FRAME_WIDTH_CASE_SENSITIVE
: MY_FRAME_WIDTH;
this.frame.setSize(newWidth, this.frame.getHeight());
}
buttons.add(button);
+ /*
+ * make initial button colour that of the current colour scheme,
+ * if it is a simple per-residue colouring, else white
+ */
col = Color.white;
- if (oldColourScheme != null)
+ if (oldColourScheme != null && oldColourScheme.isSimple())
{
- try
- {
- col = oldColourScheme.findColour(residue.charAt(0), -1, null);
- } catch (Exception ex)
- {
- }
+ col = oldColourScheme.findColour(residue.charAt(0));
}
}
Cache.getProperty(LAST_DIRECTORY), "jc",
"Jalview User Colours");
- chooser.setFileView(new JalviewFileView());
+ JalviewFileView fileView = new JalviewFileView();
+ chooser.setFileView(fileView);
chooser.setDialogTitle(MessageManager
.getString("label.save_colour_scheme"));
chooser.setToolTipText(MessageManager.getString("action.save"));
if (value == JalviewFileChooser.APPROVE_OPTION)
{
- String choice = chooser.getSelectedFile().getPath();
- addNewColourScheme(choice);
- saveToFile(choice);
+ File file = chooser.getSelectedFile();
+ addNewColourScheme(file.getPath());
+ saveToFile(file);
}
}
/**
* Saves the colour scheme to file in XML format
*
- * @param filePath
+ * @param path
*/
- protected void saveToFile(String filePath)
+ protected void saveToFile(File toFile)
{
/*
* build a Java model of colour scheme as XML, and
try
{
PrintWriter out = new PrintWriter(new OutputStreamWriter(
- new FileOutputStream(filePath), "UTF-8"));
+ new FileOutputStream(toFile), "UTF-8"));
for (int i = 0; i < buttonPanel.getComponentCount(); i++)
{
import jalview.datamodel.SequenceI;
import java.awt.Color;
+import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.LinkedHashMap;
* definition of residue colours in XML format as defined in
* JalviewUserColours.xsd.
*
- * @param file
+ * @param filePath
*
* @return
*/
- public static UserColourScheme loadColourScheme(String file)
+ public static UserColourScheme loadColourScheme(String filePath)
{
UserColourScheme ucs = null;
Color[] newColours = null;
+ File file = new File(filePath);
try
{
InputStreamReader in = new InputStreamReader(
@Override
public Color findColour(char c, int j, SequenceI seq)
{
- Color currentColour;
+ Color colour = Color.white;
- if (colors != null && symbolIndex != null && (threshold == 0)
- || aboveThreshold(c, j))
+ if (colors != null && symbolIndex != null)
{
- currentColour = colors[symbolIndex[c]];
+ colour = colors[symbolIndex[c]];
}
- else
+ colour = adjustColour(c, j, colour);
+
+ return colour;
+ }
+
+ /**
+ * Adjusts colour by applying thresholding or conservation shading, if in
+ * force. That is
+ * <ul>
+ * <li>if there is a threshold set for colouring, and the residue doesn't
+ * match the consensus (or a joint consensus) residue, or the consensus score
+ * is not above the threshold, then the colour is set to white</li>
+ * <li>if conservation colouring is selected, the colour is faded by an amount
+ * depending on the conservation score for the column, and the conservation
+ * colour threshold</li>
+ * </ul>
+ *
+ * @param symbol
+ * @param column
+ * @param colour
+ * @return
+ */
+ protected Color adjustColour(char symbol, int column, Color colour)
+ {
+ if (!aboveThreshold(symbol, column))
{
- currentColour = Color.white;
+ colour = Color.white;
}
if (conservationColouring)
{
- currentColour = applyConservation(currentColour, j);
+ colour = applyConservation(colour, column);
}
-
- return currentColour;
+ return colour;
}
/**
*/
public boolean aboveThreshold(char residue, int column)
{
+ if (threshold == 0)
+ {
+ return true;
+ }
if ('a' <= residue && residue <= 'z')
{
// TO UPPERCASE !!!
public ColourSchemeI getInstance(AnnotatedCollectionI sg,
Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
{
- UserColourScheme usc = new UserColourScheme(colors);
- if (lowerCaseColours != null)
+ return new UserColourScheme(this);
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @return
+ */
+ protected UserColourScheme(UserColourScheme from)
+ {
+ this(from.colors);
+ schemeName = from.schemeName;
+ if (from.lowerCaseColours != null)
{
- usc.schemeName = schemeName;
- usc.lowerCaseColours = new Color[lowerCaseColours.length];
- System.arraycopy(lowerCaseColours, 0, usc.lowerCaseColours, 0,
- lowerCaseColours.length);
+ lowerCaseColours = new Color[lowerCaseColours.length];
+ System.arraycopy(from.lowerCaseColours, 0, lowerCaseColours, 0,
+ from.lowerCaseColours.length);
}
- return usc;
}
/**
// TODO more test cases; check if help documentation matches implementation
}
+
+ // @formatter:on
+
+ /**
+ * Test for colour calculation when the consensus percentage ignores gapped
+ * sequences
+ */
+ @Test(groups = "Functional")
+ public void testFindColour_ignoreGaps()
+ {
+ /*
+ * CCC
+ * CCC
+ * -CC
+ * first column is 66% C (blue) including gaps
+ * or 100% C ignoring gaps
+ */
+ String fasta = ">seq1\nCCC\n>seq2\nccc\n>seq3\n-CC\n";
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(fasta,
+ DataSourceType.PASTE);
+ AlignmentI al = af.getViewport().getAlignment();
+ ClustalxColourScheme cs = new ClustalxColourScheme(al, null);
+
+ /*
+ * column 1 is 66% C which is above Clustalx threshold of 60%
+ */
+ Color clustalBlue = ClustalxColourScheme.ClustalColour.BLUE.colour;
+ assertEquals(cs.findColour('C', 0, al.getSequenceAt(0)), clustalBlue);
+
+ /*
+ * set directly to ignore gaps
+ */
+ cs.setIncludeGaps(false);
+ Color clustalPink = ClustalxColourScheme.ClustalColour.PINK.colour;
+ assertEquals(cs.findColour('C', 0, al.getSequenceAt(0)), clustalPink);
+
+ /*
+ * set ignore gaps on the viewport...
+ */
+ cs.setIncludeGaps(true);
+ assertEquals(cs.findColour('C', 0, al.getSequenceAt(0)), clustalBlue);
+ af.getViewport().setIgnoreGapsConsensus(true, af.alignPanel);
+ // next test fails: colour scheme does not read ignore gaps flag from
+ // viewport
+ // assertEquals(cs.findColour('C', 0, al.getSequenceAt(0)), clustalPink);
+ }
}
rcs.setThreshold(0, true);
assertTrue(rcs.aboveThreshold('a', 0));
assertTrue(rcs.aboveThreshold('S', 0));
- assertFalse(rcs.aboveThreshold('W', 0));
+ assertTrue(rcs.aboveThreshold('W', 0));
assertTrue(rcs.aboveThreshold('R', 1));
- assertFalse(rcs.aboveThreshold('W', 2));
+ assertTrue(rcs.aboveThreshold('W', 2));
assertTrue(rcs.aboveThreshold('t', 3));
- assertFalse(rcs.aboveThreshold('Q', 3));
+ assertTrue(rcs.aboveThreshold('Q', 3));
/*
* with threshold, include gaps