diff --git a/src/algorithms/draw.cpp b/src/algorithms/draw.cpp index 47e03e5c..1c606138 100644 --- a/src/algorithms/draw.cpp +++ b/src/algorithms/draw.cpp @@ -1,4 +1,5 @@ #include "draw.hpp" +#include "split.hpp" namespace odgi { @@ -98,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, @@ -106,7 +120,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; @@ -121,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 << " 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; + } + } } // color highlights diff --git a/src/algorithms/draw.hpp b/src/algorithms/draw.hpp index 6315e90f..f74762ad 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..2ef208dc 100644 --- a/src/subcommand/draw_main.cpp +++ b/src/subcommand/draw_main.cpp @@ -117,6 +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 + if (_path_bed_file && !args::get(_path_bed_file).empty()) { std::ifstream bed_in(args::get(_path_bed_file)); std::string line; @@ -137,6 +139,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]; @@ -157,14 +161,18 @@ 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; + // The set automatically handles uniqueness of labels within the set. + node_id_to_label_map[node_id].insert(path_range.name); + } }); } } @@ -216,7 +224,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(); }