diff --git a/src/algorithms/draw.cpp b/src/algorithms/draw.cpp index 1c606138..1c83d852 100644 --- a/src/algorithms/draw.cpp +++ b/src/algorithms/draw.cpp @@ -113,6 +113,23 @@ bool is_too_close(double x, double y, const std::string& content, double thresho } return false; } + +uint64_t node_hash(const nid_t& node_id) { + uint64_t x = node_id; + x = (~x) + (x << 21); // x = (x << 21) - x - 1; + x = x ^ (x >> 24); + x = (x + (x << 3)) + (x << 8); // x * 265 + x = x ^ (x >> 14); + x = (x + (x << 2)) + (x << 4); // x * 21 + x = x ^ (x >> 28); + x = x + (x << 31); + return x; +} +bool keep_node(const nid_t& node_id, const float f) { + // hash the node_id and check if it's accepted given our sparsification factor + return node_hash(node_id) < std::numeric_limits::max() * f; +} + void draw_svg(std::ostream &out, const std::vector &X, const std::vector &Y, @@ -121,7 +138,8 @@ 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, + const float& sparsification_factor) { std::vector> weak_components; coord_range_2d_t rendered_range; @@ -161,6 +179,11 @@ void draw_svg(std::ostream &out, for (auto& handle : component) { uint64_t a = 2 * number_bool_packing::unpack_number(handle); algorithms::color_t color = node_id_to_color.empty() ? COLOR_BLACK : node_id_to_color[graph.get_id(handle)]; + + if (!(sparsification_factor == 0 || keep_node(graph.get_id(handle), sparsification_factor) || node_id_to_label_map.count(graph.get_id(handle)))) { + continue; // Skip this node to output a lighter SVG (do not nodes with labels, if any) + } + if (color == COLOR_BLACK || color == COLOR_LIGHTGRAY) { out << "& node_id_to_color, - ska::flat_hash_map>& node_id_to_label_map); + ska::flat_hash_map>& node_id_to_label_map, + const float& sparsification_factor); 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 2ef208dc..178c8196 100644 --- a/src/subcommand/draw_main.cpp +++ b/src/subcommand/draw_main.cpp @@ -51,6 +51,7 @@ int main_draw(int argc, char **argv) { "Colors are derived from the 4th column, if present, else from the path name." "If the 4th column value is in the format 'string#RRGGBB', the RRGGBB color (in hex notation) will be used.", {'b', "bed-file"}); + args::ValueFlag node_sparsification(parser, "N", "Remove this fraction of nodes from the SVG output (to output smaller files) (default: 0.0, keep all nodes).", {'f', "sparse-factor-svg"}); args::Group threading(parser, "[ Threading ]"); args::ValueFlag nthreads(threading, "N", "Number of threads to use for parallel operations.", {'t', "threads"}); args::Group processing_info_opts(parser, "[ Processing Information ]"); @@ -182,7 +183,6 @@ int main_draw(int argc, char **argv) { const double _png_line_width = png_line_width ? args::get(png_line_width) : 10.0; const bool _color_paths = args::get(color_paths); const double _png_path_line_spacing = png_path_line_spacing ? args::get(png_path_line_spacing) : 0.0; - const double svg_scale = !svg_render_scale ? 0.01 : args::get(svg_render_scale); size_t max_node_depth = 0; graph.for_each_handle( [&](const handle_t& h) { @@ -219,12 +219,14 @@ int main_draw(int argc, char **argv) { } if (svg_out_file) { + const double svg_scale = !svg_render_scale ? 0.01 : args::get(svg_render_scale); + const float sparse_nodes = node_sparsification ? args::get(node_sparsification) : 0.0; auto& outfile = args::get(svg_out_file); ofstream f(outfile.c_str()); // 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, node_id_to_label_map); + algorithms::draw_svg(f, X, Y, graph, svg_scale, border_bp, _png_line_width, node_id_to_color, node_id_to_label_map, sparse_nodes); f.close(); }