Skip to content

Commit 8024974

Browse files
feat(highcharts): implement scatter-annotated (#11615)
## Implementation: `scatter-annotated` - javascript/highcharts Implements the **javascript/highcharts** version of `scatter-annotated`. **File:** `plots/scatter-annotated/implementations/javascript/highcharts.js` **Parent Issue:** #2790 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/33967807558)* --------- 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 0ead711 commit 8024974

2 files changed

Lines changed: 410 additions & 0 deletions

File tree

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// anyplot.ai
2+
// scatter-annotated: Annotated Scatter Plot with Text Labels
3+
// Library: highcharts 12.6.0 | JavaScript 22.23.2
4+
// Quality: 88/100 | Created: 2026-09-05
5+
6+
const t = window.ANYPLOT_TOKENS;
7+
8+
// --- Data (in-memory, deterministic) ----------------------------------------
9+
// Revenue vs. market cap for a set of well-known tech companies (illustrative
10+
// figures, not live market data). Labels annotate every point since n is small.
11+
// Two points are called out as focal outliers: Nvidia carries by far the
12+
// richest market-cap-to-revenue multiple (~36x vs. a ~3-17x range for peers),
13+
// and Amazon is the clear revenue leader — a distinct kind of standout.
14+
const companies = [
15+
{ name: "Apple", revenue: 383, marketCap: 2950 },
16+
{ name: "Microsoft", revenue: 212, marketCap: 3100 },
17+
{ name: "Alphabet", revenue: 307, marketCap: 1850 },
18+
{ name: "Amazon", revenue: 575, marketCap: 1900, highlight: true },
19+
{ name: "Nvidia", revenue: 61, marketCap: 2200, highlight: true },
20+
{ name: "Meta", revenue: 135, marketCap: 1250 },
21+
{ name: "Tesla", revenue: 97, marketCap: 780 },
22+
{ name: "Broadcom", revenue: 35, marketCap: 610 },
23+
{ name: "Oracle", revenue: 50, marketCap: 330 },
24+
{ name: "Adobe", revenue: 19, marketCap: 230 },
25+
{ name: "Salesforce", revenue: 34, marketCap: 260 },
26+
{ name: "IBM", revenue: 61, marketCap: 175 },
27+
{ name: "Intel", revenue: 54, marketCap: 105 },
28+
{ name: "Cisco", revenue: 57, marketCap: 200 },
29+
{ name: "Uber", revenue: 37, marketCap: 145 },
30+
];
31+
32+
// Data-label offset from each point (CSS px) — shared between the dataLabels
33+
// config below and the connector-line renderer so the two stay in sync.
34+
const LABEL_DX = 14;
35+
const LABEL_DY = 0;
36+
37+
const points = companies.map((c) => ({
38+
x: c.revenue,
39+
y: c.marketCap,
40+
name: c.name,
41+
marker: c.highlight
42+
? { radius: 9, fillColor: t.palette[0], lineWidth: 1.5 }
43+
: undefined,
44+
dataLabels: c.highlight
45+
? { style: { fontWeight: "700" } }
46+
: undefined,
47+
}));
48+
49+
// --- Chart -------------------------------------------------------------------
50+
Highcharts.chart("container", {
51+
chart: {
52+
type: "scatter",
53+
backgroundColor: "transparent",
54+
animation: false,
55+
style: { fontFamily: "inherit" },
56+
events: {
57+
// Draw a subtle connector from each marker's edge to its offset label
58+
// via the SVG renderer directly (Highcharts has no built-in scatter
59+
// dataLabel connector — that's a pie-only feature).
60+
render: function () {
61+
const chart = this;
62+
if (chart.connectorGroup) {
63+
chart.connectorGroup.destroy();
64+
}
65+
const group = chart.renderer.g("data-connectors").add();
66+
chart.series[0].points.forEach((point) => {
67+
if (!point.graphic || !point.dataLabel) return;
68+
const r = point.graphic.attr("r") || 7;
69+
const x1 = chart.plotLeft + point.plotX + r;
70+
const y1 = chart.plotTop + point.plotY;
71+
const x2 = chart.plotLeft + point.plotX + LABEL_DX - 2;
72+
const y2 = chart.plotTop + point.plotY + LABEL_DY;
73+
chart.renderer
74+
.path(["M", x1, y1, "L", x2, y2])
75+
.attr({ "stroke-width": 1, stroke: t.inkSoft, opacity: 0.5, zIndex: 3 })
76+
.add(group);
77+
});
78+
chart.connectorGroup = group;
79+
},
80+
},
81+
},
82+
credits: { enabled: false },
83+
colors: t.palette,
84+
title: {
85+
text: "scatter-annotated · javascript · highcharts · anyplot.ai",
86+
style: { color: t.ink, fontSize: "22px", fontWeight: "600" },
87+
},
88+
xAxis: {
89+
type: "logarithmic",
90+
title: {
91+
text: "Annual Revenue (USD billions, log scale)",
92+
style: { color: t.inkSoft, fontSize: "16px" },
93+
},
94+
lineColor: t.inkSoft,
95+
tickColor: t.inkSoft,
96+
gridLineColor: t.grid,
97+
gridLineWidth: 1,
98+
labels: { style: { color: t.inkSoft, fontSize: "14px" } },
99+
},
100+
yAxis: {
101+
type: "logarithmic",
102+
title: {
103+
text: "Market Cap (USD billions, log scale)",
104+
style: { color: t.inkSoft, fontSize: "16px" },
105+
},
106+
lineColor: t.inkSoft,
107+
tickColor: t.inkSoft,
108+
gridLineColor: t.grid,
109+
gridLineWidth: 1,
110+
labels: { style: { color: t.inkSoft, fontSize: "14px" } },
111+
},
112+
legend: { enabled: false },
113+
tooltip: {
114+
pointFormat: "Revenue: {point.x}B · Market Cap: {point.y}B",
115+
},
116+
plotOptions: {
117+
series: { animation: false },
118+
scatter: {
119+
marker: {
120+
radius: 7,
121+
fillColor: Highcharts.color(t.palette[0]).setOpacity(0.7).get(),
122+
lineWidth: 1,
123+
lineColor: t.pageBg,
124+
},
125+
dataLabels: {
126+
enabled: true,
127+
format: "{point.name}",
128+
align: "left",
129+
verticalAlign: "middle",
130+
x: LABEL_DX,
131+
y: LABEL_DY,
132+
allowOverlap: false,
133+
style: {
134+
color: t.ink,
135+
fontSize: "13px",
136+
fontWeight: "normal",
137+
textOutline: "none",
138+
},
139+
},
140+
},
141+
},
142+
series: [
143+
{
144+
name: "Companies",
145+
data: points,
146+
color: t.palette[0],
147+
},
148+
],
149+
});

0 commit comments

Comments
 (0)