Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose GraphvizFormatting and test in python #1059

Merged
merged 5 commits into from
Jan 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions gtsam/discrete/discrete.i
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ class DotWriter {
DotWriter(double figureWidthInches = 5, double figureHeightInches = 5,
bool plotFactorPoints = true, bool connectKeysToFactor = true,
bool binaryEdges = true);

double figureWidthInches;
double figureHeightInches;
bool plotFactorPoints;
bool connectKeysToFactor;
bool binaryEdges;
};

#include <gtsam/discrete/DiscreteFactorGraph.h>
Expand Down
19 changes: 17 additions & 2 deletions gtsam/nonlinear/nonlinear.i
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ class Ordering {
void serialize() const;
};

#include <gtsam/nonlinear/GraphvizFormatting.h>
class GraphvizFormatting : gtsam::DotWriter {
GraphvizFormatting();

enum Axis { X, Y, Z, NEGX, NEGY, NEGZ };
Axis paperHorizontalAxis;
Axis paperVerticalAxis;

double scale;
bool mergeSimilarFactors;
};

#include <gtsam/nonlinear/NonlinearFactorGraph.h>
class NonlinearFactorGraph {
NonlinearFactorGraph();
Expand Down Expand Up @@ -195,10 +207,13 @@ class NonlinearFactorGraph {

string dot(
const gtsam::Values& values,
const gtsam::KeyFormatter& keyFormatter = gtsam::DefaultKeyFormatter);
const gtsam::KeyFormatter& keyFormatter = gtsam::DefaultKeyFormatter,
const GraphvizFormatting& writer = GraphvizFormatting());
void saveGraph(const string& s, const gtsam::Values& values,
const gtsam::KeyFormatter& keyFormatter =
gtsam::DefaultKeyFormatter) const;
gtsam::DefaultKeyFormatter,
const GraphvizFormatting& writer =
GraphvizFormatting()) const;
};

#include <gtsam/nonlinear/NonlinearFactor.h>
Expand Down
2 changes: 1 addition & 1 deletion python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,5 @@ add_custom_target(
${CMAKE_COMMAND} -E env # add package to python path so no need to install
"PYTHONPATH=${GTSAM_PYTHON_BUILD_DIRECTORY}/$ENV{PYTHONPATH}"
${PYTHON_EXECUTABLE} -m unittest discover -v -s .
DEPENDS ${GTSAM_PYTHON_DEPENDENCIES}
DEPENDS ${GTSAM_PYTHON_DEPENDENCIES} ${GTSAM_PYTHON_TEST_FILES}
senselessDev marked this conversation as resolved.
Show resolved Hide resolved
WORKING_DIRECTORY "${GTSAM_PYTHON_BUILD_DIRECTORY}/gtsam/tests")
135 changes: 135 additions & 0 deletions python/gtsam/tests/test_GraphvizFormatting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
"""
See LICENSE for the license information

Unit tests for Graphviz formatting of NonlinearFactorGraph.
Author: senselessDev (contact by mentioning on GitHub, e.g. in PR#1059)
"""

# pylint: disable=no-member, invalid-name

import unittest
import textwrap

import numpy as np

import gtsam
from gtsam.utils.test_case import GtsamTestCase


class TestGraphvizFormatting(GtsamTestCase):
"""Tests for saving NonlinearFactorGraph to GraphViz format."""

def setUp(self):
self.graph = gtsam.NonlinearFactorGraph()

odometry = gtsam.Pose2(2.0, 0.0, 0.0)
odometryNoise = gtsam.noiseModel.Diagonal.Sigmas(
np.array([0.2, 0.2, 0.1]))
self.graph.add(gtsam.BetweenFactorPose2(0, 1, odometry, odometryNoise))
self.graph.add(gtsam.BetweenFactorPose2(1, 2, odometry, odometryNoise))

self.values = gtsam.Values()
self.values.insert_pose2(0, gtsam.Pose2(0., 0., 0.))
self.values.insert_pose2(1, gtsam.Pose2(2., 0., 0.))
self.values.insert_pose2(2, gtsam.Pose2(4., 0., 0.))

def test_default(self):
"""Test with default GraphvizFormatting"""
expected_result = """\
senselessDev marked this conversation as resolved.
Show resolved Hide resolved
graph {
size="5,5";

var0[label="0", pos="0,0!"];
var1[label="1", pos="0,2!"];
var2[label="2", pos="0,4!"];

factor0[label="", shape=point];
var0--factor0;
var1--factor0;
factor1[label="", shape=point];
var1--factor1;
var2--factor1;
}
"""

self.assertEqual(self.graph.dot(self.values),
textwrap.dedent(expected_result))
senselessDev marked this conversation as resolved.
Show resolved Hide resolved

def test_swapped_axes(self):
"""Test with user-defined GraphvizFormatting swapping x and y"""
expected_result = """\
graph {
size="5,5";

var0[label="0", pos="0,0!"];
var1[label="1", pos="2,0!"];
var2[label="2", pos="4,0!"];

factor0[label="", shape=point];
var0--factor0;
var1--factor0;
factor1[label="", shape=point];
var1--factor1;
var2--factor1;
}
"""

graphviz_formatting = gtsam.GraphvizFormatting()
graphviz_formatting.paperHorizontalAxis = gtsam.GraphvizFormatting.Axis.X
graphviz_formatting.paperVerticalAxis = gtsam.GraphvizFormatting.Axis.Y
self.assertEqual(self.graph.dot(self.values,
writer=graphviz_formatting),
textwrap.dedent(expected_result))

def test_factor_points(self):
"""Test with user-defined GraphvizFormatting without factor points"""
expected_result = """\
graph {
size="5,5";

var0[label="0", pos="0,0!"];
var1[label="1", pos="0,2!"];
var2[label="2", pos="0,4!"];

var0--var1;
var1--var2;
}
"""

graphviz_formatting = gtsam.GraphvizFormatting()
graphviz_formatting.plotFactorPoints = False

self.assertEqual(self.graph.dot(self.values,
writer=graphviz_formatting),
textwrap.dedent(expected_result))

def test_width_height(self):
"""Test with user-defined GraphvizFormatting for width and height"""
expected_result = """\
graph {
size="20,10";

var0[label="0", pos="0,0!"];
var1[label="1", pos="0,2!"];
var2[label="2", pos="0,4!"];

factor0[label="", shape=point];
var0--factor0;
var1--factor0;
factor1[label="", shape=point];
var1--factor1;
var2--factor1;
}
"""

graphviz_formatting = gtsam.GraphvizFormatting()
graphviz_formatting.figureWidthInches = 20
graphviz_formatting.figureHeightInches = 10

self.assertEqual(self.graph.dot(self.values,
writer=graphviz_formatting),
textwrap.dedent(expected_result))


if __name__ == "__main__":
unittest.main()