Beispiel #1
0
def sam():
    """Render the landing page for SAM file analysis."""
    if 'id' in session and len(list_dir('sam', session['id'], ('.bam'))) > 0:
        # At least one SAM file is uploaded, so show extended menu
        return render_template('sam.html', showHidden=True)
    return render_template('sam.html', showHidden=False)
Beispiel #2
0
def sam_upload():
    """Render the file manager for handling SAM and FASTA files.

    Methods:
        GET: Render the File Management Page with form.
        POST: Process the form upload and redirect user.

    """

    # Quick shortcut method so I don't have to rewrite this code
    def render_form(session_id, samfiles=None, fastafile=None):
        """Render the form associated with this route."""
        return render_template('sam/upload.html',
                               session_id=escape(session_id),
                               samfiles=basename(samfiles, session_id),
                               fastafile=basename(fastafile, session_id))

    # Generate a new session ID if it doesn't already exist
    if 'id' not in session:
        session['id'] = random_id()

    # Get all files associated with this session id
    oldbams = list_dir('sam', session['id'], ('.bam'))
    oldfasta = get_firstfile('sam', session['id'], ('.fa', '.fasta'))

    # Render an empty form for a GET request
    if request.method == 'GET':
        return render_form(session['id'], oldbams, oldfasta)

    # Otherwise validate the form on a POST request
    if request.method == 'POST':
        sams = request.files.getlist('sam')
        fasta = request.files['fasta']

        # Throw error if entire form is empty
        if not fasta and not sams[0]:
            flash('No files were selected for upload.', 'alert-warning')
            return render_form(session['id'], oldbams, oldfasta)

        # Throw error if any file does not have the appropriate extension
        abort = False
        for sam in sams:
            if len(sam.filename) > 0:
                ext = os.path.splitext(secure_filename(sam.filename))[1]
                if ext.lower() not in ['.bam', '.sam']:
                    abort = True
        if fasta:
            ext = os.path.splitext(secure_filename(fasta.filename))[1]
            if ext.lower() not in ['.fa', '.fasta']:
                abort = True
        if abort:
            flash('Invalid file types were uploaded', 'alert-warning')
            return render_form(session['id'], oldbams, oldfasta)

        # Upload SAM files
        if sams:
            error_count = 0
            for sam in sams:
                if len(sam.filename) > 0:
                    try:
                        upload_sam(sam, sam.filename, escape(session['id']))
                    except IOError, message:
                        flash(message, 'alert-warning')
                        error_count = error_count + 1
            if len(sams) == error_count:
                return render_form(session['id'], oldbams, oldfasta)

        # Upload Fasta file; first delete old fasta files if they exist
        if fasta:
            delete_files('sam', session['id'], None, ('.fa', '.fasta'))
            fa = upload(fasta, fasta.filename, 'sam', escape(session['id']))
            try:
                Fasta(fa)
            except:
                flash(message, 'alert-warning')
                if not sams:
                    return render_form(session['id'], oldbams, oldfasta)

        flash('Files were successfully uploaded.', 'alert-success')
        return render_template('sam.html', showHidden=True)
