GraphML Export¶
The graphml render type produces a GraphML
document that can be opened directly in yEd Graph Editor.
Edges are colored on a six-stop perceptual gradient derived from a composite
narrative tension score.
How to export¶
# Start the API server
docker compose up -d
# Ingest a narrative
curl -X POST http://localhost:8000/v1/notes/import \
-H "Content-Type: application/json" \
-d '{"title": "My Story", "text": "Alice locked the door. Bob arrived and tried the handle. He could not enter."}'
# Export as GraphML (replace <narrative_id> with the returned ID)
curl -X POST http://localhost:8000/v1/render/<narrative_id> \
-H "Content-Type: application/json" \
-d '{"type": "graphml"}' \
| jq -r '.content' > my_story.graphml
Opening in yEd¶
- Launch yEd Graph Editor (version 3.x or later).
- File → Open and select
my_story.graphml. - yEd reads the yFiles extension keys (
d3for node graphics,d6for edge graphics) and applies colors automatically. - Use Layout → Hierarchical (or Organic) for a readable layout — yEd does not auto-layout on import.
- The Properties panel shows each node/edge's
tension_scoreattribute (d8key), useful for filtering high-tension edges.
Node color legend¶
| Node type | Color | Hex |
|---|---|---|
| Narrative | Blue | #4A90D9 |
| Scene | Green | #7ED321 |
| Atom | Amber | #F5A623 |
| Event | Red | #D0021B |
| PatternInstance | Purple | #9B59B6 |
| Pattern | Dark red | #C0392B |
| Perspective | Teal | #1ABC9C |
| MoodState | Coral | #E74C3C |
| GenreProfile | Sky blue | #3498DB |
| Chronotope | Dark green | #27AE60 |
| CodeTag | Orange | #F39C12 |
| Transform | Grey | #95A5A6 |
| Character | Violet | #8E44AD |
Edge tension scoring¶
Tension is a composite score in [0.0, 1.0] combining three signals:
1. Relationship type (base score)¶
| Relationship | Base score | Rationale |
|---|---|---|
PREVENTS |
0.9 | Highest conflict; direct opposition of agency |
CAUSES |
0.7 | Strong causal force; irreversible consequence |
PARTICIPATES_IN |
0.4 | Character involvement; stakes present |
ENABLES |
0.4 | Facilitation; indirect force |
PRECEDES |
0.2 | Temporal sequence; low inherent tension |
Structural (HAS_SCENE, CONTAINS, etc.) |
0.0 | Containment; no narrative force |
2. Barthesian code modifier (additive)¶
Only the highest-ranking code tag in the source scene contributes, preventing inflation from heavily-tagged scenes.
| Code | Bonus | Rationale |
|---|---|---|
HERMENEUTIC |
+0.4 | Unresolved mystery — maximum reader tension |
PROAIRETIC |
+0.3 | Imminent action — suspense |
SYMBOLIC |
+0.2 | Thematic opposition — latent tension |
SEMIC |
+0.1 | Connotative load — background unease |
CULTURAL |
+0.0 | Shared knowledge — neutral |
3. Scene mood modifier (additive)¶
High arousal combined with negative valence produces the anxious mood profile most associated with narrative tension.
Maximum mood contribution: +0.6 (arousal = 1.0, valence = −1.0).
Final score¶
Edge color gradient¶
Six stops map the [0.0, 1.0] range to a perceptual gradient. Colors were chosen to remain distinguishable under common forms of color-vision deficiency (the grey → blue axis is distinguishable from grey → red for protanopia / deuteranopia).
graph LR
A["0.0 · #A0A0A0 · grey"]
B["0.2 · #4682B4 · steel-blue"]
C["0.4 · #DAA520 · gold"]
D["0.6 · #FF8C00 · orange"]
E["0.8 · #DC143C · crimson"]
F["1.0 · #8B0000 · dark-red"]
A --> B --> C --> D --> E --> F
| Stop | Score | Color | Hex |
|---|---|---|---|
| 1 | 0.0 | Grey | #A0A0A0 |
| 2 | 0.2 | Steel blue | #4682B4 |
| 3 | 0.4 | Goldenrod | #DAA520 |
| 4 | 0.6 | Dark orange | #FF8C00 |
| 5 | 0.8 | Crimson | #DC143C |
| 6 | 1.0 | Dark red | #8B0000 |
Colors between stops are linearly interpolated in RGB space.
Architecture¶
The GraphML feature follows the existing Strategy renderer pattern:
classDiagram
class RendererProtocol {
<<Protocol>>
+render(graph_state, params) RenderOutput
}
class GraphMLRenderer {
+render(graph_state, params) RenderOutput
}
class TensionScorer {
+score_edge(relation_type, atoms, mood) TensionScore
+score_structural_edge() TensionScore
}
class _GraphMLBuilder {
-_walk()
-_serialise() str
}
RendererProtocol <|.. GraphMLRenderer
GraphMLRenderer --> _GraphMLBuilder
_GraphMLBuilder --> TensionScorer
tension_scorer.py— pure scoring functions; no XML or graph concerns.graphml_renderer.py— XML construction only; delegates tension scoring.- Neither module issues Cypher; all data arrives as a
GraphStatesnapshot fromRenderService.
Module reference¶
tng.renderers.graphml_renderer
¶
GraphML renderer — yEd-compatible export with tension-coloured edges.
Implements RendererProtocol. Traverses a GraphState snapshot and
produces a GraphML document that can be opened directly in yEd Graph Editor.
Node colouring by label type:
+-------------------+--------------------+ | Node label | Fill colour | +===================+====================+ | Narrative | #4A90D9 (blue) | | Scene | #7ED321 (green) | | Atom | #F5A623 (amber) | | Event | #D0021B (red) | | PatternInstance | #9B59B6 (purple) | | Pattern | #C0392B (dark-red) | | Perspective | #1ABC9C (teal) | | MoodState | #E74C3C (coral) | | GenreProfile | #3498DB (sky-blue) | | Chronotope | #27AE60 (dark-grn) | | CodeTag | #F39C12 (orange) | | Transform | #95A5A6 (grey) | | Character | #8E44AD (violet) | +-------------------+--------------------+
Edge colouring by narrative tension:
Edges are coloured by a composite tension score computed by
tension_scorer.score_edge(). The six-stop gradient runs from neutral
grey (0.0) through steel-blue → gold → orange → crimson to dark-red (1.0).
yEd import: File → Open → select the .graphml file. The yFiles
extension keys (d3/d6 for node/edge graphics) are automatically
interpreted when the file is opened in yEd 3.x or later.
GraphMLRenderer
¶
Renders a GraphState as a yEd-compatible GraphML document.
Edges are coloured by narrative tension (see tension_scorer).
Structural containment edges (HAS_SCENE, CONTAINS, etc.) are rendered
in neutral grey; causal/preventive event relations are coloured on the
full tension gradient.
:method render: Convert GraphState to a GraphML XML string.
Source code in src/tng/renderers/graphml_renderer.py
render(graph_state, params)
¶
Produce a yEd-compatible GraphML document from the graph state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph_state
|
GraphState
|
Complete narrative snapshot. |
required |
params
|
dict[str, Any]
|
Optional renderer parameters (currently unused). |
required |
Returns:
| Type | Description |
|---|---|
RenderOutput
|
|
Source code in src/tng/renderers/graphml_renderer.py
tng.renderers.tension_scorer
¶
Narrative tension scoring for GraphML edge visualisation.
Tension is a composite score in [0.0, 1.0] derived from three sources:
- Relationship type — causal/preventive relations carry more tension than
temporal ones (base scores defined in
RELATION_BASE). - Barthesian codes — atoms tagged with HERMENEUTIC or PROAIRETIC codes signal unresolved mystery or imminent action, boosting tension.
- Scene mood — high arousal combined with negative valence produces the anxious state associated with peak narrative tension.
The final score is clamped to [0.0, 1.0] and mapped through a six-stop perceptual gradient from neutral grey to deep red. The colour values are chosen so that even viewers with common forms of colour-vision deficiency can perceive the low→high gradient (grey→blue is distinguishable from grey→red for protanopia/deuteranopia).
TensionScore
dataclass
¶
Tension assessment for a single edge.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
score
|
float
|
Composite tension value in [0.0, 1.0]. |
required |
hex_color
|
str
|
Six-character hex RGB string (e.g. |
required |
base
|
float
|
Base score from relationship type alone. |
required |
code_bonus
|
float
|
Additive modifier from Barthesian codes. |
required |
mood_bonus
|
float
|
Additive modifier from scene mood. |
required |
Source code in src/tng/renderers/tension_scorer.py
score_edge(relation_type, atoms=None, mood=None)
¶
Compute a tension score for a single graph edge.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
relation_type
|
str
|
The Cypher relationship type string
(e.g. |
required |
atoms
|
Sequence[Atom] | None
|
Atoms in the source scene whose code tags contribute
Barthesian code modifiers. Pass |
None
|
mood
|
MoodState | None
|
The active |
None
|
Returns:
| Type | Description |
|---|---|
TensionScore
|
A |
Source code in src/tng/renderers/tension_scorer.py
score_structural_edge(label='')
¶
Return a zero-tension score for structural/containment edges.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
Optional label for the edge (unused, kept for call-site readability). |
''
|
Returns:
| Type | Description |
|---|---|
TensionScore
|
A |