codefig 0.17.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. codefig-0.17.0/LICENSE +21 -0
  2. codefig-0.17.0/PKG-INFO +542 -0
  3. codefig-0.17.0/README.md +506 -0
  4. codefig-0.17.0/pyproject.toml +50 -0
  5. codefig-0.17.0/setup.cfg +4 -0
  6. codefig-0.17.0/src/codefig/__init__.py +210 -0
  7. codefig-0.17.0/src/codefig/_validate.py +12 -0
  8. codefig-0.17.0/src/codefig/autowrap.py +277 -0
  9. codefig-0.17.0/src/codefig/charts.py +1806 -0
  10. codefig-0.17.0/src/codefig/code.py +602 -0
  11. codefig-0.17.0/src/codefig/compose.py +374 -0
  12. codefig-0.17.0/src/codefig/constraints.py +1571 -0
  13. codefig-0.17.0/src/codefig/dim.py +214 -0
  14. codefig-0.17.0/src/codefig/edge_align.py +231 -0
  15. codefig-0.17.0/src/codefig/edges.py +2824 -0
  16. codefig-0.17.0/src/codefig/export.py +204 -0
  17. codefig-0.17.0/src/codefig/figure.py +1923 -0
  18. codefig-0.17.0/src/codefig/fills.py +146 -0
  19. codefig-0.17.0/src/codefig/flows.py +102 -0
  20. codefig-0.17.0/src/codefig/glyphs.py +395 -0
  21. codefig-0.17.0/src/codefig/icon.py +288 -0
  22. codefig-0.17.0/src/codefig/icons/LICENSE-tabler-icons.txt +21 -0
  23. codefig-0.17.0/src/codefig/icons/__init__.py +101 -0
  24. codefig-0.17.0/src/codefig/icons/tabler.json +1 -0
  25. codefig-0.17.0/src/codefig/legend.py +483 -0
  26. codefig-0.17.0/src/codefig/lint.py +1737 -0
  27. codefig-0.17.0/src/codefig/lint_geom.py +528 -0
  28. codefig-0.17.0/src/codefig/node.py +864 -0
  29. codefig-0.17.0/src/codefig/notices.py +34 -0
  30. codefig-0.17.0/src/codefig/overlaps.py +392 -0
  31. codefig-0.17.0/src/codefig/policy.py +137 -0
  32. codefig-0.17.0/src/codefig/primitives.py +2721 -0
  33. codefig-0.17.0/src/codefig/py.typed +0 -0
  34. codefig-0.17.0/src/codefig/regions.py +727 -0
  35. codefig-0.17.0/src/codefig/render_svg.py +512 -0
  36. codefig-0.17.0/src/codefig/routing.py +932 -0
  37. codefig-0.17.0/src/codefig/shapes.py +642 -0
  38. codefig-0.17.0/src/codefig/solids.py +514 -0
  39. codefig-0.17.0/src/codefig/steps.py +203 -0
  40. codefig-0.17.0/src/codefig/styles.py +893 -0
  41. codefig-0.17.0/src/codefig/textutil.py +889 -0
  42. codefig-0.17.0/src/codefig/timeline.py +1288 -0
  43. codefig-0.17.0/src/codefig/tree.py +277 -0
  44. codefig-0.17.0/src/codefig/venues.py +93 -0
  45. codefig-0.17.0/src/codefig.egg-info/PKG-INFO +542 -0
  46. codefig-0.17.0/src/codefig.egg-info/SOURCES.txt +73 -0
  47. codefig-0.17.0/src/codefig.egg-info/dependency_links.txt +1 -0
  48. codefig-0.17.0/src/codefig.egg-info/requires.txt +6 -0
  49. codefig-0.17.0/src/codefig.egg-info/top_level.txt +1 -0
  50. codefig-0.17.0/tests/test_back_edges.py +145 -0
  51. codefig-0.17.0/tests/test_block_tracks.py +40 -0
  52. codefig-0.17.0/tests/test_codeblock_tokens.py +33 -0
  53. codefig-0.17.0/tests/test_color_strict.py +40 -0
  54. codefig-0.17.0/tests/test_constraints.py +221 -0
  55. codefig-0.17.0/tests/test_docs.py +104 -0
  56. codefig-0.17.0/tests/test_fig2_features.py +286 -0
  57. codefig-0.17.0/tests/test_fit_aspect.py +135 -0
  58. codefig-0.17.0/tests/test_flagship.py +15 -0
  59. codefig-0.17.0/tests/test_legend_corner.py +77 -0
  60. codefig-0.17.0/tests/test_lint.py +188 -0
  61. codefig-0.17.0/tests/test_round1.py +300 -0
  62. codefig-0.17.0/tests/test_round2.py +284 -0
  63. codefig-0.17.0/tests/test_round3.py +329 -0
  64. codefig-0.17.0/tests/test_v0100.py +199 -0
  65. codefig-0.17.0/tests/test_v0110.py +173 -0
  66. codefig-0.17.0/tests/test_v0120.py +228 -0
  67. codefig-0.17.0/tests/test_v0130.py +242 -0
  68. codefig-0.17.0/tests/test_v0140.py +38 -0
  69. codefig-0.17.0/tests/test_v0160.py +63 -0
  70. codefig-0.17.0/tests/test_v0170.py +63 -0
  71. codefig-0.17.0/tests/test_v019.py +252 -0
  72. codefig-0.17.0/tests/test_v060.py +206 -0
  73. codefig-0.17.0/tests/test_v070.py +244 -0
  74. codefig-0.17.0/tests/test_v080.py +194 -0
  75. codefig-0.17.0/tests/test_v090.py +252 -0
