Skip to content

Commit

Permalink
graphviewer: Allow to explicitely switch on/off temp-syn
Browse files Browse the repository at this point in the history
  • Loading branch information
thvitt committed Jul 13, 2020
1 parent 601e5da commit 534e3ca
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 6 deletions.
7 changes: 5 additions & 2 deletions src/graphviewer/graphviewer.py
Expand Up @@ -43,14 +43,17 @@ def prepare_agraph():
no_edge_labels = request.values.get('no_edge_labels', False)
tred = request.values.get('tred', False)
nohl = request.values.get('nohl', False)
syn = request.values.get('syn', False)
if nodes:
g = info.subgraph(*nodes, context=context, abs_dates=abs_dates, paths=extra, keep_timeline=True,
paths_without_timeline=paths_wo_timeline,
direct_assertions=direct_assertions)
direct_assertions=direct_assertions, include_syn_clusters=syn)
if induced_edges:
g = info.base.subgraph(g.nodes).copy()
if not ignored_edges or tred:
g = remove_edges(g, lambda u, v, attr: attr.get('ignore', False))
g = remove_edges(g, lambda u, v, attr: attr.get('ignore', False) and not attr.get('kind', '') == 'temp-syn')
if not syn:
g = remove_edges(g, lambda u, v, attr: attr.get('kind', None) == "temp-syn")
if tred:
g = remove_edges(g, lambda u, v, attr: attr.get('delete', False))
if tred:
Expand Down
1 change: 1 addition & 0 deletions src/graphviewer/templates/form.html
Expand Up @@ -63,6 +63,7 @@ <h3>Zusätzliche Pfade</h3>
<h3>Kantenauswahl und -gestaltung:</h3>
<p><input type="checkbox" name="induced_edges" id="induced_edges" {% if induced_edges %}checked{% endif %}> <label for="induced_edges">alle induzierten Kanten</label></p>
<p><input type="checkbox" name="ignored_edges" id="ignored_edges" {% if ignored_edges %}checked{% endif %}> <label for="ignored_edges">ignorierte (graue) Kanten</label> </p>
<p><input type="checkbox" name="syn" id="syn" {% if syn %}checked{% endif %}> <label for="syn">Kanten für »ungefähr gleichzeitig«</label> </p>
<p><input type="checkbox" name="tred" id="tred" {% if tred %}checked{% endif %}> <label for="tred">Transitive Reduktion</label> </p>
<p><input type="checkbox" name="no_edge_labels" id="no_edge_labels" {% if no_edge_labels %}checked{% endif %}> <label for="no_edge_labels">keine Kantenbeschriftung</label> </p>
</form>
Expand Down
11 changes: 9 additions & 2 deletions src/macrogen/graph.py
Expand Up @@ -18,7 +18,7 @@
import pandas as pd
from dataclasses import dataclass

from macrogen.graphutils import is_orphan
from macrogen.graphutils import is_orphan, find_reachable_by_edge

from .graphutils import mark_edges_to_delete, remove_edges, in_path, first
from .bibliography import BiblSource
Expand Down Expand Up @@ -637,7 +637,7 @@ def add_path(self, graph: nx.MultiDiGraph, source: Node, target: Node, weight='i
def subgraph(self, *nodes: Node, context: bool = True, path_to: Iterable[Node] = {}, abs_dates: bool = True,
path_from: Iterable[Node] = {}, paths: Iterable[Node] = {}, paths_without_timeline: bool = False,
paths_between_nodes: bool = True, keep_timeline: bool = False, direct_assertions: bool = False,
temp_syn_context: bool = False) \
temp_syn_context: bool = False, include_syn_clusters: bool = False) \
-> nx.MultiDiGraph:
"""
Extracts a sensible subgraph from the base graph.
Expand Down Expand Up @@ -682,6 +682,13 @@ def subgraph(self, *nodes: Node, context: bool = True, path_to: Iterable[Node] =
if context:
for node in central_nodes:
relevant_nodes |= set(self.dag.pred[node]).union(self.dag.succ[node])

if include_syn_clusters:
for node in central_nodes:
cluster = find_reachable_by_edge(self.base, node, 'kind', 'temp-syn')
logger.info("syn-cluster: including %s", cluster)
relevant_nodes |= cluster

if temp_syn_context:
for node in set(relevant_nodes):
if isinstance(node, SynAnchor):
Expand Down
35 changes: 33 additions & 2 deletions src/macrogen/graphutils.py
@@ -1,7 +1,7 @@
from collections import defaultdict
from datetime import date
from pathlib import Path
from typing import List, Iterable, Tuple, Any, Generator, Union, TypeVar, Callable, Dict, Sequence, Optional
from typing import List, Iterable, Tuple, Any, Generator, Union, TypeVar, Callable, Dict, Sequence, Optional, Set

import networkx as nx

Expand Down Expand Up @@ -280,4 +280,35 @@ def base_n(number: int, base: int = 10, neg: Optional[str] = '-') -> str:


def is_orphan(node, graph: nx.DiGraph):
return node not in graph.nodes or graph.in_degree[node] == 0 and graph.out_degree[node] == 0
return node not in graph.nodes or graph.in_degree[node] == 0 and graph.out_degree[node] == 0


def find_reachable_by_edge(graph: nx.MultiDiGraph, source: T, key, value, symmetric=True) -> Set[T]:
"""
Finds all nodes that are reachable via edges with a certain attribute/value combination.
Args:
graph: the graph we're searching in
source: the source node
key: attribute key we're looking for
value: attribute vaue we're looking for
Returns:
a set of nodes, includes at least source
"""
result = set()
todo = [source]
while todo:
logger.warn('looking for %s=%s, todo: %s, result: %s', key, value, todo, result)
node = todo.pop()
if node in result:
continue
result.add(node)
items = list(graph[node].items())
if symmetric:
items.extend(graph.pred[node].items())
for neighbor, edges in items:
for k, attr in edges.items():
if key in attr and attr[key] == value:
todo.insert(0, neighbor)
return result

0 comments on commit 534e3ca

Please sign in to comment.