Skip to content

Commit 4202ce1

Browse files
feat(echarts): implement scatter-color-mapped (#11627)
## Implementation: `scatter-color-mapped` - javascript/echarts Implements the **javascript/echarts** version of `scatter-color-mapped`. **File:** `plots/scatter-color-mapped/implementations/javascript/echarts.js` **Parent Issue:** #2004 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/33969911907)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com>
1 parent 9420406 commit 4202ce1

2 files changed

Lines changed: 350 additions & 0 deletions

File tree

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// anyplot.ai
2+
// scatter-color-mapped: Color-Mapped Scatter Plot
3+
// Library: echarts 6.1.0 | JavaScript 22.23.2
4+
// Quality: 90/100 | Created: 2026-09-05
5+
6+
//# anyplot-orientation: landscape
7+
const t = window.ANYPLOT_TOKENS;
8+
9+
// --- Data (in-memory, deterministic LCG) ------------------------------------
10+
let seed = 42;
11+
function rand() {
12+
seed = (seed * 1103515245 + 12345) & 0x7fffffff;
13+
return seed / 0x7fffffff;
14+
}
15+
16+
const stationCount = 220;
17+
const points = [];
18+
for (let i = 0; i < stationCount; i++) {
19+
const rawLongitude = -170 + rand() * 60; // degrees W, Pacific basin (negative = west)
20+
const latitude = -10 + rand() * 50; // degrees N, equator to mid-latitude
21+
const baseTemp = 29 - 0.32 * Math.abs(latitude - 5); // warmer near the equator
22+
const gradient = (rawLongitude + 170) * 0.02; // mild east-west drift
23+
const noise = (rand() - 0.5) * 2.5;
24+
const seaSurfaceTemp = baseTemp + gradient + noise;
25+
const longitudeW = -rawLongitude; // positive magnitude, paired with the "(°W)" suffix below
26+
points.push([longitudeW, latitude, Number(seaSurfaceTemp.toFixed(2))]);
27+
}
28+
29+
const temps = points.map((p) => p[2]);
30+
const tempMin = Math.min(...temps);
31+
const tempMax = Math.max(...temps);
32+
let warmest = points[0];
33+
let coldest = points[0];
34+
for (const p of points) {
35+
if (p[2] > warmest[2]) warmest = p;
36+
if (p[2] < coldest[2]) coldest = p;
37+
}
38+
39+
// --- Init --------------------------------------------------------------------
40+
const chart = echarts.init(document.getElementById("container"));
41+
42+
// --- Option --------------------------------------------------------------------
43+
chart.setOption({
44+
animation: false,
45+
backgroundColor: "transparent",
46+
title: {
47+
text: "scatter-color-mapped · javascript · echarts · anyplot.ai",
48+
left: "center",
49+
textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },
50+
},
51+
grid: { left: 90, right: 220, top: 100, bottom: 90 },
52+
xAxis: {
53+
type: "value",
54+
name: "Longitude (°W)",
55+
nameLocation: "middle",
56+
nameGap: 40,
57+
nameTextStyle: { color: t.ink, fontSize: 16 },
58+
min: 110,
59+
max: 170,
60+
axisLabel: { color: t.inkSoft, fontSize: 14 },
61+
axisLine: { lineStyle: { color: t.inkSoft } },
62+
splitLine: { lineStyle: { color: t.grid, opacity: 0.6 } },
63+
},
64+
yAxis: {
65+
type: "value",
66+
name: "Latitude (°N)",
67+
nameLocation: "middle",
68+
nameGap: 55,
69+
nameTextStyle: { color: t.ink, fontSize: 16 },
70+
min: -10,
71+
max: 40,
72+
axisLabel: { color: t.inkSoft, fontSize: 14 },
73+
axisLine: { lineStyle: { color: t.inkSoft } },
74+
splitLine: { lineStyle: { color: t.grid, opacity: 0.6 } },
75+
},
76+
visualMap: {
77+
type: "continuous",
78+
dimension: 2,
79+
min: Math.floor(tempMin),
80+
max: Math.ceil(tempMax),
81+
orient: "vertical",
82+
right: 40,
83+
top: "middle",
84+
itemHeight: 500,
85+
text: ["Sea Surface Temp (°C)", ""],
86+
textStyle: { color: t.inkSoft, fontSize: 14 },
87+
inRange: { color: t.seq },
88+
calculable: true,
89+
},
90+
series: [
91+
{
92+
type: "scatter",
93+
data: points,
94+
symbolSize: 16,
95+
itemStyle: {
96+
opacity: 0.75,
97+
borderColor: t.pageBg,
98+
borderWidth: 1,
99+
},
100+
markPoint: {
101+
symbol: "circle",
102+
symbolSize: 30,
103+
itemStyle: { color: "transparent", borderColor: t.ink, borderWidth: 2 },
104+
label: {
105+
color: t.ink,
106+
fontSize: 13,
107+
fontWeight: 600,
108+
position: "top",
109+
formatter: (p) => `${p.data.name} ${p.value.toFixed(1)}°C`,
110+
},
111+
data: [
112+
{ name: "Warmest", coord: [warmest[0], warmest[1]], value: warmest[2] },
113+
{ name: "Coldest", coord: [coldest[0], coldest[1]], value: coldest[2] },
114+
],
115+
},
116+
},
117+
],
118+
});
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
library: echarts
2+
language: javascript
3+
specification_id: scatter-color-mapped
4+
created: '2026-09-05T13:51:43Z'
5+
updated: '2026-09-05T14:04:29Z'
6+
generated_by: claude-sonnet
7+
workflow_run: 33969911907
8+
issue: 2004
9+
language_version: 22.23.2
10+
library_version: 6.1.0
11+
preview_url_light: https://storage.googleapis.com/anyplot-images/plots/scatter-color-mapped/javascript/echarts/plot-light.png
12+
preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/scatter-color-mapped/javascript/echarts/plot-dark.png
13+
preview_html_light: https://storage.googleapis.com/anyplot-images/plots/scatter-color-mapped/javascript/echarts/plot-light.html
14+
preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/scatter-color-mapped/javascript/echarts/plot-dark.html
15+
quality_score: 90
16+
review:
17+
strengths: []
18+
weaknesses: []
19+
image_description: |-
20+
Light render (plot-light.png):
21+
Background: Warm off-white, consistent with #FAF8F1 — not pure white.
22+
Chrome: Title "scatter-color-mapped · javascript · echarts · anyplot.ai" centered at top in dark ink, clearly legible. "Longitude (°W)" and "Latitude (°N)" axis names in dark ink, tick labels in a softer dark gray. Subtle light-gray gridlines on both axes. Vertical colorbar ("Sea Surface Temp (°C)") on the right with min/max labels "17" and "31".
23+
Data: 220 scatter points spanning the full green-to-blue imprint_seq range, from brand-green (~17°C, high-latitude stations) to blue (~29-31°C, near-equator stations). White-ish borders on markers for definition against the light background.
24+
Legibility verdict: PASS — all text (title, axis names, tick labels, colorbar labels) reads clearly against the light background.
25+
26+
Dark render (plot-dark.png):
27+
Background: Warm near-black, consistent with #1A1A17 — not pure black.
28+
Chrome: Same title, now in light/off-white ink, clearly legible. Axis names and tick labels rendered in light gray tones. Gridlines are subtle but visible against the dark background. Colorbar labels and title text are light-colored and readable.
29+
Data: Same 220 points in the identical green-to-blue imprint_seq gradient as the light render — confirmed data colors are unchanged between themes, only the chrome (background, text, grid, marker border color) flipped.
30+
Legibility verdict: PASS — no dark-on-dark or light-on-light failures observed; all text is clearly visible against the near-black surface.
31+
criteria_checklist:
32+
visual_quality:
33+
score: 28
34+
max: 30
35+
items:
36+
- id: VQ-01
37+
name: Text Legibility
38+
score: 7
39+
max: 8
40+
passed: true
41+
comment: All font sizes explicitly set (title 22px, axis names 16px, tick/visualMap
42+
text 14px); readable in both themes, no overflow or clipping
43+
- id: VQ-02
44+
name: No Overlap
45+
score: 6
46+
max: 6
47+
passed: true
48+
comment: No text overlap; a few data markers touch in dense clusters but text
49+
stays fully clear
50+
- id: VQ-03
51+
name: Element Visibility
52+
score: 5
53+
max: 6
54+
passed: true
55+
comment: 220 points at symbolSize 20 with 0.85 opacity is visible and mostly
56+
well-adapted to medium density; a few dense clusters overlap slightly
57+
- id: VQ-04
58+
name: Color Accessibility
59+
score: 2
60+
max: 2
61+
passed: true
62+
comment: imprint_seq is a CVD-safe perceptually-uniform gradient; good contrast
63+
against both surfaces
64+
- id: VQ-05
65+
name: Layout & Canvas
66+
score: 4
67+
max: 4
68+
passed: true
69+
comment: Plot area + colorbar use most of the canvas with balanced margins;
70+
nothing cut off
71+
- id: VQ-06
72+
name: Axis Labels & Title
73+
score: 2
74+
max: 2
75+
passed: true
76+
comment: Longitude (°W) / Latitude (°N) — descriptive with units, though the
77+
negative-number + W-suffix combination is a minor convention nit
78+
- id: VQ-07
79+
name: Palette Compliance
80+
score: 2
81+
max: 2
82+
passed: true
83+
comment: Uses imprint_seq (t.seq) correctly for single-polarity continuous
84+
data; theme-correct backgrounds and chrome in both renders
85+
design_excellence:
86+
score: 12
87+
max: 20
88+
items:
89+
- id: DE-01
90+
name: Aesthetic Sophistication
91+
score: 4
92+
max: 8
93+
passed: false
94+
comment: 'Well-configured default: correct palette and border treatment, but
95+
no strong custom hierarchy beyond that'
96+
- id: DE-02
97+
name: Visual Refinement
98+
score: 4
99+
max: 6
100+
passed: false
101+
comment: L-shaped implicit axis lines, subtle gridlines, white-bordered markers
102+
— some refinement visible
103+
- id: DE-03
104+
name: Data Storytelling
105+
score: 4
106+
max: 6
107+
passed: false
108+
comment: Color pattern visibly correlates with latitude (warm equatorial cluster
109+
vs. cool high-latitude cluster), giving the viewer a discoverable insight
110+
without explicit annotation
111+
spec_compliance:
112+
score: 15
113+
max: 15
114+
items:
115+
- id: SC-01
116+
name: Plot Type
117+
score: 5
118+
max: 5
119+
passed: true
120+
comment: Correct color-mapped scatter plot
121+
- id: SC-02
122+
name: Required Features
123+
score: 4
124+
max: 4
125+
passed: true
126+
comment: Perceptually uniform colormap, labeled colorbar with units, moderate
127+
marker size, transparency for overlap — all present
128+
- id: SC-03
129+
name: Data Mapping
130+
score: 3
131+
max: 3
132+
passed: true
133+
comment: x=longitude, y=latitude, color=temperature; full data range visible
134+
on both axes
135+
- id: SC-04
136+
name: Title & Legend
137+
score: 3
138+
max: 3
139+
passed: true
140+
comment: Title matches the mandated format exactly; colorbar substitutes appropriately
141+
for a legend on single-series continuous data
142+
data_quality:
143+
score: 15
144+
max: 15
145+
items:
146+
- id: DQ-01
147+
name: Feature Coverage
148+
score: 6
149+
max: 6
150+
passed: true
151+
comment: Full continuum of color values represented, visualMap bounds set
152+
from actual data min/max
153+
- id: DQ-02
154+
name: Realistic Context
155+
score: 5
156+
max: 5
157+
passed: true
158+
comment: Sea-surface-temperature-by-coordinate is a real, neutral scientific
159+
scenario directly matching the spec's suggested application
160+
- id: DQ-03
161+
name: Appropriate Scale
162+
score: 4
163+
max: 4
164+
passed: true
165+
comment: 17-31°C SST range and -10 to 40°N / -170 to -110°W Pacific-basin
166+
coordinates are physically plausible, with a correct warmer-near-equator
167+
trend
168+
code_quality:
169+
score: 10
170+
max: 10
171+
items:
172+
- id: CQ-01
173+
name: KISS Structure
174+
score: 3
175+
max: 3
176+
passed: true
177+
comment: Imports/data/init/option, no functions or classes
178+
- id: CQ-02
179+
name: Reproducibility
180+
score: 2
181+
max: 2
182+
passed: true
183+
comment: Fixed-seed LCG (seed=42)
184+
- id: CQ-03
185+
name: Clean Imports
186+
score: 2
187+
max: 2
188+
passed: true
189+
comment: Only the echarts global used, no extraneous imports
190+
- id: CQ-04
191+
name: Code Elegance
192+
score: 2
193+
max: 2
194+
passed: true
195+
comment: Appropriate complexity, no fake functionality
196+
- id: CQ-05
197+
name: Output & API
198+
score: 1
199+
max: 1
200+
passed: true
201+
comment: Mount-node contract respected, animation:false set, no explicit size/devicePixelRatio
202+
passed
203+
library_mastery:
204+
score: 7
205+
max: 10
206+
items:
207+
- id: LM-01
208+
name: Idiomatic Usage
209+
score: 4
210+
max: 5
211+
passed: true
212+
comment: Correct high-level setOption usage with continuous visualMap bound
213+
to the color dimension
214+
- id: LM-02
215+
name: Distinctive Features
216+
score: 3
217+
max: 5
218+
passed: true
219+
comment: visualMap.calculable enables an ECharts-distinctive interactive range
220+
slider in the HTML detail view, not easily replicated in a static library
221+
verdict: REJECTED
222+
impl_tags:
223+
dependencies: []
224+
techniques:
225+
- colorbar
226+
patterns:
227+
- data-generation
228+
dataprep: []
229+
styling:
230+
- custom-colormap
231+
- alpha-blending
232+
- edge-highlighting

0 commit comments

Comments
 (0)