Skip to content

Commit

Permalink
Collapse timeline in conflict graphs.
Browse files Browse the repository at this point in the history
This removes 'inner' timeline nodes that don't carry any useful
information.
  • Loading branch information
thvitt committed Mar 5, 2019
1 parent e103498 commit 5738961
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 5 deletions.
33 changes: 31 additions & 2 deletions src/macrogen/graph.py
Expand Up @@ -3,11 +3,11 @@
"""

import csv
from collections import defaultdict, Counter, Sequence
from collections import defaultdict, Counter
from dataclasses import dataclass
from datetime import date, timedelta
from pathlib import Path
from typing import List, Callable, Any, Dict, Tuple, Union, Iterable, Generator
from typing import List, Callable, Any, Dict, Tuple, Union, Iterable, Generator, Sequence, TypeVar

import networkx as nx

Expand Down Expand Up @@ -249,6 +249,35 @@ def collapse_edges_by_source(graph: nx.MultiDiGraph) -> nx.MultiDiGraph:
return result


T = TypeVar('T')
S = TypeVar('S')


def first(sequence: Iterable[T], default: S = None) -> Union[T, S]:
try:
return next(iter(sequence))
except StopIteration:
return default


def collapse_timeline(graph: nx.MultiDiGraph) -> nx.MultiDiGraph:
"""
Returns a new graph in which unneeded datetime nodes are removed.
"""
g: nx.MultiDiGraph = graph.copy()
timeline = sorted(node for node in g.nodes() if isinstance(node, date))
if not timeline:
return g # nothing to do
for node in timeline[1:]:
pred = first(g.predecessors(node))
succ = first(g.successors(node))
if g.in_degree(node) == 1 and g.out_degree(node) == 1 \
and isinstance(pred, date) and isinstance(succ, date):
g.add_edge(pred, succ, **g[pred][node][0])
g.remove_node(node)
return g


@dataclass
class MacrogenesisInfo:
base: nx.MultiDiGraph
Expand Down
6 changes: 3 additions & 3 deletions src/macrogen/report.py
Expand Up @@ -20,7 +20,7 @@

from .config import config
from .bibliography import BiblSource
from .graph import MacrogenesisInfo, pathlink, EARLIEST, LATEST, DAY
from .graph import MacrogenesisInfo, pathlink, EARLIEST, LATEST, DAY, collapse_timeline
from .uris import Reference, Witness, Inscription, UnknownRef, AmbiguousRef
from .visualize import write_dot, simplify_graph

Expand Down Expand Up @@ -657,10 +657,10 @@ def _report_conflict(graphs: MacrogenesisInfo, u, v):
except nx.NodeNotFound:
logger.exception('Node not found!? %s or %s', u, v)
counter_html = ''
subgraph: nx.MultiDiGraph = nx.subgraph(graphs.base, relevant_nodes).copy()
subgraph: nx.MultiDiGraph = collapse_timeline(nx.subgraph(graphs.base, relevant_nodes))

# Highlight conflicting edges, counter path and the two nodes of the conflicting edge(s)
for v1, v2 in [(u, v)] + list(pairwise(counter_path)):
for v1, v2 in [(u, v)] + list(pairwise(nx.shortest_path(subgraph, v, u))):
for k, attr in subgraph.get_edge_data(v1, v2).items():
attr['highlight'] = True
subgraph.node[u]['highlight'] = True
Expand Down

0 comments on commit 5738961

Please sign in to comment.