vecwire 0.3.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.
- vecwire-0.3.0/.gitignore +10 -0
- vecwire-0.3.0/AGENTS.md +45 -0
- vecwire-0.3.0/CHANGELOG.md +78 -0
- vecwire-0.3.0/LICENSE +21 -0
- vecwire-0.3.0/PKG-INFO +281 -0
- vecwire-0.3.0/README.md +249 -0
- vecwire-0.3.0/docs/development.md +48 -0
- vecwire-0.3.0/examples/fig1a.svg +99 -0
- vecwire-0.3.0/examples/fig1a_cqed.py +91 -0
- vecwire-0.3.0/examples/harmonic_junctions.py +105 -0
- vecwire-0.3.0/examples/harmonic_junctions.svg +164 -0
- vecwire-0.3.0/pyproject.toml +73 -0
- vecwire-0.3.0/src/vecwire/__init__.py +14 -0
- vecwire-0.3.0/src/vecwire/core.py +529 -0
- vecwire-0.3.0/src/vecwire/elements/__init__.py +24 -0
- vecwire-0.3.0/src/vecwire/elements/ground.py +43 -0
- vecwire-0.3.0/src/vecwire/elements/junctions.py +270 -0
- vecwire-0.3.0/src/vecwire/elements/passive.py +62 -0
- vecwire-0.3.0/src/vecwire/geometry.py +120 -0
- vecwire-0.3.0/src/vecwire/node.py +22 -0
- vecwire-0.3.0/src/vecwire/py.typed +0 -0
- vecwire-0.3.0/tests/test_circuit.py +371 -0
- vecwire-0.3.0/tests/test_elements.py +213 -0
- vecwire-0.3.0/tests/test_package_metadata.py +42 -0
vecwire-0.3.0/.gitignore
ADDED
vecwire-0.3.0/AGENTS.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# VecWire agent guidance
|
|
2
|
+
|
|
3
|
+
VecWire is a focused Python package for readable, deterministic SVG circuit
|
|
4
|
+
schematics, especially circuit-QED publication figures. Keep its public API
|
|
5
|
+
small and grounded in the Fig. 1(a) example.
|
|
6
|
+
|
|
7
|
+
- Connect components through named, positioned `Node` objects. A node is a placed
|
|
8
|
+
point; a net may contain several nodes joined by wires. Via points affect only
|
|
9
|
+
routing and do not establish connectivity.
|
|
10
|
+
- Accept node names as concise references in examples. A wire may pass through
|
|
11
|
+
several connected nodes, and its centerline must pass through each of them.
|
|
12
|
+
- Preserve semantic SVG IDs and `data-from`/`data-to` endpoint metadata.
|
|
13
|
+
- Render each routed wire as one SVG path so line joins and corner radii work.
|
|
14
|
+
- Keep output deterministic and editable; use `to_svg_document()` for FigWorks integration.
|
|
15
|
+
- Treat VecTeX as optional. Plain SVG labels must work without TeX.
|
|
16
|
+
- Add symbols or routing features when a real figure needs them; avoid a circuit
|
|
17
|
+
simulation or netlist abstraction without an explicit requirement.
|
|
18
|
+
- Keep symbols in `vecwire.elements` as plain functions of the circuit, drawn
|
|
19
|
+
only through the public drawing API of `vecwire.core` (`branch`, `group`,
|
|
20
|
+
`line`, `rect`, `dot`, `path`) and `vecwire.geometry`. The library must not
|
|
21
|
+
import the core at run time; built-in symbols are bound as `Circuit` methods
|
|
22
|
+
by one class attribute each. No registries or plugin hooks.
|
|
23
|
+
- Leave number formatting to the core so output stays byte-identical; check
|
|
24
|
+
`examples/fig1a.svg` is unchanged after refactors.
|
|
25
|
+
- Preserve user-authored examples and unrelated changes.
|
|
26
|
+
|
|
27
|
+
## Development
|
|
28
|
+
|
|
29
|
+
- Supported Python: 3.12 and newer.
|
|
30
|
+
- `uv venv && uv pip install -e '.[dev]'` for a development environment; add
|
|
31
|
+
`.[tex]` (and a TeX installation) to exercise VecTeX labels.
|
|
32
|
+
- Run `ruff format --check .`, `ruff check .`, `ty check`, and `pytest` before
|
|
33
|
+
reporting a change complete. ty checks `src`; type the
|
|
34
|
+
duck-typed inputs with a `Protocol`, not `Any`.
|
|
35
|
+
- Typing serves the code, not the other way round. Type public signatures and
|
|
36
|
+
what types naturally, and keep `ty check` passing; where precise types would
|
|
37
|
+
contort the code -- a decorator that changes what a parameter accepts, say --
|
|
38
|
+
use a looser annotation or a targeted `# ty: ignore[code]`. Do not raise the
|
|
39
|
+
Python floor for typing features.
|
|
40
|
+
- Run `python examples/fig1a_cqed.py` and `python examples/harmonic_junctions.py`
|
|
41
|
+
after touching drawing code, and diff what they write against
|
|
42
|
+
`examples/fig1a.svg` and `examples/harmonic_junctions.svg`. Any byte that
|
|
43
|
+
changes must be one the change intended.
|
|
44
|
+
- Keep `CHANGELOG.md` current in Keep a Changelog 1.1.0 format.
|
|
45
|
+
- Do not commit, tag, upload, or publish unless the user explicitly asks.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.3.0] - 2026-10-16
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- A publish workflow: a pushed `v<version>` tag is checked against the package
|
|
15
|
+
version, tested on the full CI matrix, built, checked with `twine check
|
|
16
|
+
--strict`, and uploaded to PyPI by trusted publishing. `docs/development.md`
|
|
17
|
+
describes the release steps.
|
|
18
|
+
- Optional `font_family` on plain-text `Circuit.label` calls, so labels can
|
|
19
|
+
use the same typeface as other figure sources.
|
|
20
|
+
- `Circuit.to_svg_document()` credits VecWire: the document opens with Dublin
|
|
21
|
+
Core metadata naming "VecWire vX, https://github.com/maiani/vecwire" as its
|
|
22
|
+
creator, as Matplotlib and Inkscape do. The circuit's own tree is unchanged.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Use ty for type checking in development and CI instead of mypy.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- `label(..., color=...)` colours VecTeX fragments again. Since VecTeX 0.3 a
|
|
31
|
+
fragment paints in `currentColor`, which follows the CSS `color`, not the
|
|
32
|
+
`fill` the label group set, so every TeX label came out black: the grey
|
|
33
|
+
`C_J` of `fig1a_cqed.py --tex` among them. A fragment label's group now sets
|
|
34
|
+
`color` too, to the label colour or the circuit's stroke; a fragment rendered
|
|
35
|
+
with a colour of its own keeps it. Plain-text labels are unchanged.
|
|
36
|
+
|
|
37
|
+
## [0.2.0] - 2026-10-05
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- **Renamed from cirquit to VecWire.** The distribution and import name is now
|
|
42
|
+
`vecwire` (was `cirquit`), because `cirquit` on PyPI belongs to an unrelated
|
|
43
|
+
quantum-computing platform; the new name joins the `vec` family of its
|
|
44
|
+
siblings. Output is unchanged.
|
|
45
|
+
|
|
46
|
+
## [0.1.0] - 2026-10-05
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- `Circuit`, an SVG canvas of named, positioned nodes joined by wires, with
|
|
51
|
+
`row()`, `column()` and `nodes()` to declare them, `via` routing, a
|
|
52
|
+
per-circuit or per-wire `corner_radius`, labels from plain text or a VecTeX
|
|
53
|
+
fragment, dashed `box()` enclosures, and `to_svg_document()`, the only
|
|
54
|
+
interface FigWorks needs to place a circuit.
|
|
55
|
+
- The symbol library: `capacitor`, `inductor`, `ground`, the bare-X
|
|
56
|
+
`junction`, the boxed `harmonic_junction` for one `cos(mφ)` or `sin(mφ)`
|
|
57
|
+
term, and `harmonic_sum` for a multiharmonic junction.
|
|
58
|
+
- Byte-identical output: the core owns number formatting (`.12g`) and
|
|
59
|
+
attribute order.
|
|
60
|
+
- Examples reproducing a circuit-QED sketch (`fig1a_cqed.py`) and the junction
|
|
61
|
+
symbol legend (`harmonic_junctions.py`).
|
|
62
|
+
- Type information: the package ships `py.typed` and passes `mypy --strict`.
|
|
63
|
+
Label fragments are typed by the structural `vecwire.core.Fragment`
|
|
64
|
+
protocol (`width`, `height`, `to_svg()`), so VecTeX stays optional.
|
|
65
|
+
- `vecwire.__version__`, kept equal to the distribution version by a test.
|
|
66
|
+
- Package metadata: MIT licence (with a `LICENSE` file), keywords,
|
|
67
|
+
classifiers, and project URLs.
|
|
68
|
+
|
|
69
|
+
### Changed
|
|
70
|
+
|
|
71
|
+
- The bare-X `junction` draws its leads on to the centre of the X, so the wire
|
|
72
|
+
runs continuously through the symbol instead of stopping at the square's
|
|
73
|
+
edge.
|
|
74
|
+
- Python 3.12 is the minimum supported version, matching VecTeX and VecView.
|
|
75
|
+
- The build backend is hatchling, as in the sibling projects; the wheel ships
|
|
76
|
+
`py.typed`.
|
|
77
|
+
- Ruff checks the `B`, `E`, `F`, `I`, `N`, `RUF`, `S` and `UP` rule sets, and
|
|
78
|
+
pytest runs with `--strict-config --strict-markers`.
|
vecwire-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andrea Maiani
|
|
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.
|
vecwire-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: vecwire
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Readable, editable SVG schematics for electrical and circuit-QED circuits
|
|
5
|
+
Project-URL: Source, https://github.com/maiani/vecwire
|
|
6
|
+
Project-URL: Issues, https://github.com/maiani/vecwire/issues
|
|
7
|
+
Author-email: Andrea Maiani <dev@andreamaiani.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: circuit,circuit-qed,figures,schematic,svg,vector-graphics
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.12
|
|
23
|
+
Requires-Dist: lxml>=4.9
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: lxml-stubs>=0.5; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.12; extra == 'dev'
|
|
28
|
+
Requires-Dist: ty>=0.0.84; extra == 'dev'
|
|
29
|
+
Provides-Extra: tex
|
|
30
|
+
Requires-Dist: vectex>=0.1; extra == 'tex'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# VecWire
|
|
34
|
+
|
|
35
|
+
VecWire draws electrical circuit schematics as SVG, with circuit-QED figures as
|
|
36
|
+
the first use case. The schematic is generated from code and stays editable
|
|
37
|
+
afterwards: each component becomes a named SVG group, the same script writes
|
|
38
|
+
byte-identical SVG, and the output opens in Inkscape.
|
|
39
|
+
|
|
40
|
+
<p align="center">
|
|
41
|
+
<img src="https://raw.githubusercontent.com/maiani/vecwire/v0.3.0/docs/images/readme.svg" alt="A circuit-QED schematic: capacitor, inductor and a Josephson junction with its capacitance, labels typeset by TeX" width="340">
|
|
42
|
+
</p>
|
|
43
|
+
|
|
44
|
+
<p align="center"><sub>A circuit-QED schematic with labels typeset by VecTeX, from <a href="https://github.com/maiani/vecwire/blob/v0.3.0/examples/fig1a_cqed.py"><code>examples/fig1a_cqed.py</code></a> with <code>--tex</code>.</sub></p>
|
|
45
|
+
|
|
46
|
+
The symbol set covers wires, capacitors, inductors, Josephson junctions (the
|
|
47
|
+
bare X, boxed harmonic junctions, and multiharmonic junctions), ground symbols,
|
|
48
|
+
connection nodes, dashed enclosures, and labels. Components connect named,
|
|
49
|
+
positioned nodes and draw their own leads.
|
|
50
|
+
|
|
51
|
+
VecWire is alpha: an early version, with an API that will still change.
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
VecWire needs Python 3.12 or newer:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
python -m pip install vecwire
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The only runtime dependency is lxml. For labels typeset by TeX, install the
|
|
62
|
+
optional VecTeX extra; VecTeX also needs `pdflatex` and `dvisvgm` on `PATH`:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
python -m pip install "vecwire[tex]"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Quick start
|
|
69
|
+
|
|
70
|
+
A capacitively shunted Josephson junction, grounded at the bottom:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from vecwire import Circuit
|
|
74
|
+
|
|
75
|
+
circuit = Circuit(70, 96)
|
|
76
|
+
circuit.row(14, top_left=18, phi=35, top_right=52, dots={"phi"})
|
|
77
|
+
circuit.row(78, bottom_left=18, gnd=35, bottom_right=52)
|
|
78
|
+
|
|
79
|
+
circuit.wire("top_left", "phi", "top_right")
|
|
80
|
+
circuit.wire("bottom_left", "gnd", "bottom_right")
|
|
81
|
+
circuit.capacitor("top_left", "bottom_left", id="C")
|
|
82
|
+
circuit.junction("top_right", "bottom_right", id="JJ")
|
|
83
|
+
circuit.ground("gnd", id="ground")
|
|
84
|
+
|
|
85
|
+
circuit.label("C", (11, 46), anchor="rc")
|
|
86
|
+
circuit.label("φ", "phi", offset=(0, -3), anchor="cb")
|
|
87
|
+
circuit.write_svg("transmon.svg")
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Coordinates are SVG user units, points by default (`Circuit(..., unit="pt")`;
|
|
91
|
+
`"px"` and `"mm"` are also accepted). `to_svg_document()` returns the same
|
|
92
|
+
document as a string.
|
|
93
|
+
|
|
94
|
+
## Examples
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
python examples/fig1a_cqed.py # writes examples/output/fig1a.svg
|
|
98
|
+
python examples/fig1a_cqed.py --tex # editable TeX labels through Vectex
|
|
99
|
+
python examples/harmonic_junctions.py # the junction symbol legend
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`fig1a_cqed.py` draws a shunt capacitance `C` across an inductor `L` in series
|
|
103
|
+
with a parallel junction branch of `V_J` and `C_J`, marking the node phases `φ`
|
|
104
|
+
and `δ`. `harmonic_junctions.py` draws the bare X beside the boxed
|
|
105
|
+
`m = 1, 2, 3` and `sin` symbols, and an inductor in series with a sinusoidal
|
|
106
|
+
junction next to the multiharmonic junction it acts like. Both previews are
|
|
107
|
+
checked in: [fig1a.svg](https://github.com/maiani/vecwire/blob/v0.3.0/examples/fig1a.svg) and
|
|
108
|
+
[harmonic_junctions.svg](https://github.com/maiani/vecwire/blob/v0.3.0/examples/harmonic_junctions.svg). Without `--tex`
|
|
109
|
+
the examples use plain SVG text and need no TeX installation.
|
|
110
|
+
|
|
111
|
+
## Nodes and wires
|
|
112
|
+
|
|
113
|
+
A `Node` is a placed connection point, and wires join nodes into an electrical
|
|
114
|
+
net. `row()` and `column()` declare several nodes sharing one coordinate;
|
|
115
|
+
`nodes()` takes arbitrary positions. None of them draws anything. Methods
|
|
116
|
+
accept node names or the `Node` values these calls return.
|
|
117
|
+
|
|
118
|
+
A wire visits its nodes in the order given and may pass through several of
|
|
119
|
+
them; a route that doubles back is rejected. Crossing or overlapping in the
|
|
120
|
+
drawing does not make a connection. Optional `via` points shape a route without
|
|
121
|
+
adding connections:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
circuit.wire("left", "right", via=((18, 30), (52, 30)), corner_radius=2)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Each routed wire is one SVG path, so `linejoin="round"` softens a bend and
|
|
128
|
+
`corner_radius` curves the centerline; both can be set on the `Circuit` or per
|
|
129
|
+
wire. A route still passes exactly through every named node it visits, even
|
|
130
|
+
with a corner radius. Two-terminal symbols are placed horizontally or
|
|
131
|
+
vertically.
|
|
132
|
+
|
|
133
|
+
Labels take plain text or a VecTeX fragment; a fragment's SVG group is embedded
|
|
134
|
+
as is, so it stays editable through TexText.
|
|
135
|
+
|
|
136
|
+
The `Circuit` records drawing geometry only. It does not infer electrical
|
|
137
|
+
topology or compute circuit parameters; those belong to the scientific model
|
|
138
|
+
that produces the figure.
|
|
139
|
+
|
|
140
|
+
Plain-text labels accept `font_family` and `size` (in the circuit's user units):
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
circuit.label("Capacitance", (40, 20), size=8, font_family="TeX Gyre Heros")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Omitting `font_family` preserves inherited SVG typography. For fragment labels,
|
|
147
|
+
choose typography when rendering the fragment; these text options do not
|
|
148
|
+
rescale or replace its glyphs.
|
|
149
|
+
|
|
150
|
+
## Josephson junctions
|
|
151
|
+
|
|
152
|
+
`junction()` draws the bare X, the standard Josephson-junction symbol, which
|
|
153
|
+
leaves the current-phase relation unspecified; its leads meet at the centre of
|
|
154
|
+
the X, so the wire runs through it. `harmonic_junction()` draws the boxed
|
|
155
|
+
symbol of one tunnelling harmonic: its square holds `order` crossed diagonals
|
|
156
|
+
each way for a `cos(mφ)` term, in which `m` Cooper pairs tunnel together, and
|
|
157
|
+
`kind="sin"` adds two dots for the odd `sin(mφ)` term of a φ0 junction. The
|
|
158
|
+
`m = 1` box is the bare X inside its square, so the two symbols line up. In
|
|
159
|
+
both, `color` sets the glyph and `lead_color` keeps the leads in the circuit
|
|
160
|
+
ink.
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
circuit.junction("top", "bottom", id="JJ") # bare X
|
|
164
|
+
circuit.harmonic_junction("top", "bottom", 2, color="#8075c1", lead_color="#262626")
|
|
165
|
+
circuit.harmonic_junction("top", "bottom", kind="sin") # sin φ, m = 1
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Both groups carry `data-component="josephson-junction"`; the boxed one also
|
|
169
|
+
records `data-harmonic` and `data-kind`, so a stylesheet or selector can tell
|
|
170
|
+
them apart.
|
|
171
|
+
|
|
172
|
+
`harmonic_sum()` draws a multiharmonic junction: a dashed box holding
|
|
173
|
+
`⊠ + ⊠⊠ + ⊠⊠⊠ + ⋯` between two terminals. The harmonics of one junction add as
|
|
174
|
+
energies, so the terms hang in parallel between two rails, which the branch
|
|
175
|
+
leads join at the centre of the box. `rails=False` ends each term in terminal
|
|
176
|
+
dots instead, a shorthand notation. The sum reads left to right on a vertical
|
|
177
|
+
branch and top to bottom on a horizontal one. `colors` and `kinds` set each
|
|
178
|
+
term, and `ellipsis=False` drops the trailing `+ ⋯`.
|
|
179
|
+
|
|
180
|
+
`box()` draws a dashed enclosure around a subcircuit that acts as one element;
|
|
181
|
+
it is decoration only and creates no connection. Both return a `Box` with the
|
|
182
|
+
bounds: `Box.at("rb")` uses the label anchors, and `Box.terms` holds the
|
|
183
|
+
centres of the summed glyphs for per-term labels:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
box = circuit.harmonic_sum("top", "bottom", (1, 2, 3), colors=shades)
|
|
187
|
+
for order, centre in zip((1, 2, 3), box.terms):
|
|
188
|
+
circuit.label(f"E{order}", (centre[0], box.bottom + 2), anchor="ct")
|
|
189
|
+
circuit.box((10, 18), (60, 95), id="effective-junction")
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Architecture
|
|
193
|
+
|
|
194
|
+
| Module | Contents |
|
|
195
|
+
| --- | --- |
|
|
196
|
+
| `vecwire.core` | `Circuit`: the SVG root and unique ids, nodes, wire routing, labels, `box()`, `to_svg_document()`, and the drawing API symbols are built from |
|
|
197
|
+
| `vecwire.elements` | the symbol library: `capacitor`, `inductor`, `junction`, `harmonic_junction`, `harmonic_glyph`, `harmonic_sum`, `ground` |
|
|
198
|
+
| `vecwire.geometry` | value types and checks shared by both: `Point`, `Box`, `Branch`, `positive`, `offset`, … |
|
|
199
|
+
| `vecwire.node` | `Node`, a named, placed connection point |
|
|
200
|
+
|
|
201
|
+
A symbol is a plain function whose first argument is the circuit, and it draws
|
|
202
|
+
only through the public drawing API: `circuit.branch(start, end)` resolves the
|
|
203
|
+
terminals into a `Branch`, `circuit.group(kind, id, branch=...)` opens a
|
|
204
|
+
semantic group with `data-from`/`data-to`, and `line`, `rect`, `dot`, and
|
|
205
|
+
`path` add strokes in the circuit ink. Symbols are written in branch
|
|
206
|
+
coordinates (`branch.at(along, across)`), so one definition serves every
|
|
207
|
+
orientation. A new symbol is a new function, in `vecwire.elements` or your own
|
|
208
|
+
script, with no change to the core:
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
def resistor(circuit, start, end, *, id=None):
|
|
212
|
+
branch = circuit.branch(start, end)
|
|
213
|
+
group = circuit.group("resistor", id, branch=branch)
|
|
214
|
+
lead, step = branch.length / 4, branch.length / 12
|
|
215
|
+
points = [branch.at(lead + (i + 0.5) * step, 3 * (-1) ** i) for i in range(6)]
|
|
216
|
+
circuit.path(
|
|
217
|
+
group,
|
|
218
|
+
[
|
|
219
|
+
("M", *branch.start.position),
|
|
220
|
+
("L", *branch.at(lead)),
|
|
221
|
+
*(("L", *p) for p in points),
|
|
222
|
+
("L", *branch.at(3 * lead)),
|
|
223
|
+
("L", *branch.end.position),
|
|
224
|
+
],
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
resistor(circuit, "top", "bottom", id="R")
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The built-in symbols are also `Circuit` methods, bound by one class attribute
|
|
232
|
+
each (`capacitor = elements.capacitor`), so `circuit.capacitor(a, b)` is the
|
|
233
|
+
same call as `elements.capacitor(circuit, a, b)`, with the same signature and
|
|
234
|
+
docstring. There is no registry or plugin hook. The core imports the library
|
|
235
|
+
for these bindings, and the library never imports the core at run time
|
|
236
|
+
(`tests/test_elements.py` checks this), so the dependency points one way.
|
|
237
|
+
|
|
238
|
+
The core owns number formatting (`.12g`) and attribute order, so every symbol
|
|
239
|
+
serializes coordinates the same way and output is byte-identical from run to
|
|
240
|
+
run.
|
|
241
|
+
|
|
242
|
+
**Why not svg.py.** [svg.py](https://github.com/orsinium-labs/svg) was
|
|
243
|
+
evaluated for the symbols and is not used. It writes floats with `repr`
|
|
244
|
+
(`0.30000000000000004`, `1e-07`) and fixes its own attribute order, so adopting
|
|
245
|
+
it would change every byte of existing figures, or mean passing preformatted
|
|
246
|
+
strings and losing its typed fields. A symbol's size depends on the circuit's
|
|
247
|
+
ink, stroke width, and line caps, which svg.py has no notion of, so element
|
|
248
|
+
code would get longer, not shorter. The canvas needs lxml anyway, to embed
|
|
249
|
+
VecTeX fragments and reorder connection dots. (Its `svg.A` is also the `<a>`
|
|
250
|
+
element, not an arc.)
|
|
251
|
+
|
|
252
|
+
## Development
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
python -m pip install -e '.[dev]'
|
|
256
|
+
ruff format --check .
|
|
257
|
+
ruff check .
|
|
258
|
+
ty check
|
|
259
|
+
pytest
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
After touching drawing code, rerun both examples and diff their output against
|
|
263
|
+
`examples/fig1a.svg` and `examples/harmonic_junctions.svg`; every changed byte
|
|
264
|
+
should be one the change intended. Releases are described in
|
|
265
|
+
[docs/development.md](https://github.com/maiani/vecwire/blob/main/docs/development.md).
|
|
266
|
+
|
|
267
|
+
## Related projects
|
|
268
|
+
|
|
269
|
+
VecWire is developed alongside [FigWorks](https://github.com/maiani/figworks),
|
|
270
|
+
which composes multi-panel figures, and two other producers of editable SVG:
|
|
271
|
+
[VecTeX](https://github.com/maiani/vectex) (TeX equations) and
|
|
272
|
+
[VecView](https://github.com/maiani/vecview) (layered 3D schematics). All four
|
|
273
|
+
share one premise: figures generated from code, with stable ids and
|
|
274
|
+
byte-identical output, that stay editable in Inkscape.
|
|
275
|
+
|
|
276
|
+
VecWire does not depend on FigWorks. FigWorks places a `Circuit` in a panel
|
|
277
|
+
through `to_svg_document()` alone; see its README.
|
|
278
|
+
|
|
279
|
+
## License
|
|
280
|
+
|
|
281
|
+
MIT
|