public void analyze(String name, Object data) { if (!(data instanceof SequenceGroup)) { ErrorWindow.showErrorWindow( new Exception("Got a non-sequencegroup object for a dot plot analysis")); } SequenceGroup sg = (SequenceGroup) data; currentSG = sg; titleLabel.setText(name); DefaultComboBoxModel cModel1 = new DefaultComboBoxModel(); DefaultComboBoxModel cModel2 = new DefaultComboBoxModel(); for (int j = 0; j < sg.size(); j++) { cModel1.addElement(sg.get(j).getName()); cModel2.addElement(sg.get(j).getName()); } seq1Box.setModel(cModel1); seq2Box.setModel(cModel2); seq1Box.setSelectedIndex(0); seq2Box.setSelectedIndex(1); dotPlot.setBlockWidth((Integer) blockWidthSpinner.getValue()); changeSequences(); }
/** * Called by AnalysisPane when this analyzer is dismissed, removes this as a listener from all * sg's we're tracking */ public void closed() { originalSG.removePartitionListener(this); originalSG.removeSGChangeListener(this); for (SequenceGroup sg : sgSeriesMap.keySet()) { sg.removeSGChangeListener(this); sg.removePartitionListener(this); } }
/** * Uses the calculator with name calcName to construct & display a series for the sg. This should * be the only way new series' are added to the chart, since we need to keep track of all the * current series in the sgSeriesMap * * @param calcName * @param sg */ protected void addSeriesForSG(String calcName, SequenceGroup sg) { BaseCounter calc = null; try { calc = sgReg.getBaseCounterInstance(calcName, sg); } catch (IllegalArgumentException ex) { System.err.println("Could not find base counter of type : " + calcName); return; } List<AbstractSeries> seriesList = sgSeriesMap.get(sg); if (seriesList == null) { System.out.println( "Uh-oh, this sequence group doesn't have an associated list in the sgSeriesMap..."); } // Make a new series from the calculator int windowsize = ((Integer) windowSizeSpinner.getValue()).intValue(); int windowStep = ((Integer) windowStepSpinner.getValue()).intValue(); if (usePartitionsBox.isSelected()) { for (int i = 0; i < sg.getPartitionCount(); i++) { BaseCounterSeries ser = calc.getWindowSeries(windowsize, windowStep, i); ser.setPartitionIndex(i); seriesList.add(ser); ser.setName(calc.getName() + " - " + sg.getPartitionKeyForIndex(i)); if (ser != null && ser.size() > 0) { chart.addDataSeries(ser); chart.repaint(); } } } else { BaseCounterSeries ser = calc.getWindowSeries(windowsize, windowStep); seriesList.add(ser); if (sgSeriesMap.size() > 1) { String name = sg.getName(); if (name == null) { ser.setName(calc.getName()); } else { ser.setName(calc.getName() + " - " + sg.getName()); } } if (ser != null && ser.size() > 0) { chart.addDataSeries(ser); chart.repaint(); } } }
/** * Called when either the state of the partitions has changed, or when the user has clicked on the * 'Use Partitions..' box. Either way, we recalculate the series data here to reflect the change */ public void partitionStateChanged(Partitionable source, PartitionChangeType type) { if (type == PartitionChangeType.NEW_PARTITION) { usePartitionsBox.setEnabled(true); if (usePartitionsBox.isSelected()) repaintAllSeries(); } if (type == PartitionChangeType.PARTITIONS_CLEARED) { // Do all sg's have no partitions? If so, set the box to disabled int max = 0; for (SequenceGroup sg : sgSeriesMap.keySet()) { if (max < sg.getPartitionCount()) max = sg.getPartitionCount(); } if (max < 2) usePartitionsBox.setEnabled(false); repaintAllSeries(); } }
/** * Returns an array of the base frequencies for this column, in order A C T G * * @param colNum * @return */ public double[] getColumnBaseCounts(int colNum) { double[] freqs = new double[4]; char[] col = sg.getColumn(colNum); double counted = 0; for (int i = 0; i < col.length; i++) switch (col[i]) { case 'A': freqs[0]++; counted++; break; case 'C': freqs[1]++; counted++; break; case 'T': freqs[2]++; counted++; break; case 'G': freqs[3]++; counted++; break; default: counted++; break; } return freqs; }
/** * Called when a file has been dropped on this analyzer, we see if we can parse a sequencegroup * from the file and attempt to display it if possible * * @param file */ public void fileDropped(File file) { FileParser parser = SunFishFrame.getSunFishFrame().getParserForFileAndClass(file, SequenceGroup.class); if (parser != null && parser.getDataClass() == SequenceGroup.class) { try { Object obj = parser.readFile(file); if (obj instanceof SequenceGroup) { SequenceGroup sg = (SequenceGroup) obj; sg.setName(file.getName()); addSequenceGroup(sg); } } catch (Exception ex) { ErrorWindow.showErrorWindow(ex, SunFishFrame.getSunFishFrame().getLogger()); } } }
public void analyze(String name, Object data) { if (data.getClass() != SequenceGroup.class) { ErrorWindow.showErrorWindow( new IllegalArgumentException( "Got a incompatible data type for SequenceLineChart: " + data.getClass())); return; } SequenceGroup currentSG = (SequenceGroup) data; originalSG = currentSG; originalSG.addPartitionListener(this); originalSG.addSGChangeListener(this); sgSeriesMap.put((SequenceGroup) data, new ArrayList<AbstractSeries>()); currentName = name; if (topLabel != null) topLabel.setText(currentName); else topLabel = new JLabel(currentName); topLabel.setFont(defaultFont); int maxLength = currentSG.getMaxSeqLength(); // Guess some decent initial values for size of window and step int windowSize = Math.min(100, maxLength); int windowStep = maxLength > 50 ? 10 : 1; if (maxLength > 9999) { windowSize = 1000; windowStep = 100; } SpinnerModel sizeModel = new SpinnerNumberModel(windowSize, 1, maxLength, 1); SpinnerModel stepModel = new SpinnerNumberModel(windowStep, 1, maxLength / 2, 1); windowSizeSpinner.setModel(sizeModel); windowStepSpinner.setModel(stepModel); if (currentSG.getPartitionCount() < 2) { usePartitionsBox.setSelected(false); usePartitionsBox.setEnabled(false); } else { usePartitionsBox.setEnabled(true); usePartitionsBox.setSelected(true); } toggleCalculator(SGStatisticsRegistry.NUC_DIVERSITY); chart.repaint(); }
protected void changeSequences() { String name1 = (String) seq1Box.getSelectedItem(); Sequence seq1 = currentSG.getSequenceForName(name1); if (revComp1Box.isSelected()) { seq1 = seq1.getReverseComplement(); seq1.setName(name1); } String name2 = (String) seq2Box.getSelectedItem(); Sequence seq2 = currentSG.getSequenceForName(name2); if (revComp2Box.isSelected()) { seq2 = seq2.getReverseComplement(); seq2.setName(name2); } dotPlot.setSequences(seq1, seq2); repaint(); }
/** * Retrieve a new window series * * @param windowSize * @param stepSize * @return */ public ArrayList<Point2D> getWindowPointSeries(int windowSize, int stepSize) { ArrayList<Point2D> points = new ArrayList<Point2D>(); for (int i = 0; i + windowSize < sg.getMaxSeqLength(); i += stepSize) { points.add(new Point2D.Double(i, getValueRange(i, windowSize))); } return points; }
/** * Retrieve a new window series, but only using those sites in the specified partition. This is * trickier than it should be. We only add a new value if TWO conditions are met: 1. The central * site is in the specified partition. 2. At least windowSize / 10 sites in the range are in the * partition * * @param windowSize The breadth of the window (in sites) over which to calculate a single value * @param stepSize The amount the window is moved each step * @param partitionIndex The partition to calculate the value for * @return */ public ArrayList<Point2D> getWindowPointSeries(int windowSize, int stepSize, int partitionIndex) { ArrayList<Point2D> points = new ArrayList<Point2D>(); for (int i = 0; i + windowSize < sg.getMaxSeqLength(); i += stepSize) { double xValue = i; double yValue = Double.NaN; int startSite = Math.max(0, i - windowSize / 2); if (sg.getPartitionNumForSite(i) == partitionIndex || sg.getPartitionNumForSite(i + 1) == partitionIndex || sg.getPartitionNumForSite(i + 2) == partitionIndex) { Double[] sumCount = getSumAndCount(startSite, windowSize, partitionIndex); if (sumCount[1] > ((double) windowSize / 10.0)) yValue = sumCount[0] / sumCount[1]; else yValue = Double.NaN; } points.add(new Point2D.Double(xValue, yValue)); } return points; }
/** * This works just like getValueRange, in that it computes the sum of the values in the * frequencies array over a the given range. But instead of returning sum / number counted, this * returns the two values separately in the array (sum first, then number counted). * * @param begin * @param length * @param partitionIndex * @return */ public Double[] getSumAndCount(int begin, int length, double partitionIndex) { if (freqs == null || freqs.length == 0) { // ErrorWindow.showErrorWindow(new NullPointerException("BaseCounter " + getName() + " was not // properly initialized"), null); System.out.println("Value is NaN, freqs is : " + freqs); return new Double[] {0.0, Double.NaN}; } double sum = 0; double counted = 0; for (int i = begin; i < (begin + length); i++) { if (partitionIndex < 0 || sg.getPartitionNumForSite(i) == partitionIndex) { if (!Double.isNaN(freqs[i])) { sum += freqs[i]; counted++; } } } return new Double[] {sum, counted}; }
/** * Returns true if there is more than one base in this column Gap characters (as defined by * Sequence.GAP) don't count one way or the other. All gaps in this colum return false */ public boolean isPolymorphic(int site) { if (sg.size() == 0) return false; char base = sg.get(0).at(site); int seqNum = 0; while (seqNum < sg.size() && charIsGap(base)) { base = sg.get(seqNum).at(site); seqNum++; } // Every base is a gap in this column, I guess we return false here if (seqNum == sg.size()) { return false; } boolean same = true; for (int i = seqNum; i < sg.size() && same; i++) { char compBase = sg.get(i).at(site); if ((!charIsGap(compBase)) && compBase != base) same = false; } return !same; }
/** Returns true if any sequence has a gap at this site */ public boolean hasGap(int site) { for (int i = 0; i < sg.size(); i++) if (sg.get(i).isGap(site)) return true; return false; }