Beispiel #3
0
def sam_browse():
    """Render the sam browser.

    Methods:
        GET: Render the SAM browser page with form.
        POST: Process the form upload display browser results.

    """
    # Redirect user if there are no bam files uploaded
    if not session['id']:
        return redirect(url_for('sam_upload'), code=302)
    bampaths = list_dir('sam', session['id'], ('.bam'))
    fastapath = get_firstfile('sam', session['id'], ('.fa', '.fasta'))
    if len(bampaths) == 0:
        return redirect(url_for('sam_upload'), code=302)

    # Load samfiles and get list of genes in samfile
    bamfiles = load_sams(bampaths, 'rb')
    gene_list = get_all_genes(bamfiles)

    # Load Fasta file and validate it
    badFasta = True
    if fastapath:
        try:
            fasta = Fasta(fastapath)
            if fasta.validate(gene_list):
                badFasta = False
                gene_list = sorted(fasta.genes.keys())
        except:
            badFasta = True

    # Render an empty form for a GET request
    if request.method == 'GET':

        # Construct table where (rows, columns) = (genes, samples)
        gene_rows = []
        for gene in gene_list:
            row = []
            for bam in bamfiles:
                if gene in bam.references:
                    row.append(True)
                else:
                    row.append(False)
            gene_rows.append(row)

        # Render an empty form for a GET request
        return render_template('sam/browse.html',
                               session_id=escape(session['id']),
                               samfiles=basename(bampaths, session['id']),
                               fastafile=basename(fastapath, session['id']),
                               badFasta=badFasta,
                               genes=gene_list,
                               rows=gene_rows)

    # Process form POST
    if request.method == 'POST':

        # Load common variables
        form = {
            'mode': request.form.get('mode'),
            'gene': request.form.get('gene'),
            'start': request.form.get('start'),
            'end': request.form.get('end'),
            'custom': request.form.get('custom'),
            'output': request.form.get('output'),
        }

        # Validate and parse form
        try:
            parsed_form = _validate_and_parse(form)
        except ((KeyError, ValueError), message):
            flash(str(message), 'alert-warning')
            return redirect(url_for('sam_browse'), code=302)

        # Begin main loop
        i = 0
        error_count = 0
        results = []
        for bam in bamfiles:

            # Get coordinate positions of the selected gene as a list
            try:
                positions = _get_positions(bam, parsed_form)
            except (ValueError, message):
                error_count = error_count + 1
                continue

            # Make the universal position container
            positionContainer = OrderedDict({parsed_form['gene']: positions})

            # Handle the fasta file if present
            if badFasta:
                fasta_seq = None
                cpg_positionContainer = None
            else:
                # Get reference sequence from fasta file
                fasta_seq = _fasta_fetch_positions(fasta, positionContainer)
                # Get coordinates of CpG sites from fasta file
                cpg_positionContainer = _fasta_fetch_cpg(
                    fasta, positionContainer)

            # Get the read bases at the requested coordinated positions
            readDict = _bam_fetch_positions(bam, positionContainer,
                                            cpg_positionContainer)

            results.append({
                'sample':
                basename(bampaths, session['id'])[i],
                'positions':
                _flatten_position_container(positionContainer),
                'cpg_positions':
                _flatten_position_container(cpg_positionContainer),
                'reads':
                readDict,
                'fasta':
                fasta_seq
            })
            i = i + 1

        # Abort if all the bamfiles errored
        if len(bamfiles) == error_count:
            flash('Coordinates not found in sample(s)', 'alert-warning')
            return redirect(url_for('sam_browse'), code=302)

        # Determine output method - HTML
        if parsed_form['output'] == 'html':
            genes, positions = _split_and_add1(results[0]['positions'])
            return render_template('sam/browse_results.html',
                                   sample=results[0]['sample'],
                                   gene=genes[0],
                                   positions=positions,
                                   reads=results[0]['reads'],
                                   fasta=results[0]['fasta'])

        # Output method - CSV
        if parsed_form['output'] == 'csv':
            if len(bamfiles) == 1:  # Single CSV file, send back a .csv file
                data = _format_csv_file(results[0])
                filename = os.path.splitext(results[0]['sample'])[0] + '.csv'
                return csv_response('result_' + filename, data)

            else:  # Multiple CSV files, send back a .zip file
                data = {}
                for result in results:
                    csvdata = _format_csv_file(result)
                    filename = os.path.splitext(result['sample'])[0] + '.csv'
                    data[filename] = csvdata
                return zip_csv_response('results.zip', data)

        # Output method - Excel
        if len(bamfiles) == 1:  # Single Excel file, send back a .xlsx file
            workbook = _format_exl_file(results[0])
            filename = os.path.splitext(results[0]['sample'])[0] + '.xlsx'
            return exl_response('result_' + filename, workbook)

        else:  # Multiple Excel files, send back a .zip file
            data = {}
            for result in results:
                exl_data = _format_exl_file(result)
                filename = os.path.splitext(result['sample'])[0] + '.xlsx'
                data[filename] = exl_data
            return zip_exl_response('results.zip', data)
Beispiel #4
0
def sam_browse():
    """Render the sam browser.

    Methods:
        GET: Render the SAM browser page with form.
        POST: Process the form upload display browser results.

    """
    # Redirect user if there are no bam files uploaded
    if not session['id']:
        return redirect(url_for('sam_upload'), code=302)
    bampaths = list_dir('sam', session['id'], ('.bam'))
    fastapath = get_firstfile('sam', session['id'], ('.fa', '.fasta'))
    if len(bampaths) == 0:
        return redirect(url_for('sam_upload'), code=302)

    # Load samfiles and get list of genes in samfile
    bamfiles = load_sams(bampaths, 'rb')
    gene_list = get_all_genes(bamfiles)

    # Load Fasta file and validate it
    badFasta = True
    if fastapath:
        try:
            fasta = Fasta(fastapath)
            if fasta.validate(gene_list):
                badFasta = False
                gene_list = sorted(fasta.genes.keys())
        except:
            badFasta = True

    # Render an empty form for a GET request
    if request.method == 'GET':

        # Construct table where (rows, columns) = (genes, samples)
        gene_rows = []
        for gene in gene_list:
            row = []
            for bam in bamfiles:
                if gene in bam.references:
                    row.append(True)
                else:
                    row.append(False)
            gene_rows.append(row)

        # Render an empty form for a GET request
        return render_template('sam/browse.html',
                               session_id=escape(session['id']),
                               samfiles=basename(bampaths, session['id']),
                               fastafile=basename(fastapath, session['id']),
                               badFasta=badFasta,
                               genes=gene_list,
                               rows=gene_rows)

    # Process form POST
    if request.method == 'POST':

        # Load common variables
        form = {
            'mode': request.form.get('mode'),
            'gene': request.form.get('gene'),
            'start': request.form.get('start'),
            'end': request.form.get('end'),
            'custom': request.form.get('custom'),
            'output': request.form.get('output'),
        }

        # Validate and parse form
        try:
            parsed_form = _validate_and_parse(form)
        except (KeyError, ValueError), message:
            flash(str(message), 'alert-warning')
            return redirect(url_for('sam_browse'), code=302)

        # Begin main loop
        i = 0
        error_count = 0
        results = []
        for bam in bamfiles:

            # Get coordinate positions of the selected gene as a list
            try:
                positions = _get_positions(bam, parsed_form)
            except ValueError, message:
                error_count = error_count + 1
                continue

            # Make the universal position container
            positionContainer = OrderedDict({parsed_form['gene']: positions})

            # Get the read bases at the requested coordinated positions
            readDict = _bam_fetch_positions(bam, positionContainer)

            # Handle the fasta file if present
            if badFasta:
                fasta_seq = None
            else:
                fasta_seq = _fasta_fetch_positions(fasta, positionContainer)

            results.append({
                'sample':
                basename(bampaths, session['id'])[i],
                'positions':
                _flatten_position_container(positionContainer),
                'reads':
                readDict,
                'fasta':
                fasta_seq
            })
            i = i + 1