[geneagrapher] 104/226: Added ability for user to specify the sort order of nodes in the graph. This fixes #10.
Doug Torrance
dtorrance-guest at moszumanska.debian.org
Sat Jul 11 17:10:50 UTC 2015
This is an automated email from the git hooks/post-receive script.
dtorrance-guest pushed a commit to branch master
in repository geneagrapher.
commit 8cb28f159779cb64a0c7d5d1db30a5167d012737
Author: David Alber <alber.david at gmail.com>
Date: Mon Dec 29 04:21:04 2008 +0000
Added ability for user to specify the sort order of nodes in the graph. This fixes #10.
---
Geneagrapher/geneagrapher/GGraph.py | 50 ++++++++--
Geneagrapher/geneagrapher/geneagrapher.py | 35 +++++--
Geneagrapher/geneagrapher/ggrapher.py | 5 +
Geneagrapher/geneagrapher/grab.py | 2 +-
Geneagrapher/tests/tests.py | 157 +++++++++++++++++++++++++++---
5 files changed, 220 insertions(+), 29 deletions(-)
diff --git a/Geneagrapher/geneagrapher/GGraph.py b/Geneagrapher/geneagrapher/GGraph.py
index 04218db..f6c984d 100644
--- a/Geneagrapher/geneagrapher/GGraph.py
+++ b/Geneagrapher/geneagrapher/GGraph.py
@@ -10,7 +10,7 @@ class Record:
"""
Container class storing record of a mathematician in the graph.
"""
- def __init__(self, name, institution=None, year=None, id=None):
+ def __init__(self, name, institution=None, year=None, id=None, sort_order='year'):
"""
Record class constructor.
@@ -20,11 +20,14 @@ class Record:
(empty if none)
year: integer containing year degree was earned
id: integer containing Math Genealogy Project id value
+ sort_order: 'year', 'surname', or 'id'; defines the order
+ to sort nodes
"""
self.name = name
self.institution = institution
self.year = year
self.id = id
+ self.sort_order = sort_order
# Verify we got the types wanted.
if not isinstance(self.name, basestring):
@@ -38,9 +41,34 @@ class Record:
def __cmp__(self, r2):
"""
- Compare a pair of mathematician records based on ids.
+ Compare a pair of mathematician records based on surnames,
+ ids, or graduation years.
"""
- return self.id.__cmp__(r2.id)
+ if self.sort_order == "surname":
+ sname1 = self.name.split()[-1]
+ sname2 = r2.name.split()[-1]
+ if sname1 > sname2:
+ return 1
+ elif sname1 < sname2:
+ return -1
+ else:
+ return 0
+ elif self.sort_order == "id":
+ id1 = int(self.id)
+ id2 = int(r2.id)
+ return id1.__cmp__(id2)
+ else:
+ # Do the 'year' sort order.
+ if self.year is not None:
+ if r2.year is not None:
+ return self.year.__cmp__(r2.year)
+ else:
+ return -1
+ else:
+ if r2.year is not None:
+ return 1
+ else:
+ return 0
def hasInstitution(self):
"""
@@ -173,12 +201,13 @@ class Graph:
"""
return self.nodes.keys()
- def addNode(self, name, institution, year, id, ancestors, descendants, isHead=False):
+ def addNode(self, name, institution, year, id, ancestors,
+ descendants, sort_order='year', isHead=False):
"""
Add a new node to the graph if a matching node is not already
present.
"""
- record = Record(name, institution, year, id)
+ record = Record(name, institution, year, id, sort_order)
node = Node(record, ancestors, descendants)
self.addNodeObject(node, isHead)
@@ -212,6 +241,7 @@ class Graph:
for head in self.heads:
queue.append(head.id())
edges = ""
+ nodes = []
dotfile = ""
dotfile += """digraph genealogy {
@@ -239,9 +269,8 @@ class Graph:
# Add this node's descendants to queue.
queue += node.descendants
- # Print this node's information.
- nodestr = " %d [label=\"%s\"];" % (node_id, node)
- dotfile += nodestr
+ # Add this node to the front of the node list.
+ nodes.insert(0, node)
# Store the connection information for this node.
for advisor in node.ancestors:
@@ -249,7 +278,10 @@ class Graph:
edgestr = "\n %d -> %d;" % (advisor, node_id)
edges += edgestr
- dotfile += "\n"
+ # Generate nodes list text.
+ nodes.sort()
+ for node in nodes:
+ dotfile += " %d [label=\"%s\"];\n" % (node.id(), node)
# Now print the connections between the nodes.
dotfile += edges
diff --git a/Geneagrapher/geneagrapher/geneagrapher.py b/Geneagrapher/geneagrapher/geneagrapher.py
index 60acc59..3db9f2c 100644
--- a/Geneagrapher/geneagrapher/geneagrapher.py
+++ b/Geneagrapher/geneagrapher/geneagrapher.py
@@ -1,7 +1,14 @@
from optparse import OptionParser
+import sys
import GGraph
import grab
+class BadSortTypeError(ValueError):
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return self.value
+
class Geneagrapher:
"""
A class for building Graphviz "dot" files for math genealogies
@@ -37,6 +44,8 @@ class Geneagrapher:
help="print version and exit")
self.parser.add_option("-n", "--attach-node-file", dest="supp_node_filename", metavar="FILE",
help="attach supplementary nodes returned by function 'define_supp_nodes()' in FILE to the graph", default=None)
+ self.parser.add_option("-s", "--node-sort", dest="node_sort_order", metavar="SORT_TYPE",
+ help="sort the nodes based on SORT_TYPE [defalut: 'year']; valid values: 'year' (sort by graduation year), 'surname' (sort by surname), 'id' (sort by node ID)", default="year")
(options, args) = self.parser.parse_args()
@@ -51,9 +60,16 @@ class Geneagrapher:
self.get_descendants = options.get_descendants
self.verbose = options.verbose
self.supp_node_filename = options.supp_node_filename
+ self.node_sort_order = options.node_sort_order
self.write_filename = options.filename
for arg in args:
self.leaf_ids.append(int(arg))
+
+ # Verify the node sort order value is valid.
+ if self.node_sort_order != "year" and self.node_sort_order != "surname" and \
+ self.node_sort_order != "id":
+ msg = "Node sort order type '%s' invalid" % (self.node_sort_order)
+ raise BadSortTypeError(msg)
def buildGraph(self):
"""
@@ -86,10 +102,11 @@ class Geneagrapher:
print "Grabbing record #%d" % (id)
try:
[name, institution, year, advisors, descendants] = grabber.extractNodeInformation()
- except ValueError:
+ except grab.BadIdError, msg:
# The given id does not exist in the Math Genealogy Project's database.
- raise
- self.graph.addNode(name, institution, year, id, advisors, descendants, True)
+ print msg
+ sys.exit()
+ self.graph.addNode(name, institution, year, id, advisors, descendants, self.node_sort_order, True)
if self.get_ancestors:
ancestor_grab_queue += advisors
if self.get_descendants:
@@ -109,7 +126,7 @@ class Geneagrapher:
except ValueError:
# The given id does not exist in the Math Genealogy Project's database.
raise
- self.graph.addNode(name, institution, year, id, advisors, descendants)
+ self.graph.addNode(name, institution, year, id, advisors, descendants, self.node_sort_order)
ancestor_grab_queue += advisors
# Grab descendants of leaf nodes.
@@ -126,7 +143,7 @@ class Geneagrapher:
except ValueError:
# The given id does not exist in the Math Genealogy Project's database.
raise
- self.graph.addNode(name, institution, year, id, advisors, descendants)
+ self.graph.addNode(name, institution, year, id, advisors, descendants, self.node_sort_order)
descendant_grab_queue += descendants
def generateDotFile(self):
@@ -142,8 +159,12 @@ if __name__ == "__main__":
geneagrapher = Geneagrapher()
try:
geneagrapher.parseInput()
- except SyntaxError, e:
+ except SyntaxError, msg:
print geneagrapher.parser.get_usage()
- print e
+ print msg
+ sys.exit()
+ except BadSortTypeError, msg:
+ print msg
+ sys.exit()
geneagrapher.buildGraph()
geneagrapher.generateDotFile()
diff --git a/Geneagrapher/geneagrapher/ggrapher.py b/Geneagrapher/geneagrapher/ggrapher.py
index d816605..d117a2e 100644
--- a/Geneagrapher/geneagrapher/ggrapher.py
+++ b/Geneagrapher/geneagrapher/ggrapher.py
@@ -1,3 +1,4 @@
+import sys
import geneagrapher
def ggrapher():
@@ -9,5 +10,9 @@ def ggrapher():
except SyntaxError, e:
print ggrapher.parser.get_usage()
print e
+ sys.exit()
+ except geneagrapher.BadSortTypeError, msg:
+ print msg
+ sys.exit()
ggrapher.buildGraph()
ggrapher.generateDotFile()
diff --git a/Geneagrapher/geneagrapher/grab.py b/Geneagrapher/geneagrapher/grab.py
index e190f3e..e227ca6 100644
--- a/Geneagrapher/geneagrapher/grab.py
+++ b/Geneagrapher/geneagrapher/grab.py
@@ -6,7 +6,7 @@ class BadIdError(ValueError):
def __init__(self, value):
self.value = value
def __str__(self):
- return repr(self.value)
+ return self.value
class Grabber:
"""
diff --git a/Geneagrapher/tests/tests.py b/Geneagrapher/tests/tests.py
index 36b4b16..3fd2617 100644
--- a/Geneagrapher/tests/tests.py
+++ b/Geneagrapher/tests/tests.py
@@ -14,6 +14,7 @@ class TestRecordMethods(unittest.TestCase):
self.assertEqual(record.institution, "Universitaet Helmstedt")
self.assertEqual(record.year, 1799)
self.assertEqual(record.id, 18231)
+ self.assertEqual(record.sort_order, "year")
def test002_init_bad_name(self):
# Test constructor with bad 'name' parameter.
@@ -39,28 +40,53 @@ class TestRecordMethods(unittest.TestCase):
record2 = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231)
self.assert_(record1 == record2)
+ record1 = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231, "surname")
+ record2 = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231, "surname")
+ self.assert_(record1 == record2)
+
+ record1 = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231, "id")
+ record2 = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231, "id")
+ self.assert_(record1 == record2)
+
def test007_cmp_unequal(self):
# Verify two 'unequal' records are compared correctly.
record1 = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231)
record2 = GGraph.Record("Leonhard Euler", "Universitaet Basel", 1726, 38586)
- self.assert_(record1 < record2)
-
- def test008_hasInstitution_yes(self):
+ self.assertTrue(record1 > record2)
+
+ record1 = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231, "surname")
+ record2 = GGraph.Record("Leonhard Euler", "Universitaet Basel", 1726, 38586, "surname")
+ self.assertTrue(record1 > record2)
+
+ record1 = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231, "id")
+ record2 = GGraph.Record("Leonhard Euler", "Universitaet Basel", 1726, 38586, "id")
+ self.assertTrue(record1 < record2)
+
+ def test008_cmp_no_year(self):
+ # Verify year-based comparison acts as expected when one
+ # record is missing a year.
+ record1 = GGraph.Record(name="Record 1", institution="Universitaet Helmstedt",
+ year=1999, id=18231)
+ record2 = GGraph.Record(name="Record 1", institution="Universitaet Helmstedt", id=18231)
+ self.assertTrue(record1 < record2)
+ self.assertTrue(record2 > record1)
+
+ def test009_hasInstitution_yes(self):
# Verify hasInstitution() method returns True when the conditions are right.
record = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231)
self.assert_(record.hasInstitution())
- def test009_hasInstitution_no(self):
+ def test010_hasInstitution_no(self):
# Verify hasInstitution() method returns False when the conditions are right.
record = GGraph.Record("Carl Friedrich Gauss", None, 1799, 18231)
self.assert_(not record.hasInstitution())
- def test010_hasYear_yes(self):
+ def test011_hasYear_yes(self):
# Verify hasYear() method returns True when the conditions are right.
record = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231)
self.assert_(record.hasYear())
- def test011_hasYear_no(self):
+ def test012_hasYear_no(self):
# Verify hasYear() method returns False when the conditions are right.
record = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", None, 18231)
self.assert_(not record.hasYear())
@@ -136,7 +162,7 @@ class TestNodeMethods(unittest.TestCase):
record2 = GGraph.Record("Leonhard Euler", "Universitaet Basel", 1726, 38586)
node1 = GGraph.Node(self.record, [], [])
node2 = GGraph.Node(record2, [], [])
- self.assert_(node1 < node2)
+ self.assert_(node1 > node2)
def test010_add_ancestor(self):
# Test the addAncestor() method.
@@ -221,7 +247,7 @@ class TestGraphMethods(unittest.TestCase):
def test010_add_second_node_head(self):
# Test the addNode() method when adding a second node and
# marking it as a head node.
- self.graph1.addNode("Leonhard Euler", "Universitaet Basel", 1726, 38586, [], [], True)
+ self.graph1.addNode("Leonhard Euler", "Universitaet Basel", 1726, 38586, [], [], isHead=True)
self.assertEquals([38586, 18231], self.graph1.getNodeList())
self.assertEquals(self.graph1.heads, [self.node1, self.graph1.getNode(38586)])
@@ -259,7 +285,7 @@ class TestGraphMethods(unittest.TestCase):
dotfile = self.graph1.generateDotFile(True, False)
self.assertEquals(dotfile, dotfileexpt)
- def test015_generate_dot_file(self):
+ def test015_generate_dot_file1(self):
# Test the generateDotFile() method.
graph = GGraph.Graph()
graph.addNode("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231, [18230], [])
@@ -274,12 +300,76 @@ class TestGraphMethods(unittest.TestCase):
node [shape=plaintext];
edge [style=bold];
- 18231 [label="Carl Friedrich Gauss \\nUniversitaet Helmstedt (1799)"];
- 18230 [label="Johann Friedrich Pfaff \\nGeorg-August-Universitaet Goettingen (1786)"];
+ 21235 [label="Otto Mencke \\nUniversitaet Leipzig (1665)"];
+ 72669 [label="Johann Christoph Wichmannshausen \\nUniversitaet Leipzig (1685)"];
+ 57670 [label="Christian August Hausen \\nMartin-Luther-Universitaet Halle-Wittenberg (1713)"];
66476 [label="Abraham Gotthelf Kaestner \\nUniversitaet Leipzig (1739)"];
+ 18230 [label="Johann Friedrich Pfaff \\nGeorg-August-Universitaet Goettingen (1786)"];
+ 18231 [label="Carl Friedrich Gauss \\nUniversitaet Helmstedt (1799)"];
+
+ 18230 -> 18231;
+ 66476 -> 18230;
+ 57670 -> 66476;
+ 72669 -> 57670;
+ 21235 -> 72669;
+}
+"""
+ dotfile = graph.generateDotFile(True, False)
+ self.assertEquals(dotfile, dotfileexpt)
+
+ def test016_generate_dot_file2(self):
+ # Test the generateDotFile() method.
+ graph = GGraph.Graph()
+ graph.addNode("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231, [18230], [], sort_order="surname")
+ graph.addNode("Johann Friedrich Pfaff", "Georg-August-Universitaet Goettingen", 1786, 18230, [66476], [], sort_order="surname")
+ graph.addNode("Abraham Gotthelf Kaestner", "Universitaet Leipzig", 1739, 66476, [57670], [], sort_order="surname")
+ graph.addNode("Christian August Hausen", "Martin-Luther-Universitaet Halle-Wittenberg", 1713, 57670, [72669], [], sort_order="surname")
+ graph.addNode("Johann Christoph Wichmannshausen", "Universitaet Leipzig", 1685, 72669, [21235], [], sort_order="surname")
+ graph.addNode("Otto Mencke", "Universitaet Leipzig", 1665, 21235, [], [], sort_order="surname")
+
+ dotfileexpt = """digraph genealogy {
+ graph [charset="utf-8"];
+ node [shape=plaintext];
+ edge [style=bold];
+
+ 18231 [label="Carl Friedrich Gauss \\nUniversitaet Helmstedt (1799)"];
57670 [label="Christian August Hausen \\nMartin-Luther-Universitaet Halle-Wittenberg (1713)"];
+ 66476 [label="Abraham Gotthelf Kaestner \\nUniversitaet Leipzig (1739)"];
+ 21235 [label="Otto Mencke \\nUniversitaet Leipzig (1665)"];
+ 18230 [label="Johann Friedrich Pfaff \\nGeorg-August-Universitaet Goettingen (1786)"];
72669 [label="Johann Christoph Wichmannshausen \\nUniversitaet Leipzig (1685)"];
+
+ 18230 -> 18231;
+ 66476 -> 18230;
+ 57670 -> 66476;
+ 72669 -> 57670;
+ 21235 -> 72669;
+}
+"""
+ dotfile = graph.generateDotFile(True, False)
+ self.assertEquals(dotfile, dotfileexpt)
+
+ def test017_generate_dot_file3(self):
+ # Test the generateDotFile() method.
+ graph = GGraph.Graph()
+ graph.addNode("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231, [18230], [], sort_order="id")
+ graph.addNode("Johann Friedrich Pfaff", "Georg-August-Universitaet Goettingen", 1786, 18230, [66476], [], sort_order="id")
+ graph.addNode("Abraham Gotthelf Kaestner", "Universitaet Leipzig", 1739, 66476, [57670], [], sort_order="id")
+ graph.addNode("Christian August Hausen", "Martin-Luther-Universitaet Halle-Wittenberg", 1713, 57670, [72669], [], sort_order="id")
+ graph.addNode("Johann Christoph Wichmannshausen", "Universitaet Leipzig", 1685, 72669, [21235], [], sort_order="id")
+ graph.addNode("Otto Mencke", "Universitaet Leipzig", 1665, 21235, [], [], sort_order="id")
+
+ dotfileexpt = """digraph genealogy {
+ graph [charset="utf-8"];
+ node [shape=plaintext];
+ edge [style=bold];
+
+ 18230 [label="Johann Friedrich Pfaff \\nGeorg-August-Universitaet Goettingen (1786)"];
+ 18231 [label="Carl Friedrich Gauss \\nUniversitaet Helmstedt (1799)"];
21235 [label="Otto Mencke \\nUniversitaet Leipzig (1665)"];
+ 57670 [label="Christian August Hausen \\nMartin-Luther-Universitaet Halle-Wittenberg (1713)"];
+ 66476 [label="Abraham Gotthelf Kaestner \\nUniversitaet Leipzig (1739)"];
+ 72669 [label="Johann Christoph Wichmannshausen \\nUniversitaet Leipzig (1685)"];
18230 -> 18231;
66476 -> 18230;
@@ -427,17 +517,19 @@ class TestGeneagrapherMethods(unittest.TestCase):
self.assertEquals(self.ggrapher.get_descendants, False)
self.assertEquals(self.ggrapher.verbose, False)
self.assertEquals(self.ggrapher.supp_node_filename, None)
+ self.assertEquals(self.ggrapher.node_sort_order, "year")
self.assertEquals(self.ggrapher.write_filename, None)
self.assertEquals(self.ggrapher.leaf_ids, [3])
def test004_parse_options(self):
# Test parseInput() with options.
- sys.argv = ['geneagrapher', '--with-ancestors', '--with-descendants', '--file=filler', '--verbose', '-n', 'suppfiller', '3', '43']
+ sys.argv = ['geneagrapher', '--with-ancestors', '--with-descendants', '--file=filler', '--verbose', '-n', 'suppfiller', '--node-sort=surname', '3', '43']
self.ggrapher.parseInput()
self.assertEquals(self.ggrapher.get_ancestors, True)
self.assertEquals(self.ggrapher.get_descendants, True)
self.assertEquals(self.ggrapher.verbose, True)
self.assertEquals(self.ggrapher.supp_node_filename, "suppfiller")
+ self.assertEquals(self.ggrapher.node_sort_order, "surname")
self.assertEquals(self.ggrapher.write_filename, "filler")
self.assertEquals(self.ggrapher.leaf_ids, [3, 43])
@@ -448,6 +540,47 @@ class TestGeneagrapherMethods(unittest.TestCase):
self.ggrapher.parseInput()
self.assertRaises(AttributeError, self.ggrapher.buildGraph)
+ def test006_sort_order_type_test1(self):
+ # Test the parseInput() method with a valid sort order.
+ sys.argv = ['geneagrapher', '--node-sort=year', '3', '43']
+ self.ggrapher.parseInput()
+ self.assertEquals(self.ggrapher.get_ancestors, False)
+ self.assertEquals(self.ggrapher.get_descendants, False)
+ self.assertEquals(self.ggrapher.verbose, False)
+ self.assertEquals(self.ggrapher.supp_node_filename, None)
+ self.assertEquals(self.ggrapher.node_sort_order, "year")
+ self.assertEquals(self.ggrapher.write_filename, None)
+ self.assertEquals(self.ggrapher.leaf_ids, [3, 43])
+
+ def test007_sort_order_type_test2(self):
+ # Test the parseInput() method with a valid sort order.
+ sys.argv = ['geneagrapher', '--node-sort=surname', '3', '43']
+ self.ggrapher.parseInput()
+ self.assertEquals(self.ggrapher.get_ancestors, False)
+ self.assertEquals(self.ggrapher.get_descendants, False)
+ self.assertEquals(self.ggrapher.verbose, False)
+ self.assertEquals(self.ggrapher.supp_node_filename, None)
+ self.assertEquals(self.ggrapher.node_sort_order, "surname")
+ self.assertEquals(self.ggrapher.write_filename, None)
+ self.assertEquals(self.ggrapher.leaf_ids, [3, 43])
+
+ def test008_sort_order_type_test3(self):
+ # Test the parseInput() method with a valid sort order.
+ sys.argv = ['geneagrapher', '--node-sort=id', '3', '43']
+ self.ggrapher.parseInput()
+ self.assertEquals(self.ggrapher.get_ancestors, False)
+ self.assertEquals(self.ggrapher.get_descendants, False)
+ self.assertEquals(self.ggrapher.verbose, False)
+ self.assertEquals(self.ggrapher.supp_node_filename, None)
+ self.assertEquals(self.ggrapher.node_sort_order, "id")
+ self.assertEquals(self.ggrapher.write_filename, None)
+ self.assertEquals(self.ggrapher.leaf_ids, [3, 43])
+
+ def test009_sort_order_type_test4(self):
+ # Test the parseInput() method with an invalid sort order.
+ sys.argv = ['geneagrapher', '--node-sort=notreal', '3', '43']
+ self.assertRaises(geneagrapher.BadSortTypeError, self.ggrapher.parseInput)
+
class GeneagrapherTestSuite(unittest.TestSuite):
def __init__(self):
unittest.TestSuite.__init__(self)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/geneagrapher.git
More information about the debian-science-commits
mailing list