[med-svn] [Git][med-team/fastqc][upstream] 2 commits: New upstream version 0.11.8+dfsg

Steffen Möller gitlab at salsa.debian.org
Wed Oct 17 18:43:19 BST 2018


Steffen Möller pushed to branch upstream at Debian Med / fastqc


Commits:
3b97b25a by Steffen Moeller at 2018-10-17T17:24:27Z
New upstream version 0.11.8+dfsg
- - - - -
9f214d8c by Steffen Moeller at 2018-10-17T17:38:22Z
New upstream version 0.11.8+dfsg
- - - - -


8 changed files:

- RELEASE_NOTES.txt
- fastqc
- run_fastqc.bat
- uk/ac/babraham/FastQC/FastQCApplication.java
- uk/ac/babraham/FastQC/Graphs/LineGraph.java
- uk/ac/babraham/FastQC/Modules/DuplicationLevel.java
- uk/ac/babraham/FastQC/Modules/SequenceLengthDistribution.java
- uk/ac/babraham/FastQC/Results/ResultsPanel.java


Changes:

=====================================
RELEASE_NOTES.txt
=====================================
@@ -1,3 +1,11 @@
+RELEASE NOTES FOR FastQC v0.11.8
+--------------------------------
+
+This release works around some edge cases in unusual sequence libraries
+and changes the behaviour of the read length module when run with the
+--nogroup option. Other minor fixes are also present.
+
+
 RELEASE NOTES FOR FastQC v0.11.7
 --------------------------------
 


=====================================
fastqc
=====================================
@@ -327,7 +327,7 @@ DESCRIPTION
                     (including being gzipped and ending with .gz) otherwise they
                     won't be grouped together correctly.
                     
-    --nano          Files come from naopore sequences and are in fast5 format. In
+    --nano          Files come from nanopore sequences and are in fast5 format. In
                     this mode you can pass in directories to process and the program
                     will take in all fast5 files within those directories and produce
                     a single output file from the sequences found in all files.                    
@@ -405,4 +405,4 @@ BUGS
     Any bugs in fastqc should be reported either to simon.andrews at babraham.ac.uk
     or in www.bioinformatics.babraham.ac.uk/bugzilla/
                    
-    
\ No newline at end of file
+    


=====================================
run_fastqc.bat
=====================================
@@ -1 +1 @@
-java -Xmx250m -classpath .;./sam-1.103.jar;./jbzip2-0.9.jar uk.ac.babraham.FastQC.FastQCApplication
+java -Xmx250m -classpath .;./sam-1.103.jar;./jbzip2-0.9.jar uk.ac.babraham.FastQC.FastQCApplication %*


