Scatter / Bubble Plot

A read-only, CSS-only scatter plot. Each point is positioned by its --x / --y (0–100). Color encodes a category (pass / fail); points are circles, and --size would make bubbles. The blue line is an optional trend line — here the data shows a strong positive correlation between study hours and exam score. No JavaScript.

Study hours vs. exam score
Exam score by hours studied
HoursScoreResult
1.030Fail
2.042Fail
2.538Fail
3.055Fail
4.058Fail
4.565Pass
5.062Pass
5.570Pass
6.075Pass
7.080Pass
8.088Pass
9.595Pass
Exam score
0 50 100
0h 5h 10h
Study hours
Pass (≥ 60)
Fail (< 60)

Markup

<!-- .casca-plot frames the plot with axis bands; each tick sits at
     --pos (0..100, percent of the axis). Each point is positioned by
     --x / --y (0..100); --color encodes a category, --size makes bubbles. -->
<div class="casca-plot">
  <span class="casca-axis-title" data-axis="y">Exam score</span>
  <div class="casca-axis" data-axis="y">
    <span class="casca-axis-tick" style="--pos: 0">0</span>
    <span class="casca-axis-tick" style="--pos: 50">50</span>
    <span class="casca-axis-tick" style="--pos: 100">100</span>
  </div>

  <div class="casca-scatter" aria-hidden="true" data-grid>
    <!-- optional trend line: server-fit y at the left (--y1) and right (--y2) edge -->
    <div class="casca-scatter-trend" style="--y1: 24; --y2: 96"></div>
    <div class="casca-scatter-point"
         style="--x: 30; --y: 55; --color: var(--casca-color-8)" title="3.0h → 55"></div>
    <div class="casca-scatter-point"
         style="--x: 70; --y: 80; --color: var(--casca-color-5)" title="7.0h → 80"></div>
    <!-- ...one .casca-scatter-point per observation... -->
  </div>

  <div class="casca-axis" data-axis="x">
    <span class="casca-axis-tick" style="--pos: 0">0h</span>
    <span class="casca-axis-tick" style="--pos: 50">5h</span>
    <span class="casca-axis-tick" style="--pos: 100">10h</span>
  </div>
  <span class="casca-axis-title" data-axis="x">Study hours</span>
</div>

Four-quadrant matrix

The same plot with optional quadrant dividers (--qx / --qy, 0–100) splitting it into four cells for 2×2 analysis — here effort vs. impact. Corner labels are plain positioned text. No JavaScript.

Effort vs. impact
Backlog items by effort and impact
ItemEffortImpactQuadrant
Search filters2082Quick win
Dark mode3468Quick win
New onboarding7888Big bet
Billing rewrite7260Big bet
Tooltip copy2228Fill-in
Legacy migration8524Money pit
Icon refresh6238Money pit
Impact
Low High
Low High
Effort

Markup

<!-- quadrant dividers split the plot at --qx / --qy (0..100); labels are
     positioned by --x / --y like points -->
<div class="casca-scatter" aria-hidden="true">
  <div class="casca-scatter-quadrants" style="--qx: 50; --qy: 50">
    <span class="casca-scatter-quadrant-label" style="--x: 25; --y: 90">Quick wins</span>
    <span class="casca-scatter-quadrant-label" style="--x: 75; --y: 90">Big bets</span>
    <!-- ...one label per quadrant... -->
  </div>
  <div class="casca-scatter-point" style="--x: 20; --y: 82"></div>
  <!-- ...points... -->
</div>

Clustering by category

Color-code points by category to show clusters — here customer segments by spend (x) vs. visit frequency (y). Each cluster gets a distinct --color; a legend names them. No JavaScript.

Customer segments
Spend vs. visit frequency by segment
SpendFrequencySegment
8085Loyal
8878Loyal
7590Loyal
9282Loyal
4550Regular
5258Regular
4045Regular
5548Regular
1520New
2215New
1028New
2522New
Frequency
Low High
Low High
Spend
Loyal
Regular
New

Markup (clustering)

<!-- color-code points by category; a legend names the clusters -->
<div class="casca-scatter" aria-hidden="true" data-grid>
  <div class="casca-scatter-point" style="--x: 80; --y: 85; --color: var(--casca-color-1)"></div>
  <div class="casca-scatter-point" style="--x: 45; --y: 50; --color: var(--casca-color-5)"></div>
  <div class="casca-scatter-point" style="--x: 15; --y: 20; --color: var(--casca-color-3)"></div>
  <!-- ...one point per observation, --color per cluster... -->
</div>