diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index dd0744f..85ab7c7 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -133,3 +133,10 @@ Vendored WordPerfect-family test files. Per-file provenance (upstream path, revi - **License:** CDLA-Permissive-1.0 - **Used here:** 2 financial-report pages (`images/doclaynet_page_01..02.jpg`) from the `test` split (`NASDAQ_ATRI_2003.pdf` p24, `NYSE_MGM_2004.pdf` p49). - **Modifications:** authoritative PDF text cells linearized in reading order (top-to-bottom, then left-to-right). No OCR and no model used; text is DocLayNet's verbatim PDF-layer cell text. + +## Diagram fixtures (this repository) + +- **Source:** authored here, not derived from any third-party dataset. +- **License:** same as this repository. +- **Used here:** `diagrams/*.svg` plus their `diagrams/src/*.dot` sources and `ground_truth/dot/*.dot`. +- **Modifications:** four SVGs are rendered from the committed `.dot` sources with Graphviz 15.1.1 (`dot`/`neato`), which is EPL-1.0 licensed; its output is not a derivative of the tool. `nested_transforms.svg` is hand-written. Ground truth is the source graph restated by node label, so it is independent of any recogniser's numbering. diff --git a/diagrams/README.md b/diagrams/README.md new file mode 100644 index 0000000..14821bd --- /dev/null +++ b/diagrams/README.md @@ -0,0 +1,61 @@ +# Diagram fixtures + +Vector diagrams for node/edge recovery (xberg-io/xberg#579). A vector diagram +carries its own graph, so recovery from one is exact rather than probabilistic, +and these fixtures are what say whether it actually is. + +## Why generated, not hand-drawn + +Hand-written SVG exercises almost none of what a real diagram tool emits. The +four SVGs already in `xml/` have no transform chain, no arrowheads, no double +borders and no curved connectors, and a recogniser can pass all four while being +wrong about every file a user would actually bring. + +Rendering a known graph through Graphviz fixes that, and it also gives ground +truth for free: the source `.dot` **is** the correct answer, so the corpus +measures recovery rather than freezing whatever it currently produces. + +## Layout + +| file | exercises | +|---|---| +| `graphviz_flow.svg` | box, diamond and ellipse nodes; arrowheads; edge labels; a dashed edge; root `translate` with negative coordinates | +| `graphviz_states.svg` | `doublecircle` (one node drawn as two concentric outlines); a pair of antiparallel edges between adjacent nodes | +| `graphviz_network.svg` | undirected `--` edges, so no arrowhead anywhere; `neato` layout | +| `graphviz_bidirectional.svg` | `dir=both` and `dir=back` | +| `nested_transforms.svg` | hand-authored: nested `translate`/`scale` groups plus a viewBox that differs from the viewport, so nothing sits at the coordinate it is written at | +| `src/*.dot` | the Graphviz sources, so every SVG above is regenerable | + +`ground_truth/dot/.dot` holds the graph each fixture draws, keyed by node +label rather than by generated id so it does not depend on any one recogniser's +numbering. Two entries are deliberately empty, `data_dashboard` and +`simple_svg`: those files are a bar chart and a two-shape drawing, they are not +diagrams, and recovering a graph from either would be a false positive. + +Ground truth also covers `xml/org_chart.svg` and `xml/flowchart.svg`, which stay +where they are. + +## Regenerate + +``` +brew install graphviz # or apt-get install graphviz +cd diagrams/src +for f in graphviz_flow graphviz_states graphviz_bidirectional; do + dot -Tsvg "$f.dot" -o "../$f.svg" +done +neato -Tsvg graphviz_network.dot -o ../graphviz_network.svg +``` + +Output is stable for a given Graphviz version. This was built with 15.1.1; +a different version may lay the graphs out differently, which changes +coordinates but not the graph, and the ground truth is written in terms of the +graph. + +`nested_transforms.svg` is hand-authored and is not regenerated. + +## Not included + +A vector PDF of the same graph (`dot -Tpdf`) would exercise the PDF path, but +`*.pdf` is excluded from git here and lives in the corpus bucket, so it has to +go through `scripts/publish_corpus.py`. Happy to supply the file for a +maintainer to publish. diff --git a/diagrams/graphviz_bidirectional.svg b/diagrams/graphviz_bidirectional.svg new file mode 100644 index 0000000..8b95e24 --- /dev/null +++ b/diagrams/graphviz_bidirectional.svg @@ -0,0 +1,50 @@ + + + + + + +graphviz_bidirectional + + + +api + +API + + + +db + +Database + + + +api->db + + + + + + +cache + +Cache + + + +api->cache + + + + + +cache->db + + + + + diff --git a/diagrams/graphviz_flow.svg b/diagrams/graphviz_flow.svg new file mode 100644 index 0000000..aea1e67 --- /dev/null +++ b/diagrams/graphviz_flow.svg @@ -0,0 +1,63 @@ + + + + + + +graphviz_flow + + + +a + +Start + + + +b + +Validate + + + +a->b + + + + + +c + +Process + + + +b->c + + +ok + + + +d + +Done + + + +b->d + + +skip + + + +c->d + + + + + diff --git a/diagrams/graphviz_network.svg b/diagrams/graphviz_network.svg new file mode 100644 index 0000000..4807a3d --- /dev/null +++ b/diagrams/graphviz_network.svg @@ -0,0 +1,63 @@ + + + + + + +graphviz_network + + + +gw + +Gateway + + + +s1 + +Switch A + + + +gw--s1 + + + + +s2 + +Switch B + + + +gw--s2 + + + + +h1 + +Host 1 + + + +s1--h1 + + + + +h2 + +Host 2 + + + +s2--h2 + + + + diff --git a/diagrams/graphviz_states.svg b/diagrams/graphviz_states.svg new file mode 100644 index 0000000..9146004 --- /dev/null +++ b/diagrams/graphviz_states.svg @@ -0,0 +1,66 @@ + + + + + + +graphviz_states + + + +idle + +idle + + + +running + +running + + + +idle->running + + +start + + + +paused + +paused + + + +running->paused + + +pause + + + +done + + +done + + + +running->done + + +finish + + + +paused->running + + +resume + + + diff --git a/diagrams/nested_transforms.svg b/diagrams/nested_transforms.svg new file mode 100644 index 0000000..31a01e3 --- /dev/null +++ b/diagrams/nested_transforms.svg @@ -0,0 +1,43 @@ + + + + Nested Transforms + Three-stage pipeline drawn inside translated, scaled and rotated groups + + + + + + + Ingest + + + + + Transform + + + + + Publish + + + + + + + + Quarantine + + + + on error + + + + diff --git a/diagrams/src/graphviz_bidirectional.dot b/diagrams/src/graphviz_bidirectional.dot new file mode 100644 index 0000000..54b6150 --- /dev/null +++ b/diagrams/src/graphviz_bidirectional.dot @@ -0,0 +1,10 @@ +digraph graphviz_bidirectional { + rankdir=LR; + node [shape=box style=filled fillcolor="#fdb462"]; + api [label="API"]; + db [label="Database"]; + cache [label="Cache"]; + api -> db [dir=both]; + api -> cache; + cache -> db [dir=back]; +} diff --git a/diagrams/src/graphviz_flow.dot b/diagrams/src/graphviz_flow.dot new file mode 100644 index 0000000..f00b5e3 --- /dev/null +++ b/diagrams/src/graphviz_flow.dot @@ -0,0 +1,11 @@ +digraph graphviz_flow { + rankdir=TB; + a [label="Start" shape=box style=filled fillcolor="#a6cee3"]; + b [label="Validate" shape=diamond style=filled fillcolor="#b2df8a"]; + c [label="Process" shape=box style=filled fillcolor="#fb9a99"]; + d [label="Done" shape=ellipse style=filled fillcolor="#fdbf6f"]; + a -> b; + b -> c [label="ok"]; + b -> d [label="skip" style=dashed]; + c -> d; +} diff --git a/diagrams/src/graphviz_network.dot b/diagrams/src/graphviz_network.dot new file mode 100644 index 0000000..aed4a52 --- /dev/null +++ b/diagrams/src/graphviz_network.dot @@ -0,0 +1,13 @@ +graph graphviz_network { + layout=neato; + node [shape=ellipse style=filled fillcolor="#cccccc"]; + gw [label="Gateway" fillcolor="#8dd3c7"]; + s1 [label="Switch A" fillcolor="#ffffb3"]; + s2 [label="Switch B" fillcolor="#ffffb3"]; + h1 [label="Host 1"]; + h2 [label="Host 2"]; + gw -- s1; + gw -- s2; + s1 -- h1; + s2 -- h2; +} diff --git a/diagrams/src/graphviz_states.dot b/diagrams/src/graphviz_states.dot new file mode 100644 index 0000000..ecdaa0f --- /dev/null +++ b/diagrams/src/graphviz_states.dot @@ -0,0 +1,9 @@ +digraph graphviz_states { + rankdir=LR; + node [shape=circle style=filled fillcolor="#b3de69"]; + idle -> running [label="start"]; + running -> paused [label="pause"]; + paused -> running [label="resume"]; + running -> done [label="finish"]; + done [shape=doublecircle fillcolor="#fb8072"]; +} diff --git a/ground_truth/dot/data_dashboard.dot b/ground_truth/dot/data_dashboard.dot new file mode 100644 index 0000000..e69de29 diff --git a/ground_truth/dot/flowchart.dot b/ground_truth/dot/flowchart.dot new file mode 100644 index 0000000..8a8f8b4 --- /dev/null +++ b/ground_truth/dot/flowchart.dot @@ -0,0 +1,9 @@ +digraph flowchart { + "Requirements" [shape=box fillcolor="#4a90d9"]; + "Design" [shape=box fillcolor="#50b848"]; + "Implementation" [shape=box fillcolor="#f5a623"]; + "Testing" [shape=box fillcolor="#d0021b"]; + "Requirements" -> "Design"; + "Design" -> "Implementation"; + "Implementation" -> "Testing"; +} diff --git a/ground_truth/dot/graphviz_bidirectional.dot b/ground_truth/dot/graphviz_bidirectional.dot new file mode 100644 index 0000000..cb95d4b --- /dev/null +++ b/ground_truth/dot/graphviz_bidirectional.dot @@ -0,0 +1,8 @@ +digraph graphviz_bidirectional { + "API" [shape=box fillcolor="#fdb462"]; + "Database" [shape=box fillcolor="#fdb462"]; + "Cache" [shape=box fillcolor="#fdb462"]; + "API" -> "Database" [dir=both]; + "API" -> "Cache"; + "Database" -> "Cache"; +} diff --git a/ground_truth/dot/graphviz_flow.dot b/ground_truth/dot/graphviz_flow.dot new file mode 100644 index 0000000..520333f --- /dev/null +++ b/ground_truth/dot/graphviz_flow.dot @@ -0,0 +1,10 @@ +digraph graphviz_flow { + "Start" [shape=box fillcolor="#a6cee3"]; + "Validate" [shape=diamond fillcolor="#b2df8a"]; + "Process" [shape=box fillcolor="#fb9a99"]; + "Done" [shape=ellipse fillcolor="#fdbf6f"]; + "Start" -> "Validate"; + "Validate" -> "Process" [label="ok"]; + "Validate" -> "Done" [label="skip" style=dashed]; + "Process" -> "Done"; +} diff --git a/ground_truth/dot/graphviz_network.dot b/ground_truth/dot/graphviz_network.dot new file mode 100644 index 0000000..e7642b4 --- /dev/null +++ b/ground_truth/dot/graphviz_network.dot @@ -0,0 +1,11 @@ +digraph graphviz_network { + "Gateway" [shape=ellipse fillcolor="#8dd3c7"]; + "Switch A" [shape=ellipse fillcolor="#ffffb3"]; + "Switch B" [shape=ellipse fillcolor="#ffffb3"]; + "Host 1" [shape=ellipse fillcolor="#cccccc"]; + "Host 2" [shape=ellipse fillcolor="#cccccc"]; + "Gateway" -> "Switch A"; + "Gateway" -> "Switch B"; + "Switch A" -> "Host 1"; + "Switch B" -> "Host 2"; +} diff --git a/ground_truth/dot/graphviz_states.dot b/ground_truth/dot/graphviz_states.dot new file mode 100644 index 0000000..b68677b --- /dev/null +++ b/ground_truth/dot/graphviz_states.dot @@ -0,0 +1,10 @@ +digraph graphviz_states { + "idle" [shape=ellipse fillcolor="#b3de69"]; + "running" [shape=ellipse fillcolor="#b3de69"]; + "paused" [shape=ellipse fillcolor="#b3de69"]; + "done" [shape=ellipse fillcolor="#fb8072"]; + "idle" -> "running" [label="start"]; + "running" -> "paused" [label="pause"]; + "paused" -> "running" [label="resume"]; + "running" -> "done" [label="finish"]; +} diff --git a/ground_truth/dot/nested_transforms.dot b/ground_truth/dot/nested_transforms.dot new file mode 100644 index 0000000..18a1822 --- /dev/null +++ b/ground_truth/dot/nested_transforms.dot @@ -0,0 +1,9 @@ +digraph nested_transforms { + "Ingest" [shape=box fillcolor="#4e79a7"]; + "Transform" [shape=box fillcolor="#f28e2b"]; + "Publish" [shape=box fillcolor="#59a14f"]; + "Quarantine" [shape=box fillcolor="#e15759" style=dashed]; + "Ingest" -> "Transform"; + "Transform" -> "Publish"; + "Transform" -> "Quarantine" [label="on error" style=dashed]; +} diff --git a/ground_truth/dot/org_chart.dot b/ground_truth/dot/org_chart.dot new file mode 100644 index 0000000..a0f0d72 --- /dev/null +++ b/ground_truth/dot/org_chart.dot @@ -0,0 +1,14 @@ +digraph org_chart { + "Jane Smith\nChief Executive Officer" [shape=box fillcolor="#2c3e50"]; + "Bob Chen\nChief Technology Officer" [shape=box fillcolor="#2980b9"]; + "Maria Garcia\nChief Financial Officer" [shape=box fillcolor="#27ae60"]; + "Alex Johnson\nChief Operating Officer" [shape=box fillcolor="#8e44ad"]; + "Engineering" [shape=box fillcolor="#3498db"]; + "Product" [shape=box fillcolor="#3498db"]; + "Finance" [shape=box fillcolor="#2ecc71"]; + "Sales" [shape=box fillcolor="#9b59b6"]; + "Operations" [shape=box fillcolor="#9b59b6"]; + "Jane Smith\nChief Executive Officer" -> "Bob Chen\nChief Technology Officer"; + "Jane Smith\nChief Executive Officer" -> "Maria Garcia\nChief Financial Officer"; + "Jane Smith\nChief Executive Officer" -> "Alex Johnson\nChief Operating Officer"; +} diff --git a/ground_truth/dot/simple_svg.dot b/ground_truth/dot/simple_svg.dot new file mode 100644 index 0000000..e69de29 diff --git a/ground_truth/ground_truth_mapping.json b/ground_truth/ground_truth_mapping.json index d5ce093..6344531 100644 --- a/ground_truth/ground_truth_mapping.json +++ b/ground_truth/ground_truth_mapping.json @@ -102,6 +102,15 @@ "docx_rich_cells.docx": "test_documents/ground_truth/json/docx_rich_cells.docx.txt", "docx_simple": "test_documents/ground_truth/docx/docx_simple.txt", "docx_tables": "test_documents/ground_truth/docx/docx_tables.txt", + "dot_data_dashboard": "test_documents/ground_truth/dot/data_dashboard.dot", + "dot_flowchart": "test_documents/ground_truth/dot/flowchart.dot", + "dot_graphviz_bidirectional": "test_documents/ground_truth/dot/graphviz_bidirectional.dot", + "dot_graphviz_flow": "test_documents/ground_truth/dot/graphviz_flow.dot", + "dot_graphviz_network": "test_documents/ground_truth/dot/graphviz_network.dot", + "dot_graphviz_states": "test_documents/ground_truth/dot/graphviz_states.dot", + "dot_nested_transforms": "test_documents/ground_truth/dot/nested_transforms.dot", + "dot_org_chart": "test_documents/ground_truth/dot/org_chart.dot", + "dot_simple_svg": "test_documents/ground_truth/dot/simple_svg.dot", "drawingml.docx": "test_documents/ground_truth/json/drawingml.docx.txt", "duck.md": "test_documents/ground_truth/md/duck.md.txt", "duplicate-paragraphs": "test_documents/ground_truth/doc/duplicate-paragraphs.txt",