=====================================
uk/ac/babraham/FastQC/FastQCApplication.java
=====================================
@@ -54,7 +54,7 @@ import uk.ac.babraham.FastQC.Utilities.NanoporeBasename;
 
 public class FastQCApplication extends JFrame {	
 	
-	public static final String VERSION = "0.11.7";
+	public static final String VERSION = "0.11.8";
 	
 	private JTabbedPane fileTabs;
 	private WelcomePanel welcomePanel;


=====================================
uk/ac/babraham/FastQC/Graphs/LineGraph.java
=====================================
@@ -1,235 +1,235 @@
-/**
- * Copyright Copyright 2010-17 Simon Andrews
- *
- *    This file is part of FastQC.
- *
- *    FastQC is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 3 of the License, or
- *    (at your option) any later version.
- *
- *    FastQC is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with FastQC; if not, write to the Free Software
- *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-package uk.ac.babraham.FastQC.Graphs;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.RenderingHints;
-
-import javax.swing.JPanel;
-
-public class LineGraph extends JPanel {
-
-	private String [] xTitles;
-	private String xLabel;
-	private String [] xCategories;
-	private double [][] data;
-	private String graphTitle;
-	private double minY;
-	private double maxY;
-	private double yInterval;
-	
-	private static final Color [] COLOURS = new Color[] {new Color(220,0,0), new Color(0,0,220), new Color(0,220,0), Color.DARK_GRAY, Color.MAGENTA, Color.ORANGE,Color.YELLOW,Color.CYAN,Color.PINK,Color.LIGHT_GRAY};
-	
-	public LineGraph (double [] [] data, double minY, double maxY, String xLabel, String [] xTitles, int [] xCategories, String graphTitle) {
-		this(data,minY,maxY,xLabel,xTitles,new String[0],graphTitle);
-		this.xCategories = new String [xCategories.length];
-		for (int i=0;i<xCategories.length;i++) {
-			this.xCategories[i] = ""+xCategories[i];
-		}
-		
-	}
-	
-	public LineGraph (double [] [] data, double minY, double maxY, String xLabel, String [] xTitles, String [] xCategories, String graphTitle) {
-		this.data = data;
-		this.minY = minY;
-		this.maxY = maxY;
-		this.xTitles = xTitles;
-		this.xLabel = xLabel;
-		this.xCategories = xCategories;
-		this.graphTitle = graphTitle;
-		this.yInterval = findOptimalYInterval(maxY);
-	}
-	
-	private double findOptimalYInterval(double max) {
-		
-		int base = 1;
-		double [] divisions = new double [] {1,2,2.5,5};
-		
-		while (true) {
-			
-			for (int d=0;d<divisions.length;d++) {
-				double tester = base * divisions[d];
-				if (max / tester <= 10) {
-					return tester;
-				}
-			}
-		
-			base *=10;
-			
-		}
-		
-		
-		
-	}
-	
-	public Dimension getPreferredSize () {
-		return new Dimension(800,600);
-	}
-
-	public Dimension getMinimumSize () {
-		return new Dimension(100,200);
-	}
-	
-	public void paint (Graphics g) {
-		super.paint(g);
-		
-		g.setColor(Color.WHITE);
-		g.fillRect(0, 0, getWidth(), getHeight());
-		g.setColor(Color.BLACK);
-		
-		int lastY = 0;
-		
-		double yStart;
-		
-		if (minY % yInterval == 0) {
-			yStart = minY;
-		}
-		else {
-			yStart = yInterval * (((int)minY/yInterval)+1);
-		}
-		
-		int xOffset = 0;
-		
-		for (double i=yStart;i<=maxY;i+=yInterval) {
-			String label = ""+i;
-			label = label.replaceAll(".0$", ""); // Don't leave trailing .0s where we don't need them.
-			int width = g.getFontMetrics().stringWidth(label);
-			if (width > xOffset) {
-				xOffset = width;
-			}
-			
-			g.drawString(label, 2, getY(i)+(g.getFontMetrics().getAscent()/2));			
-		}
-	
-		// Give the x axis a bit of breathing space
-		xOffset += 5;
-		
-		// Draw the graph title
-		int titleWidth = g.getFontMetrics().stringWidth(graphTitle);
-		g.drawString(graphTitle, (xOffset + ((getWidth()-(xOffset+10))/2)) - (titleWidth/2), 30);
-		
-		
-		// Now draw the axes
-		g.drawLine(xOffset, getHeight()-40, getWidth()-10,getHeight()-40);
-		g.drawLine(xOffset, getHeight()-40, xOffset, 40);
-		
-		// Draw the xLabel under the xAxis
-		g.drawString(xLabel, (getWidth()/2) - (g.getFontMetrics().stringWidth(xLabel)/2), getHeight()-5);
-		
-		
-		// Now draw the data points
-		int baseWidth = (getWidth()-(xOffset+10))/data[0].length;
-		if (baseWidth<1) baseWidth=1;
-		
-//		System.out.println("Base Width is "+baseWidth);
-		
-		// First draw faint boxes over alternating bases so you can see which is which
-		
-		// Let's find the longest label, and then work out how often we can draw labels
-		
-		int lastXLabelEnd = 0;
-		
-		for (int i=0;i<data[0].length;i++) {
-			if (i%2 != 0) {
-				g.setColor(new Color(230, 230, 230));
-				g.fillRect(xOffset+(baseWidth*i), 40, baseWidth, getHeight()-80);
-			}
-			g.setColor(Color.BLACK);
-			String baseNumber = ""+xCategories[i];
-			int baseNumberWidth = g.getFontMetrics().stringWidth(baseNumber);
-			int baseNumberPosition =  (baseWidth/2)+xOffset+(baseWidth*i)-(baseNumberWidth/2);
-			
-			if (baseNumberPosition > lastXLabelEnd) {
-				g.drawString(baseNumber,baseNumberPosition, getHeight()-25);
-				lastXLabelEnd = baseNumberPosition+baseNumberWidth+5;
-			}
-		}
-		
-		// Now draw horizontal lines across from the y axis
-
-		g.setColor(new Color(180,180,180));
-		for (double i=yStart;i<=maxY;i+=yInterval) {
-			g.drawLine(xOffset, getY(i), getWidth()-10, getY(i));
-		}
-		g.setColor(Color.BLACK);
-		
-		// Now draw the datasets
-		
-		if (g instanceof Graphics2D) {
-			((Graphics2D)g).setStroke(new BasicStroke(2));
-			((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-		}
-		
-		for (int d=0;d<data.length;d++) {
-			g.setColor(COLOURS[d % COLOURS.length]);
-						
-			lastY = getY(data[d][0]);
-			for (int i=1;i<data[d].length;i++) {
-				int thisY = getY(data[d][i]);
-				g.drawLine((baseWidth/2)+xOffset+(baseWidth*(i-1)), lastY, (baseWidth/2)+xOffset+(baseWidth*i), thisY);
-				lastY = thisY;
-			}
-			
-		}
-		
-		// Now draw the data legend
-
-		if (g instanceof Graphics2D) {
-			((Graphics2D)g).setStroke(new BasicStroke(1));
-			((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
-		}
-
-		
-		// First we need to find the widest label
-		int widestLabel = 0;
-		for (int t=0;t<xTitles.length;t++) {
-			int width = g.getFontMetrics().stringWidth(xTitles[t]);
-			if (width > widestLabel) widestLabel = width;
-		}
-		
-		// Add 3px either side for a bit of space;
-		widestLabel += 6;
-		
-		// First draw a box to put the legend in
-		g.setColor(Color.WHITE);
-		g.fillRect((getWidth()-10)-widestLabel, 40, widestLabel, 3+(20*xTitles.length));
-		g.setColor(Color.LIGHT_GRAY);
-		g.drawRect((getWidth()-10)-widestLabel, 40, widestLabel, 3+(20*xTitles.length));
-
-		// Now draw the actual labels
-		for (int t=0;t<xTitles.length;t++) {
-			g.setColor(COLOURS[t % COLOURS.length]);
-			g.drawString(xTitles[t], ((getWidth()-10)-widestLabel)+3, 40+(20*(t+1)));
-		}
-		
-
-		
-		
-	}
-
-	private int getY(double y) {
-		return (getHeight()-40) - (int)(((getHeight()-80)/(maxY-minY))*y);
-	}
-	
-}
+/**
+ * Copyright Copyright 2010-17 Simon Andrews
+ *
+ *    This file is part of FastQC.
+ *
+ *    FastQC is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 3 of the License, or
+ *    (at your option) any later version.
+ *
+ *    FastQC is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with FastQC; if not, write to the Free Software
+ *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package uk.ac.babraham.FastQC.Graphs;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+
+import javax.swing.JPanel;
+
+public class LineGraph extends JPanel {
+
+	private String [] xTitles;
+	private String xLabel;
+	private String [] xCategories;
+	private double [][] data;
+	private String graphTitle;
+	private double minY;
+	private double maxY;
+	private double yInterval;
+	
+	private static final Color [] COLOURS = new Color[] {new Color(220,0,0), new Color(0,0,220), new Color(0,220,0), Color.DARK_GRAY, Color.MAGENTA, Color.ORANGE,Color.YELLOW,Color.CYAN,Color.PINK,Color.LIGHT_GRAY};
+	
+	public LineGraph (double [] [] data, double minY, double maxY, String xLabel, String [] xTitles, int [] xCategories, String graphTitle) {
+		this(data,minY,maxY,xLabel,xTitles,new String[0],graphTitle);
+		this.xCategories = new String [xCategories.length];
+		for (int i=0;i<xCategories.length;i++) {
+			this.xCategories[i] = ""+xCategories[i];
+		}
+		
+	}
+	
+	public LineGraph (double [] [] data, double minY, double maxY, String xLabel, String [] xTitles, String [] xCategories, String graphTitle) {
+		this.data = data;
+		this.minY = minY;
+		this.maxY = maxY;
+		this.xTitles = xTitles;
+		this.xLabel = xLabel;
+		this.xCategories = xCategories;
+		this.graphTitle = graphTitle;
+		this.yInterval = findOptimalYInterval(maxY);
+	}
+	
+	private double findOptimalYInterval(double max) {
+		
+		int base = 1;
+		double [] divisions = new double [] {1,2,2.5,5};
+		
+		while (true) {
+			
+			for (int d=0;d<divisions.length;d++) {
+				double tester = base * divisions[d];
+				if (max / tester <= 10) {
+					return tester;
+				}
+			}
+		
+			base *=10;
+			
+		}
+		
+		
+		
+	}
+	
+	public Dimension getPreferredSize () {
+		return new Dimension(800,600);
+	}
+
+	public Dimension getMinimumSize () {
+		return new Dimension(100,200);
+	}
+	
+	public void paint (Graphics g) {
+		super.paint(g);
+		
+		g.setColor(Color.WHITE);
+		g.fillRect(0, 0, getWidth(), getHeight());
+		g.setColor(Color.BLACK);
+		
+		int lastY = 0;
+		
+		double yStart;
+		
+		if (minY % yInterval == 0) {
+			yStart = minY;
+		}
+		else {
+			yStart = yInterval * (((int)minY/yInterval)+1);
+		}
+		
+		int xOffset = 0;
+		
+		for (double i=yStart;i<=maxY;i+=yInterval) {
+			String label = ""+i;
+			label = label.replaceAll(".0$", ""); // Don't leave trailing .0s where we don't need them.
+			int width = g.getFontMetrics().stringWidth(label);
+			if (width > xOffset) {
+				xOffset = width;
+			}
+			
+			g.drawString(label, 2, getY(i)+(g.getFontMetrics().getAscent()/2));			
+		}
+	
+		// Give the x axis a bit of breathing space
+		xOffset += 5;
+		
+		// Draw the graph title
+		int titleWidth = g.getFontMetrics().stringWidth(graphTitle);
+		g.drawString(graphTitle, (xOffset + ((getWidth()-(xOffset+10))/2)) - (titleWidth/2), 30);
+		
+		
+		// Now draw the axes
+		g.drawLine(xOffset, getHeight()-40, getWidth()-10,getHeight()-40);
+		g.drawLine(xOffset, getHeight()-40, xOffset, 40);
+		
+		// Draw the xLabel under the xAxis
+		g.drawString(xLabel, (getWidth()/2) - (g.getFontMetrics().stringWidth(xLabel)/2), getHeight()-5);
+		
+		
+		// Now draw the data points
+		int baseWidth = (getWidth()-(xOffset+10))/data[0].length;
+		if (baseWidth<1) baseWidth=1;
+		
+//		System.out.println("Base Width is "+baseWidth);
+		
+		// First draw faint boxes over alternating bases so you can see which is which
+		
+		// Let's find the longest label, and then work out how often we can draw labels
+		
+		int lastXLabelEnd = 0;
+		
+		for (int i=0;i<data[0].length;i++) {
+			if (i%2 != 0) {
+				g.setColor(new Color(230, 230, 230));
+				g.fillRect(xOffset+(baseWidth*i), 40, baseWidth, getHeight()-80);
+			}
+			g.setColor(Color.BLACK);
+			String baseNumber = ""+xCategories[i];
+			int baseNumberWidth = g.getFontMetrics().stringWidth(baseNumber);
+			int baseNumberPosition =  (baseWidth/2)+xOffset+(baseWidth*i)-(baseNumberWidth/2);
+			
+			if (baseNumberPosition > lastXLabelEnd) {
+				g.drawString(baseNumber,baseNumberPosition, getHeight()-25);
+				lastXLabelEnd = baseNumberPosition+baseNumberWidth+5;
+			}
+		}
+		
+		// Now draw horizontal lines across from the y axis
+
+		g.setColor(new Color(180,180,180));
+		for (double i=yStart;i<=maxY;i+=yInterval) {
+			g.drawLine(xOffset, getY(i), getWidth()-10, getY(i));
+		}
+		g.setColor(Color.BLACK);
+		
+		// Now draw the datasets
+		
+		if (g instanceof Graphics2D) {
+			((Graphics2D)g).setStroke(new BasicStroke(2));
+			((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+		}
+		
+		for (int d=0;d<data.length;d++) {
+			g.setColor(COLOURS[d % COLOURS.length]);
+						
+			lastY = getY(data[d][0]);
+			for (int i=1;i<data[d].length;i++) {
+				int thisY = getY(data[d][i]);
+				g.drawLine((baseWidth/2)+xOffset+(baseWidth*(i-1)), lastY, (baseWidth/2)+xOffset+(baseWidth*i), thisY);
+				lastY = thisY;
+			}
+			
+		}
+		
+		// Now draw the data legend
+
+		if (g instanceof Graphics2D) {
+			((Graphics2D)g).setStroke(new BasicStroke(1));
+			((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
+		}
+
+		
+		// First we need to find the widest label
+		int widestLabel = 0;
+		for (int t=0;t<xTitles.length;t++) {
+			int width = g.getFontMetrics().stringWidth(xTitles[t]);
+			if (width > widestLabel) widestLabel = width;
+		}
+		
+		// Add 3px either side for a bit of space;
+		widestLabel += 6;
+		
+		// First draw a box to put the legend in
+		g.setColor(Color.WHITE);
+		g.fillRect((getWidth()-10)-widestLabel, 40, widestLabel, 3+(20*xTitles.length));
+		g.setColor(Color.LIGHT_GRAY);
+		g.drawRect((getWidth()-10)-widestLabel, 40, widestLabel, 3+(20*xTitles.length));
+
+		// Now draw the actual labels
+		for (int t=0;t<xTitles.length;t++) {
+			g.setColor(COLOURS[t % COLOURS.length]);
+			g.drawString(xTitles[t], ((getWidth()-10)-widestLabel)+3, 40+(20*(t+1)));
+		}
+		
+
+		
+		
+	}
+
+	private int getY(double y) {
+		return (getHeight()-40) - (int)(((getHeight()-80)/(maxY-minY))*y);
+	}
+	
+}


=====================================
uk/ac/babraham/FastQC/Modules/DuplicationLevel.java
=====================================
@@ -1,264 +1,274 @@
-/**
- * Copyright Copyright 2010-17 Simon Andrews
- *
- *    This file is part of FastQC.
- *
- *    FastQC is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 3 of the License, or
- *    (at your option) any later version.
- *
- *    FastQC is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with FastQC; if not, write to the Free Software
- *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-package uk.ac.babraham.FastQC.Modules;
-
-import java.io.IOException;
-import java.text.DecimalFormat;
-import java.util.HashMap;
-import java.util.Iterator;
-
-import javax.swing.JPanel;
-import javax.xml.stream.XMLStreamException;
-
-import uk.ac.babraham.FastQC.Graphs.LineGraph;
-import uk.ac.babraham.FastQC.Report.HTMLReportArchive;
-import uk.ac.babraham.FastQC.Sequence.Sequence;
-
-public class DuplicationLevel extends AbstractQCModule {
-
-	private OverRepresentedSeqs overrepresentedModule;
-	private double [] deduplicatedPercentages = null;
-	private double [] totalPercentages = null;
-	private double maxCount = 100;
-	private double percentDifferentSeqs = 0;
-	private String [] labels;
-	private static final DecimalFormat df = new DecimalFormat("#.##");
-	
-	protected DuplicationLevel (OverRepresentedSeqs overrepresentedModule) {
-		this.overrepresentedModule = overrepresentedModule;
-	}
-	
-	public String description() {
-		return "Plots the number of sequences which are duplicated to different levels";
-	}
-
-	public boolean ignoreFilteredSequences() {
-		if (ModuleConfig.getParam("duplication", "ignore") > 0) {
-			return true;
-		}
-		return false;
-	}
-	
-	public boolean ignoreInReport () {
-		if (ModuleConfig.getParam("duplication", "ignore") > 0) {
-			return true;
-		}
-		return false;
-	}
-	
-	protected synchronized void calculateLevels () {
-		
-		if (deduplicatedPercentages != null) return;
-		
-		deduplicatedPercentages = new double[16];
-		totalPercentages = new double[16];
-		
-		HashMap<Integer, Integer> collatedCounts = new HashMap<Integer, Integer>();
-		
-		Iterator<String> it = overrepresentedModule.sequences.keySet().iterator();
-				
-		while (it.hasNext()) {
-			int thisCount = overrepresentedModule.sequences.get(it.next());
-		
-			if (collatedCounts.containsKey(thisCount)) {
-				collatedCounts.put(thisCount,collatedCounts.get(thisCount)+1);
-			}
-			else {
-				collatedCounts.put(thisCount,1);
-			}
-		}
-		
-		// Now we can correct each of these
-		
-		HashMap<Integer, Double> correctedCounts = new HashMap<Integer, Double>();
-		
-		Iterator<Integer> itr = collatedCounts.keySet().iterator();
-		
-		while (itr.hasNext()) {
-			int dupLevel = itr.next();
-			int count = collatedCounts.get(dupLevel);
-			
-			correctedCounts.put(dupLevel,getCorrectedCount(overrepresentedModule.countAtUniqueLimit, overrepresentedModule.count, dupLevel, count));
-			
-//			System.err.println("For dup level "+dupLevel+" raw count was "+count+" corrected count was "+correctedCounts.get(dupLevel));
-			
-		}
-		
-		// From the corrected counts we can now work out the raw and deduplicated proportions
-		
-		double dedupTotal = 0;
-		double rawTotal = 0;
-
-		Iterator<Integer> itc = correctedCounts.keySet().iterator();
-		
-		while (itc.hasNext()) {
-			int dupLevel = itc.next();
-			double count = correctedCounts.get(dupLevel);
-			
-			dedupTotal += count;
-			rawTotal += count * dupLevel;
-
-			int dupSlot = dupLevel - 1;
-			
-			if (dupSlot > 9999) dupSlot = 15;
-			else if (dupSlot > 4999) dupSlot = 14;
-			else if (dupSlot > 999) dupSlot = 13;
-			else if (dupSlot > 499) dupSlot = 12;
-			else if (dupSlot > 99) dupSlot = 11;
-			else if (dupSlot > 49) dupSlot = 10;
-			else if (dupSlot > 9) dupSlot = 9;
-
-			
-			deduplicatedPercentages[dupSlot] += count;
-			totalPercentages[dupSlot] += count * dupLevel;
-			
-		}
-		
-//		System.err.println("True total = "+overrepresentedModule.count+" inferred total is "+rawTotal+" dedup total is "+dedupTotal);
-		
-		
-		labels = new String [16];
-		for (int i=0;i<deduplicatedPercentages.length;i++) {
-			if (i<9) labels[i] = ""+(i+1);
-			else if (i==9) labels[i]=">10";
-			else if (i==10) labels[i]=">50";
-			else if (i==11) labels[i]=">100";
-			else if (i==12) labels[i]=">500";
-			else if (i==13) labels[i]=">1k";
-			else if (i==14) labels[i]=">5k";
-			else if (i==15) labels[i]=">10k";
-			
-			
-			deduplicatedPercentages[i] /= dedupTotal;
-			totalPercentages[i] /= rawTotal;
-			deduplicatedPercentages[i] *= 100;
-			totalPercentages[i] *= 100;
-		}
-		
-		
-		percentDifferentSeqs = (dedupTotal/rawTotal)*100;
-		
-	}
-	
-	private static double getCorrectedCount (long countAtLimit, long totalCount, int duplicationLevel, int numberOfObservations) {
-		
-//		System.err.println("Count at limit = "+countAtLimit+" total = "+totalCount+" Dup level = "+duplicationLevel+" no obs = "+numberOfObservations);
-		
-		// See if we can bail out early
-		if (countAtLimit == totalCount) return numberOfObservations;
-		
-		// If there aren't enough sequences left to hide another sequence with this count then
-		// we can also skip the calculation
-		if (totalCount - numberOfObservations < countAtLimit) return numberOfObservations;
-		
-		// If not then we need to see what the likelihood is that we had another sequence
-		// with this number of observations which we would have missed.
-
-		// We'll start by working out the probability of NOT seeing a sequence with this duplication level
-		// within the first countAtLimit sequences of numberOfObservations.  This is easier than calculating
-		// the probability of seeing it.
-		
-		double pNotSeeingAtLimit = 1;
-		
-		for (int i=0;i<countAtLimit;i++) {
-			pNotSeeingAtLimit *= ((totalCount-i)-duplicationLevel)/(double)(totalCount-i);
-//			System.err.println("At i="+i+" p is "+pNotSeeingAtLimit);
-		}
-		
-		// Now we can invert this to get the chance of seeing a sequence with this count
-		double pSeeingAtLimit = 1 - pNotSeeingAtLimit;
-		
-		// Now we can assume that the number we observed can be scaled up by this proportion
-		double trueCount = numberOfObservations/pSeeingAtLimit;
-		
-		return trueCount;
-		
-	}
-	
-
-	public JPanel getResultsPanel() {
-		if (deduplicatedPercentages == null) calculateLevels();
-
-		return new LineGraph(new double [][] {deduplicatedPercentages,totalPercentages}, 0d, maxCount, "Sequence Duplication Level",new String [] {"% Deduplicated sequences","% Total sequences"}, labels, "Percent of seqs remaining if deduplicated "+df.format(percentDifferentSeqs)+"%");
-	}
-	
-	public void makeReport(HTMLReportArchive report) throws IOException,XMLStreamException {
-		if (deduplicatedPercentages == null) calculateLevels();
-
-		writeDefaultImage(report, "duplication_levels.png", "Duplication level graph", 800, 600);
-				
-		StringBuffer sb = report.dataDocument();
-		
-		sb.append("#Total Deduplicated Percentage\t");
-		sb.append(percentDifferentSeqs);
-		sb.append("\n");
-		
-		sb.append("#Duplication Level\tPercentage of deduplicated\tPercentage of total\n");
-		for (int i=0;i<labels.length;i++) {
-			sb.append(labels[i]);
-			if (i == labels.length-1) {
-				sb.append("+");
-			}
-			sb.append("\t");
-			sb.append(deduplicatedPercentages[i]);
-			sb.append("\t");
-			sb.append(totalPercentages[i]);
-			sb.append("\n");
-		}
-		
-	}
-
-	public String name() {
-		return "Sequence Duplication Levels";
-	}
-
-	public void processSequence(Sequence sequence) {
-		// We don't need to do anything since we use 
-		// the data structure from the overrepresented sequences
-		// module.
-	}
-
-	public boolean raisesError() {
-		if (deduplicatedPercentages == null) calculateLevels();
-		
-		// Anything over 50% duplicate gets us a error
-		if (percentDifferentSeqs < ModuleConfig.getParam("duplication", "error")) {
-			return true;
-		}
-		
-		return false;
-	}
-
-	public boolean raisesWarning() {
-		if (deduplicatedPercentages == null) calculateLevels();
-
-		// Anything over 20% duplicate gets us a warning
-		if (percentDifferentSeqs < ModuleConfig.getParam("duplication", "warn")) {
-			return true;
-		}
-		
-		return false;
-	}
-
-	public void reset() {
-		deduplicatedPercentages = null;
-	}
-
-}
+/**
+ * Copyright Copyright 2010-17 Simon Andrews
+ *
+ *    This file is part of FastQC.
+ *
+ *    FastQC is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 3 of the License, or
+ *    (at your option) any later version.
+ *
+ *    FastQC is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with FastQC; if not, write to the Free Software
+ *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package uk.ac.babraham.FastQC.Modules;
+
+import java.io.IOException;
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.swing.JPanel;
+import javax.xml.stream.XMLStreamException;
+
+import uk.ac.babraham.FastQC.Graphs.LineGraph;
+import uk.ac.babraham.FastQC.Report.HTMLReportArchive;
+import uk.ac.babraham.FastQC.Sequence.Sequence;
+
+public class DuplicationLevel extends AbstractQCModule {
+
+	private OverRepresentedSeqs overrepresentedModule;
+	private double [] deduplicatedPercentages = null;
+	private double [] totalPercentages = null;
+	private double maxCount = 100;
+	private double percentDifferentSeqs = 0;
+	private String [] labels;
+	private static final DecimalFormat df = new DecimalFormat("#.##");
+	
+	protected DuplicationLevel (OverRepresentedSeqs overrepresentedModule) {
+		this.overrepresentedModule = overrepresentedModule;
+	}
+	
+	public String description() {
+		return "Plots the number of sequences which are duplicated to different levels";
+	}
+
+	public boolean ignoreFilteredSequences() {
+		if (ModuleConfig.getParam("duplication", "ignore") > 0) {
+			return true;
+		}
+		return false;
+	}
+	
+	public boolean ignoreInReport () {
+		if (ModuleConfig.getParam("duplication", "ignore") > 0) {
+			return true;
+		}
+		return false;
+	}
+	
+	protected synchronized void calculateLevels () {
+		
+		if (deduplicatedPercentages != null) return;
+		
+		deduplicatedPercentages = new double[16];
+		totalPercentages = new double[16];
+		
+		HashMap<Integer, Integer> collatedCounts = new HashMap<Integer, Integer>();
+		
+		Iterator<String> it = overrepresentedModule.sequences.keySet().iterator();
+			
+		while (it.hasNext()) {
+			int thisCount = overrepresentedModule.sequences.get(it.next());
+		
+			if (collatedCounts.containsKey(thisCount)) {
+				collatedCounts.put(thisCount,collatedCounts.get(thisCount)+1);
+			}
+			else {
+				collatedCounts.put(thisCount,1);
+			}
+		}
+		
+		// Now we can correct each of these
+		
+		HashMap<Integer, Double> correctedCounts = new HashMap<Integer, Double>();
+		
+		Iterator<Integer> itr = collatedCounts.keySet().iterator();
+		
+		while (itr.hasNext()) {
+			int dupLevel = itr.next();
+			int count = collatedCounts.get(dupLevel);
+			
+			correctedCounts.put(dupLevel,getCorrectedCount(overrepresentedModule.countAtUniqueLimit, overrepresentedModule.count, dupLevel, count));
+
+		}
+		
+		// From the corrected counts we can now work out the raw and deduplicated proportions
+		
+		double dedupTotal = 0;
+		double rawTotal = 0;
+
+		Iterator<Integer> itc = correctedCounts.keySet().iterator();
+		
+		while (itc.hasNext()) {
+			int dupLevel = itc.next();
+			double count = correctedCounts.get(dupLevel);
+			
+			dedupTotal += count;
+			rawTotal += count * dupLevel;
+
+			int dupSlot = dupLevel - 1;
+			
+			if (dupSlot > 9999) dupSlot = 15;
+			else if (dupSlot > 4999) dupSlot = 14;
+			else if (dupSlot > 999) dupSlot = 13;
+			else if (dupSlot > 499) dupSlot = 12;
+			else if (dupSlot > 99) dupSlot = 11;
+			else if (dupSlot > 49) dupSlot = 10;
+			else if (dupSlot > 9) dupSlot = 9;
+
+			
+			deduplicatedPercentages[dupSlot] += count;
+			totalPercentages[dupSlot] += count * dupLevel;
+			
+		}
+		
+//		System.err.println("True total = "+overrepresentedModule.count+" inferred total is "+rawTotal+" dedup total is "+dedupTotal);
+		
+		labels = new String [16];
+		for (int i=0;i<deduplicatedPercentages.length;i++) {
+			if (i<9) labels[i] = ""+(i+1);
+			else if (i==9) labels[i]=">10";
+			else if (i==10) labels[i]=">50";
+			else if (i==11) labels[i]=">100";
+			else if (i==12) labels[i]=">500";
+			else if (i==13) labels[i]=">1k";
+			else if (i==14) labels[i]=">5k";
+			else if (i==15) labels[i]=">10k";
+			
+			
+			deduplicatedPercentages[i] /= dedupTotal;
+			totalPercentages[i] /= rawTotal;
+			deduplicatedPercentages[i] *= 100;
+			totalPercentages[i] *= 100;
+		}
+		
+		
+		percentDifferentSeqs = (dedupTotal/rawTotal)*100;
+		
+	}
+	
+	private static double getCorrectedCount (long countAtLimit, long totalCount, int duplicationLevel, int numberOfObservations) {
+		
+//		System.err.println("Count at limit = "+countAtLimit+" total = "+totalCount+" Dup level = "+duplicationLevel+" no obs = "+numberOfObservations);
+		
+		// See if we can bail out early
+		if (countAtLimit == totalCount) return numberOfObservations;
+		
+		// If there aren't enough sequences left to hide another sequence with this count then
+		// we can also skip the calculation
+		if (totalCount - numberOfObservations < countAtLimit) return numberOfObservations;
+		
+		// If not then we need to see what the likelihood is that we had another sequence
+		// with this number of observations which we would have missed.
+
+		// We'll start by working out the probability of NOT seeing a sequence with this duplication level
+		// within the first countAtLimit sequences of numberOfObservations.  This is easier than calculating
+		// the probability of seeing it.
+		
+		double pNotSeeingAtLimit = 1;
+		
+		
+		// To save doing long calculations which are never going to produce anything meaningful
+		// we'll set a limit to our p-value calculation.  This is the probability below which we
+		// won't increase our count by 0.01 of an observation.  Once we're below this we stop caring
+		// about the corrected value since it's going to be so close to the observed value that
+		// we can just return that instead.
+		double limitOfCaring = 1d - (numberOfObservations/(numberOfObservations+0.01d));
+				
+		for (int i=0;i<countAtLimit;i++) {
+			pNotSeeingAtLimit *= ((totalCount-i)-duplicationLevel)/(double)(totalCount-i);
+			
+			if (pNotSeeingAtLimit < limitOfCaring) {
+				pNotSeeingAtLimit = 0;
+				break;
+			}
+			
+		}
+				
+		// Now we can invert this to get the chance of seeing a sequence with this count
+		double pSeeingAtLimit = 1 - pNotSeeingAtLimit;
+		
+		// Now we can assume that the number we observed can be scaled up by this proportion
+		double trueCount = numberOfObservations/pSeeingAtLimit;
+		
+		return trueCount;
+		
+	}
+	
+
+	public JPanel getResultsPanel() {
+		if (deduplicatedPercentages == null) calculateLevels();
+
+		return new LineGraph(new double [][] {deduplicatedPercentages,totalPercentages}, 0d, maxCount, "Sequence Duplication Level",new String [] {"% Deduplicated sequences","% Total sequences"}, labels, "Percent of seqs remaining if deduplicated "+df.format(percentDifferentSeqs)+"%");
+	}
+	
+	public void makeReport(HTMLReportArchive report) throws IOException,XMLStreamException {
+		if (deduplicatedPercentages == null) calculateLevels();
+
+		writeDefaultImage(report, "duplication_levels.png", "Duplication level graph", 800, 600);
+				
+		StringBuffer sb = report.dataDocument();
+		
+		sb.append("#Total Deduplicated Percentage\t");
+		sb.append(percentDifferentSeqs);
+		sb.append("\n");
+		
+		sb.append("#Duplication Level\tPercentage of deduplicated\tPercentage of total\n");
+		for (int i=0;i<labels.length;i++) {
+			sb.append(labels[i]);
+			if (i == labels.length-1) {
+				sb.append("+");
+			}
+			sb.append("\t");
+			sb.append(deduplicatedPercentages[i]);
+			sb.append("\t");
+			sb.append(totalPercentages[i]);
+			sb.append("\n");
+		}
+		
+	}
+
+	public String name() {
+		return "Sequence Duplication Levels";
+	}
+
+	public void processSequence(Sequence sequence) {
+		// We don't need to do anything since we use 
+		// the data structure from the overrepresented sequences
+		// module.
+	}
+
+	public boolean raisesError() {
+		if (deduplicatedPercentages == null) calculateLevels();
+		
+		// Anything over 50% duplicate gets us a error
+		if (percentDifferentSeqs < ModuleConfig.getParam("duplication", "error")) {
+			return true;
+		}
+		
+		return false;
+	}
+
+	public boolean raisesWarning() {
+		if (deduplicatedPercentages == null) calculateLevels();
+
+		// Anything over 20% duplicate gets us a warning
+		if (percentDifferentSeqs < ModuleConfig.getParam("duplication", "warn")) {
+			return true;
+		}
+		
+		return false;
+	}
+
+	public void reset() {
+		deduplicatedPercentages = null;
+	}
+	
+}


=====================================
uk/ac/babraham/FastQC/Modules/SequenceLengthDistribution.java
=====================================
@@ -1,240 +1,246 @@
-/**
- * Copyright Copyright 2010-17 Simon Andrews
- *
- *    This file is part of FastQC.
- *
- *    FastQC is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 3 of the License, or
- *    (at your option) any later version.
- *
- *    FastQC is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with FastQC; if not, write to the Free Software
- *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-package uk.ac.babraham.FastQC.Modules;
-
-import java.io.IOException;
-
-import javax.swing.JPanel;
-import javax.xml.stream.XMLStreamException;
-
-import uk.ac.babraham.FastQC.Graphs.LineGraph;
-import uk.ac.babraham.FastQC.Report.HTMLReportArchive;
-import uk.ac.babraham.FastQC.Sequence.Sequence;
-
-public class SequenceLengthDistribution extends AbstractQCModule {
-
-	private long [] lengthCounts = new long[0];
-	private double [] graphCounts = null;
-	private String [] xCategories = new String[0];
-	private double max = 0;
-	private boolean calculated = false;
-	
-	public JPanel getResultsPanel() {
-	
-		if (!calculated) calculateDistribution();
-				
-		return new LineGraph(new double [][] {graphCounts}, 0d, max, "Sequence Length (bp)",new String [] {"Sequence Length"}, xCategories, "Distribution of sequence lengths over all sequences");
-	}
-	
-	public boolean ignoreFilteredSequences() {
-		return true;
-	}
-	
-	public boolean ignoreInReport () {
-		if (ModuleConfig.getParam("sequence_length", "ignore") > 0) {
-			return true;
-		}
-		return false;
-	}
-	
-	private synchronized void calculateDistribution () {
-		int maxLen = 0;
-		int minLen = -1;
-		max = 0;
-		
-		// Find the min and max lengths
-		for (int i=0;i<lengthCounts.length;i++) {
-			if (lengthCounts[i]>0) {
-				if (minLen < 0) {
-					minLen = i;
-				}
-				maxLen = i;
-			}
-		}		
-		
-		// We put one extra category either side of the actual size
-		if (minLen>0) minLen--;
-		maxLen++;
-		
-		int [] startAndInterval = getSizeDistribution(minLen, maxLen);
-				
-		// Work out how many categories we need
-		int categories = 0;
-		int currentValue = startAndInterval[0];
-		while (currentValue<= maxLen) {
-			++categories;
-			currentValue+= startAndInterval[1];
-		}
-		
-		graphCounts = new double[categories];
-		xCategories = new String[categories];
-		
-		for (int i=0;i<graphCounts.length;i++) {
-			
-			int minValue = startAndInterval[0]+(startAndInterval[1]*i);
-			int maxValue = (startAndInterval[0]+(startAndInterval[1]*(i+1)))-1;
-
-			if (maxValue > maxLen) {
-				maxValue = maxLen;
-			}
-			
-			for (int bp=minValue;bp<=maxValue;bp++) {
-				if (bp < lengthCounts.length) {
-					graphCounts[i] += lengthCounts[bp];
-				}
-			}
-
-			if (startAndInterval[1] == 1) {
-				xCategories[i] = ""+minValue;
-			}
-			else {
-				xCategories[i] = minValue+"-"+maxValue;
-			}
-			
-			if (graphCounts[i] > max) max = graphCounts[i];
-		}
-		calculated = true;
-	}
-
-	public void processSequence(Sequence sequence) {
-		int seqLen = sequence.getSequence().length();
-
-		if (seqLen+2 > lengthCounts.length) {
-			long [] newLengthCounts = new long[seqLen+2];
-			for (int i=0;i<lengthCounts.length;i++) {
-				newLengthCounts[i] = lengthCounts[i];
-			}
-			lengthCounts = newLengthCounts;
-		}
-		
-		++lengthCounts[seqLen];
-		
-	}
-	
-	private int [] getSizeDistribution (int min, int max) {
-		
-		int base = 1;
-		
-		while (base > (max-min)) {
-			base /= 10;
-		}
-				
-		int interval;
-		int starting;
-
-		int [] divisions = new int [] {1,2,5};
-		
-		OUTER: while (true) {
-			
-			for (int d=0;d<divisions.length;d++) {
-				int tester = base * divisions[d];
-				if (((max-min) / tester) <= 50) {
-					interval = tester;
-					break OUTER;
-				}
-			}
-		
-			base *=10;
-			
-		}
-		
-		// Now we work out the first value to be plotted
-		int basicDivision = (int)(min/interval);
-				
-		int testStart = basicDivision * interval;
-				
-		starting = testStart;
-		
-		return new int[] {starting,interval};
-		
-	}
-	
-	
-	
-	public void reset () {
-		lengthCounts = new long[0];
-	}
-
-	public String description() {
-		return "Shows the distribution of sequence length over all sequences";
-	}
-
-	public String name() {
-		return "Sequence Length Distribution";
-	}
-
-	public boolean raisesError() {
-		if (!calculated) calculateDistribution();
-		
-		// See if they've turned this test off
-		if (ModuleConfig.getParam("sequence_length", "error") == 0) {
-			return false;
-		}
-
-
-		if (lengthCounts[0] > 0) {
-			return true;
-		}
-		return false;
-	}
-
-	public boolean raisesWarning() {
-		if (!calculated) calculateDistribution();
-
-		// See if they've turned this test off
-		if (ModuleConfig.getParam("sequence_length", "warn") == 0) {
-			return false;
-		}
-		
-		// Warn if they're not all the same length
-		boolean seenLength = false;
-		for (int i=0;i<lengthCounts.length;i++) {
-			if (lengthCounts[i] > 0) {
-				if (seenLength) {
-					return true;
-				}
-				else {
-					seenLength = true;
-				}
-			}
-		}
-		return false;
-	}
-
-	public void makeReport(HTMLReportArchive report) throws IOException,XMLStreamException {
-		if (!calculated) calculateDistribution();
-
-		writeDefaultImage(report, "sequence_length_distribution.png", "Sequence length distribution", 800, 600);
-		
-		StringBuffer sb = report.dataDocument();
-		sb.append("#Length\tCount\n");
-		for (int i=0;i<xCategories.length;i++) {
-			// Remove any padding we added to make the graph look better
-			if ((i==0 || i== xCategories.length-1) && graphCounts[i] == 0) {
-				continue;
-			}
-			sb.append(xCategories[i]);
-			sb.append("\t");
-			sb.append(graphCounts[i]);
-			sb.append("\n");
-		}
-	}
-
-}
+/**
+ * Copyright Copyright 2010-17 Simon Andrews
+ *
+ *    This file is part of FastQC.
+ *
+ *    FastQC is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 3 of the License, or
+ *    (at your option) any later version.
+ *
+ *    FastQC is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with FastQC; if not, write to the Free Software
+ *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package uk.ac.babraham.FastQC.Modules;
+
+import java.io.IOException;
+
+import javax.swing.JPanel;
+import javax.xml.stream.XMLStreamException;
+
+import uk.ac.babraham.FastQC.FastQCConfig;
+import uk.ac.babraham.FastQC.Graphs.LineGraph;
+import uk.ac.babraham.FastQC.Report.HTMLReportArchive;
+import uk.ac.babraham.FastQC.Sequence.Sequence;
+
+public class SequenceLengthDistribution extends AbstractQCModule {
+
+	private long [] lengthCounts = new long[0];
+	private double [] graphCounts = null;
+	private String [] xCategories = new String[0];
+	private double max = 0;
+	private boolean calculated = false;
+	
+	public JPanel getResultsPanel() {
+	
+		if (!calculated) calculateDistribution();
+				
+		return new LineGraph(new double [][] {graphCounts}, 0d, max, "Sequence Length (bp)",new String [] {"Sequence Length"}, xCategories, "Distribution of sequence lengths over all sequences");
+	}
+	
+	public boolean ignoreFilteredSequences() {
+		return true;
+	}
+	
+	public boolean ignoreInReport () {
+		if (ModuleConfig.getParam("sequence_length", "ignore") > 0) {
+			return true;
+		}
+		return false;
+	}
+	
+	private synchronized void calculateDistribution () {
+		int maxLen = 0;
+		int minLen = -1;
+		max = 0;
+		
+		// Find the min and max lengths
+		for (int i=0;i<lengthCounts.length;i++) {
+			if (lengthCounts[i]>0) {
+				if (minLen < 0) {
+					minLen = i;
+				}
+				maxLen = i;
+			}
+		}		
+		
+		// We put one extra category either side of the actual size
+		if (minLen>0) minLen--;
+		maxLen++;
+		
+		int [] startAndInterval = getSizeDistribution(minLen, maxLen);
+				
+		// Work out how many categories we need
+		int categories = 0;
+		int currentValue = startAndInterval[0];
+		while (currentValue<= maxLen) {
+			++categories;
+			currentValue+= startAndInterval[1];
+		}
+		
+		graphCounts = new double[categories];
+		xCategories = new String[categories];
+		
+		for (int i=0;i<graphCounts.length;i++) {
+			
+			int minValue = startAndInterval[0]+(startAndInterval[1]*i);
+			int maxValue = (startAndInterval[0]+(startAndInterval[1]*(i+1)))-1;
+
+			if (maxValue > maxLen) {
+				maxValue = maxLen;
+			}
+			
+			for (int bp=minValue;bp<=maxValue;bp++) {
+				if (bp < lengthCounts.length) {
+					graphCounts[i] += lengthCounts[bp];
+				}
+			}
+
+			if (startAndInterval[1] == 1) {
+				xCategories[i] = ""+minValue;
+			}
+			else {
+				xCategories[i] = minValue+"-"+maxValue;
+			}
+			
+			if (graphCounts[i] > max) max = graphCounts[i];
+		}
+		calculated = true;
+	}
+
+	public void processSequence(Sequence sequence) {
+		int seqLen = sequence.getSequence().length();
+
+		if (seqLen+2 > lengthCounts.length) {
+			long [] newLengthCounts = new long[seqLen+2];
+			for (int i=0;i<lengthCounts.length;i++) {
+				newLengthCounts[i] = lengthCounts[i];
+			}
+			lengthCounts = newLengthCounts;
+		}
+		
+		++lengthCounts[seqLen];
+		
+	}
+	
+	private int [] getSizeDistribution (int min, int max) {
+		
+		// We won't group if they've asked us not to
+		if (FastQCConfig.getInstance().nogroup) {
+			return(new int [] {min,1});
+		}
+		
+		int base = 1;
+		
+		while (base > (max-min)) {
+			base /= 10;
+		}
+				
+		int interval;
+		int starting;
+
+		int [] divisions = new int [] {1,2,5};
+		
+		OUTER: while (true) {
+			
+			for (int d=0;d<divisions.length;d++) {
+				int tester = base * divisions[d];
+				if (((max-min) / tester) <= 50) {
+					interval = tester;
+					break OUTER;
+				}
+			}
+		
+			base *=10;
+			
+		}
+		
+		// Now we work out the first value to be plotted
+		int basicDivision = (int)(min/interval);
+				
+		int testStart = basicDivision * interval;
+				
+		starting = testStart;
+		
+		return new int[] {starting,interval};
+		
+	}
+	
+	
+	
+	public void reset () {
+		lengthCounts = new long[0];
+	}
+
+	public String description() {
+		return "Shows the distribution of sequence length over all sequences";
+	}
+
+	public String name() {
+		return "Sequence Length Distribution";
+	}
+
+	public boolean raisesError() {
+		if (!calculated) calculateDistribution();
+		
+		// See if they've turned this test off
+		if (ModuleConfig.getParam("sequence_length", "error") == 0) {
+			return false;
+		}
+
+
+		if (lengthCounts[0] > 0) {
+			return true;
+		}
+		return false;
+	}
+
+	public boolean raisesWarning() {
+		if (!calculated) calculateDistribution();
+
+		// See if they've turned this test off
+		if (ModuleConfig.getParam("sequence_length", "warn") == 0) {
+			return false;
+		}
+		
+		// Warn if they're not all the same length
+		boolean seenLength = false;
+		for (int i=0;i<lengthCounts.length;i++) {
+			if (lengthCounts[i] > 0) {
+				if (seenLength) {
+					return true;
+				}
+				else {
+					seenLength = true;
+				}
+			}
+		}
+		return false;
+	}
+
+	public void makeReport(HTMLReportArchive report) throws IOException,XMLStreamException {
+		if (!calculated) calculateDistribution();
+
+		writeDefaultImage(report, "sequence_length_distribution.png", "Sequence length distribution",  Math.max(800, graphCounts.length*15), 600);
+		
+		StringBuffer sb = report.dataDocument();
+		sb.append("#Length\tCount\n");
+		for (int i=0;i<xCategories.length;i++) {
+			// Remove any padding we added to make the graph look better
+			if ((i==0 || i== xCategories.length-1) && graphCounts[i] == 0) {
+				continue;
+			}
+			sb.append(xCategories[i]);
+			sb.append("\t");
+			sb.append(graphCounts[i]);
+			sb.append("\n");
+		}
+	}
+
+}


=====================================
uk/ac/babraham/FastQC/Results/ResultsPanel.java
=====================================
@@ -1,162 +1,163 @@
-/**
- * Copyright Copyright 2010-17 Simon Andrews
- *
- *    This file is part of FastQC.
- *
- *    FastQC is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 3 of the License, or
- *    (at your option) any later version.
- *
- *    FastQC is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with FastQC; if not, write to the Free Software
- *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-package uk.ac.babraham.FastQC.Results;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Component;
-import java.util.Vector;
-
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.ImageIcon;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.ListSelectionModel;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-
-import uk.ac.babraham.FastQC.Analysis.AnalysisListener;
-import uk.ac.babraham.FastQC.Modules.QCModule;
-import uk.ac.babraham.FastQC.Sequence.SequenceFile;
-
-public class ResultsPanel extends JPanel implements ListSelectionListener, AnalysisListener{
-
-	private static final ImageIcon ERROR_ICON = new ImageIcon(ClassLoader.getSystemResource("uk/ac/babraham/FastQC/Resources/error.png"));
-	private static final ImageIcon WARNING_ICON = new ImageIcon(ClassLoader.getSystemResource("uk/ac/babraham/FastQC/Resources/warning.png"));
-	private static final ImageIcon OK_ICON = new ImageIcon(ClassLoader.getSystemResource("uk/ac/babraham/FastQC/Resources/tick.png"));
-
-	
-	private QCModule [] modules;
-	private JList moduleList;
-	private JPanel [] panels;
-	private JPanel currentPanel = null;
-	private JLabel progressLabel;
-	private SequenceFile sequenceFile;
-	
-	public ResultsPanel (SequenceFile sequenceFile) {
-		this.sequenceFile = sequenceFile;
-		setLayout(new BorderLayout());
-		progressLabel = new JLabel("Waiting to start...",JLabel.CENTER);
-		add(progressLabel,BorderLayout.CENTER);
-	}
-
-	public void valueChanged(ListSelectionEvent e) {
-		int index = moduleList.getSelectedIndex();
-		if (index >= 0) {
-			remove(currentPanel);
-			currentPanel = panels[index]; 
-			add(currentPanel,BorderLayout.CENTER);
-			validate();
-			repaint();
-		}
-	}
-	
-	public SequenceFile sequenceFile () {
-		return sequenceFile;
-	}
-	
-	public QCModule [] modules () {
-		return modules;
-	}
-	
-	private class ModuleRenderer extends DefaultListCellRenderer {
-
-		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-			if (! (value instanceof QCModule)) {
-				return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
-			}
-			
-			QCModule module = (QCModule)value;
-			ImageIcon icon = OK_ICON;
-			if (module.raisesError()) {
-				icon = ERROR_ICON;
-			}
-			else if (module.raisesWarning()) {
-				icon = WARNING_ICON;
-			}
-
-			JLabel returnLabel = new JLabel(module.name(),icon,JLabel.LEFT);
-			returnLabel.setOpaque(true);
-			if (isSelected) {
-				returnLabel.setBackground(Color.LIGHT_GRAY);
-			}
-			else {
-				returnLabel.setBackground(Color.WHITE);
-			}
-			
-			return returnLabel;
-		}
-		
-	}
-
-	public void analysisComplete(SequenceFile file, QCModule[] rawModules) {
-		remove(progressLabel);
-
-		Vector<QCModule> modulesToDisplay = new Vector<QCModule>();
-		
-		for (int m=0;m<rawModules.length;m++) {
-			if (!rawModules[m].ignoreInReport()) {
-				modulesToDisplay.add(rawModules[m]);
-			}
-		}
-		
-		modules = modulesToDisplay.toArray(new QCModule[0]);
-		
-		panels = new JPanel[modules.length];
-		
-		for (int m=0;m<modules.length;m++) {
-			panels[m] = modules[m].getResultsPanel();
-		}
-		
-		moduleList = new JList(modules);
-		moduleList.setCellRenderer(new ModuleRenderer());
-		moduleList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-		moduleList.setSelectedIndex(0);
-		moduleList.addListSelectionListener(this);
-		
-		add(new JScrollPane(moduleList),BorderLayout.WEST);
-		
-		currentPanel = panels[0];
-		add(currentPanel,BorderLayout.CENTER);
-		validate();
-		
-	}
-
-	public void analysisUpdated(SequenceFile file, int sequencesProcessed, int percentComplete) {
-		if (percentComplete > 99) {
-			progressLabel.setText("Read "+sequencesProcessed+" sequences");			
-		}
-		else {
-			progressLabel.setText("Read "+sequencesProcessed+" sequences ("+percentComplete+"%)");
-		}
-	}
-
-	public void analysisExceptionReceived(SequenceFile file, Exception e) {
-		progressLabel.setText("Failed to process file: "+e.getLocalizedMessage());
-	}
-
-	public void analysisStarted(SequenceFile file) {
-		progressLabel.setText("Starting analysis...");		
-	}
-	
-	
-}
+/**
+ * Copyright Copyright 2010-17 Simon Andrews
+ *
+ *    This file is part of FastQC.
+ *
+ *    FastQC is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 3 of the License, or
+ *    (at your option) any later version.
+ *
+ *    FastQC is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with FastQC; if not, write to the Free Software
+ *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package uk.ac.babraham.FastQC.Results;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.util.Vector;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import uk.ac.babraham.FastQC.Analysis.AnalysisListener;
+import uk.ac.babraham.FastQC.Modules.QCModule;
+import uk.ac.babraham.FastQC.Sequence.SequenceFile;
+
+public class ResultsPanel extends JPanel implements ListSelectionListener, AnalysisListener{
+
+	private static final ImageIcon ERROR_ICON = new ImageIcon(ClassLoader.getSystemResource("uk/ac/babraham/FastQC/Resources/error.png"));
+	private static final ImageIcon WARNING_ICON = new ImageIcon(ClassLoader.getSystemResource("uk/ac/babraham/FastQC/Resources/warning.png"));
+	private static final ImageIcon OK_ICON = new ImageIcon(ClassLoader.getSystemResource("uk/ac/babraham/FastQC/Resources/tick.png"));
+
+	
+	private QCModule [] modules;
+	private JList moduleList;
+	private JPanel [] panels;
+	private JPanel currentPanel = null;
+	private JLabel progressLabel;
+	private SequenceFile sequenceFile;
+	
+	public ResultsPanel (SequenceFile sequenceFile) {
+		this.sequenceFile = sequenceFile;
+		setLayout(new BorderLayout());
+		progressLabel = new JLabel("Waiting to start...",JLabel.CENTER);
+		add(progressLabel,BorderLayout.CENTER);
+	}
+
+	public void valueChanged(ListSelectionEvent e) {
+		int index = moduleList.getSelectedIndex();
+		if (index >= 0) {
+			remove(currentPanel);
+			currentPanel = panels[index]; 
+			add(currentPanel,BorderLayout.CENTER);
+			validate();
+			repaint();
+		}
+	}
+	
+	public SequenceFile sequenceFile () {
+		return sequenceFile;
+	}
+	
+	public QCModule [] modules () {
+		return modules;
+	}
+	
+	private class ModuleRenderer extends DefaultListCellRenderer {
+
+		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+			if (! (value instanceof QCModule)) {
+				return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+			}
+			
+			QCModule module = (QCModule)value;
+			ImageIcon icon = OK_ICON;
+			if (module.raisesError()) {
+				icon = ERROR_ICON;
+			}
+			else if (module.raisesWarning()) {
+				icon = WARNING_ICON;
+			}
+
+			JLabel returnLabel = new JLabel(module.name(),icon,JLabel.LEFT);
+			returnLabel.setOpaque(true);
+			if (isSelected) {
+				returnLabel.setBackground(Color.LIGHT_GRAY);
+			}
+			else {
+				returnLabel.setBackground(Color.WHITE);
+			}
+			
+			return returnLabel;
+		}
+		
+	}
+
+	public void analysisComplete(SequenceFile file, QCModule[] rawModules) {
+		remove(progressLabel);
+
+		Vector<QCModule> modulesToDisplay = new Vector<QCModule>();
+		
+		for (int m=0;m<rawModules.length;m++) {
+			if (!rawModules[m].ignoreInReport()) {
+				modulesToDisplay.add(rawModules[m]);
+			}
+		}
+		
+		modules = modulesToDisplay.toArray(new QCModule[0]);
+		
+		panels = new JPanel[modules.length];
+		
+		for (int m=0;m<modules.length;m++) {
+			System.err.println("Getting panel for "+modules[m].name()+" with "+modules[m].description());
+			panels[m] = modules[m].getResultsPanel();
+		}
+		
+		moduleList = new JList(modules);
+		moduleList.setCellRenderer(new ModuleRenderer());
+		moduleList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+		moduleList.setSelectedIndex(0);
+		moduleList.addListSelectionListener(this);
+		
+		add(new JScrollPane(moduleList),BorderLayout.WEST);
+		
+		currentPanel = panels[0];
+		add(currentPanel,BorderLayout.CENTER);
+		validate();
+		
+	}
+
+	public void analysisUpdated(SequenceFile file, int sequencesProcessed, int percentComplete) {
+		if (percentComplete > 99) {
+			progressLabel.setText("Read "+sequencesProcessed+" sequences");			
+		}
+		else {
+			progressLabel.setText("Read "+sequencesProcessed+" sequences ("+percentComplete+"%)");
+		}
+	}
+
+	public void analysisExceptionReceived(SequenceFile file, Exception e) {
+		progressLabel.setText("Failed to process file: "+e.getLocalizedMessage());
+	}
+
+	public void analysisStarted(SequenceFile file) {
+		progressLabel.setText("Starting analysis...");		
+	}
+	
+	
+}



View it on GitLab: https://salsa.debian.org/med-team/fastqc/compare/dd57a3ed1fe610f8dde3d1f0537c10a771d32893...9f214d8c4e7ce422cbf3912c2f583aaad6044b05

-- 
View it on GitLab: https://salsa.debian.org/med-team/fastqc/compare/dd57a3ed1fe610f8dde3d1f0537c10a771d32893...9f214d8c4e7ce422cbf3912c2f583aaad6044b05
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20181017/3edcd0ba/attachment-0001.html>


More information about the debian-med-commit mailing list