//Copyright 2017 Ryan Wick //This file is part of Bandage. //Bandage 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. //Bandage 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 Bandage. If not, see . #include "querypathsdialog.h" #include "ui_querypathsdialog.h" #include "../blast/blastquery.h" #include "../blast/blastquerypath.h" #include "tablewidgetitemint.h" #include "tablewidgetitemdouble.h" #include "../program/globals.h" #include "../program/memory.h" #include #include "querypathsequencecopybutton.h" QueryPathsDialog::QueryPathsDialog(QWidget * parent, BlastQuery * query) : QDialog(parent), ui(new Ui::QueryPathsDialog) { ui->setupUi(this); setWindowFlags(windowFlags() | Qt::Tool); connect(this, SIGNAL(rejected()), this, SLOT(hidden())); connect(ui->tableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(tableSelectionChanged())); g_memory->queryPathDialogIsVisible = true; g_memory->queryPaths.clear(); ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "Path" << "Length\n(bp)" << "Query\ncovered\nby path" << "Query\ncovered\nby hits" << "Mean hit\nidentity" << "Total\nhit mis-\nmatches" << "Total\nhit gap\nopens" << "Relative\nlength" << "Length\ndiscre-\npancy" << "E-value\nproduct" << "Copy sequence\nto clipboard"); QString queryDescription = "Query name: " + query->getName(); queryDescription += " type: " + query->getTypeString(); queryDescription += " length: " + formatIntForDisplay(query->getLength()); if (query->getSequenceType() == PROTEIN) queryDescription += " (" + formatIntForDisplay(3 * query->getLength()) + " bp)"; else queryDescription += " bp"; ui->queryLabel->setText(queryDescription); ui->tableWidget->clearContents(); ui->tableWidget->setSortingEnabled(false); int pathCount = query->getPathCount(); ui->tableWidget->setRowCount(pathCount); if (pathCount == 0) return; QList paths = query->getPaths(); for (int i = 0; i < pathCount; ++i) { BlastQueryPath * queryPath = &paths[i]; QTableWidgetItem * pathString = new QTableWidgetItem(queryPath->getPath().getString(true)); pathString->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); int length = queryPath->getPath().getLength(); TableWidgetItemInt * pathLength = new TableWidgetItemInt(formatIntForDisplay(length), length); pathLength->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); double queryCoveragePath = queryPath->getPathQueryCoverage(); TableWidgetItemDouble * pathQueryCoveragePath = new TableWidgetItemDouble(formatDoubleForDisplay(100.0 * queryCoveragePath, 2) + "%", queryCoveragePath); pathQueryCoveragePath->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); pathLength->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); double queryCoverageHits = queryPath->getHitsQueryCoverage(); TableWidgetItemDouble * pathQueryCoverageHits = new TableWidgetItemDouble(formatDoubleForDisplay(100.0 * queryCoverageHits, 2) + "%", queryCoverageHits); pathQueryCoverageHits->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); double percIdentity = queryPath->getMeanHitPercIdentity(); TableWidgetItemDouble * pathPercIdentity = new TableWidgetItemDouble(formatDoubleForDisplay(percIdentity, 2) + "%", percIdentity); pathPercIdentity->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); int mismatches = queryPath->getTotalHitMismatches(); TableWidgetItemInt * pathMismatches = new TableWidgetItemInt(formatIntForDisplay(mismatches), mismatches); pathMismatches->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); int gapOpens = queryPath->getTotalHitGapOpens(); TableWidgetItemInt * pathGapOpens = new TableWidgetItemInt(formatIntForDisplay(gapOpens), gapOpens); pathGapOpens->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); double relativeLength = queryPath->getRelativePathLength(); TableWidgetItemDouble * pathRelativeLength = new TableWidgetItemDouble(formatDoubleForDisplay(100.0 * relativeLength, 2) + "%", relativeLength); pathRelativeLength->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); int lengthDisc = queryPath->getAbsolutePathLengthDifference(); QString lengthDiscString = queryPath->getAbsolutePathLengthDifferenceString(true); TableWidgetItemInt * pathLengthDisc = new TableWidgetItemInt(lengthDiscString, lengthDisc); pathLengthDisc->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); SciNot evalueProduct = queryPath->getEvalueProduct(); TableWidgetItemDouble * pathEvalueProduct = new TableWidgetItemDouble(evalueProduct.asString(false), evalueProduct.toDouble()); pathEvalueProduct->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); QByteArray pathSequence = queryPath->getPath().getPathSequence(); QString pathStart; if (pathSequence.length() <= 8) pathStart = pathSequence; else pathStart = pathSequence.left(8) + "..."; QTableWidgetItem * sequenceCopy = new QTableWidgetItem(pathStart); QueryPathSequenceCopyButton * sequenceCopyButton = new QueryPathSequenceCopyButton(pathSequence, pathStart); ui->tableWidget->setItem(i, 0, pathString); ui->tableWidget->setItem(i, 1, pathLength); ui->tableWidget->setItem(i, 2, pathQueryCoveragePath); ui->tableWidget->setItem(i, 3, pathQueryCoverageHits); ui->tableWidget->setItem(i, 4, pathPercIdentity); ui->tableWidget->setItem(i, 5, pathMismatches); ui->tableWidget->setItem(i, 6, pathGapOpens); ui->tableWidget->setItem(i, 7, pathRelativeLength); ui->tableWidget->setItem(i, 8, pathLengthDisc); ui->tableWidget->setItem(i, 9, pathEvalueProduct); ui->tableWidget->setItem(i, 10, sequenceCopy); ui->tableWidget->setCellWidget(i, 10, sequenceCopyButton); } ui->tableWidget->resizeColumns(); ui->tableWidget->setSortingEnabled(true); ui->queryPathsInfoText->setInfoText("This table shows information about the possible paths through the graph which " "represent the query. These paths can be either simple (residing within a single " "node) or complex (spanning multiple nodes). The columns in the table are as " "follows:" "

