Start over #1
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This tool was a re-implementation of something I had written before, and it just didn't come out the same. The purpose was to visualize our backlog in jira and how projects flow and overlap. The visual concept was largely based off the london tube map.
The way it works:
That gives the primary visualization, but there were some extras I also put in
I originally implemented this in python and graphviz, but graphviz is simply too limited to really achieve the look I want.
@hermes-bot Search around for existing tools that could create this visual. Come up with a plan for developing. Test some visuals and post them here. Do not implement the project, but make a development plan. Post the plan here when you're done
Research, tested visuals, and development plan
Per the ask: I searched the tool landscape, tested two visual prototypes, and drafted a plan. No project implementation — prototypes only (code + renders are in the repo under
prototypes/, branchmain).1. Existing tools — survey
Conclusion: no off-the-shelf tool does this. The layout is a small custom metro-map drawing problem (there's real literature on it: abstract metro network layout, e.g. the Birmingham metro-map work — worth citing as design inspiration). The right architecture is a thin custom SVG renderer with a small layout pass; everything below is ~600 lines of code, not a framework job.
2. Tested visuals
I built a data-driven prototype renderer (sample backlog: 5 labels, 16 issues, 5 interchanges, 4 sprints with 2 done) and iterated twice:
v2 — dark theme, sprint boxes, greyed done sprints, interchange rings with connectors:
v3 — TfL light style, white interchange rings on each joined lane:
Source (runnable, stdlib + cairosvg only):
prototypes/proto.py(dark) andprototypes/proto_light.py(light). The geometry model from the issue maps 1:1 onto the rendering model:Key thing the tests proved: the hard visual problems are station-label collisions (solved with alternating above/below placement) and interchange connector geometry (vertical link vs. 45° dog-leg — both viable, 45° looks more "tube"). Neither is possible cleanly in Graphviz; both are trivial in direct SVG.
3. Development plan
Stack: TypeScript + Vite, plain SVG rendering (d3 only for zoom/pan and scales if needed). Output: static map JSON + SPA, or server-rendered PNG/SVG snapshot. Keep the renderer pure-function (
mapSpec → SVG) — the prototype already validates this shape.Phase 1 — Jira data layer (1–2 days).
rankcustom field orRankcomposite) and sort client-side per label — the API's rank ordering matches "only that label displayed" if you sort by rank and treat epics as irrelevant (per the brief, epics are ignored entirely; a task's projects come from labels only).startDate/sequence); "done" from sprint state.Phase 2 — Layout engine (2–4 days, the interesting part).
Phase 3 — Renderer polish (1–2 days).
Phase 4 — Delivery (1 day).
Total: roughly a week of focused work for v1; the layout engine is the only part with depth, and the prototype has already de-risked its geometry.
Open questions before implementation:
The visuals you made really stand out, but they don't really convey the meaning of when lines converge. The importance there is it shows when a particular task really needs attention. A lot of initiatives depend on it. Therefore, the version I made before drew the lines generally vertically, but they were allowed to curve and cross each other. See if you can draw something along those lines, but using similar data to what you had before. Also, do it with a hundred tasks, not just a handful.
@hermes-bot Just some drawings. This was nice. I'm just looking for another response here.
v4 — back to the vertical look: lanes run top→bottom through the sprints, and they're free to curve, cross and converge. Convergence is now the point: every time initiatives share a task, their lines pull off their columns and braid into one interchange; the more that pile on, the more lines converge at that spot. Stations where 3+ initiatives meet get an amber halo — the "this needs attention" signal.
Same data model as v2/v3 (labels = lanes, tasks = stations, rank order within each sprint band, grey = done sprints), but at 100 tasks: 56 single-label, 32 two-label, 9 three-label, 3 four-label → 44 interchanges, 10 hot stations, and ~186 line crossings measured in the geometry. The underpass casing (dark outline per line) keeps crossings readable where lines overlap.
Routing rules, for the record:
Source:
prototypes/proto_v4.py(renderedv4_tube_map.svg/.pngnext to it; same stdlib + cairosvg recipe).Trade-off I can see from this experiment: at 100 tasks the crossing density is the honest picture of the dependency pile-on, but it does make individual lanes hard to trace across a hot band — which is arguably exactly when you shouldn't be able to trace a single initiative through it. Two knobs if you want the map to stay traceable: thinner lines + wider columns, or dim non-interchange tasks in done sprints even further so the braids dominate.
No implementation — drawings only, as asked.
Much closer this time around. Let's do one more iteration. The interchange stations should be drawn as a single circle. Don't make a separate circle for each line. And see if you can straighten out those lines a bit. Catmull-rom is possibly not the best choice. Points close together can cause strange tangents. bezier spline would probably do better.
v5 — both fixes in:
1. Single interchange circle. All lines of a multi-label task now converge on one shared centre point and one white circle is drawn over the join (TfL style) — no more per-line rings. The braid visibly disappears into the station. 44 interchanges, 44 circles (checked programmatically against the SVG).
2. Bezier instead of Catmull-Rom. You were right about the tangents. Every Catmull-Rom tangent derives from the neighbouring waypoints, and with stations only 22px apart vertically those tangents got wild. The new curve is a cubic bezier chain whose control arms are always vertical (the time axis) with length clamped to half the segment — so tangent at a station no longer depends on point spacing, and consecutive same-column stations render as exactly straight verticals.
Straightness, measured over all 167 curve segments (same seed, same 100 tasks —
prototypes/compare_v4_v5.pysamples both chains and compares):So: lines between stations are now near-straight sweeps with one controlled lane-change curve each, and the geometry can't loop no matter how close the points get.
Source:
prototypes/proto_v5.py(rendersv5_tube_map.svg/.pngalongside).One honest trade-off of the single circle: at an interchange you can no longer see which line is which inside the station — the lines visually terminate at the ring. That's how the real Tube map does it, so arguably correct, but if you want traceability through hot stations, an option is to colour the circle's stroke with a pie of the converging line colours. Still drawings-only, as instructed.