Skip to content

Make the crowding strip readable: level columns, one lollipop mark, a colour per meaning - #37

Merged
mspinola merged 7 commits into
mainfrom
claude/strip-visual-fixes
Aug 22, 2026
Merged

Make the crowding strip readable: level columns, one lollipop mark, a colour per meaning#37
mspinola merged 7 commits into
mainfrom
claude/strip-visual-fixes

Conversation

@mspinola

Copy link
Copy Markdown
Owner

Seven visual fixes to /strip, each driven by looking at the rendered page and each pinned by tests (224 pass).

Layout

  • Level the columns. The in-figure legend stacked its groups, outgrew the margin arithmetic, and pushed the left column ~40px below the right; Bootstrap's equal-height stretch then re-drew the shorter column on a different row pitch. The legend is page chrome now (legend_items + HTML), every figure carries one constant top margin, and the graph row uses align="start".
  • Room to read. Row pitch 19px → 22px; alternating row bands calibrated twice on a real monitor (invisible 0.035 → stripe-bright 0.06 → 0.045).

The mark

  • One form: a lollipop. The Dot/Bar toggle existed because neither form had won. The lollipop is the working part of each — hairline stem from neutral 50 (how far, which way), full-strength head at the value (position + hover) — so the Mark control is gone.

Colour, one meaning each

  • Green and red belong to the verdicts alone. Quiet rows went grey → Commercial red → back to the app's neutral dim: the Commercial red is the bear verdict's own hue family, and forty quiet rows whispered bearish. Neutral is now a small faint grey dot; the only colour on the board is a verdict.
  • Ticks light with their row. Leg-tick opacity used to carry the leg's own gate state (redundant with its axis position) at an illegible 0.4 idle. It now follows the row's tier: verdict rows light whole — lollipop, name, every leg — quiet rows knock back to a still-readable 0.55.

Verified in the browser at each step (columns level to the pixel, one shared row pitch, tier ordering full > near > quiet on hue, size and intensity).

🤖 Generated with Claude Code

mspinola and others added 7 commits August 21, 2026 23:01
Two rendering defects left the two-column strip reading as two different
charts. The legend, drawn as traces inside the first figure, was laid out
by Plotly as two vertically stacked groups; the stack outgrew the margin
arithmetic that tried to predict its height, and Plotly silently pushed
that one figure's top margin out, so the left column's axis and rows sat
~40px below the right's. And Bootstrap's default column stretch, combined
with responsive figures, inflated the shorter column to the taller one's
height, spreading its rows on a ~23px pitch beside the other's 19px.

The legend is page chrome now — strip_traces.legend_items says what the
entries are, the page renders them as one line of coloured text above
both columns — so every figure carries the same constant top margin, and
align="start" lets each column keep its natural height. Tests hold the
new invariants: no figure draws a legend of its own, and every column
figure gets the same top margin whatever the model or mark.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Measured on screen rather than reasoned about: at 19px a row's four
marks blurred into one lane, and the 0.035 alternating band — chosen to
be 'faint enough to group without reading as shading' — was simply
imperceptible over the near-black background, so nothing grouped a row's
marks or parted it from its neighbours. ROW_PX goes to 22 (the pitch the
stretch bug accidentally demonstrated was more readable), the row band
to 0.06, and the gate-zone bands to 0.09 so the shading that carries
meaning stays the strongest on the page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Dot/Bar toggle existed because neither form had won, and read side
by side neither deserved to: the bar's fill was a half-row of colour
saying one number, and the bare diamond scattered over an empty row and
did not scan. The lollipop is the working part of each — a hairline stem
from neutral carries the bar's at-a-glance 'how far, which way' on a
twentieth of the ink, and a full-strength head carries the diamond's
precise position and the hover. With one form there is nothing left to
toggle, so the Mark control goes too.

Quiet rows draw in the app's Commercial series colour rather than the
old grey, which read as disabled rather than as quiet: the mark is
Commercial positioning whatever the gate thinks of it, and every other
panel names that series by this colour. 'No setup' stays a legend entry
precisely because it is now a colour a reader could mistake for a
verdict. The blocked-extreme pin (Orange Juice at 96 with a leg
blocking) updates with the scheme: its lollipop sits deep in the bull
band in the plain Commercial colour, position saying the level and
colour withholding the verdict, same rule as before in the new clothes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
0.06 was calibrated against the old marks and overshot the new ones:
beside a hairline stem, a white band at 0.06 is the brightest thing on
the row, and the page read as stripes with data in the gaps. 0.045 sits
between that and the invisible 0.035 this started from — visible as
association, beaten for attention by any actual mark.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The palette's Commercial slot is #F87171-family red and grid_colors
builds the bear verdicts from the same family — #FF4D4D full, the same
at 0.5 for near — so a quiet row at full strength completed a line-up of
three nearly identical reds, and a board of mostly-quiet markets read as
a board of almost-bear-setups.

Colour cannot fix this without giving up the series identity the quiet
tier exists to state, so the separation comes from the channels colour
does not own: quiet heads shrink from 9px to 5px and fade to 0.45,
below even the near tier's 0.5, with stems at 0.22. Full setup > near >
quiet, in size and intensity, whatever the hues. The legend's
comm-coloured keys (No setup, 6w ago) fade to match the marks they
stand for — a full-strength swatch would promise a red the plot never
draws, and promise it in the bear family.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The quiet tier's colour completes the loop. Grey slabs read as disabled,
so it took the Commercial series red; the red sat in the bear verdict's
own hue family, so it shrank and faded; and even faded, forty quiet rows
still whispered bearish, because hue is the loudest channel and theirs
said the wrong thing. If green means setup-long and red means
setup-short, neutral cannot wear either.

Quiet rows now draw in the app's own neutral — colors.dim, the same
DIM_TEXT the Heatmap uses for 'no verdict' — whose 0.35 sits below the
near tier's 0.5 by the ordering viz_constants already documents. The
prior-position ring and the legend's neutral keys go with it. 'Disabled'
was the slabs' failure, not the colour's: a 5px dim dot is texture, and
whose series it is needs no colour to say — every lollipop on this chart
is Commercials, and the legend and caption both say so. The smaller head
stays, keeping full > near > quiet legible where hue is weak.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The leg ticks carried their own gate state as opacity — bright when the
leg sat through its extreme opposite Commercials, 0.4 otherwise. That
spent the channel on something the axis already says (a gating leg is by
definition at its own extreme, which is where its tick is drawn; the
hover names it besides), and 0.4 had sunk the legs to the background
tier where the quiet lollipops live. The legs are data — where the other
side of the trade sits — not chrome.

Opacity now follows the ROW's tier, the same rule every other mark on
the row obeys: rows with a verdict light whole — lollipop, name, and
every leg on them, ready to be inspected — and quiet rows knock their
ticks back to 0.55, dimmed but solidly readable. One prominence system
for the whole row instead of three.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mspinola
mspinola merged commit 7501a9c into main Aug 22, 2026
0 of 3 checks passed
@mspinola
mspinola deleted the claude/strip-visual-fixes branch August 22, 2026 03:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant