inklet 2.5.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 (388) hide show
  1. inklet-2.5.0/.gitattributes +2 -0
  2. inklet-2.5.0/.github/workflows/checks.yml +77 -0
  3. inklet-2.5.0/.gitignore +35 -0
  4. inklet-2.5.0/CHANGELOG.md +62 -0
  5. inklet-2.5.0/CONTRACT.md +76 -0
  6. inklet-2.5.0/CONTRIBUTING.md +94 -0
  7. inklet-2.5.0/LICENSE +21 -0
  8. inklet-2.5.0/PKG-INFO +171 -0
  9. inklet-2.5.0/README.md +145 -0
  10. inklet-2.5.0/THIRD_PARTY_NOTICES.md +67 -0
  11. inklet-2.5.0/docs/api.md +1085 -0
  12. inklet-2.5.0/docs/cli.md +92 -0
  13. inklet-2.5.0/docs/concepts.md +92 -0
  14. inklet-2.5.0/docs/cookbook.md +2723 -0
  15. inklet-2.5.0/docs/data.md +101 -0
  16. inklet-2.5.0/docs/design/page_grid.md +133 -0
  17. inklet-2.5.0/docs/design/v2.md +40 -0
  18. inklet-2.5.0/docs/diagram-components.md +25 -0
  19. inklet-2.5.0/docs/diagrams.md +93 -0
  20. inklet-2.5.0/docs/examples.md +63 -0
  21. inklet-2.5.0/docs/export-review.md +135 -0
  22. inklet-2.5.0/docs/index.md +49 -0
  23. inklet-2.5.0/docs/installation.md +101 -0
  24. inklet-2.5.0/docs/layout.md +87 -0
  25. inklet-2.5.0/docs/migration.md +66 -0
  26. inklet-2.5.0/docs/plotting.md +105 -0
  27. inklet-2.5.0/docs/publication-plots.md +70 -0
  28. inklet-2.5.0/docs/quickstart.md +106 -0
  29. inklet-2.5.0/docs/release-checks.md +48 -0
  30. inklet-2.5.0/docs/stress20.md +77 -0
  31. inklet-2.5.0/docs/stylesheets/code.css +162 -0
  32. inklet-2.5.0/docs/stylesheets/inklet.css +30 -0
  33. inklet-2.5.0/docs/three-images.md +85 -0
  34. inklet-2.5.0/docs/troubleshooting.md +85 -0
  35. inklet-2.5.0/docs/v2.5.md +169 -0
  36. inklet-2.5.0/docs/v2.md +172 -0
  37. inklet-2.5.0/examples/broken_axis.py +59 -0
  38. inklet-2.5.0/examples/feature_flow.py +21 -0
  39. inklet-2.5.0/examples/gallery.py +217 -0
  40. inklet-2.5.0/examples/graph.py +79 -0
  41. inklet-2.5.0/examples/hello_figure.py +30 -0
  42. inklet-2.5.0/examples/panels.py +72 -0
  43. inklet-2.5.0/examples/polar.py +93 -0
  44. inklet-2.5.0/examples/render_smoke.py +61 -0
  45. inklet-2.5.0/examples/state_machine.py +52 -0
  46. inklet-2.5.0/examples/stress20.py +289 -0
  47. inklet-2.5.0/examples/v25_document.py +64 -0
  48. inklet-2.5.0/examples/v2_cases.py +63 -0
  49. inklet-2.5.0/examples/v2_document.py +61 -0
  50. inklet-2.5.0/figures/annot.py +169 -0
  51. inklet-2.5.0/figures/bio3d.py +69 -0
  52. inklet-2.5.0/figures/cartoon.py +7 -0
  53. inklet-2.5.0/figures/chem_data.py +2154 -0
  54. inklet-2.5.0/figures/chem_fingerprints.py +887 -0
  55. inklet-2.5.0/figures/data/1m17-kinase.pdb +1395 -0
  56. inklet-2.5.0/figures/data/README.md +8 -0
  57. inklet-2.5.0/figures/drug_discovery.py +664 -0
  58. inklet-2.5.0/figures/mouse_brain_data.py +269 -0
  59. inklet-2.5.0/figures/neural_activity.py +154 -0
  60. inklet-2.5.0/figures/pdbfile.py +181 -0
  61. inklet-2.5.0/figures/showcase_part.py +80 -0
  62. inklet-2.5.0/figures/showcase_process.py +81 -0
  63. inklet-2.5.0/figures/showcase_season.py +97 -0
  64. inklet-2.5.0/figures/structure.py +1022 -0
  65. inklet-2.5.0/figures/structure_data.py +201 -0
  66. inklet-2.5.0/figures/target.py +468 -0
  67. inklet-2.5.0/figures/trial.py +229 -0
  68. inklet-2.5.0/gallery/README.md +27 -0
  69. inklet-2.5.0/gallery/chem_fingerprints.png +0 -0
  70. inklet-2.5.0/gallery/flow.png +0 -0
  71. inklet-2.5.0/gallery/part.png +0 -0
  72. inklet-2.5.0/gallery/plots.png +0 -0
  73. inklet-2.5.0/gallery/polar.png +0 -0
  74. inklet-2.5.0/gallery/process.png +0 -0
  75. inklet-2.5.0/gallery/season.png +0 -0
  76. inklet-2.5.0/gallery/stress20.png +0 -0
  77. inklet-2.5.0/gallery/structure.png +0 -0
  78. inklet-2.5.0/mkdocs.yml +68 -0
  79. inklet-2.5.0/pyproject.toml +57 -0
  80. inklet-2.5.0/requirements-ci.txt +24 -0
  81. inklet-2.5.0/requirements-docs.txt +47 -0
  82. inklet-2.5.0/scripts/bench_svg.py +291 -0
  83. inklet-2.5.0/scripts/rasterise.sh +19 -0
  84. inklet-2.5.0/scripts/sanity_typeset.py +40 -0
  85. inklet-2.5.0/src/inklet/__init__.py +451 -0
  86. inklet-2.5.0/src/inklet/__main__.py +2 -0
  87. inklet-2.5.0/src/inklet/assets/__init__.py +42 -0
  88. inklet-2.5.0/src/inklet/assets/asset.py +374 -0
  89. inklet-2.5.0/src/inklet/assets/cache.py +134 -0
  90. inklet-2.5.0/src/inklet/assets/cutout.py +205 -0
  91. inklet-2.5.0/src/inklet/assets/deps.py +83 -0
  92. inklet-2.5.0/src/inklet/assets/harmonise.py +191 -0
  93. inklet-2.5.0/src/inklet/assets/lineart.py +313 -0
  94. inklet-2.5.0/src/inklet/assets/mask.py +117 -0
  95. inklet-2.5.0/src/inklet/assets/provenance.py +135 -0
  96. inklet-2.5.0/src/inklet/assets/raster.py +157 -0
  97. inklet-2.5.0/src/inklet/assets/sidecar.py +112 -0
  98. inklet-2.5.0/src/inklet/assets/silhouette.py +300 -0
  99. inklet-2.5.0/src/inklet/cli.py +197 -0
  100. inklet-2.5.0/src/inklet/components.py +143 -0
  101. inklet-2.5.0/src/inklet/core/__init__.py +26 -0
  102. inklet-2.5.0/src/inklet/core/diagram.py +574 -0
  103. inklet-2.5.0/src/inklet/core/envelope.py +269 -0
  104. inklet-2.5.0/src/inklet/core/geom.py +201 -0
  105. inklet-2.5.0/src/inklet/core/prims.py +342 -0
  106. inklet-2.5.0/src/inklet/core/style.py +179 -0
  107. inklet-2.5.0/src/inklet/core/trace.py +165 -0
  108. inklet-2.5.0/src/inklet/core/units.py +61 -0
  109. inklet-2.5.0/src/inklet/diagnostics/__init__.py +126 -0
  110. inklet-2.5.0/src/inklet/diagnostics/abut.py +54 -0
  111. inklet-2.5.0/src/inklet/diagnostics/break_rules.py +292 -0
  112. inklet-2.5.0/src/inklet/diagnostics/color.py +149 -0
  113. inklet-2.5.0/src/inklet/diagnostics/cross.py +97 -0
  114. inklet-2.5.0/src/inklet/diagnostics/image.py +164 -0
  115. inklet-2.5.0/src/inklet/diagnostics/key_rules.py +570 -0
  116. inklet-2.5.0/src/inklet/diagnostics/link_rules.py +572 -0
  117. inklet-2.5.0/src/inklet/diagnostics/path_rules.py +886 -0
  118. inklet-2.5.0/src/inklet/diagnostics/plot_rules.py +122 -0
  119. inklet-2.5.0/src/inklet/diagnostics/report.py +58 -0
  120. inklet-2.5.0/src/inklet/diagnostics/rules.py +3137 -0
  121. inklet-2.5.0/src/inklet/diagnostics/three_rules.py +218 -0
  122. inklet-2.5.0/src/inklet/document/__init__.py +15 -0
  123. inklet-2.5.0/src/inklet/document/compiler.py +504 -0
  124. inklet-2.5.0/src/inklet/document/composition.py +233 -0
  125. inklet-2.5.0/src/inklet/document/data.py +301 -0
  126. inklet-2.5.0/src/inklet/document/module.py +75 -0
  127. inklet-2.5.0/src/inklet/document/publication.py +61 -0
  128. inklet-2.5.0/src/inklet/document/spec.py +255 -0
  129. inklet-2.5.0/src/inklet/draw/__init__.py +51 -0
  130. inklet-2.5.0/src/inklet/draw/annotate.py +892 -0
  131. inklet-2.5.0/src/inklet/draw/clip.py +531 -0
  132. inklet-2.5.0/src/inklet/draw/coords.py +283 -0
  133. inklet-2.5.0/src/inklet/draw/path.py +249 -0
  134. inklet-2.5.0/src/inklet/draw/place.py +155 -0
  135. inklet-2.5.0/src/inklet/draw/shapes.py +226 -0
  136. inklet-2.5.0/src/inklet/figure.py +418 -0
  137. inklet-2.5.0/src/inklet/layout/__init__.py +27 -0
  138. inklet-2.5.0/src/inklet/layout/fit.py +228 -0
  139. inklet-2.5.0/src/inklet/layout/flow.py +754 -0
  140. inklet-2.5.0/src/inklet/layout/graph.py +712 -0
  141. inklet-2.5.0/src/inklet/layout/graph_force.py +202 -0
  142. inklet-2.5.0/src/inklet/layout/graph_layered.py +1129 -0
  143. inklet-2.5.0/src/inklet/layout/graph_tree.py +226 -0
  144. inklet-2.5.0/src/inklet/layout/labels.py +490 -0
  145. inklet-2.5.0/src/inklet/layout/sankey.py +1054 -0
  146. inklet-2.5.0/src/inklet/links/__init__.py +29 -0
  147. inklet-2.5.0/src/inklet/links/curves.py +173 -0
  148. inklet-2.5.0/src/inklet/links/link.py +2464 -0
  149. inklet-2.5.0/src/inklet/plot/__init__.py +73 -0
  150. inklet-2.5.0/src/inklet/plot/axis.py +523 -0
  151. inklet-2.5.0/src/inklet/plot/breaks.py +429 -0
  152. inklet-2.5.0/src/inklet/plot/categories.py +130 -0
  153. inklet-2.5.0/src/inklet/plot/facets.py +255 -0
  154. inklet-2.5.0/src/inklet/plot/inset.py +310 -0
  155. inklet-2.5.0/src/inklet/plot/key.py +202 -0
  156. inklet-2.5.0/src/inklet/plot/marks.py +1150 -0
  157. inklet-2.5.0/src/inklet/plot/notes.py +220 -0
  158. inklet-2.5.0/src/inklet/plot/panel.py +1775 -0
  159. inklet-2.5.0/src/inklet/plot/png.py +125 -0
  160. inklet-2.5.0/src/inklet/plot/polar.py +1717 -0
  161. inklet-2.5.0/src/inklet/plot/ramp.py +74 -0
  162. inklet-2.5.0/src/inklet/plot/raster.py +191 -0
  163. inklet-2.5.0/src/inklet/plot/ribbon.py +187 -0
  164. inklet-2.5.0/src/inklet/plot/scale.py +1202 -0
  165. inklet-2.5.0/src/inklet/plot/scatter_raster.py +161 -0
  166. inklet-2.5.0/src/inklet/plot/series.py +138 -0
  167. inklet-2.5.0/src/inklet/plot/timescale.py +417 -0
  168. inklet-2.5.0/src/inklet/render/__init__.py +18 -0
  169. inklet-2.5.0/src/inklet/render/bundle.py +75 -0
  170. inklet-2.5.0/src/inklet/render/fontembed.py +391 -0
  171. inklet-2.5.0/src/inklet/render/glyphs.py +200 -0
  172. inklet-2.5.0/src/inklet/render/outline.py +173 -0
  173. inklet-2.5.0/src/inklet/render/paint.py +60 -0
  174. inklet-2.5.0/src/inklet/render/pathdata.py +207 -0
  175. inklet-2.5.0/src/inklet/render/pdf.py +853 -0
  176. inklet-2.5.0/src/inklet/render/pdftext.py +213 -0
  177. inklet-2.5.0/src/inklet/render/preview.py +70 -0
  178. inklet-2.5.0/src/inklet/render/review.py +94 -0
  179. inklet-2.5.0/src/inklet/render/revision.py +47 -0
  180. inklet-2.5.0/src/inklet/render/svg.py +1005 -0
  181. inklet-2.5.0/src/inklet/themes/__init__.py +46 -0
  182. inklet-2.5.0/src/inklet/themes/color.py +384 -0
  183. inklet-2.5.0/src/inklet/themes/palettes.py +192 -0
  184. inklet-2.5.0/src/inklet/themes/theme.py +422 -0
  185. inklet-2.5.0/src/inklet/three/__init__.py +136 -0
  186. inklet-2.5.0/src/inklet/three/api.py +1545 -0
  187. inklet-2.5.0/src/inklet/three/backend.py +942 -0
  188. inklet-2.5.0/src/inklet/three/blender/__init__.py +58 -0
  189. inklet-2.5.0/src/inklet/three/blender/discover.py +204 -0
  190. inklet-2.5.0/src/inklet/three/blender/lineart.py +451 -0
  191. inklet-2.5.0/src/inklet/three/blender/options.py +133 -0
  192. inklet-2.5.0/src/inklet/three/blender/script.py +541 -0
  193. inklet-2.5.0/src/inklet/three/blender/svgread.py +214 -0
  194. inklet-2.5.0/src/inklet/three/blender/tracing.py +220 -0
  195. inklet-2.5.0/src/inklet/three/blender_backend.py +202 -0
  196. inklet-2.5.0/src/inklet/three/camera.py +326 -0
  197. inklet-2.5.0/src/inklet/three/deps.py +93 -0
  198. inklet-2.5.0/src/inklet/three/depth.py +196 -0
  199. inklet-2.5.0/src/inklet/three/drill.py +1129 -0
  200. inklet-2.5.0/src/inklet/three/edges.py +478 -0
  201. inklet-2.5.0/src/inklet/three/hlr.py +463 -0
  202. inklet-2.5.0/src/inklet/three/linalg.py +195 -0
  203. inklet-2.5.0/src/inklet/three/mesh.py +462 -0
  204. inklet-2.5.0/src/inklet/three/occlude.py +372 -0
  205. inklet-2.5.0/src/inklet/three/order.py +945 -0
  206. inklet-2.5.0/src/inklet/three/parse.py +602 -0
  207. inklet-2.5.0/src/inklet/three/place.py +156 -0
  208. inklet-2.5.0/src/inklet/three/protein.py +679 -0
  209. inklet-2.5.0/src/inklet/three/shade.py +828 -0
  210. inklet-2.5.0/src/inklet/three/solids.py +594 -0
  211. inklet-2.5.0/src/inklet/typeset/__init__.py +42 -0
  212. inklet-2.5.0/src/inklet/typeset/fonts.py +383 -0
  213. inklet-2.5.0/src/inklet/typeset/markup.py +421 -0
  214. inklet-2.5.0/src/inklet/typeset/onpath.py +760 -0
  215. inklet-2.5.0/src/inklet/typeset/outline.py +275 -0
  216. inklet-2.5.0/src/inklet/typeset/shaping.py +761 -0
  217. inklet-2.5.0/stress/assets/mouse.inklet.json +2 -0
  218. inklet-2.5.0/stress/assets/mouse.png +0 -0
  219. inklet-2.5.0/stress/dense_graph.py +36 -0
  220. inklet-2.5.0/stress/draw_probe.py +148 -0
  221. inklet-2.5.0/stress/electro/assets/sem.png +0 -0
  222. inklet-2.5.0/stress/electro/assets/tem.png +0 -0
  223. inklet-2.5.0/stress/electro/cell.py +707 -0
  224. inklet-2.5.0/stress/electro/common.py +141 -0
  225. inklet-2.5.0/stress/electro/data.py +267 -0
  226. inklet-2.5.0/stress/electro/imaging.py +332 -0
  227. inklet-2.5.0/stress/electro/kinetics.py +600 -0
  228. inklet-2.5.0/stress/electro/micrograph.py +165 -0
  229. inklet-2.5.0/stress/electro/system.py +566 -0
  230. inklet-2.5.0/stress/electro_figure.py +210 -0
  231. inklet-2.5.0/stress/fidelity.py +59 -0
  232. inklet-2.5.0/stress/flow.py +109 -0
  233. inklet-2.5.0/stress/hard_figure.py +126 -0
  234. inklet-2.5.0/stress/label_storm.py +107 -0
  235. inklet-2.5.0/stress/mega_figure.py +226 -0
  236. inklet-2.5.0/stress/meshes/README.md +13 -0
  237. inklet-2.5.0/stress/meshes/brain-lh.obj +27003 -0
  238. inklet-2.5.0/stress/meshes/spot.obj +12311 -0
  239. inklet-2.5.0/stress/panels/apparatus.py +904 -0
  240. inklet-2.5.0/stress/panels/graphs.py +1261 -0
  241. inklet-2.5.0/stress/panels/relations.py +1142 -0
  242. inklet-2.5.0/stress/panels/responses.py +1114 -0
  243. inklet-2.5.0/stress/panels/sections.py +1267 -0
  244. inklet-2.5.0/stress/probes.py +319 -0
  245. inklet-2.5.0/stress/three_figure.py +148 -0
  246. inklet-2.5.0/tests/test_alignment_contract.py +437 -0
  247. inklet-2.5.0/tests/test_annotate.py +368 -0
  248. inklet-2.5.0/tests/test_annotate_letters.py +176 -0
  249. inklet-2.5.0/tests/test_assets.py +733 -0
  250. inklet-2.5.0/tests/test_assets_provenance.py +110 -0
  251. inklet-2.5.0/tests/test_categories.py +44 -0
  252. inklet-2.5.0/tests/test_chem_figure.py +708 -0
  253. inklet-2.5.0/tests/test_cli.py +33 -0
  254. inklet-2.5.0/tests/test_components.py +37 -0
  255. inklet-2.5.0/tests/test_contrast_and_labels.py +164 -0
  256. inklet-2.5.0/tests/test_cookbook.py +52 -0
  257. inklet-2.5.0/tests/test_core.py +377 -0
  258. inklet-2.5.0/tests/test_core_amendments.py +526 -0
  259. inklet-2.5.0/tests/test_diagnostics.py +2163 -0
  260. inklet-2.5.0/tests/test_diagnostics_api.py +95 -0
  261. inklet-2.5.0/tests/test_diagnostics_artwork.py +41 -0
  262. inklet-2.5.0/tests/test_diagnostics_break_distorts.py +240 -0
  263. inklet-2.5.0/tests/test_diagnostics_crossing.py +181 -0
  264. inklet-2.5.0/tests/test_diagnostics_image_contrast.py +118 -0
  265. inklet-2.5.0/tests/test_diagnostics_ink.py +81 -0
  266. inklet-2.5.0/tests/test_diagnostics_keys.py +314 -0
  267. inklet-2.5.0/tests/test_diagnostics_links.py +328 -0
  268. inklet-2.5.0/tests/test_diagnostics_paths.py +309 -0
  269. inklet-2.5.0/tests/test_diagnostics_plot_box.py +132 -0
  270. inklet-2.5.0/tests/test_docs.py +157 -0
  271. inklet-2.5.0/tests/test_docs_site.py +56 -0
  272. inklet-2.5.0/tests/test_document.py +179 -0
  273. inklet-2.5.0/tests/test_document_data.py +65 -0
  274. inklet-2.5.0/tests/test_document_v25.py +234 -0
  275. inklet-2.5.0/tests/test_draw_clip.py +365 -0
  276. inklet-2.5.0/tests/test_draw_path.py +325 -0
  277. inklet-2.5.0/tests/test_draw_place.py +161 -0
  278. inklet-2.5.0/tests/test_draw_shapes.py +169 -0
  279. inklet-2.5.0/tests/test_export_bundle.py +45 -0
  280. inklet-2.5.0/tests/test_figure.py +256 -0
  281. inklet-2.5.0/tests/test_fit.py +161 -0
  282. inklet-2.5.0/tests/test_guides.py +74 -0
  283. inklet-2.5.0/tests/test_layout.py +697 -0
  284. inklet-2.5.0/tests/test_layout_graph.py +498 -0
  285. inklet-2.5.0/tests/test_layout_graph_fit.py +148 -0
  286. inklet-2.5.0/tests/test_layout_origin.py +264 -0
  287. inklet-2.5.0/tests/test_layout_sankey.py +410 -0
  288. inklet-2.5.0/tests/test_links.py +645 -0
  289. inklet-2.5.0/tests/test_links_avoid.py +201 -0
  290. inklet-2.5.0/tests/test_links_shapes.py +397 -0
  291. inklet-2.5.0/tests/test_neural_activity.py +42 -0
  292. inklet-2.5.0/tests/test_output_contract.py +305 -0
  293. inklet-2.5.0/tests/test_paint_program.py +42 -0
  294. inklet-2.5.0/tests/test_place_labels.py +285 -0
  295. inklet-2.5.0/tests/test_plot_axis.py +698 -0
  296. inklet-2.5.0/tests/test_plot_broken_axis.py +362 -0
  297. inklet-2.5.0/tests/test_plot_clip.py +128 -0
  298. inklet-2.5.0/tests/test_plot_facets.py +247 -0
  299. inklet-2.5.0/tests/test_plot_inset.py +231 -0
  300. inklet-2.5.0/tests/test_plot_key.py +233 -0
  301. inklet-2.5.0/tests/test_plot_labels.py +199 -0
  302. inklet-2.5.0/tests/test_plot_legend.py +187 -0
  303. inklet-2.5.0/tests/test_plot_marks.py +702 -0
  304. inklet-2.5.0/tests/test_plot_notes.py +181 -0
  305. inklet-2.5.0/tests/test_plot_polar.py +498 -0
  306. inklet-2.5.0/tests/test_plot_publication.py +174 -0
  307. inklet-2.5.0/tests/test_plot_raster.py +331 -0
  308. inklet-2.5.0/tests/test_plot_ribbon.py +183 -0
  309. inklet-2.5.0/tests/test_plot_scale.py +439 -0
  310. inklet-2.5.0/tests/test_plot_swarm.py +255 -0
  311. inklet-2.5.0/tests/test_plot_time.py +204 -0
  312. inklet-2.5.0/tests/test_render_embed.py +168 -0
  313. inklet-2.5.0/tests/test_render_glyphs.py +201 -0
  314. inklet-2.5.0/tests/test_render_outline.py +323 -0
  315. inklet-2.5.0/tests/test_render_pdf.py +495 -0
  316. inklet-2.5.0/tests/test_render_pdf_text.py +323 -0
  317. inklet-2.5.0/tests/test_render_style_fields.py +215 -0
  318. inklet-2.5.0/tests/test_render_svg_perf.py +290 -0
  319. inklet-2.5.0/tests/test_review_v25.py +83 -0
  320. inklet-2.5.0/tests/test_round4_plot.py +259 -0
  321. inklet-2.5.0/tests/test_routing_avoid.py +471 -0
  322. inklet-2.5.0/tests/test_scatter_rendering.py +63 -0
  323. inklet-2.5.0/tests/test_showcase_round3.py +342 -0
  324. inklet-2.5.0/tests/test_structure_figure.py +392 -0
  325. inklet-2.5.0/tests/test_svg.py +762 -0
  326. inklet-2.5.0/tests/test_target_pose.py +151 -0
  327. inklet-2.5.0/tests/test_text_markup.py +561 -0
  328. inklet-2.5.0/tests/test_text_on_path.py +394 -0
  329. inklet-2.5.0/tests/test_theme_font_style.py +82 -0
  330. inklet-2.5.0/tests/test_themes.py +645 -0
  331. inklet-2.5.0/tests/test_three_anchor_pin.py +158 -0
  332. inklet-2.5.0/tests/test_three_api.py +1730 -0
  333. inklet-2.5.0/tests/test_three_backend_blender.py +163 -0
  334. inklet-2.5.0/tests/test_three_blender.py +748 -0
  335. inklet-2.5.0/tests/test_three_depth_order.py +215 -0
  336. inklet-2.5.0/tests/test_three_drill.py +276 -0
  337. inklet-2.5.0/tests/test_three_hlr.py +532 -0
  338. inklet-2.5.0/tests/test_three_mesh.py +347 -0
  339. inklet-2.5.0/tests/test_three_order_vector.py +331 -0
  340. inklet-2.5.0/tests/test_three_overlay.py +196 -0
  341. inklet-2.5.0/tests/test_three_parse.py +311 -0
  342. inklet-2.5.0/tests/test_three_patches.py +258 -0
  343. inklet-2.5.0/tests/test_three_place.py +252 -0
  344. inklet-2.5.0/tests/test_three_protein.py +262 -0
  345. inklet-2.5.0/tests/test_three_ridges.py +159 -0
  346. inklet-2.5.0/tests/test_three_sort.py +181 -0
  347. inklet-2.5.0/tests/test_three_sort_budget.py +256 -0
  348. inklet-2.5.0/tests/test_three_view.py +211 -0
  349. inklet-2.5.0/tests/test_typeset.py +766 -0
  350. inklet-2.5.0/tests/test_watch_review.py +57 -0
  351. inklet-2.5.0/tests/visual/README.md +26 -0
  352. inklet-2.5.0/tests/visual/baseline/categories-pdf.png +0 -0
  353. inklet-2.5.0/tests/visual/baseline/categories-svg.png +0 -0
  354. inklet-2.5.0/tests/visual/baseline/components-pdf.png +0 -0
  355. inklet-2.5.0/tests/visual/baseline/components-svg.png +0 -0
  356. inklet-2.5.0/tests/visual/baseline/dense-pdf.png +0 -0
  357. inklet-2.5.0/tests/visual/baseline/dense-svg.png +0 -0
  358. inklet-2.5.0/tests/visual/baseline/fonts.json +5 -0
  359. inklet-2.5.0/tests/visual/baseline/inset-pdf.png +0 -0
  360. inklet-2.5.0/tests/visual/baseline/inset-svg.png +0 -0
  361. inklet-2.5.0/tests/visual/baseline/markers-pdf.png +0 -0
  362. inklet-2.5.0/tests/visual/baseline/markers-svg.png +0 -0
  363. inklet-2.5.0/tests/visual/baseline/type-opacity-pdf.png +0 -0
  364. inklet-2.5.0/tests/visual/baseline/type-opacity-svg.png +0 -0
  365. inklet-2.5.0/tests/visual/baseline/v2-category-subset-pdf.png +0 -0
  366. inklet-2.5.0/tests/visual/baseline/v2-category-subset-svg.png +0 -0
  367. inklet-2.5.0/tests/visual/baseline/v2-dense-pdf.png +0 -0
  368. inklet-2.5.0/tests/visual/baseline/v2-dense-svg.png +0 -0
  369. inklet-2.5.0/tests/visual/baseline/v2-late-inset-pdf.png +0 -0
  370. inklet-2.5.0/tests/visual/baseline/v2-late-inset-svg.png +0 -0
  371. inklet-2.5.0/tests/visual/baseline/v2-shared-scales-pdf.png +0 -0
  372. inklet-2.5.0/tests/visual/baseline/v2-shared-scales-svg.png +0 -0
  373. inklet-2.5.0/tests/visual/baseline/v2-twins-matrix-pdf.png +0 -0
  374. inklet-2.5.0/tests/visual/baseline/v2-twins-matrix-svg.png +0 -0
  375. inklet-2.5.0/tests/visual/baseline/v2-workflow-pdf.png +0 -0
  376. inklet-2.5.0/tests/visual/baseline/v2-workflow-svg.png +0 -0
  377. inklet-2.5.0/tests/visual/baseline/v25-document-pdf.png +0 -0
  378. inklet-2.5.0/tests/visual/baseline/v25-document-svg.png +0 -0
  379. inklet-2.5.0/tests/visual/fixtures.py +61 -0
  380. inklet-2.5.0/tests/visual/v2-budgets.json +9 -0
  381. inklet-2.5.0/tools/benchmark_v2.py +35 -0
  382. inklet-2.5.0/tools/check_wheel.py +69 -0
  383. inklet-2.5.0/tools/dock_ligand.py +263 -0
  384. inklet-2.5.0/tools/docs_site.py +51 -0
  385. inklet-2.5.0/tools/gen_api.py +180 -0
  386. inklet-2.5.0/tools/stress20.py +139 -0
  387. inklet-2.5.0/tools/strip_pdb.py +105 -0
  388. inklet-2.5.0/tools/visual_check.py +80 -0
@@ -0,0 +1,2 @@
1
+ # PDB records use fixed-width, space-padded columns.
2
+ *.pdb whitespace=-blank-at-eol
@@ -0,0 +1,77 @@
1
+ name: Release checks
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: checks-${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ figures:
18
+ runs-on: ubuntu-24.04
19
+ timeout-minutes: 25
20
+ steps:
21
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
22
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
23
+ with:
24
+ python-version: '3.12'
25
+ - name: Install fonts and independent PDF renderer
26
+ run: |
27
+ sudo apt-get update
28
+ sudo apt-get install -y fonts-dejavu-core fonts-dejavu-extra fonts-noto-core fonts-liberation fonts-urw-base35 poppler-utils
29
+ google-chrome --version
30
+ pdftoppm -v
31
+ - name: Install locked test dependencies
32
+ run: |
33
+ uv venv
34
+ uv pip install -r requirements-ci.txt -e .
35
+ .venv/bin/inklet doctor
36
+ - name: Unit and integration tests
37
+ run: .venv/bin/python -m pytest -q --junitxml=out/tests.xml
38
+ - name: Generated API documentation
39
+ run: .venv/bin/python tools/gen_api.py --check
40
+ - name: Build documentation with strict link validation
41
+ run: |
42
+ uv pip install -r requirements-docs.txt
43
+ .venv/bin/python -m mkdocs build --strict
44
+ .venv/bin/python -m pytest -q tests/test_docs_site.py
45
+ - name: Build the v2.5 publication review
46
+ run: .venv/bin/inklet build examples/v25_document.py --output out/v25 --name document
47
+ - name: Complete figure visual regressions
48
+ run: .venv/bin/python tools/visual_check.py --output out/visual
49
+ - name: Complete figure performance checks
50
+ run: .venv/bin/python tools/benchmark_v2.py --output out/benchmarks
51
+ - name: Twenty-panel mixed-media stress test
52
+ run: .venv/bin/python tools/stress20.py --output out/stress20
53
+ - name: Preserve review artifacts
54
+ if: always()
55
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
56
+ with:
57
+ name: figure-checks
58
+ path: out/
59
+ retention-days: 7
60
+ if-no-files-found: ignore
61
+
62
+ wheel:
63
+ runs-on: ubuntu-24.04
64
+ timeout-minutes: 10
65
+ strategy:
66
+ fail-fast: false
67
+ matrix:
68
+ python: ['3.11', '3.12', '3.13']
69
+ steps:
70
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
71
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
72
+ with:
73
+ python-version: ${{ matrix.python }}
74
+ - name: Build and install with core dependencies only
75
+ run: |
76
+ uv build --wheel --out-dir out/dist
77
+ uv run --no-project python tools/check_wheel.py out/dist/inklet-*.whl
@@ -0,0 +1,35 @@
1
+ # Environments and local configuration
2
+ .venv/
3
+ .env
4
+ .env.*
5
+ !.env.example
6
+ __pycache__/
7
+ *.py[cod]
8
+ .pytest_cache/
9
+ .remember/
10
+
11
+ # Builds, exports and development experiments
12
+ /out/
13
+ /tmp/
14
+ /dist/
15
+ /build/
16
+ /site/
17
+ *.egg-info/
18
+ /figures/out/
19
+ /examples/*.svg
20
+ /examples/*.png
21
+ /examples/*.pdf
22
+ /stress/*.svg
23
+ /stress/*.png
24
+ /stress/*.pdf
25
+ /stress/panels/*.svg
26
+ /stress/panels/*.png
27
+ /stress/panels/*.pdf
28
+ /stress/electro/*.svg
29
+ /stress/electro/*.png
30
+ /stress/electro/*.pdf
31
+
32
+ # Editor / OS files
33
+ .DS_Store
34
+ .idea/
35
+ .vscode/
@@ -0,0 +1,62 @@
1
+ # Changelog
2
+
3
+ ## 2.5.0
4
+
5
+ - Prepare the standalone release tree with an MIT license, third-party notices,
6
+ maintained examples, and explicit source-distribution contents.
7
+ - Refresh Blender's evaluated scene after baking Line Art so SVG exports retain
8
+ every baked stroke. Invalidate earlier bake caches and verify fresh exports.
9
+ - Rework the README around installation, a runnable first figure and supported
10
+ workflows. Add task-based guides, command-line and troubleshooting references,
11
+ a searchable local documentation site and contributor instructions.
12
+ - Execute introductory documentation examples and validate links and site
13
+ navigation in CI. Preserve the generated API reference and existing recipes.
14
+
15
+ - Add nested subfigures that share measurement caches and inherit page themes.
16
+ - Add measured compositions with named children, algebraic size/anchor references,
17
+ cycle detection, branch and return routing, and editable architecture modules.
18
+ - Reserve panel-letter space during layout. Resolve deferred callouts after
19
+ insets and brackets, considering measured marks and existing furniture.
20
+ - Add general publication presets for physical widths, typography, stroke sizes,
21
+ export defaults and print-size diagnostics; record profiles in manifests.
22
+ - Add component/severity filters and search to review pages, plus saved-revision
23
+ overlays and pixel differences. Handle size/DPI changes without invalid scores.
24
+ Watch mode compares successive successful builds and preserves failed-build output.
25
+ - Rebuild the AlphaFold architecture and full proteome layout with public
26
+ composition APIs, removing their custom renderer classes. Preserve the reviewed
27
+ PDF appearance and existing SVG tolerance.
28
+ - Add a complete v2.5 example, regression coverage and installed-wheel checks.
29
+
30
+
31
+ - Migrate AlphaFold Figure 1e to measured module components and named ports;
32
+ migrate the complete proteome figure to live plots, data and category filters.
33
+ - Add `derive()` for explicit transformations of live data dependencies.
34
+ - Consolidate thin-stroke warnings within named, intentionally touching artwork
35
+ while retaining all targets; show component paths in HTML and JSON findings.
36
+ - Check unit tests, complete SVG/PDF figures, performance budgets and isolated
37
+ wheel installations in GitHub Actions. Lock the scientific test dependencies.
38
+ - Preserve the native mesh when optional trimesh repair dependencies are absent.
39
+ - Avoid global theme changes when importing the Nature examples, and keep the
40
+ generated API reference consistent across Python versions.
41
+ - Check repeated drawing identities with a set, avoiding quadratic placement
42
+ work for dense scatter layers.
43
+
44
+ ## 2.0.0
45
+
46
+ - Add live documents with versioned plot and component definitions, compiled
47
+ snapshots, bounded geometry caches and deterministic drawing identities.
48
+ - Fit plots to physical pages with weighted tracks, spanning cells, shared
49
+ furniture margins and explicit errors for unsatisfiable constraints.
50
+ - Add datasets, shared numeric scales, series with uncertainty, live category
51
+ selections, units, data sources and file dependencies.
52
+ - Resolve inherited paint once for SVG and PDF while preserving clipping,
53
+ transformations and group compositing.
54
+ - Add `inklet build`, `watch` and `doctor`, clickable SVG diagnostics, JSON
55
+ findings, and export manifests with data, font and asset provenance.
56
+ - Add six complete v2 visual fixtures, performance budgets and compatibility
57
+ comparisons for all four Nature Figure 1 reconstructions.
58
+ - Avoid repeated child-index construction in crowding diagnostics for large
59
+ drawings, and isolate document themes throughout text and shape creation.
60
+
61
+ Existing Diagram, Panel and Figure APIs remain available. See
62
+ [the migration guide](docs/migration.md) and [v2 guide](docs/v2.md).
@@ -0,0 +1,76 @@
1
+ # Inklet module contract
2
+
3
+ The core represents geometry, styles, primitives and immutable diagram trees.
4
+ Typesetting measures text; layout places nodes; routing connects them;
5
+ diagnostics inspect the resolved figure; rendering exports it.
6
+
7
+ Core changes affect every layer. Preserve the invariants below and add focused
8
+ regression coverage for changes to measurement, placement or traversal.
9
+
10
+ ## Non-negotiables
11
+
12
+ - **Millimetres everywhere.** `core.units.mm("89mm") -> 89.0`, `pt(7) -> 2.47`.
13
+ Bare numbers are already mm. Pixels exist only inside a raster backend.
14
+ - **y grows downward** (SVG convention). North is `-y`.
15
+ - **Primitives are centred on their local origin.**
16
+ - **Deterministic output.** No `uuid4`, no dict-order dependence, no
17
+ `time`/`random`. The same script must emit byte-identical SVG twice.
18
+ - **Core never measures text.** `TextPrim` arrives pre-shaped.
19
+ - Python 3.11 or later, `from __future__ import annotations`, dataclasses, type hints.
20
+ Stdlib + the deps already in `pyproject.toml` only.
21
+
22
+ ## Core API you build against
23
+
24
+ ```python
25
+ Vec2(x, y) # + - * dot cross length normalized perp angle
26
+ Affine(a,b,c,d,e,f) # .translation .rotation .scaling A @ B = B then A
27
+ # .apply(pt) .apply_vector(v) .inverse() .is_identity
28
+ Rect(x0,y0,x1,y1) # .width .height .center .corners .union .pad .overlap
29
+ Envelope # .extent(unit_dir) -> float|None support function
30
+ # .union .transform .pad .bbox()
31
+ Trace # .exit(origin, dir) .boundary_point(origin, dir)
32
+ Style(...) # all fields Optional, None = inherit; .over(base) .with_()
33
+ Prim: RectPrim(w,h,radius) EllipsePrim(rx,ry)
34
+ PathPrim(subpaths,filled,fill_rule) # fill_rule: nonzero | evenodd
35
+ TextPrim(lines,font_family,font_size,ascent,descent,align,font_path,
36
+ ...,features) # features = sorted (tag, value) pairs it was
37
+ # shaped with; core.text_features() canonicalises
38
+ ImagePrim(source,width,height,pixel_size,outline,data,smooth)
39
+ # data = encoded PNG/JPEG bytes; then source is a label
40
+ # smooth: None = backend's call, False = nearest-neighbour
41
+ PhantomPrim(box) # occupies space, draws nothing, empty trace
42
+ Envelope.expand(t,r,b,l) # padding: a disc sweep when uniform, box sum when not
43
+ Diagram(envelope_override=...) # claim space the contents do not; trace untouched
44
+ Diagram(prim=, children=(), transform=, style=, kind=, name=, notes={})
45
+ .local_envelope .envelope # local = before self.transform; plain = after
46
+ .local_trace .trace .bbox .local_bbox .width .height .extent(dir)
47
+ .anchor(name, (u,v)|Vec2) # (u,v) are fractions of local bbox, (0,0)=top-left
48
+ .anchor_point(name) # compass: n s e w ne nw se sw center. LOCAL:
49
+ # pre-transform. Placement.point re-reads the
50
+ # compass off the placed box (M10)
51
+ .registered_point(name) # a registered anchor, looking through the
52
+ # wrappers translated/rotated/scaled leave
53
+ # behind, or None (M16)
54
+ .note(key, value) -> self # per-node annotation core does not read;
55
+ .notes # survives replace/apply_theme/build (M17)
56
+ .carry_notes(source) # inherit a single child's notes, moved into
57
+ # this node's frame (M19)
58
+ note_through(affine, value) # how one note value moves: a Rect is re-cornered,
59
+ # everything else is carried verbatim (M19)
60
+ .at(name) -> AnchorRef
61
+ .placed(affine) .translated .rotated .scaled .centered .styled .named .copy
62
+ .walk() .find(name)
63
+ resolve(root) -> {id: Placement} # Placement: .world .style .envelope .trace
64
+ # .bbox .point(anchor) .depth
65
+ flatten(root) -> [RenderItem] # RenderItem: .prim .world .style .id .name
66
+ world_point(ref_or_diagram, placements) -> Vec2
67
+ ```
68
+
69
+ Combinators **wrap, never rewrite**: `d.translated(3)` returns a new parent
70
+ whose child is the very same `d` object, so a caller's handle stays valid after
71
+ being stacked. Never place one Diagram object twice — `resolve()` raises.
72
+
73
+ ## Testing
74
+
75
+ `.venv/bin/python -m pytest tests/ -q`. Place regression tests alongside the relevant feature tests. Test behaviour
76
+ and numerical results.
@@ -0,0 +1,94 @@
1
+ # Contributing to Inklet
2
+
3
+ Use a focused change with a runnable example or minimal reproducer. Describe
4
+ the resulting behavior and how it was checked. Keep numerical inputs and
5
+ expected results explicit; use simulated data when source data cannot be shared.
6
+
7
+ ## Development environment
8
+
9
+ From a checkout with Python 3.12 and `uv` installed:
10
+
11
+ ```sh
12
+ uv venv --python 3.12
13
+ uv pip install -r requirements-ci.txt -e .
14
+ .venv/bin/python -m inklet doctor
15
+ ```
16
+
17
+ The lock file is the tested scientific environment. Vector-only development
18
+ needs fewer packages, but the full suite also exercises optional image and 3D
19
+ features. CI installs fonts, Chrome and Poppler as described in
20
+ [release checks](docs/release-checks.md).
21
+
22
+ ## Test a change
23
+
24
+ Run the tests relevant to the modified behavior first:
25
+
26
+ ```sh
27
+ .venv/bin/python -m pytest -q tests/test_document.py tests/test_document_v25.py
28
+ ```
29
+
30
+ For a release or a broad rendering change:
31
+
32
+ ```sh
33
+ .venv/bin/python -m pytest -q
34
+ .venv/bin/python tools/gen_api.py --check
35
+ .venv/bin/python tools/visual_check.py --output out/visual
36
+ .venv/bin/python tools/benchmark_v2.py --output out/benchmarks
37
+ .venv/bin/python tools/stress20.py --output out/stress20
38
+ ```
39
+
40
+ Visual checks need the preview tools. Inspect differences before changing a
41
+ baseline; see [visual test instructions](tests/visual/README.md). Performance
42
+ results are machine-dependent, so include workload and environment details.
43
+
44
+ ## Documentation
45
+
46
+ User guides live in `docs/`, with navigation in `mkdocs.yml`. Markdown should
47
+ remain readable in both GitHub and the local site. Link to repository files
48
+ relatively; the site hook includes gallery images and converts other
49
+ out-of-docs links to repository URLs. This avoids duplicate copies of examples
50
+ and preview assets.
51
+
52
+ ```sh
53
+ uv pip install -r requirements-docs.txt
54
+ .venv/bin/python -m pytest -q tests/test_docs.py tests/test_cookbook.py tests/test_guides.py tests/test_docs_site.py
55
+ .venv/bin/python tools/gen_api.py --check
56
+ .venv/bin/python -m mkdocs build --strict
57
+ .venv/bin/python -m mkdocs serve
58
+ ```
59
+
60
+ The static site is written to `out/docs-site/`; local serving uses port 8000.
61
+ The [MkDocs configuration reference](https://www.mkdocs.org/user-guide/configuration/)
62
+ describes navigation and strict validation. CI builds the site and uploads it
63
+ as an artifact. There is no automatic public deployment.
64
+
65
+ New introductory guides should use complete Python examples or clearly state
66
+ what preceding blocks they depend on. `tests/test_guides.py` executes registered
67
+ pages in a temporary directory, sharing a namespace only within each page.
68
+ Prefix a Python fence with `<!-- Requires preview renderers. -->` followed by
69
+ a blank line for examples needing preview tools; those examples are exercised
70
+ when the tools are available. File-dependent fragments
71
+ should state which user files are needed.
72
+
73
+ `docs/api.md` is generated from public signatures and docstrings. Change the
74
+ source docstrings or `tools/gen_api.py`, then regenerate it; do not edit the
75
+ generated file by hand. Keep instructions literal and document limitations
76
+ alongside the corresponding feature.
77
+
78
+ ## Repository structure
79
+
80
+ | Path | Purpose |
81
+ |---|---|
82
+ | `src/inklet/document/` | Live definitions, data, measurement and compilation |
83
+ | `src/inklet/plot/`, `draw/`, `layout/`, `links/` | Charts, geometry composition and routing |
84
+ | `src/inklet/three/`, `assets/` | Meshes, vector 3D and image processing |
85
+ | `src/inklet/typeset/`, `themes/` | Shaped text and physical styling |
86
+ | `src/inklet/render/`, `diagnostics/` | Export backends, review and drawing checks |
87
+ | `tests/` | Unit, integration and visual regression checks |
88
+ | `examples/`, `figures/`, `stress/` | Runnable figures and larger workloads |
89
+ | `tools/` | Documentation generation, wheel checks and benchmarks |
90
+
91
+ Read [the core contract](CONTRACT.md) before changing fundamental geometry,
92
+ and [the compilation contract](docs/design/v2.md) before changing dependency,
93
+ measurement or caching semantics. Update [the changelog](CHANGELOG.md) for
94
+ user-visible changes.
inklet-2.5.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mapika and Inklet contributors
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.
inklet-2.5.0/PKG-INFO ADDED
@@ -0,0 +1,171 @@
1
+ Metadata-Version: 2.5
2
+ Name: inklet
3
+ Version: 2.5.0
4
+ Summary: Scientific figures with live data, measured layout, and consistent vector exports.
5
+ Project-URL: Repository, https://github.com/Mapika/inklet
6
+ Project-URL: Documentation, https://github.com/Mapika/inklet/blob/master/docs/index.md
7
+ Project-URL: Issues, https://github.com/Mapika/inklet/issues
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ License-File: THIRD_PARTY_NOTICES.md
11
+ Requires-Python: >=3.11
12
+ Requires-Dist: fonttools>=4.53
13
+ Requires-Dist: uharfbuzz>=0.39
14
+ Provides-Extra: dev
15
+ Requires-Dist: pytest>=8.0; extra == 'dev'
16
+ Provides-Extra: docs
17
+ Requires-Dist: mkdocs<2,>=1.6; extra == 'docs'
18
+ Requires-Dist: pygments<3,>=2.18; extra == 'docs'
19
+ Provides-Extra: images
20
+ Requires-Dist: numpy>=1.24; extra == 'images'
21
+ Requires-Dist: pillow>=10.0; extra == 'images'
22
+ Provides-Extra: three
23
+ Requires-Dist: numpy>=1.24; extra == 'three'
24
+ Requires-Dist: trimesh>=4.0; extra == 'three'
25
+ Description-Content-Type: text/markdown
26
+
27
+ # Inklet
28
+
29
+ **Scientific figures from Python, with measured layout and editable SVG/PDF output.**
30
+
31
+ Combine plots, diagrams, images and native 3D artwork on a page sized in
32
+ millimetres. Keep data and labels live, compile the figure, and inspect its
33
+ layout and print diagnostics before exporting.
34
+
35
+ [Get started](docs/quickstart.md) · [Documentation](docs/index.md) ·
36
+ [Examples](docs/examples.md) · [API reference](docs/api.md)
37
+
38
+ ![Twenty-panel Inklet figure with 3D surfaces, architecture diagrams, dense scatter, statistical charts, polar plots and Sankey flows](gallery/stress20.png)
39
+
40
+ This [twenty-panel stress test](docs/stress20.md) includes 30,000 scatter points,
41
+ 5,580 mesh triangles and 7,200 vector events. Its data are simulated. Only the
42
+ dense scatter and scalar field are rasterized; the other artwork remains vector.
43
+
44
+ ## Install
45
+
46
+ Python **3.11 or later** is required. Install from this repository using an
47
+ account with access to `Mapika/inklet`:
48
+
49
+ ```sh
50
+ git clone https://github.com/Mapika/inklet.git
51
+ cd inklet
52
+ python -m venv .venv
53
+ source .venv/bin/activate
54
+ python -m pip install -e .
55
+ ```
56
+
57
+ SVG/PDF output and the built-in 3D renderer need no browser or external rendering
58
+ engine. Text needs an installed font. For PNG layers and visual review, install
59
+ `python -m pip install -e '.[images]'` plus Chrome/Chromium and Poppler.
60
+ See [installation](docs/installation.md) for system packages, Windows activation,
61
+ optional dependencies and environment checks.
62
+
63
+ ## Your first figure
64
+
65
+ Save this as `first_figure.py` and run `python first_figure.py`:
66
+
67
+ ```python
68
+ import inklet as i
69
+
70
+
71
+ def make_document():
72
+ data = i.dataset(
73
+ {'time': [0, 1, 2, 3], 'signal': [1, 3, 2, 4]},
74
+ name='response',
75
+ source=i.Source('Quickstart demonstration', method='simulated'),
76
+ )
77
+ plot = i.plot_spec(x=(0, 3), y=(0, 5))
78
+ plot.line(data.points('time', 'signal'), name='Signal', stroke='#176b9b')
79
+ plot.axes(x='Time / s', y='Signal / mV').legend(side='bottom')
80
+
81
+ doc = i.publication('single-column').document()
82
+ doc.add('response', plot, min_height=55)
83
+ return doc
84
+
85
+
86
+ if __name__ == '__main__':
87
+ figure = make_document().compile()
88
+ figure.save('response.svg', 'response.pdf')
89
+ print(figure.report())
90
+ ```
91
+
92
+ The document measures axis labels and the legend, fits the plot to an 89 mm
93
+ page, and saves SVG and PDF with embedded text. It does not shrink the font to
94
+ make the plot fit. The [quickstart](docs/quickstart.md) continues with live data
95
+ edits, multiple panels and review exports.
96
+
97
+ ## Build, inspect, revise
98
+
99
+ With the [preview dependencies](docs/installation.md#visual-review) installed:
100
+
101
+ ```sh
102
+ inklet doctor
103
+ inklet build first_figure.py --output out/review
104
+ inklet watch first_figure.py --output out/review
105
+ ```
106
+
107
+ `build` writes the vector files, PNG previews, diagnostics, a provenance manifest
108
+ and a local HTML review page. `watch` serves a preview at
109
+ `http://127.0.0.1:8765/` and rebuilds when the authoring code changes. Review pages
110
+ support diagnostic filters, SVG highlights and comparisons with a saved revision.
111
+
112
+ For an environment without preview tools, use
113
+ `inklet build first_figure.py --output out/review --vectors-only`.
114
+
115
+ ## What you can build
116
+
117
+ | Task | Main tools | Guide |
118
+ |---|---|---|
119
+ | Multi-panel figures | `document`, `subfigure`, weighted columns, spans, panel letters | [Layout](docs/layout.md) |
120
+ | Scientific plots | `plot_spec`, axes, bands, distributions, heatmaps, insets, polar plots | [Plotting](docs/plotting.md) |
121
+ | Data-driven revisions | `Dataset`, `Series`, shared scales, categories, `derive`, source records | [Live data](docs/data.md) |
122
+ | Architecture and flow diagrams | `composition`, `module`, named ports, measured connections, `graph` | [Diagrams](docs/diagrams.md) |
123
+ | 3D and image panels | `solid`, `model`, `scene`, `asset`, explicit file dependencies | [3D and images](docs/three-images.md) |
124
+ | Publication exports | Physical presets, embedded or outlined text, SVG/PDF, review bundles | [Export and review](docs/export-review.md) |
125
+
126
+ ## How Inklet works
127
+
128
+ A `Document` holds live definitions. `compile()` measures their contents, places
129
+ them, routes connections and produces a snapshot used by both export backends.
130
+ Updating a dataset or named instruction invalidates dependent components;
131
+ unchanged definitions can reuse their cached geometry. Earlier snapshots remain
132
+ unchanged.
133
+
134
+ Numeric lengths, including low-level text sizes, are **millimetres**. Use
135
+ `i.pt(8)` for an 8-point text size; publication profile options such as
136
+ `font_pt=8` take points explicitly. Plot coordinates follow their data scales.
137
+
138
+ The direct `Figure`, `Panel` and `Diagram` APIs remain supported for fixed
139
+ drawings. See [the authoring model](docs/concepts.md) for when to use each layer.
140
+
141
+ ## Scope and limits
142
+
143
+ - Layout respects physical constraints. Impossible fits raise `LayoutError`;
144
+ changing page width does not automatically rearrange the number of columns.
145
+ - Diagnostics help find collisions, small type and other print issues. Review
146
+ the rendered figure as well; a clean report does not establish scientific accuracy.
147
+ - Rasterization keeps dense exports compact, but dense-scatter rebuilds can
148
+ still be expensive. The [stress report](docs/stress20.md) records the workload,
149
+ timings and remaining limitations.
150
+ - Reproducible appearance requires consistent inputs, fonts and dependencies.
151
+ The export manifest records dataset and font hashes for comparison.
152
+
153
+ ## Documentation and development
154
+
155
+ Start at the [documentation index](docs/index.md). The source Markdown is readable
156
+ on GitHub; a searchable site can also be served locally:
157
+
158
+ ```sh
159
+ python -m pip install -e '.[docs]'
160
+ python -m mkdocs serve
161
+ ```
162
+
163
+ See [contributing](CONTRIBUTING.md) for tests, documentation checks and visual
164
+ regressions. Existing users can consult [migration](docs/migration.md),
165
+ [the v2.5 changes](docs/v2.5.md) and [the changelog](CHANGELOG.md).
166
+
167
+ ## License
168
+
169
+ Inklet code is available under the [MIT license](LICENSE). Included third-party
170
+ meshes and structural data retain their own terms; see
171
+ [third-party notices](THIRD_PARTY_NOTICES.md).