Create reports from the abundance estimation

def reports(self):
        """
        Create reports from the abundance estimation
        """
        logging.info('Creating CLARK report for {} files'.format(self.extension))
        # Create a workbook to store the report. Using xlsxwriter rather than a simple csv format, as I want to be
        # able to have appropriately sized, multi-line cells
        workbook = xlsxwriter.Workbook(self.report)
        make_path(self.reportpath)
        # New worksheet to store the data
        worksheet = workbook.add_worksheet()
        # Add a bold format for header cells. Using a monotype font size 8
        bold = workbook.add_format({'bold': True, 'font_name': 'Courier New', 'font_size': 8})
        bold.set_align('center')
        # Format for data cells. Monotype, size 8, top vertically justified
        courier = workbook.add_format({'font_name': 'Courier New', 'font_size': 8})
        courier.set_align('top')
        # Set the custom width for 5 and 6 to be 15
        worksheet.set_column(5, 5, 15)
        worksheet.set_column(6, 6, 20)
        # Initialise the position within the worksheet to be (0,0)
        row = 0
        col = 0
        # List of the headers to use
        headers = ['Strain', 'Name', 'TaxID', 'Lineage', 'Count', 'Proportion_All(%)', 'Proportion_Classified(%)']
        # Add an additional header for .fasta analyses
        if self.extension == 'fasta':
            headers.insert(4, 'TotalBP')
        # Populate the headers
        for category in headers:
            # Write the data in the specified cell (row, col) using the bold format
            worksheet.write(row, col, category, bold)
            # Move to the next column to write the next category
            col += 1
        # Data starts in row 1
        row = 1
        # Initialise variables to hold the longest names; used in setting the column width
        longeststrain = 0
        longestname = 0
        longestlineage = 0
        # Extract all the taxonomic groups that pass the cutoff from the abundance file
        for sample in self.runmetadata.samples:
            # Every record starts at column 0
            col = 0
            # Write the strain name
            worksheet.write(row, col, sample.name, courier)
            col += 1
            # Initialise a dictionary to store the species above the cutoff in the sample
            sample.general.passfilter = list()
            try:
                # Abundance file as a dictionary
                abundancedict = DictReader(open(sample.general.abundance))
                # Filter abundance to taxIDs with at least self.cutoff% of the total proportion
                for result in abundancedict:
                    # The UNKNOWN category doesn't contain a 'Lineage' column, and therefore, subsequent columns are
                    # shifted out of proper alignment, and do not contain the appropriate data
                    try:
                        if float(result['Proportion_All(%)']) > self.cutoff:
                            sample.general.passfilter.append(result)
                    except ValueError:
                        pass
                # Determine the longest name of all the strains, and use it to set the width of column 0
                if len(sample.name) > longeststrain:
                    longeststrain = len(sample.name)
                    worksheet.set_column(0, 0, longeststrain)
                # Sort the abundance results based on the highest count
                sortedabundance = sorted(sample.general.passfilter, key=lambda x: int(x['Count']), reverse=True)
                # Set of contigs from the classification file. For some reason, certain contigs are represented multiple
                # times in the classification file. As far as I can tell, these multiple representations are always
                # classified the same, and, therefore, should be treated as duplicates, and ignored
                contigset = set()
                for result in sortedabundance:
                    # Add the total number of base pairs classified for each TaxID. As only the total number of contigs
                    # classified as a particular TaxID are in the report, it can be misleading if a large number
                    # of small contigs are classified to a particular TaxID e.g. 56 contigs map to TaxID 28901, and 50
                    # contigs map to TaxID 630, however, added together, those 56 contigs are 4705838 bp, while the 50
                    # contigs added together are only 69602 bp. While this is unlikely a pure culture, only
                    # 69602 / (4705838 + 69602) = 1.5% of the total bp map to TaxID 630 compared to 45% of the contigs
                    if self.extension == 'fasta':
                        # Initialise a variable to store the total bp mapped to the TaxID
                        result['TotalBP'] = int()
                        # Read the classification file into a dictionary
                        classificationdict = DictReader(open(sample.general.classification))
                        # Read through each contig classification in the dictionary
                        for contig in classificationdict:
                            # Pull out each contig with a TaxID that matches the TaxID of the result of interest, and
                            # is not present in a set of contigs that have already been added to the dictionary
                            if result['TaxID'] == contig[' Assignment'] and contig['Object_ID'] not in contigset:
                                # Increment the total bp mapping to the TaxID by the integer of each contig
                                result['TotalBP'] += int(contig[' Length'])
                                # Avoid duplicates by adding the contig name to the set of contigs
                                contigset.add(contig['Object_ID'])
                    # Print the results to file
                    # Ignore the first header, as it is the strain name, which has already been added to the report
                    dictionaryheaders = headers[1:]
                    for header in dictionaryheaders:
                        data = result[header]
                        worksheet.write(row, col, data, courier)
                        col += 1
                        # Determine the longest name of all the matches, and use it to set the width of column 0
                        if len(result['Name']) > longestname:
                            longestname = len(result['Name'])
                            worksheet.set_column(1, 1, longestname)
                        # Do the same for the lineages
                        if len(result['Lineage']) > longestlineage:
                            longestlineage = len(result['Lineage'])
                            worksheet.set_column(3, 3, longestlineage)
                    # Increase the row
                    row += 1
                    # Set the column to 1
                    col = 1
            except KeyError:
                # Increase the row
                row += 1
        # Close the workbook
        workbook.close()