3 import static jalview.gui.FeatureSettings.COLOUR_COLUMN;
4 import static jalview.gui.FeatureSettings.FILTER_COLUMN;
5 import static jalview.gui.FeatureSettings.SHOW_COLUMN;
6 import static jalview.gui.FeatureSettings.TYPE_COLUMN;
7 import static org.testng.Assert.assertEquals;
8 import static org.testng.Assert.assertFalse;
9 import static org.testng.Assert.assertNull;
10 import static org.testng.Assert.assertTrue;
12 import jalview.api.FeatureColourI;
13 import jalview.datamodel.SequenceFeature;
14 import jalview.datamodel.SequenceI;
15 import jalview.datamodel.features.FeatureMatcher;
16 import jalview.datamodel.features.FeatureMatcherSet;
17 import jalview.datamodel.features.FeatureMatcherSetI;
18 import jalview.io.DataSourceType;
19 import jalview.io.FileFormat;
20 import jalview.io.FileLoader;
21 import jalview.schemes.FeatureColour;
22 import jalview.util.matcher.Condition;
24 import java.awt.Color;
26 import java.io.IOException;
27 import java.util.HashMap;
29 import org.testng.annotations.Test;
31 public class FeatureSettingsTest
34 * Test a roundtrip of save and reload of feature colours and filters as XML
38 @Test(groups = "Functional")
39 public void testSaveLoad() throws IOException
41 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
42 ">Seq1\nACDEFGHIKLM", DataSourceType.PASTE, FileFormat.Fasta);
43 SequenceI seq1 = af.getViewport().getAlignment().getSequenceAt(0);
46 * add some features to the sequence
49 addFeatures(seq1, "type1", score++);
50 addFeatures(seq1, "type2", score++);
51 addFeatures(seq1, "type3", score++);
52 addFeatures(seq1, "type4", score++);
53 addFeatures(seq1, "type5", score++);
56 * set colour schemes for features
58 FeatureRenderer fr = af.getFeatureRenderer();
61 fr.setColour("type1", new FeatureColour(Color.red));
64 FeatureColourI byLabel = new FeatureColour();
65 byLabel.setColourByLabel(true);
66 fr.setColour("type2", byLabel);
68 // type3: by score above threshold
69 FeatureColourI byScore = new FeatureColour(Color.BLACK, Color.BLUE, 1,
71 byScore.setAboveThreshold(true);
72 byScore.setThreshold(2f);
73 fr.setColour("type3", byScore);
75 // type4: by attribute AF
76 FeatureColourI byAF = new FeatureColour();
77 byAF.setColourByLabel(true);
78 byAF.setAttributeName("AF");
79 fr.setColour("type4", byAF);
81 // type5: by attribute CSQ:PolyPhen below threshold
82 FeatureColourI byPolyPhen = new FeatureColour(Color.BLACK, Color.BLUE,
84 byPolyPhen.setBelowThreshold(true);
85 byPolyPhen.setThreshold(3f);
86 byPolyPhen.setAttributeName("CSQ", "PolyPhen");
87 fr.setColour("type5", byPolyPhen);
90 * set filters for feature types
93 // filter type1 features by (label contains "x")
94 FeatureMatcherSetI filterByX = new FeatureMatcherSet();
95 filterByX.and(FeatureMatcher.byLabel(Condition.Contains, "x"));
96 fr.setFeatureFilter("type1", filterByX);
98 // filter type2 features by (score <= 2.4 and score > 1.1)
99 FeatureMatcherSetI filterByScore = new FeatureMatcherSet();
100 filterByScore.and(FeatureMatcher.byScore(Condition.LE, "2.4"));
101 filterByScore.and(FeatureMatcher.byScore(Condition.GT, "1.1"));
102 fr.setFeatureFilter("type2", filterByScore);
104 // filter type3 features by (AF contains X OR CSQ:PolyPhen != 0)
105 FeatureMatcherSetI filterByXY = new FeatureMatcherSet();
107 .and(FeatureMatcher.byAttribute(Condition.Contains, "X", "AF"));
108 filterByXY.or(FeatureMatcher.byAttribute(Condition.NE, "0", "CSQ",
110 fr.setFeatureFilter("type3", filterByXY);
113 * save colours and filters to an XML file
115 File coloursFile = File.createTempFile("testSaveLoad", ".fc");
116 coloursFile.deleteOnExit();
117 FeatureSettings fs = new FeatureSettings(af);
118 fs.save(coloursFile);
121 * change feature colours and filters
123 FeatureColourI pink = new FeatureColour(Color.pink);
124 fr.setColour("type1", pink);
125 fr.setColour("type2", pink);
126 fr.setColour("type3", pink);
127 fr.setColour("type4", pink);
128 fr.setColour("type5", pink);
130 FeatureMatcherSetI filter2 = new FeatureMatcherSet();
131 filter2.and(FeatureMatcher.byLabel(Condition.NotContains, "y"));
132 fr.setFeatureFilter("type1", filter2);
133 fr.setFeatureFilter("type2", filter2);
134 fr.setFeatureFilter("type3", filter2);
135 fr.setFeatureFilter("type4", filter2);
136 fr.setFeatureFilter("type5", filter2);
139 * reload colours and filters from file and verify they are restored
141 fs.load(coloursFile);
142 FeatureColourI fc = fr.getFeatureStyle("type1");
143 assertTrue(fc.isSimpleColour());
144 assertEquals(fc.getColour(), Color.red);
145 fc = fr.getFeatureStyle("type2");
146 assertTrue(fc.isColourByLabel());
147 fc = fr.getFeatureStyle("type3");
148 assertTrue(fc.isGraduatedColour());
149 assertNull(fc.getAttributeName());
150 assertTrue(fc.isAboveThreshold());
151 assertEquals(fc.getThreshold(), 2f);
152 fc = fr.getFeatureStyle("type4");
153 assertTrue(fc.isColourByLabel());
154 assertTrue(fc.isColourByAttribute());
155 assertEquals(fc.getAttributeName(), new String[] { "AF" });
156 fc = fr.getFeatureStyle("type5");
157 assertTrue(fc.isGraduatedColour());
158 assertTrue(fc.isColourByAttribute());
159 assertEquals(fc.getAttributeName(), new String[] { "CSQ", "PolyPhen" });
160 assertTrue(fc.isBelowThreshold());
161 assertEquals(fc.getThreshold(), 3f);
163 assertEquals(fr.getFeatureFilter("type1").toStableString(), "Label Contains x");
164 assertEquals(fr.getFeatureFilter("type2").toStableString(),
165 "(Score LE 2.4) AND (Score GT 1.1)");
166 assertEquals(fr.getFeatureFilter("type3").toStableString(),
167 "(AF Contains X) OR (CSQ:PolyPhen NE 0.0)");
171 * Adds two features of the given type to the given sequence, also setting the
172 * score as the value of attribute "AF" and sub-attribute "CSQ:PolyPhen"
178 private void addFeatures(SequenceI seq, String featureType, int score)
180 addFeature(seq, featureType, score++);
181 addFeature(seq, featureType, score);
184 private void addFeature(SequenceI seq, String featureType, int score)
186 SequenceFeature sf = new SequenceFeature(featureType, "desc", 1, 2,
188 sf.setValue("AF", score);
189 sf.setValue("CSQ", new HashMap<String, String>()
192 put("PolyPhen", Integer.toString(score));
195 seq.addSequenceFeature(sf);
199 * Test of the behaviour of the Show / Hide checkbox
201 @Test(groups = "Functional")
202 public void testHideShow()
204 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
205 ">Seq1\nACDEFGHIKLM", DataSourceType.PASTE, FileFormat.Fasta);
206 SequenceI seq1 = af.getViewport().getAlignment().getSequenceAt(0);
207 seq1.addSequenceFeature(
208 new SequenceFeature("type1", "", 1, 4, "group1"));
210 FeatureRenderer fr = af.getFeatureRenderer();
211 fr.setColour("type1", new FeatureColour(Color.red));
213 af.showSeqFeatures_actionPerformed(null);
214 FeatureSettings dialog = new FeatureSettings(af);
216 assertTrue(fr.getDisplayedFeatureTypes().contains("type1"));
219 * check the table has one row, for type1, visible, no filter, red
221 assertEquals(dialog.table.getRowCount(), 1);
222 assertEquals(dialog.table.getColumnCount(), 4);
223 assertEquals(dialog.table.getModel().getValueAt(0, TYPE_COLUMN),
225 FeatureColourI colour = (FeatureColourI) dialog.table.getModel()
226 .getValueAt(0, COLOUR_COLUMN);
227 assertTrue(colour.isSimpleColour());
228 assertEquals(colour.getColour(), Color.red);
229 FeatureMatcherSetI filter = (FeatureMatcherSetI) dialog.table.getModel()
230 .getValueAt(0, FILTER_COLUMN);
231 assertTrue(filter.isEmpty());
232 assertEquals(dialog.table.getModel().getValueAt(0, SHOW_COLUMN),
236 * set feature type to hidden by clicking the checkbox in column 4,
237 * and verify that now no feature types are displayed
239 dialog.table.setValueAt(Boolean.FALSE, 0, SHOW_COLUMN);
240 assertTrue(fr.getDisplayedFeatureTypes().isEmpty());
243 * set feature type back to visible by clicking the checkbox in column 4,
244 * and verify that now the feature type is displayed
246 dialog.table.setValueAt(Boolean.TRUE, 0, SHOW_COLUMN);
247 assertTrue(fr.getDisplayedFeatureTypes().contains("type1"));
251 * Test Cancel resets any changes made
253 @Test(groups = "Functional")
254 public void testCancel()
256 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
257 ">Seq1\nACDEFGHIKLM", DataSourceType.PASTE, FileFormat.Fasta);
258 SequenceI seq1 = af.getViewport().getAlignment().getSequenceAt(0);
259 seq1.addSequenceFeature(
260 new SequenceFeature("type1", "", 1, 4, "group1"));
261 seq1.addSequenceFeature(
262 new SequenceFeature("type2", "", 1, 4, "group2"));
265 * set type1: red, filter 'Label Contains metal'
266 * type2: variable colour red:blue, no filter
268 FeatureRenderer fr = af.getFeatureRenderer();
269 fr.setColour("type1", new FeatureColour(Color.red));
270 fr.setColour("type2", new FeatureColour(Color.red, Color.blue, 0f, 1f));
271 FeatureMatcherSetI f = new FeatureMatcherSet();
272 f.and(FeatureMatcher.byLabel(Condition.Contains, "metal"));
273 fr.setFeatureFilter("type1", f);
275 af.showSeqFeatures_actionPerformed(null);
276 FeatureSettings dialog = new FeatureSettings(af);
278 assertTrue(fr.getDisplayedFeatureTypes().contains("type1"));
279 assertTrue(fr.getDisplayedFeatureTypes().contains("type2"));
282 * check the table has two rows, for type1 and type2
283 * note type2 is shown first; the initial ordering is 'random' as driven by
284 * the Set of feature groups for the sequence
286 assertEquals(dialog.table.getRowCount(), 2);
287 assertEquals(dialog.table.getColumnCount(), 4);
289 assertEquals(dialog.table.getModel().getValueAt(0, TYPE_COLUMN),
291 FeatureColourI colour = (FeatureColourI) dialog.table.getModel()
292 .getValueAt(0, COLOUR_COLUMN);
293 assertFalse(colour.isSimpleColour());
294 assertEquals(colour.getMinColour(), Color.red);
295 assertEquals(colour.getMaxColour(), Color.blue);
296 FeatureMatcherSetI filter = (FeatureMatcherSetI) dialog.table.getModel()
297 .getValueAt(0, FILTER_COLUMN);
298 assertTrue(filter.isEmpty());
299 assertEquals(dialog.table.getModel().getValueAt(0, SHOW_COLUMN),
302 assertEquals(dialog.table.getModel().getValueAt(1, TYPE_COLUMN),
304 colour = (FeatureColourI) dialog.table.getModel().getValueAt(1,
306 assertTrue(colour.isSimpleColour());
307 assertEquals(colour.getColour(), Color.red);
308 filter = (FeatureMatcherSetI) dialog.table.getModel().getValueAt(1,
310 assertFalse(filter.isEmpty());
311 assertEquals(dialog.table.getModel().getValueAt(1, SHOW_COLUMN),
316 * - set type1 to hidden by clicking the checkbox in column 4
317 * - change type2 to plain colour green
318 * We can do these by setting values in the table model -
319 * updateFeatureRenderer then updates visibility and colour
321 dialog.table.setValueAt(Boolean.FALSE, 1, SHOW_COLUMN);
322 dialog.table.setValueAt(new FeatureColour(Color.green), 0,
326 * - remove the filter on type1
327 * - set a filter on type2
328 * We have to do this directly on FeatureRendererModel (as done in the
329 * application from FeatureTypeSettings)
331 fr.setFeatureFilter("type1", null);
332 fr.setFeatureFilter("type2",
333 FeatureMatcherSet.fromString("Label matches Metal"));
336 * verify the changes reached the FeatureRender
338 assertFalse(fr.getDisplayedFeatureTypes().contains("type1"));
339 assertNull(fr.getFeatureFilter("type1"));
340 colour = fr.getFeatureColours().get("type2");
341 assertTrue(colour.isSimpleColour());
342 assertEquals(colour.getColour(), Color.green);
343 filter = fr.getFeatureFilter("type2");
344 assertFalse(filter.isEmpty());
345 assertEquals(filter.toStableString(), "Label Matches Metal");
348 * add a new feature type and 'notify' FeatureRenderer
349 * it should appear in the first row of FeatureSettings table
351 seq1.addSequenceFeature(
352 new SequenceFeature("type3", "desc", 4, 5, null));
354 assertEquals(dialog.table.getRowCount(), 3);
355 assertEquals(dialog.table.getModel().getValueAt(0, TYPE_COLUMN),
357 assertEquals(dialog.table.getModel().getValueAt(0, SHOW_COLUMN),
359 assertTrue(fr.getDisplayedFeatureTypes().contains("type3"));
362 * cancel the dialog, and verify FeatureRenderer data has been reset
365 // type1 has been reset to visible:
366 assertTrue(fr.getDisplayedFeatureTypes().contains("type1"));
367 // type3 has been reset to not visible:
368 assertTrue(fr.getDisplayedFeatureTypes().contains("type3"));
369 // type2 colour has been reset to graduated:
370 colour = fr.getFeatureColours().get("type2");
371 assertFalse(colour.isSimpleColour());
372 assertEquals(colour.getMaxColour(), Color.blue);
373 // type2 filter has been reset to none (held as null):
374 assertNull(fr.getFeatureFilter("type2"));
375 // type1 filter has been reset:
376 filter = fr.getFeatureFilter("type1");
377 assertEquals(filter.toStableString(), "Label Contains metal");