codefig-0.17.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Justin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,542 @@
1
+ Metadata-Version: 2.4
2
+ Name: codefig
3
+ Version: 0.17.0
4
+ Summary: Research-paper figures from code: compose layout primitives, get venue-width, lint-checked PDF/SVG/PNG. AI-friendly (llms.txt).
5
+ Author: Justin
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/justinhk001/codefig
8
+ Project-URL: Documentation, https://github.com/justinhk001/codefig/tree/main/docs
9
+ Project-URL: Repository, https://github.com/justinhk001/codefig
10
+ Project-URL: Issues, https://github.com/justinhk001/codefig/issues
11
+ Project-URL: Changelog, https://github.com/justinhk001/codefig/blob/main/CHANGELOG.md
12
+ Keywords: research figures,scientific figures,diagrams,paper,LaTeX,architecture diagram,academic,publication,svg,pdf,layout,visualization,LLM,AI,llms.txt
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Scientific/Engineering :: Visualization
24
+ Classifier: Topic :: Multimedia :: Graphics
25
+ Classifier: Topic :: Text Processing :: Markup :: LaTeX
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.10
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Requires-Dist: cairosvg>=2.7
31
+ Requires-Dist: pillow>=10
32
+ Requires-Dist: kiwisolver>=1.4
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ <div align="center">
38
+ <h1>codefig</h1>
39
+
40
+ **Paper figures as code: no coordinates, real column widths, a linter for figures.**
41
+
42
+ Compose architecture, memory, pipeline and attention diagrams in Python.
43
+ Design at print size, inspect the result, and keep the source alongside your paper.
44
+
45
+ ![PyPI](https://img.shields.io/pypi/v/codefig)
46
+ ![Python](https://img.shields.io/pypi/pyversions/codefig)
47
+ ![MIT](https://img.shields.io/badge/license-MIT-blue)
48
+ ![CI](https://github.com/justinhk001/codefig/actions/workflows/ci.yml/badge.svg)
49
+
50
+ [Quickstart](#quickstart) · [Gallery](#gallery) · [Why](#why-codefig) · [Docs](#documentation) · [AI](#ai-first-authoring)
51
+
52
+ [English](https://github.com/justinhk001/codefig/blob/main/README.md) | [简体中文](https://github.com/justinhk001/codefig/blob/main/README.zh-CN.md)
53
+
54
+ <img src="https://raw.githubusercontent.com/justinhk001/codefig/main/docs/assets/flagship.png" width="90%" alt="Original LLM serving architecture, overlap schedule and illustrative tradeoff">
55
+
56
+ </div>
57
+
58
+ ## Flagship example
59
+
60
+ An original disaggregated LLM serving design with nested GPU/CPU groups, an overlap timeline, and illustrative throughput–latency curves. [Read the source](https://github.com/justinhk001/codefig/blob/main/examples/flagship_llm_serving.py).
61
+
62
+
63
+ <a id="why-codefig"></a>
64
+
65
+ ## Why codefig
66
+
67
+ Drawing a paper figure often means nudging boxes in draw.io or PowerPoint,
68
+ then discovering that LaTeX scaling made the labels 4 pt tall.
69
+ TikZ makes the source reviewable, but detailed placement can still take time.
70
+ Colours drift between panels; every reviewer comment can trigger another redraw.
71
+
72
+ codefig makes the composition explicit and checks the exported result:
73
+
74
+ - **Layout instead of coordinates:** describe rows, columns, groups and relationships.
75
+ - **Real venue widths:** choose the final column or text width before drawing.
76
+ - **Publication defaults:** shared typography, stroke roles and semantic categories.
77
+ - **Figure lint:** catch small text, collisions, missing keys and export problems.
78
+ - **Reviewable Python:** version the structure, labels and data with your manuscript.
79
+
80
+ ### An honest comparison
81
+
82
+ ✅ natural strength · ⚠️ possible with setup or tradeoffs · ❌ not the intended workflow.
83
+ This is a workflow comparison, not a benchmark of every extension.
84
+
85
+ | Capability | codefig | matplotlib | TikZ | draw.io | Mermaid | Graphviz |
86
+ |---|---|---|---|---|---|---|
87
+ | No manual coordinates | ✅ | ⚠️ | ⚠️ | ⚠️ | ✅ | ✅ |
88
+ | Diffable code/text source | ✅ | ✅ | ✅ | ⚠️ XML | ✅ | ✅ |
89
+ | Layout at real venue width | ✅ presets | ⚠️ figsize | ✅ TeX | ⚠️ | ⚠️ | ⚠️ |
90
+ | Built-in paper figure lint | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
91
+ | Publication theme | ✅ | ⚠️ styles | ✅ control | ⚠️ | ⚠️ | ⚠️ |
92
+ | CVD-safe palette workflow | ✅ | ✅ palettes | ⚠️ | ⚠️ | ⚠️ | ⚠️ |
93
+ | Rich data plotting | ⚠️ embedded charts | ✅ | ✅ PGFPlots | ❌ | ⚠️ | ❌ |
94
+ | Freehand editing | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
95
+ | Huge auto-laid graphs | ❌ | ❌ | ⚠️ | ⚠️ | ⚠️ | ✅ |
96
+ | Gentle learning curve | ⚠️ Python | ⚠️ Python | ❌ | ✅ | ✅ | ⚠️ DOT |
97
+ | Ecosystem maturity | ⚠️ pre-1.0 | ✅ | ✅ | ✅ | ✅ | ✅ |
98
+ | Ultimate typography/control | ⚠️ | ⚠️ | ✅ | ⚠️ | ⚠️ | ⚠️ |
99
+
100
+ ### When NOT to use codefig
101
+
102
+ - Use matplotlib for exploratory analysis, scientific axes and specialised plots.
103
+ - Use draw.io for direct mouse editing and unconstrained visual sketches.
104
+ - Use Graphviz for large automatically laid-out dependency graphs.
105
+ - Use TikZ when precise TeX typography and unrestricted control dominate.
106
+ - Use Mermaid when a short Markdown diagram is the whole requirement.
107
+
108
+ <a id="quickstart"></a>
109
+
110
+ ## Quickstart
111
+
112
+ ```sh
113
+ pip install codefig
114
+ ```
115
+
116
+ Three boxes, two semantic categories, two edges, and an automatic legend.
117
+
118
+ ```python
119
+ from codefig import Figure, Box, Row, Col, Diagram, Edge, Legend
120
+
121
+ fig = Figure(venue="icml", width="column", panel_caption="none")
122
+ enc = Box("Encoder", category="model")
123
+ kv = Box("KV cache", category="memory")
124
+ dec = Box("Decoder", category="model")
125
+ body = Col([Col([enc, kv, dec], gap=18), Legend(direction="row")], gap=10)
126
+ with fig.panel("a") as p:
127
+ p += Diagram(body, [Edge(enc.port("bottom"), kv.port("top")),
128
+ Edge(kv.port("bottom"), dec.port("top"))])
129
+ alt = "Encoder writes a KV cache read by the decoder."
130
+ print(fig.lint(alt=alt))
131
+ fig.save("quickstart.png", alt=alt)
132
+ fig.save("quickstart.pdf", alt=alt)
133
+ ```
134
+
135
+ ```text
136
+ codefig lint (icml, 234 pt): 0 error(s), 0 warning(s), 0 info
137
+ ```
138
+
139
+ ![Quickstart](https://raw.githubusercontent.com/justinhk001/codefig/main/docs/assets/quickstart.png)
140
+
141
+ The example uses a vertical composition to fit a column without shrinking labels.
142
+ Change the labels and categories first; let the containers handle placement.
143
+ `Legend()` collects the categories automatically.
144
+
145
+ Include the PDF at its native width:
146
+
147
+ ```tex
148
+ \includegraphics{quickstart.pdf}
149
+ ```
150
+
151
+ Do not add a width here: the PDF is already designed at the exact column width.
152
+ Keeping that size preserves the intended 6–8 pt theme typography.
153
+ If the composition grows too wide, reflow it and re-lint rather than scaling it down.
154
+
155
+ <a id="gallery"></a>
156
+
157
+ ## Gallery
158
+
159
+ Original demonstrations and cookbook recipes; click an image for runnable source.
160
+
161
+ <table>
162
+ <tr>
163
+ <td><a href="examples/survey_round1_demo.py"><img src="https://raw.githubusercontent.com/justinhk001/codefig/main/docs/assets/survey1.png" width="280" alt="Memory and serving"><br><b>Memory and serving</b></a><br>Tables, attention matrices and routed pools.</td>
164
+ <td><a href="examples/survey_round3_demo.py"><img src="https://raw.githubusercontent.com/justinhk001/codefig/main/docs/assets/survey3.png" width="280" alt="Schedules and operators"><br><b>Schedules and operators</b></a><br>Timelines, pipeline bubbles and code blocks.</td>
165
+ <td><a href="docs/cookbook/03_serving_cluster.py"><img src="https://raw.githubusercontent.com/justinhk001/codefig/main/docs/cookbook/03_serving_cluster.png" width="280" alt="Serving cluster"><br><b>Serving cluster</b></a><br>Groups and branching connections.</td>
166
+ </tr>
167
+ <tr>
168
+ <td><a href="docs/cookbook/12_solids_pyramid.py"><img src="https://raw.githubusercontent.com/justinhk001/codefig/main/docs/cookbook/12_solids_pyramid.png" width="280" alt="Solids and pyramid"><br><b>Solids and pyramid</b></a><br>Cuboids, slabs and hierarchy.</td>
169
+ <td><a href="docs/cookbook/15_chart_features.py"><img src="https://raw.githubusercontent.com/justinhk001/codefig/main/docs/cookbook/15_chart_features.png" width="280" alt="Embedded charts"><br><b>Embedded charts</b></a><br>Themed data inside a diagram.</td>
170
+ <td><a href="docs/cookbook/21_block_sparse.py"><img src="https://raw.githubusercontent.com/justinhk001/codefig/main/docs/cookbook/21_block_sparse.png" width="280" alt="Block-sparse matrix"><br><b>Block-sparse matrix</b></a><br>Unequal tracks and split lines.</td>
171
+ </tr>
172
+ <tr>
173
+ <td><a href="docs/cookbook/22_migration_timeline.py"><img src="https://raw.githubusercontent.com/justinhk001/codefig/main/docs/cookbook/22_migration_timeline.png" width="280" alt="Migration timeline"><br><b>Migration timeline</b></a><br>Tasks and migration spans.</td>
174
+ <td><a href="docs/cookbook/13_charts_wrapflow.py"><img src="https://raw.githubusercontent.com/justinhk001/codefig/main/docs/cookbook/13_charts_wrapflow.png" width="280" alt="Wrapped flow"><br><b>Wrapped flow</b></a><br>Charts beside a folded chain.</td>
175
+ <td><a href="docs/cookbook/04_kv_cache.py"><img src="https://raw.githubusercontent.com/justinhk001/codefig/main/docs/cookbook/04_kv_cache.png" width="280" alt="KV cache"><br><b>KV cache</b></a><br>Structured cache blocks and ports.</td>
176
+ </tr>
177
+ </table>
178
+
179
+ [Browse all 31 recipes](https://raw.githubusercontent.com/justinhk001/codefig/main/docs/cookbook/contact_sheet.png) · [Cookbook index](https://github.com/justinhk001/codefig/blob/main/docs/cookbook/README.md)
180
+
181
+ <a id="features"></a>
182
+
183
+ ## Features
184
+
185
+ ### Layout primitives
186
+
187
+ | Category | Public primitives |
188
+ |---|---|
189
+ | Composition | `Row`, `Col`, `Grid`, `Group`, `Stack` |
190
+ | Nodes | `Box`, `Text`, `Circle`, `Diamond`, `Triangle`, `Polygon` |
191
+ | Structured data | `Matrix`, `TokenStrip`, `Table`, `DotGrid` |
192
+ | Repetition | `Stacked`, `Repeat`, `Series` |
193
+ | Spatial structure | `Region`, `Cuboid`, `SlabStack`, `Pyramid` |
194
+ | Sequences | `WrapFlow`, `Tree`, `Timeline`, `Lanes` |
195
+ | Annotation | `Brace`, `Callout`, `Badge`, `Step`, `Dim`, `CodeBlock` |
196
+ | Connections and keys | `Diagram`, `Edge`, `Guide`, `Fork`, `Join`, `Legend` |
197
+
198
+ Compose small containers, then combine them into panels.
199
+ Use `Region` for overlapping membership rather than forcing everything into nested groups.
200
+ `WrapFlow` folds a long chain; `Matrix` expresses cell structure directly.
201
+ See [layout concepts](https://github.com/justinhk001/codefig/blob/main/docs/concepts/layout.md) for composition rules.
202
+
203
+ ### Constraints
204
+
205
+ - `same_x`, `same_y`: share an alignment axis.
206
+ - `same_width`, `same_height`: equalise dimensions.
207
+ - `align_columns`, `align_rows`: share tracks across matrices and token strips.
208
+ - `above`, `below`, `left_of`, `right_of`: express relative placement.
209
+ - `place`, `distribute`, `align`: place and space related elements.
210
+
211
+ Use constraints for relationships across containers, not as a coordinate substitute.
212
+ Read [constraints](https://github.com/justinhk001/codefig/blob/main/docs/concepts/constraints.md) before combining many relations.
213
+
214
+ ### Edges & routing
215
+
216
+ - Attach edges to visible nodes with `node.port("right")` and other side ports.
217
+ - Sliding ports and edge alignment can straighten small offsets.
218
+ - Fan-in trunks share a route; `Edge(trunk=False)` opts out.
219
+ - `Fork` and `Join` express explicit branching and merging.
220
+ - `Edge(via=...)` passes through an operator.
221
+ - `Guide` draws a helper line without pretending to be a data arrow.
222
+ - `Diagram.zoom` connects an overview to a magnified detail.
223
+
224
+ Dense crossings still need visual inspection.
225
+ Changing the ordering or leaving a routing channel often helps more than adding bends.
226
+
227
+ ### Charts
228
+
229
+ | Primitive | Intended use |
230
+ |---|---|
231
+ | `BarChart` | A compact bar comparison |
232
+ | `GroupedBarChart` | Multiple series, horizontal bars or baseline comparisons |
233
+ | `StackedBarChart` | Composition of totals |
234
+ | `LineChart` | Trends, including error bands |
235
+ | `Sparkline` | A small trend embedded beside a label |
236
+
237
+ These are themed codefig primitives, not matplotlib wrappers.
238
+ They share the figure's typography and visual language.
239
+ Use log scales for values spanning decades and error bars or bands for uncertainty.
240
+ For a specialised scientific plot, use a plotting library instead.
241
+
242
+ ### Themes & venues
243
+
244
+ The paper theme documents 6/7/8 pt annotation/label/title roles,
245
+ 0.6/0.75/1.2 pt box/arrow/emphasis strokes, and a CVD-safe categorical palette.
246
+ Use `category=` and `Legend()` for meaning; reserve accents for emphasis.
247
+ The classic theme supports older scripts and a larger screen-oriented appearance.
248
+
249
+ Preset dimensions below come from `venues.py`; they are template presets, not a
250
+ promise that every year's author kit will remain unchanged. Check your submission template.
251
+
252
+ | Venue | Column width (pt) | Text width (pt) |
253
+ |---|---:|---:|
254
+ | `neurips` | — (single column) | 396 |
255
+ | `iclr` | — (single column) | 396 |
256
+ | `icml` | 234 | 486 |
257
+ | `mlsys` | 234 | 486 |
258
+ | `vldb` | 239.76 | 504 |
259
+ | `sigmod` | 239.76 | 504 |
260
+ | `osdi` | 240.12 | 504 |
261
+ | `sosp` | 239.76 | 504 |
262
+
263
+ Aliases include `acm` for SIGMOD and `usenix`, `nsdi`, `fast`, `atc` for OSDI.
264
+ For NeurIPS and ICLR, use `width="text"`; `width="column"` requires a two-column preset.
265
+ See [themes and venues](https://github.com/justinhk001/codefig/blob/main/docs/concepts/themes-and-venues.md).
266
+
267
+ ### Lint
268
+
269
+ 38 rules inspect the figure at its final width. Examples:
270
+
271
+ | Rule | What it catches |
272
+ |---|---|
273
+ | `CF-TXT-001` | Text too small at final width |
274
+ | `CF-TXT-007` | Label overflow or insufficient padding |
275
+ | `CF-TXT-010` | Drawn text covered or struck through |
276
+ | `CF-COL-004` | Semantic categories without a key |
277
+ | `CF-ARR-003` | Edges attached to invisible containers |
278
+ | `CF-REG-001` | A region covering a non-member |
279
+ | `CF-LAY-004` | Aspect ratio outside the slot's suggested range |
280
+ | `CF-EXP-001` | Width mismatch or excessive shrink |
281
+
282
+ `save()` refuses export on lint errors under the default venue lint policy.
283
+ It writes a `<name>.lint_preview.png` with findings outlined so you can inspect the problem.
284
+ Warnings and info findings still deserve attention; lint cannot judge the scientific story.
285
+ See the complete [rule reference](https://github.com/justinhk001/codefig/blob/main/docs/lint-rules.md).
286
+
287
+ ### Export
288
+
289
+ - PDF: vector output with embedded TrueType subsets; no Type 3 fonts.
290
+ - SVG: text remains text, with alt text in the document title.
291
+ - PNG: 300 dpi by default for physical figures; configure `dpi=` as needed.
292
+ - `alt=` writes a companion `.alt.txt` file.
293
+ - `layout_report()` returns fitting diagnostics for debugging layout.
294
+
295
+ Keep Python as the authoritative source, and regenerate every format from it.
296
+
297
+ <a id="lint-in-action"></a>
298
+
299
+ ## Lint in action
300
+
301
+ Six stages in one row, one colour each, squeezed into a 234 pt ICML column. Lint tells you exactly what is wrong, by how much, and what to do:
302
+
303
+ ```python
304
+ from codefig import Figure, Box, Row, Col, Legend
305
+
306
+ fig = Figure(venue="icml", width="column", panel_caption="none")
307
+ stages = ["Tokenize", "Embed", "Encode", "Attend", "Decode", "Sample"]
308
+ with fig.panel("a") as panel:
309
+ panel += Col([Row([Box(s, category=s) for s in stages]), Legend(direction="row")])
310
+ print(fig.lint(alt="A six-stage pipeline squeezed into one column."))
311
+ ```
312
+
313
+ ```text
314
+ codefig lint (icml, 234 pt): 0 error(s), 2 warning(s), 2 info
315
+ WARN CF-EXP-001 content is 250 pt wide but the slot is 234 pt: everything shrinks ×0.94 (fonts 5.6–7.5 pt) — use width='text', cols=, or fewer/shorter boxes; …
316
+ fix: Figure(venue=..., width='column'|'text') and \includegraphics at scale 1; see docs/cookbook/30_compact_column.py
317
+ WARN CF-TXT-001 6 text run(s) below 6 pt at final size (smallest 5.61 pt) [text:'Attend', text:'Decode', text:'Embed' …]
318
+ fix: use the theme size roles (6/7/8 pt); widen the figure (width='text') or shorten labels
319
+ INFO CF-COL-001 5 categorical hue families [#4DB1F2, #FCD188, #8FCCA7 …]
320
+ INFO CF-LAY-004 aspect 6.63 outside 1.1–2.5 for a column-width figure
321
+ ```
322
+
323
+ The fix is structural, not cosmetic: two rows, and categories that mean something (at most 4). Warnings are gone, fonts stay at the theme's 6/7/8 pt roles:
324
+
325
+ ```python
326
+ from codefig import Figure, Box, Row, Col, Legend
327
+
328
+ fig = Figure(venue="icml", width="column", panel_caption="none")
329
+ kind = {"Tokenize": "data", "Embed": "model", "Encode": "model",
330
+ "Attend": "attention", "Decode": "model", "Sample": "data"}
331
+ boxes = [Box(s, category=c) for s, c in kind.items()]
332
+ with fig.panel("a") as panel:
333
+ panel += Col([Row(boxes[:3]), Row(boxes[3:]), Legend(direction="row")])
334
+ print(fig.lint(alt="A six-stage pipeline in two rows."))
335
+ ```
336
+
337
+ ```text
338
+ codefig lint (icml, 234 pt): 0 error(s), 0 warning(s), 1 info
339
+ INFO CF-LAY-004 aspect 3.37 outside 1.1–2.5 for a column-width figure
340
+ ```
341
+
342
+ <a id="ai-first-authoring"></a>
343
+
344
+ ## AI-first authoring
345
+
346
+ LLMs can describe rows, groups and connections without guessing spatial coordinates.
347
+ Lint findings carry rule identifiers and suggested fixes, giving an author a concrete repair loop.
348
+ This reduces placement guesswork; it does not remove the need to inspect the rendered PNG.
349
+
350
+ The quick card is ~12.9 KB; the full reference is ~276.0 KB (decimal KB).
351
+ Choose the short card first, then retrieve relevant sections of the full reference.
352
+
353
+ | File | Role |
354
+ |---|---|
355
+ | [llms.txt](https://github.com/justinhk001/codefig/blob/main/llms.txt) | Small entry point and authoring rules |
356
+ | [llms-full.txt](https://github.com/justinhk001/codefig/blob/main/llms-full.txt) | Consolidated reference |
357
+ | [AGENTS.md](https://github.com/justinhk001/codefig/blob/main/AGENTS.md) | Authoring and development workflow |
358
+ | [CLAUDE.md](https://github.com/justinhk001/codefig/blob/main/CLAUDE.md) | Assistant entry point |
359
+ | [API](https://github.com/justinhk001/codefig/blob/main/docs/api.md) | Real constructors and arguments |
360
+ | [Cookbook](https://github.com/justinhk001/codefig/blob/main/docs/cookbook/README.md) | Copy a working composition |
361
+
362
+ Paste this into Claude Code, Cursor or Codex:
363
+
364
+ ```text
365
+ Create an original codefig diagram for the system I describe.
366
+ 1. Read llms.txt and AGENTS.md. Confirm the intended venue and column/text width.
367
+ 2. Open the cookbook index and choose the nearest working recipe.
368
+ 3. Use documented primitives and semantic categories with Legend().
369
+ Do not guess constructor arguments or introduce absolute coordinates.
370
+ 4. Keep labels short. Compose Row/Col/Grid before adding cross-container constraints.
371
+ 5. Print fig.lint(alt=ALT). Apply each finding's suggested fix.
372
+ Repeat until there are 0 errors and 0 warnings; inspect info findings too.
373
+ 6. If save refuses, inspect the generated lint_preview.png before guessing.
374
+ 7. Render and VIEW the PNG at print width. Check the story, routes and labels.
375
+ 8. Export PDF, SVG and PNG with descriptive alt text. Keep the Python source.
376
+ 9. Include the PDF in LaTeX at native size, with no width override.
377
+ ```
378
+
379
+ For a chat AI: “Read the attached llms.txt; use llms-full.txt as reference and help me build a lint-clean codefig figure.”
380
+
381
+ <a id="evaluation"></a>
382
+
383
+ ## Measured AI usability
384
+
385
+ Fresh AI authors received only public docs and reproduced six published systems/ML figures.
386
+ An independent scorer applied a 100-point rubric:
387
+
388
+ - **A: outcome, 60 points:** structural fidelity 30, visual quality 15, lint 10, code 5.
389
+ - **B: process friction, 40 points:** authoring friction and repair process.
390
+
391
+ | Target | Figure | 0.15 independent | 0.16 independent |
392
+ |---|---|---:|---:|
393
+ | t1 | ServerlessLLM | 80 | 64.6 |
394
+ | t2 | Lero | 81 | 82.5 |
395
+ | t3 | MegaBlocks | 89 | 87.5 |
396
+ | t4 | Llumnix | 89 | 91.0 |
397
+ | t5 | Gated Attention | 81 | 72.0 |
398
+ | t6 | RETRO | 74 | 72.5 |
399
+ | Mean | | 82.3 | 78.4 |
400
+
401
+ The 0.15 independent median was 81.0.
402
+ The 0.16 mean regressed by 3.9 points, concentrated in column-width targets t1/t5.
403
+ The other four independent deltas were within ±2 points.
404
+ This is six targets with one author sample each; scorer models differed,
405
+ so calibration may explain part of the difference.
406
+ A successful process exit does not imply a lint-clean or structurally faithful figure.
407
+
408
+ ### What the findings changed
409
+
410
+ - Drawn-text collisions motivated `CF-TXT-010`.
411
+ - Refused exports without a diagnostic image motivated `lint_preview.png`.
412
+ - Missing magnification and helper lines motivated `Diagram.zoom` and `Guide`.
413
+ - Width guesswork motivated diagnostics naming the widest layout chain.
414
+ - The retest exposed compact-recipe discoverability and `widths=` confusion.
415
+
416
+ Column fitting and compact-before-shrink behaviour remain priorities.
417
+ These results are a feedback loop, not a claim of autonomous publication quality.
418
+ The target paper figures are not redistributed; this README includes no eval images.
419
+
420
+ <a id="install"></a>
421
+
422
+ ## Install
423
+
424
+ ```sh
425
+ pip install codefig
426
+ # From a source checkout:
427
+ pip install -e .
428
+ # Development dependencies:
429
+ pip install -e ".[dev]"
430
+ ```
431
+
432
+ | Platform | System Cairo setup |
433
+ |---|---|
434
+ | Linux / Debian / Ubuntu | `sudo apt install libcairo2` |
435
+ | macOS / Homebrew | `brew install cairo` |
436
+ | Windows | Install Cairo via conda-forge (`conda install -c conda-forge cairo`) or a GTK runtime; make its DLLs discoverable |
437
+
438
+ CairoSVG requires the system Cairo library in addition to Python packages.
439
+ Use a virtual environment to isolate the Python dependencies.
440
+
441
+ <a id="faq"></a>
442
+
443
+ ## FAQ
444
+
445
+ ### Is this a matplotlib replacement?
446
+
447
+ No. It focuses on composed paper diagrams and compact embedded charts.
448
+ Keep matplotlib for rich scientific plotting and exploratory analysis.
449
+
450
+ ### Can I edit the SVG?
451
+
452
+ Yes, in an SVG editor. Text remains text, but external edits are not imported
453
+ back into Python. Keep the source if you want reproducible regeneration.
454
+
455
+ ### What about fonts?
456
+
457
+ The paper theme uses a sans stack and 6/7/8 pt roles.
458
+ PDF export embeds TrueType subsets. Inspect the result on your actual machine;
459
+ font availability can affect metrics. The lint reference describes PDF font checks.
460
+
461
+ ### Does it work in Jupyter?
462
+
463
+ You can run the Python API and display a saved PNG or SVG using notebook tools.
464
+ There are no `_repr_svg_` or `_repr_png_` hooks for automatic rich display.
465
+
466
+ ### Can I use the output in Overleaf?
467
+
468
+ Export PDF locally, upload it, and use `\includegraphics{quickstart.pdf}`.
469
+ Keep the native size so the designed print typography is preserved.
470
+
471
+ ### Is the API stable?
472
+
473
+ This is pre-1.0 software. Pin the version for a paper and keep the generating script.
474
+ Review changes before upgrading a manuscript's build environment.
475
+
476
+ <a id="documentation"></a>
477
+
478
+ ## Documentation
479
+
480
+ | Read | Purpose |
481
+ |---|---|
482
+ | [Getting started](https://github.com/justinhk001/codefig/blob/main/docs/getting-started.md) | First figure and lint loop |
483
+ | [Layout](https://github.com/justinhk001/codefig/blob/main/docs/concepts/layout.md) | Composition primitives |
484
+ | [Constraints](https://github.com/justinhk001/codefig/blob/main/docs/concepts/constraints.md) | Relationships across containers |
485
+ | [Themes and venues](https://github.com/justinhk001/codefig/blob/main/docs/concepts/themes-and-venues.md) | Print typography and width presets |
486
+ | [Fit a column](https://github.com/justinhk001/codefig/blob/main/docs/guides/fit-a-column.md) | Diagnose width pressure |
487
+ | [Cookbook](https://github.com/justinhk001/codefig/blob/main/docs/cookbook/README.md) | 31 runnable recipes |
488
+ | [API](https://github.com/justinhk001/codefig/blob/main/docs/api.md) | Public constructor reference |
489
+ | [Lint rules](https://github.com/justinhk001/codefig/blob/main/docs/lint-rules.md) | All 38 rules and suggested fixes |
490
+ | [Feature tour](https://github.com/justinhk001/codefig/blob/main/docs/feature-tour.md) | Broader examples and capabilities |
491
+
492
+ <a id="roadmap"></a>
493
+
494
+ ## Roadmap
495
+
496
+ Plans, not promises; priorities follow observed authoring friction.
497
+
498
+ - [ ] Compact or reflow before shrinking below readable type sizes.
499
+ - [ ] Make compact-column recipes easier to discover.
500
+ - [ ] Clarify width budgets and spare-space semantics of `widths=`.
501
+ - [ ] Improve dense routes, annotation placement and diagnostics.
502
+ - [ ] Continue fresh-author evaluations and report regressions honestly.
503
+
504
+ <a id="contributing"></a>
505
+
506
+ ## Contributing
507
+
508
+ Start with [CONTRIBUTING.md](https://github.com/justinhk001/codefig/blob/main/CONTRIBUTING.md).
509
+ A useful bug report includes a minimal script, version, venue and lint output.
510
+ For new recipes, include descriptive alt text and inspect the rendered PNG.
511
+ Only submit diagrams and assets you have the right to redistribute.
512
+
513
+ ```sh
514
+ python -m pytest -q -W error
515
+ python tools/gen_api_docs.py
516
+ ```
517
+
518
+ [Code of conduct](https://github.com/justinhk001/codefig/blob/main/CODE_OF_CONDUCT.md) · [Security](https://github.com/justinhk001/codefig/blob/main/SECURITY.md)
519
+
520
+ If codefig helps your paper, star the repository or share an original figure and its source.
521
+
522
+ <a id="citation"></a>
523
+
524
+ ## Citation
525
+
526
+ ```bibtex
527
+ @software{codefig2026,
528
+ author = {justinhk001},
529
+ title = {codefig},
530
+ year = {2026},
531
+ url = {https://github.com/justinhk001/codefig}
532
+ }
533
+ ```
534
+
535
+ <a id="license"></a>
536
+
537
+ ## License & acknowledgements
538
+
539
+ [MIT](https://github.com/justinhk001/codefig/blob/main/LICENSE). Copyright (c) 2026 Justin.
540
+
541
+ Thanks to Tabler Icons (MIT), kiwisolver (Cassowary constraint solving),
542
+ and CairoSVG (vector/raster export).