From 8c83537a74275bd25747e49e2e4e8735f970f7ca Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Wed, 7 Feb 2024 17:53:34 +0100 Subject: [PATCH 1/3] add labels at the beginning of the path ranges. buggy --- src/algorithms/draw.cpp | 15 ++++++++++++++- src/algorithms/draw.hpp | 3 ++- src/subcommand/draw_main.cpp | 24 +++++++++++++++++++----- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/algorithms/draw.cpp b/src/algorithms/draw.cpp index 47e03e5c..5f6e0cda 100644 --- a/src/algorithms/draw.cpp +++ b/src/algorithms/draw.cpp @@ -1,4 +1,5 @@ #include "draw.hpp" +#include "split.hpp" namespace odgi { @@ -106,7 +107,8 @@ void draw_svg(std::ostream &out, const double& scale, const double& border, const double& line_width, - std::vector& node_id_to_color) { + std::vector& node_id_to_color, + ska::flat_hash_map& node_id_to_label_map) { std::vector> weak_components; coord_range_2d_t rendered_range; @@ -160,6 +162,17 @@ void draw_svg(std::ostream &out, } else { highlights.push_back(handle); } + + // Check if number_bool_packing::unpack_number(handle) is even, becasue each node is present twice + if (node_id_to_label_map.count(graph.get_id(handle)) && (number_bool_packing::unpack_number(handle) % 2) == 0){ + out << ""; + auto vals = split(node_id_to_label_map[graph.get_id(handle)], '\n'); + for (auto x : vals){ + out << "" << x << ""; + } + out << "" + << std::endl; + } } // color highlights diff --git a/src/algorithms/draw.hpp b/src/algorithms/draw.hpp index 6315e90f..4dd554aa 100644 --- a/src/algorithms/draw.hpp +++ b/src/algorithms/draw.hpp @@ -71,7 +71,8 @@ void draw_svg(std::ostream &out, const double& scale, const double& border, const double& line_width, - std::vector& node_id_to_color); + std::vector& node_id_to_color, + ska::flat_hash_map& node_id_to_label_map); std::vector rasterize(const std::vector &X, const std::vector &Y, diff --git a/src/subcommand/draw_main.cpp b/src/subcommand/draw_main.cpp index d925971c..58bfdeae 100644 --- a/src/subcommand/draw_main.cpp +++ b/src/subcommand/draw_main.cpp @@ -117,6 +117,7 @@ int main_draw(int argc, char **argv) { // handle targets from BED std::vector path_ranges; std::vector node_id_to_color; + ska::flat_hash_map node_id_to_label_map; // To remember the unique node to label for each path range if (_path_bed_file && !args::get(_path_bed_file).empty()) { std::ifstream bed_in(args::get(_path_bed_file)); std::string line; @@ -137,6 +138,8 @@ int main_draw(int argc, char **argv) { if (!path_range.name.empty()) { auto vals = split(path_range.name, '#'); if (vals.size() == 2 && vals[1].length() == 6) { + path_range.name = vals[0]; // Remove the color from the name + // Colors are given in RRGGBB in the BED file, but they are taken in BBGGRR, so we need to switch BB/RR char temp = vals[1][0]; @@ -155,11 +158,15 @@ int main_draw(int argc, char **argv) { } else { path_color = algorithms::hash_color(path_range.name); } - } - - - + const step_handle_t first_step = graph.path_begin(path_range.begin.path); + const handle_t first_handle = graph.get_handle_of_step(first_step); + if (node_id_to_label_map.find(graph.get_id(first_handle)) == node_id_to_label_map.end()) { + node_id_to_label_map[graph.get_id(first_handle)] = path_range.name; + } else{ + node_id_to_label_map[graph.get_id(first_handle)] = node_id_to_label_map[graph.get_id(first_handle)] + "\n" + path_range.name; + } + } algorithms::for_handle_in_path_range( graph, path_handle, path_range.begin.offset, path_range.end.offset, @@ -170,6 +177,13 @@ int main_draw(int argc, char **argv) { } } + + std::cerr << node_id_to_label_map.size() << " labels found" << std::endl; + for (auto x : node_id_to_label_map) { + std::cerr << "Node " << x.first << " has label " << x.second << std::endl; + } + + const uint64_t _png_height = png_height ? args::get(png_height) : 1000; const double _png_line_width = png_line_width ? args::get(png_line_width) : 10.0; const bool _color_paths = args::get(color_paths); @@ -216,7 +230,7 @@ int main_draw(int argc, char **argv) { // todo could be done with callbacks std::vector X = layout.get_X(); std::vector Y = layout.get_Y(); - algorithms::draw_svg(f, X, Y, graph, svg_scale, border_bp, _png_line_width, node_id_to_color); + algorithms::draw_svg(f, X, Y, graph, svg_scale, border_bp, _png_line_width, node_id_to_color, node_id_to_label_map); f.close(); } From daa1c9a5d2dfc4d13f056335b332fd226040716a Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Wed, 7 Feb 2024 21:52:27 +0100 Subject: [PATCH 2/3] fix labeling --- src/algorithms/draw.cpp | 7 +++---- src/subcommand/draw_main.cpp | 20 ++++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/algorithms/draw.cpp b/src/algorithms/draw.cpp index 5f6e0cda..2625a94d 100644 --- a/src/algorithms/draw.cpp +++ b/src/algorithms/draw.cpp @@ -162,10 +162,9 @@ void draw_svg(std::ostream &out, } else { highlights.push_back(handle); } - - // Check if number_bool_packing::unpack_number(handle) is even, becasue each node is present twice - if (node_id_to_label_map.count(graph.get_id(handle)) && (number_bool_packing::unpack_number(handle) % 2) == 0){ - out << ""; + + if (node_id_to_label_map.count(graph.get_id(handle))){ + out << ""; auto vals = split(node_id_to_label_map[graph.get_id(handle)], '\n'); for (auto x : vals){ out << "" << x << ""; diff --git a/src/subcommand/draw_main.cpp b/src/subcommand/draw_main.cpp index 58bfdeae..fd95633b 100644 --- a/src/subcommand/draw_main.cpp +++ b/src/subcommand/draw_main.cpp @@ -168,22 +168,26 @@ int main_draw(int argc, char **argv) { } } + bool first_handle_taken = path_range.name.empty(); // To avoid checking if there is no name to take algorithms::for_handle_in_path_range( graph, path_handle, path_range.begin.offset, path_range.end.offset, [&](const handle_t& handle) { - node_id_to_color[graph.get_id(handle)] = path_color; + const auto node_id = graph.get_id(handle); + node_id_to_color[node_id] = path_color; + + if (!first_handle_taken) { + first_handle_taken = true; + if (node_id_to_label_map.find(node_id) == node_id_to_label_map.end()) { + node_id_to_label_map[node_id] = path_range.name; + } else{ + node_id_to_label_map[node_id] = node_id_to_label_map[node_id] + "\n" + path_range.name; + } + } }); } } } - - std::cerr << node_id_to_label_map.size() << " labels found" << std::endl; - for (auto x : node_id_to_label_map) { - std::cerr << "Node " << x.first << " has label " << x.second << std::endl; - } - - const uint64_t _png_height = png_height ? args::get(png_height) : 1000; const double _png_line_width = png_line_width ? args::get(png_line_width) : 10.0; const bool _color_paths = args::get(color_paths); From 8418ea3c2b1b881769b936a14e5c88075b2925ab Mon Sep 17 00:00:00 2001 From: AndreaGuarracino Date: Wed, 7 Feb 2024 22:51:32 +0100 Subject: [PATCH 3/3] avoid duplicated labels and overlaps [sanremo powered] --- src/algorithms/draw.cpp | 44 +++++++++++++++++++++++++++++------- src/algorithms/draw.hpp | 2 +- src/subcommand/draw_main.cpp | 18 ++++----------- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/algorithms/draw.cpp b/src/algorithms/draw.cpp index 2625a94d..1c606138 100644 --- a/src/algorithms/draw.cpp +++ b/src/algorithms/draw.cpp @@ -99,7 +99,20 @@ void get_layout(const std::vector &X, } - +struct label_info_t { + double x, y; + std::string content; + // Simple constructor for convenience + label_info_t(double x, double y, std::string content) : x(x), y(y), content(std::move(content)) {} +}; +bool is_too_close(double x, double y, const std::string& content, double threshold, std::vector& placed_labels) { + for (const auto& label : placed_labels) { + if (label.content == content && std::abs(label.x - x) < threshold && std::abs(label.y - y) < threshold) { + return true; // Found a label too close with the same content + } + } + return false; +} void draw_svg(std::ostream &out, const std::vector &X, const std::vector &Y, @@ -108,7 +121,7 @@ void draw_svg(std::ostream &out, const double& border, const double& line_width, std::vector& node_id_to_color, - ska::flat_hash_map& node_id_to_label_map) { + ska::flat_hash_map>& node_id_to_label_map) { std::vector> weak_components; coord_range_2d_t rendered_range; @@ -123,6 +136,8 @@ void draw_svg(std::ostream &out, double width = rendered_range.width(); double height = rendered_range.height(); + std::vector placed_labels; + out << std::setprecision(std::numeric_limits::digits10 + 1); out << ""; - auto vals = split(node_id_to_label_map[graph.get_id(handle)], '\n'); - for (auto x : vals){ - out << "" << x << ""; + // Collect the labels that can be put without overlapping identical ones + std::vector labels; + for (auto text : node_id_to_label_map[graph.get_id(handle)]){ + if (!is_too_close(x, y, text, 30.0, placed_labels)) { + labels.push_back(text); + } + } + // Check if there is something to label + if (!labels.empty()){ + out << ""; + for (auto text : labels){ + out << "" << text << ""; + placed_labels.emplace_back(x, y, text); // Record the label's placement + } + out << "" + << std::endl; } - out << "" - << std::endl; } } diff --git a/src/algorithms/draw.hpp b/src/algorithms/draw.hpp index 4dd554aa..f74762ad 100644 --- a/src/algorithms/draw.hpp +++ b/src/algorithms/draw.hpp @@ -72,7 +72,7 @@ void draw_svg(std::ostream &out, const double& border, const double& line_width, std::vector& node_id_to_color, - ska::flat_hash_map& node_id_to_label_map); + ska::flat_hash_map>& node_id_to_label_map); std::vector rasterize(const std::vector &X, const std::vector &Y, diff --git a/src/subcommand/draw_main.cpp b/src/subcommand/draw_main.cpp index fd95633b..2ef208dc 100644 --- a/src/subcommand/draw_main.cpp +++ b/src/subcommand/draw_main.cpp @@ -117,7 +117,8 @@ int main_draw(int argc, char **argv) { // handle targets from BED std::vector path_ranges; std::vector node_id_to_color; - ska::flat_hash_map node_id_to_label_map; // To remember the unique node to label for each path range + ska::flat_hash_map> node_id_to_label_map; // To remember the unique node to label for each path range + if (_path_bed_file && !args::get(_path_bed_file).empty()) { std::ifstream bed_in(args::get(_path_bed_file)); std::string line; @@ -158,14 +159,6 @@ int main_draw(int argc, char **argv) { } else { path_color = algorithms::hash_color(path_range.name); } - - const step_handle_t first_step = graph.path_begin(path_range.begin.path); - const handle_t first_handle = graph.get_handle_of_step(first_step); - if (node_id_to_label_map.find(graph.get_id(first_handle)) == node_id_to_label_map.end()) { - node_id_to_label_map[graph.get_id(first_handle)] = path_range.name; - } else{ - node_id_to_label_map[graph.get_id(first_handle)] = node_id_to_label_map[graph.get_id(first_handle)] + "\n" + path_range.name; - } } bool first_handle_taken = path_range.name.empty(); // To avoid checking if there is no name to take @@ -177,11 +170,8 @@ int main_draw(int argc, char **argv) { if (!first_handle_taken) { first_handle_taken = true; - if (node_id_to_label_map.find(node_id) == node_id_to_label_map.end()) { - node_id_to_label_map[node_id] = path_range.name; - } else{ - node_id_to_label_map[node_id] = node_id_to_label_map[node_id] + "\n" + path_range.name; - } + // The set automatically handles uniqueness of labels within the set. + node_id_to_label_map[node_id].insert(path_range.name); } }); }