Skip to content

Commit

Permalink
impl layout and draw cml mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Shostina committed May 11, 2024
1 parent 92559e5 commit 7389764
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 61 deletions.
80 changes: 54 additions & 26 deletions command_line/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
CLI::App *addImageSubcommand(CLI::App &app, ImageCmd &cmd) {
auto *image = app.add_subcommand("image", "Generate an image file of a graph");
image->add_option("<graph>", cmd.m_graph, "A graph file of any type supported by Bandage")
->required()->check(CLI::ExistingFile);
->required()->check(CLI::ExistingPath);
image->add_option("<output_file>", cmd.m_image, "The image file to be created (must end in '.jpg', '.png' or '.svg')")
->required();
image->add_option("--height", cmd.m_height, "Image height")
Expand Down Expand Up @@ -72,12 +72,18 @@ int handleImageCmd(QApplication *app,
return 1;
}

g_assemblyGraph->clear();
g_assemblyGraph->m_graphMap[1] = new AssemblyGraph();
bool loadSuccess = g_assemblyGraph->first()->loadGraphFromFile(cmd.m_graph.c_str());
if (!loadSuccess) {
outputText(("Bandage-NG error: could not load " + cmd.m_graph.native()).c_str(), &err); // FIXME
return 1;
if(std::filesystem::is_directory(cmd.m_graph.c_str())) {
g_settings->multyGraphMode = true;
g_assemblyGraph->clear();
g_assemblyGraph->loadGraphsFromDir(cmd.m_graph.c_str());
} else {
g_assemblyGraph->clear();
g_assemblyGraph->m_graphMap[1] = new AssemblyGraph();
bool loadSuccess = g_assemblyGraph->first()->loadGraphFromFile(cmd.m_graph.c_str());
if (!loadSuccess) {
outputText(("Bandage-NG error: could not load " + cmd.m_graph.native()).c_str(), &err); // FIXME
return 1;
}
}


Expand Down Expand Up @@ -112,24 +118,20 @@ int handleImageCmd(QApplication *app,

QString errorTitle;
QString errorMessage;
auto scope = graph::scope(g_settings->graphScope,
g_settings->startingNodes,
g_settings->minDepthRange, g_settings->maxDepthRange,
&g_blastSearch->queries(), "all",
"", g_settings->nodeDistance);
std::vector<DeBruijnNode *> startingNodes = graph::getStartingNodes(&errorTitle, &errorMessage,
*g_assemblyGraph->first(), scope);
if (!errorMessage.isEmpty()) {
err << errorMessage << Qt::endl;
return 1;
}

if (!cmd.m_color.empty()) {
QString errormsg;
QStringList columns;
bool coloursLoaded = false;
bool isCSVLoaded = false;

for (auto graph : g_assemblyGraph->m_graphMap.values()) {
if (graph->loadCSV(cmd.m_color.c_str(), &columns, &errormsg, &coloursLoaded)) {
isCSVLoaded = true;
}
}

if (!g_assemblyGraph->first()->loadCSV(cmd.m_color.c_str(), &columns, &errormsg, &coloursLoaded)) {
if (!isCSVLoaded) {
err << errormsg << Qt::endl;
return 1;
}
Expand All @@ -141,17 +143,43 @@ int handleImageCmd(QApplication *app,
g_settings->initializeColorer(CUSTOM_COLOURS);
}

g_assemblyGraph->first()->markNodesToDraw(scope, startingNodes);
for(auto& assemblyGraph : g_assemblyGraph->m_graphMap.values()) {
auto scope = graph::scope(g_settings->graphScope,
g_settings->startingNodes,
g_settings->minDepthRange, g_settings->maxDepthRange,
&g_blastSearch->queries(), "all",
"", g_settings->nodeDistance);
std::vector<DeBruijnNode *> startingNodes = graph::getStartingNodes(&errorTitle, &errorMessage,
*assemblyGraph, scope);

if (!errorMessage.isEmpty()) {
err << errorMessage << Qt::endl;
return 1;
}

assemblyGraph->resetEdges();
assemblyGraph->resetNodes();
assemblyGraph->markNodesToDraw(scope, startingNodes);
}

BandageGraphicsScene scene;
{
GraphLayoutStorage layout =
*GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(g_assemblyGraph)[0];
GraphLayoutWorker(g_settings->graphLayoutQuality, g_settings->linearLayout, g_settings->componentSeparation).layoutGraph(g_assemblyGraph);

scene.clear();
scene.addGraphicsItemsToScene(*g_assemblyGraph->first(), layout);
scene.setSceneRectangle();
int drawnNodeCount = 0;
for(AssemblyGraph* graph : g_assemblyGraph->m_graphMap.values()) {
GraphLayout* layout = graph->m_layout;
scene.addGraphicsItemsToScene(*graph, *layout);

double averageNodeWidth = g_settings->averageNodeWidth / pow(g_absoluteZoom, 0.75);
graph->recalculateAllNodeWidths(averageNodeWidth,
g_settings->depthPower,
g_settings->depthEffectOnWidth);
drawnNodeCount += (graph->getDrawnNodeCount());
}
if (drawnNodeCount > 0)
scene.setSceneRectangle();
}
double sceneRectAspectRatio = scene.sceneRect().width() / scene.sceneRect().height();

Expand Down
72 changes: 48 additions & 24 deletions command_line/layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
CLI::App *addLayoutSubcommand(CLI::App &app, LayoutCmd &cmd) {
auto *layout = app.add_subcommand("layout", "Layout the graph");
layout->add_option("<graph>", cmd.m_graph, "A graph file of any type supported by Bandage")
->required()->check(CLI::ExistingFile);
->required()->check(CLI::ExistingPath);
layout->add_option("<layout>", cmd.m_layout, "The layout file to be created (must end with .tsv or .layout)")
->required();

Expand All @@ -60,10 +60,18 @@ int handleLayoutCmd(QApplication *app,
return 1;
}

bool loadSuccess = g_assemblyGraph->first()->loadGraphFromFile(cmd.m_graph.c_str());
if (!loadSuccess) {
outputText(("Bandage-NG error: could not load " + cmd.m_graph.native()).c_str(), &err); // FIXME
return 1;
if(std::filesystem::is_directory(cmd.m_graph.c_str())) {
g_settings->multyGraphMode = true;
g_assemblyGraph->clear();
g_assemblyGraph->loadGraphsFromDir(cmd.m_graph.c_str());
} else {
g_assemblyGraph->clear();
g_assemblyGraph->m_graphMap[1] = new AssemblyGraph();
bool loadSuccess = g_assemblyGraph->first()->loadGraphFromFile(cmd.m_graph.c_str());
if (!loadSuccess) {
outputText(("Bandage-NG error: could not load " + cmd.m_graph.native()).c_str(), &err); // FIXME
return 1;
}
}

if (cli.count("--query")) {
Expand All @@ -84,28 +92,44 @@ int handleLayoutCmd(QApplication *app,

QString errorTitle;
QString errorMessage;
auto scope = graph::scope(g_settings->graphScope,
g_settings->startingNodes,
g_settings->minDepthRange, g_settings->maxDepthRange,
&g_blastSearch->queries(), "all",
"", g_settings->nodeDistance);
std::vector<DeBruijnNode *> startingNodes = graph::getStartingNodes(&errorTitle, &errorMessage,
*g_assemblyGraph->first(), scope);
if (!errorMessage.isEmpty()) {
err << errorMessage << Qt::endl;
return 1;
}

g_assemblyGraph->first()->markNodesToDraw(scope, startingNodes);
for(auto& assemblyGraph : g_assemblyGraph->m_graphMap.values()) {
auto scope = graph::scope(g_settings->graphScope,
g_settings->startingNodes,
g_settings->minDepthRange, g_settings->maxDepthRange,
&g_blastSearch->queries(), "all",
"", g_settings->nodeDistance);
std::vector<DeBruijnNode *> startingNodes = graph::getStartingNodes(&errorTitle, &errorMessage,
*assemblyGraph, scope);

if (!errorMessage.isEmpty()) {
err << errorMessage << Qt::endl;
return 1;
}

GraphLayoutStorage layout =
*GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(g_assemblyGraph)[0];
assemblyGraph->resetEdges();
assemblyGraph->resetNodes();
assemblyGraph->markNodesToDraw(scope, startingNodes);
}

bool success = (isTSV ?
layout::io::saveTSV(cmd.m_layout.c_str(), layout) :
layout::io::save(cmd.m_layout.c_str(), layout));
GraphLayoutWorker(g_settings->graphLayoutQuality,
g_settings->linearLayout,
g_settings->componentSeparation).layoutGraph(g_assemblyGraph);

bool success;

if (g_assemblyGraph->size() == 1) {
if (isTSV)
success = layout::io::saveTSV(cmd.m_layout.c_str(), *g_assemblyGraph->first()->m_layout);
else
success = layout::io::save(cmd.m_layout.c_str(), *g_assemblyGraph->first()->m_layout);
} else {
if (isTSV) {
success = layout::io::saveGraphListTSV(cmd.m_layout.c_str(), g_assemblyGraph, true);
} else {
success = layout::io::saveGraphList(cmd.m_layout.c_str(), g_assemblyGraph, true);
}
}

if (!success) {
out << "There was an error writing the layout to file." << Qt::endl;
Expand Down
40 changes: 40 additions & 0 deletions graph/assemblygraphlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
#include "program/globals.h"
#include "program/settings.h"

#include <iostream>
#include <filesystem>

#include<QDebug>

AssemblyGraphList::AssemblyGraphList()
{
}
Expand Down Expand Up @@ -127,3 +132,38 @@ double AssemblyGraphList::getMeanDepth(const std::vector<DeBruijnNode *> &nodes)

return depthSum / totalLength;
}

bool AssemblyGraphList::loadGraphsFromDir(const QString& basePath) {

if (basePath.isEmpty()) //User did hit cancel
return false;

QString dirname = basePath;

clear();

loadGraphsIter(dirname, basePath);
return true;
}

void AssemblyGraphList::loadGraphsIter(QString fullDirName, const QString& basePath) {
if (fullDirName.isEmpty()) //User did hit cancel
return;
for (const auto entry : std::filesystem::directory_iterator(fullDirName.toStdString())) {
const std::filesystem::path path = entry.path();
if(std::filesystem::is_directory(path)) {
loadGraphsIter(QString::fromStdString(path), basePath);
}
if (std::filesystem::is_regular_file(path) && path.extension() != ".fasta") {
QString qpath = QString::fromStdString(path);

qInfo() << "loadGraphFromFile: " << qpath;
int graphId = g_assemblyGraph->m_graphMap.size() + 1;
g_assemblyGraph->m_graphMap[graphId] = new AssemblyGraph();
g_assemblyGraph->m_graphMap[graphId] -> setGraphId(graphId);
bool loadSuccess = g_assemblyGraph->m_graphMap[graphId]->loadGraphFromFile(qpath);

g_assemblyGraph->m_graphMap[graphId]->setGraphName(qpath.right(qpath.size() - basePath.size()));
}
}
}
3 changes: 3 additions & 0 deletions graph/assemblygraphlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ class AssemblyGraphList
return nullptr;
}

bool loadGraphsFromDir(const QString& dirname);
void loadGraphsIter(QString fullDirName, const QString& basePath);

QMap<int, AssemblyGraph*> m_graphMap;

private:
Expand Down
10 changes: 4 additions & 6 deletions layout/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ namespace layout::io {
return true;
}

bool saveGraphList(const QString &filename, QSharedPointer<AssemblyGraphList> graphList) {
bool saveGraphList(const QString &filename, QSharedPointer<AssemblyGraphList> graphList, bool isCliMode) {
QJsonObject jsonLayoutGraphList;
for (AssemblyGraph* graph : graphList->m_graphMap.values()) {
GraphLayout layout = layout::fromGraph(*graph, false);
GraphLayout layout = isCliMode ? *graph->m_layout : layout::fromGraph(*graph, false);
QJsonObject jsonLayoutGraph;
for (const auto &entry: layout) {
QJsonArray segments;
Expand Down Expand Up @@ -90,19 +90,17 @@ namespace layout::io {
return true;
}

bool saveGraphListTSV(const QString &filename, QSharedPointer<AssemblyGraphList> graphList) {
bool saveGraphListTSV(const QString &filename, QSharedPointer<AssemblyGraphList> graphList, bool isCliMode) {
QFile saveFile(filename);
if (!saveFile.open(QIODevice::WriteOnly | QIODevice::Text))
return false;

QTextStream out(&saveFile);
for (AssemblyGraph* graph : graphList->m_graphMap.values()) {
GraphLayout layout = layout::fromGraph(*graph, false);
out << graph->getGraphName() << '\n';
GraphLayout layout = isCliMode ? *graph->m_layout : layout::fromGraph(*graph, false);
for (const auto &entry: layout) {
const DeBruijnNode *node = entry.first;
QPointF pos = entry.second.front();
out << entry.first->getName() << '\t' << pos.x() << '\t' << pos.y() << '\n';
}
}

Expand Down
4 changes: 2 additions & 2 deletions layout/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ namespace layout::io {
bool saveTSV(const QString &filename,
const GraphLayout &layout);

bool saveGraphList(const QString &filename, QSharedPointer<AssemblyGraphList> graphList);
bool saveGraphListTSV(const QString &filename, QSharedPointer<AssemblyGraphList> graphList);
bool saveGraphList(const QString &filename, QSharedPointer<AssemblyGraphList> graphList, bool isCliMode = false);
bool saveGraphListTSV(const QString &filename, QSharedPointer<AssemblyGraphList> graphList, bool isCliMode = false);
}
2 changes: 1 addition & 1 deletion painting/commongraphicsitemnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class CommonGraphicsItemNode : public QGraphicsItem

static double distance(QPointF p1, QPointF p2);
void shiftPoints(QPointF difference);
void remakePath();
virtual void remakePath();
void setWidth(double width) { m_width = width; }
void updateGrabIndex(QGraphicsSceneMouseEvent* event);
QPointF getFirst() const { return m_linePoints.front(); }
Expand Down
16 changes: 16 additions & 0 deletions painting/textgraphicsitemnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,22 @@ QPainterPath TextGraphicsItemNode::shape() const
return textPath;
}

void TextGraphicsItemNode::remakePath()
{
QPainterPath path;

QFont font = g_settings->labelFont;
font.setBold(true);

QFontMetrics metrics(font);
double fontHeight = metrics.ascent();

int stepsUntilLast = m_text.size() - 1;
double shiftLeft = -metrics.boundingRect(m_text).width() / 2.0;
path.addText(0, -fontHeight, font, m_text);

m_path = path;
}

void TextGraphicsItemNode::paint(QPainter * painter, const QStyleOptionGraphicsItem *, QWidget *)
{
Expand Down
1 change: 1 addition & 0 deletions painting/textgraphicsitemnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ class TextGraphicsItemNode : public CommonGraphicsItemNode
void drawTextPathAtLocation(QPainter * painter, const QPainterPath &textPath);
void mousePressEvent(QGraphicsSceneMouseEvent * event) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent * event) override;
void remakePath() override;
};
#endif // TEXTGRAPHICSITEMNODE_H
2 changes: 1 addition & 1 deletion program/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Settings::Settings()
displayNodeCsvData = false;
displayNodeCsvDataCol = 0;
labelFont = QFont();
labelFont.setPixelSize(12);
labelFont.setPointSize(8);
textOutline = false;
antialiasing = true;
positionTextNodeCentre = false;
Expand Down
7 changes: 6 additions & 1 deletion ui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,12 @@ void MainWindow::afterMainWindowShow() {
// If the user passed a filename as a command line argument, try to open it now.
if (!m_fileToLoadOnStartup.isEmpty()) {
auto start = std::chrono::system_clock::now();
loadGraph(m_fileToLoadOnStartup);
std::filesystem::path path(m_fileToLoadOnStartup.toStdString());
if(std::filesystem::is_directory(path)) {
loadGraphs(m_fileToLoadOnStartup, m_fileToLoadOnStartup);
} else {
loadGraph(m_fileToLoadOnStartup);
}
auto end = std::chrono::system_clock::now();
std::cerr << std::filesystem::path(m_fileToLoadOnStartup.toStdString()).filename().string()
<< ", " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << std::endl;
Expand Down

0 comments on commit 7389764

Please sign in to comment.