" "Path: This is the query path through the graph, as written in Bandage's " "path notation. The nodes in the path are separated by commas. The start position " "in the first node is shown in parentheses at the beginning of the path. The end " "position in the last node is shown in parentheses at the end of the path." "

" "Length: This is the path length. It is shown in base pairs, whether the " "query is a nucleotide query or a protein query." "

" "Query covered by path: This is the fraction of the query which is covered " "by the path. It is calculated by taking 100% and subtracting the fraction of the " "query which is not captured by the start and the fraction of the query which is " "not captured by the end." "

" "Query covered by hits: This is the fraction of the query which is covered " "by the BLAST hits in this path. Since a path may contain nodes or parts of nodes which " "are not covered by BLAST hits, this value will be less than or equal to the 'Query " "covered by path' value." "

" "Mean hit identity: This is the mean of the percent identity for the BLAST " "hits in this path, weighted by the hits' lengths." "

" "Total hit mismatches: This is the sum of the mismatches for the BLAST hits " "in this path." "

" "Total hit gap opens: This is the sum of the gap opens for the BLAST hits " "in this path." "

" "Relative length: This is the length of the path compared to the length for " "the relevant fraction of the query. A value over 100% indicates that the path is " "too long; a value under 100% value indicates that the path is too short." "

" "Length discrepancy: This is the difference in the path length and " "the length for the relevant fraction of the query. A positive value " "indicates that the path is too long; a negative value indicates that the path is " "too short." "

" "E-value product: This is the product of the e-values for the BLAST hits " "in this path."); } QueryPathsDialog::~QueryPathsDialog() { delete ui; g_memory->queryPathDialogIsVisible = false; } void QueryPathsDialog::hidden() { g_memory->queryPathDialogIsVisible = false; emit selectionChanged(); } void QueryPathsDialog::tableSelectionChanged() { QList selection = ui->tableWidget->selectedRanges(); int totalSelectedRows = 0; for (int i = 0; i < selection.size(); ++i) totalSelectedRows += selection[i].rowCount(); g_memory->queryPaths.clear(); QList selectedRows; for (int i = 0; i < selection.size(); ++i) { QTableWidgetSelectionRange * selectionRange = &(selection[i]); int top = selectionRange->topRow(); int bottom = selectionRange->bottomRow(); for (int row = top; row <= bottom; ++row) { if (!selectedRows.contains(row)) selectedRows.push_back(row); } } for (int i = 0; i < selectedRows.size(); ++i) { int row = selectedRows[i]; QString pathString = ui->tableWidget->item(row, 0)->text(); QString pathStringFailure; g_memory->queryPaths.push_back(Path::makeFromString(pathString, false, &pathStringFailure)); } emit selectionChanged(); }