diff --git a/include/common/graph_attributes.h b/include/common/graph_attributes.h index ec0bf03..e63012e 100644 --- a/include/common/graph_attributes.h +++ b/include/common/graph_attributes.h @@ -20,6 +20,9 @@ namespace graph_layout { constexpr std::string_view ATTR_KEY_SPLINES = "splines"; constexpr std::string_view ATTR_KEY_ARROW_HEAD = "arrowhead"; constexpr std::string_view ATTR_KEY_ARROW_TAIL = "arrowtail"; + constexpr std::string_view ATTR_KEY_COLOR = "color"; + constexpr std::string_view ATTR_KEY_FILL_COLOR = "fillcolor"; + constexpr std::string_view ATTR_KEY_FONT_COLOR = "fontcolor"; class Attribute { public: @@ -119,6 +122,17 @@ namespace graph_layout { void setEdgeArrowHead(int edgeId, const std::string& value); void setEdgeArrowTail(int edgeId, const std::string& value); + void setVertexDefaultColor(const std::string& value); + void setVertexDefaultFillColor(const std::string& value); + void setVertexDefaultFontColor(const std::string& value); + void setEdgeDefaultColor(const std::string& value); + void setEdgeDefaultFontColor(const std::string& value); + void setVertexColor(int u, const std::string& value); + void setVertexFillColor(int u, const std::string& value); + void setVertexFontColor(int u, const std::string& value); + void setEdgeColor(int edgeId, const std::string& value); + void setEdgeFontColor(int edgeId, const std::string& value); + private: static const std::string MONOSPACE_FONT_FAMILY; diff --git a/pyproject.toml b/pyproject.toml index c834540..abf5114 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build" [project] name = "sp-graph-layout" -version = "1.3.0" +version = "1.4.0" description = "A library for visualizing directed graphs." requires-python = ">=3.8" readme = "python/README.md" diff --git a/python/bindings.cpp b/python/bindings.cpp index b2a5163..7aba7cd 100644 --- a/python/bindings.cpp +++ b/python/bindings.cpp @@ -67,18 +67,28 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { ; py::class_(m, "Attributes") .def(py::init<>()) - .def("set_rank_dir", &Attributes::setRankDir) - .def("set_vertex_shape", &Attributes::setVertexShape) + .def("set_rank_dir", &Attributes::setRankDir, py::arg("value")) + .def("set_vertex_shape", &Attributes::setVertexShape, py::arg("u"), py::arg("value")) .def("set_edge_tail_label", &Attributes::setEdgeTailLabel, py::arg("edge_id"), py::arg("label")) .def("set_edge_head_label", &Attributes::setEdgeHeadLabel, py::arg("edge_id"), py::arg("label")) .def("set_edge_label_distance", &Attributes::setEdgeLabelDistance, py::arg("edge_id"), py::arg("scale")) - .def("set_vertex_default_shape", &Attributes::setVertexDefaultShape) + .def("set_vertex_default_shape", &Attributes::setVertexDefaultShape, py::arg("value")) .def("set_vertex_default_monospace", &Attributes::setVertexDefaultMonospace) .def("set_edge_default_monospace", &Attributes::setEdgeDefaultMonospace) .def("set_edge_default_arrow_head", &Attributes::setEdgeDefaultArrowHead, py::arg("value")) .def("set_edge_default_arrow_tail", &Attributes::setEdgeDefaultArrowTail, py::arg("value")) .def("set_edge_arrow_head", &Attributes::setEdgeArrowHead, py::arg("edge_id"), py::arg("value")) .def("set_edge_arrow_tail", &Attributes::setEdgeArrowTail, py::arg("edge_id"), py::arg("value")) + .def("set_vertex_default_color", &Attributes::setVertexDefaultColor, py::arg("value")) + .def("set_vertex_default_fill_color", &Attributes::setVertexDefaultFillColor, py::arg("value")) + .def("set_vertex_default_font_color", &Attributes::setVertexDefaultFontColor, py::arg("value")) + .def("set_edge_default_color", &Attributes::setEdgeDefaultColor, py::arg("value")) + .def("set_edge_default_font_color", &Attributes::setEdgeDefaultFontColor, py::arg("value")) + .def("set_vertex_color", &Attributes::setVertexColor, py::arg("u"), py::arg("value")) + .def("set_vertex_fill_color", &Attributes::setVertexFillColor, py::arg("u"), py::arg("value")) + .def("set_vertex_font_color", &Attributes::setVertexFontColor, py::arg("u"), py::arg("value")) + .def("set_edge_color", &Attributes::setEdgeColor, py::arg("edge_id"), py::arg("value")) + .def("set_edge_font_color", &Attributes::setEdgeFontColor, py::arg("edge_id"), py::arg("value")) ; py::class_(m, "DirectedGraphHierarchicalLayout") .def(py::init<>()) diff --git a/src/common/graph_attributes.cpp b/src/common/graph_attributes.cpp index 0cd93f2..d9c717e 100644 --- a/src/common/graph_attributes.cpp +++ b/src/common/graph_attributes.cpp @@ -33,6 +33,9 @@ unordered_map Attributes::DEFAULT_GRAPH_ATTRIBUTE_VALUES = {ATTR_KEY_BG_COLOR, "none"}, {ATTR_KEY_FONT_NAME, "Times,serif"}, {ATTR_KEY_FONT_SIZE, "14"}, + {ATTR_KEY_COLOR, "black"}, + {ATTR_KEY_FILL_COLOR, "none"}, + {ATTR_KEY_FONT_COLOR, "black"}, }; unordered_map Attributes::DEFAULT_VERTEX_ATTRIBUTE_VALUES = { @@ -193,3 +196,43 @@ void Attributes::setEdgeArrowHead(const int edgeId, const string& value) { void Attributes::setEdgeArrowTail(const int edgeId, const string& value) { setEdgeAttributes(edgeId, ATTR_KEY_ARROW_TAIL, value); } + +void Attributes::setVertexDefaultColor(const string& value) { + _vertexDefaultAttributes[ATTR_KEY_COLOR] = value; +} + +void Attributes::setVertexDefaultFillColor(const string& value) { + _vertexDefaultAttributes[ATTR_KEY_FILL_COLOR] = value; +} + +void Attributes::setVertexDefaultFontColor(const string& value) { + _vertexDefaultAttributes[ATTR_KEY_FONT_COLOR] = value; +} + +void Attributes::setEdgeDefaultColor(const string& value) { + _edgeDefaultAttributes[ATTR_KEY_COLOR] = value; +} + +void Attributes::setEdgeDefaultFontColor(const string& value) { + _edgeDefaultAttributes[ATTR_KEY_FONT_COLOR] = value; +} + +void Attributes::setVertexColor(const int u, const string& value) { + setVertexAttributes(u, ATTR_KEY_COLOR, value); +} + +void Attributes::setVertexFillColor(const int u, const string& value) { + setVertexAttributes(u, ATTR_KEY_FILL_COLOR, value); +} + +void Attributes::setVertexFontColor(const int u, const string& value) { + setVertexAttributes(u, ATTR_KEY_FONT_COLOR, value); +} + +void Attributes::setEdgeColor(const int edgeId, const string& value) { + setEdgeAttributes(edgeId, ATTR_KEY_COLOR, value); +} + +void Attributes::setEdgeFontColor(const int edgeId, const string& value) { + setEdgeAttributes(edgeId, ATTR_KEY_FONT_COLOR, value); +} diff --git a/src/graph_layout.cpp b/src/graph_layout.cpp index 4aa7a08..9c85aeb 100644 --- a/src/graph_layout.cpp +++ b/src/graph_layout.cpp @@ -170,6 +170,9 @@ string DirectedGraphHierarchicalLayout::render() const { node->setShape(_attributes.vertexAttributes(u, ATTR_KEY_SHAPE)); node->setLabel(_attributes.vertexAttributes(u, ATTR_KEY_LABEL)); node->setFont(_attributes.vertexAttributes(u, ATTR_KEY_FONT_NAME), stod(_attributes.vertexAttributes(u, ATTR_KEY_FONT_SIZE))); + node->setColor(_attributes.vertexAttributes(u, ATTR_KEY_COLOR)); + node->setFillColor(_attributes.vertexAttributes(u, ATTR_KEY_FILL_COLOR)); + node->setFontColor(_attributes.vertexAttributes(u, ATTR_KEY_FONT_COLOR)); } else { node->setShape(string("none")); node->setMargin(0, 0); @@ -194,6 +197,8 @@ string DirectedGraphHierarchicalLayout::render() const { e->setMargin(2); e->setArrowHead(_attributes.edgeAttributes(edge.id, ATTR_KEY_ARROW_HEAD)); e->setArrowTail(_attributes.edgeAttributes(edge.id, ATTR_KEY_ARROW_TAIL)); + e->setColor(_attributes.edgeAttributes(edge.id, ATTR_KEY_COLOR)); + e->setFontColor(_attributes.edgeAttributes(edge.id, ATTR_KEY_FONT_COLOR)); if (edge.u != edge.v) { if (outEdges[edge.v].contains(edge.u)) { // There is a reverse edge @@ -244,6 +249,8 @@ string DirectedGraphHierarchicalLayout::render() const { e->setArrowHead(_attributes.edgeAttributes(edgeId, ATTR_KEY_ARROW_HEAD)); e->setArrowTail(_attributes.edgeAttributes(edgeId, ATTR_KEY_ARROW_TAIL)); e->setMargin(2); + e->setColor(_attributes.edgeAttributes(edgeId, ATTR_KEY_COLOR)); + e->setFontColor(_attributes.edgeAttributes(edgeId, ATTR_KEY_FONT_COLOR)); for (int i = 0; i + 1 < static_cast(edgeIds.size()); ++i) { const auto& edge = _graph->getEdge(edgeIds[i]); e->addConnectionPoint(_xs[edge.v], _ys[edge.v]); diff --git a/tests/graph_layout/test_directed_graph_hierarchical_layout.cpp b/tests/graph_layout/test_directed_graph_hierarchical_layout.cpp index 631b687..5840cb7 100644 --- a/tests/graph_layout/test_directed_graph_hierarchical_layout.cpp +++ b/tests/graph_layout/test_directed_graph_hierarchical_layout.cpp @@ -153,6 +153,11 @@ TEST(TestDirectedGraphHierarchialLayout, Monospace) { layout.attributes().setEdgeTailLabel(0, "tail"); layout.attributes().setEdgeHeadLabel(1, "head"); layout.attributes().setEdgeLabelDistance(0, 1.0); + layout.attributes().setVertexDefaultColor("darkgray"); + layout.attributes().setVertexDefaultFillColor("gray"); + layout.attributes().setVertexDefaultFontColor("white"); + layout.attributes().setEdgeDefaultColor("darkgray"); + layout.attributes().setEdgeDefaultFontColor("white"); layout.setGraph(graph); layout.setVertexLabels({"A", "BB", "C|C|C", "{DD|DD}"}); layout.layoutGraph(); diff --git a/wasm/graph_layout_wasm.cpp b/wasm/graph_layout_wasm.cpp index 80caee4..f654a8d 100644 --- a/wasm/graph_layout_wasm.cpp +++ b/wasm/graph_layout_wasm.cpp @@ -73,6 +73,16 @@ EMSCRIPTEN_BINDINGS(GraphLayoutWASM) { .function("setEdgeDefaultArrowTail", &Attributes::setEdgeDefaultArrowTail) .function("setEdgeArrowHead", &Attributes::setEdgeArrowHead) .function("setEdgeArrowTail", &Attributes::setEdgeArrowTail) + .function("setVertexDefaultColor", &Attributes::setVertexDefaultColor) + .function("setVertexDefaultFillColor", &Attributes::setVertexDefaultFillColor) + .function("setVertexDefaultFontColor", &Attributes::setVertexDefaultFontColor) + .function("setEdgeDefaultColor", &Attributes::setEdgeDefaultColor) + .function("setEdgeDefaultFontColor", &Attributes::setEdgeDefaultFontColor) + .function("setVertexColor", &Attributes::setVertexColor) + .function("setVertexFillColor", &Attributes::setVertexFillColor) + .function("setVertexFontColor", &Attributes::setVertexFontColor) + .function("setEdgeColor", &Attributes::setEdgeColor) + .function("setEdgeFontColor", &Attributes::setEdgeFontColor) ; class_("DirectedGraphHierarchicalLayout") .constructor<>() @@ -88,5 +98,5 @@ EMSCRIPTEN_BINDINGS(GraphLayoutWASM) { .function("attributes", &DirectedGraphHierarchicalLayout::attributes, return_value_policy::reference()) .function("layoutGraph", &DirectedGraphHierarchicalLayout::layoutGraph) .function("render", select_overload(&DirectedGraphHierarchicalLayout::render)) - ; + ; } diff --git a/wasm/index.d.ts b/wasm/index.d.ts index 03e203c..e301a8a 100644 --- a/wasm/index.d.ts +++ b/wasm/index.d.ts @@ -90,6 +90,16 @@ declare module 'sp-graph-layout' { setEdgeDefaultArrowTail(value: string): void setEdgeArrowHead(edgeId: number, value: string): void setEdgeArrowTail(edgeId: number, value: string): void + setVertexDefaultColor(value: string): void + setVertexDefaultFillColor(value: string): void + setVertexDefaultFontColor(value: string): void + setEdgeDefaultColor(value: string): void + setEdgeDefaultFontColor(value: string): void + setVertexColor(u: number, value: string): void + setVertexFillColor(u: number, value: string): void + setVertexFontColor(u: number, value: string): void + setEdgeColor(edgeId: number, value: string): void + setEdgeFontColor(edgeId: number, value: string): void } export class DirectedGraphHierarchicalLayout { diff --git a/wasm/package.json b/wasm/package.json index 928f1e1..0e255b4 100644 --- a/wasm/package.json +++ b/wasm/package.json @@ -1,6 +1,6 @@ { "name": "sp-graph-layout", - "version": "1.3.0", + "version": "1.4.0", "type": "module", "main": "index.js", "types": "index.d.ts",