@amcharts/amcharts5-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,368 @@
1
+ # Venn Diagram
2
+
3
+ Docs: https://www.amcharts.com/docs/v5/charts/venn/
4
+
5
+ Venn diagrams show overlapping relationships between sets. There is NO `VennDiagram` chart class — `am5venn.Venn` is both the series and the visual container, pushed directly into `root.container.children` (or any `Container`).
6
+
7
+ ## Imports
8
+
9
+ ### ES modules / TypeScript
10
+ ```ts
11
+ import * as am5 from "@amcharts/amcharts5";
12
+ import * as am5venn from "@amcharts/amcharts5/venn";
13
+ import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
14
+ ```
15
+
16
+ ### CDN / script tags
17
+ ```html
18
+ <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
19
+ <script src="https://cdn.amcharts.com/lib/5/venn.js"></script>
20
+ <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
21
+ ```
22
+
23
+ ## Setup
24
+
25
+ **IMPORTANT:** There is no `am5venn.VennDiagram` class. The `am5venn.Venn` object IS the chart — push it directly into a container.
26
+
27
+ ```js
28
+ const root = am5.Root.new("chartdiv");
29
+ root.setThemes([am5themes_Animated.new(root)]);
30
+
31
+ // Create a wrapper container (optional, useful for adding legend)
32
+ const container = root.container.children.push(am5.Container.new(root, {
33
+ width: am5.p100,
34
+ height: am5.p100,
35
+ layout: root.verticalLayout
36
+ }));
37
+
38
+ // Venn is pushed directly into the container — NOT into chart.series
39
+ const series = container.children.push(
40
+ am5venn.Venn.new(root, {
41
+ categoryField: "name",
42
+ valueField: "value",
43
+ intersectionsField: "sets", // field that holds parent set names
44
+ })
45
+ );
46
+ ```
47
+
48
+ ## Data structure
49
+
50
+ Venn data contains two types of entries:
51
+
52
+ ### 1. Sets (circles)
53
+
54
+ Each set defines a circle. `value` controls the circle's area.
55
+
56
+ ```js
57
+ { name: "Set A", value: 100 }
58
+ ```
59
+
60
+ ### 2. Intersections (overlaps)
61
+
62
+ Intersections reference their parent sets by name via the `sets` array. `value` controls the overlap area.
63
+
64
+ ```js
65
+ { name: "A ∩ B", value: 30, sets: ["Set A", "Set B"] }
66
+ ```
67
+
68
+ ### Complete example data
69
+
70
+ ```js
71
+ series.data.setAll([
72
+ // Individual sets (circles)
73
+ { name: "Set A", value: 100 },
74
+ { name: "Set B", value: 80 },
75
+ { name: "Set C", value: 60 },
76
+
77
+ // Two-set intersections
78
+ { name: "A ∩ B", value: 30, sets: ["Set A", "Set B"] },
79
+ { name: "B ∩ C", value: 20, sets: ["Set B", "Set C"] },
80
+ { name: "A ∩ C", value: 15, sets: ["Set A", "Set C"] },
81
+
82
+ // Three-set intersection
83
+ { name: "A ∩ B ∩ C", value: 10, sets: ["Set A", "Set B", "Set C"] }
84
+ ]);
85
+ ```
86
+
87
+ **Important:** The `sets` array values must exactly match the `name` field of the parent sets.
88
+
89
+ ## Customizing appearance
90
+
91
+ ### Slices (circles)
92
+
93
+ ```js
94
+ series.slices.template.setAll({
95
+ fillOpacity: 0.6,
96
+ strokeWidth: 2,
97
+ stroke: am5.color(0xffffff),
98
+ tooltipText: "{category}: {value}"
99
+ });
100
+
101
+ // Hover state
102
+ series.slices.template.states.create("hover", {
103
+ fillOpacity: 0.8,
104
+ scale: 1.02
105
+ });
106
+ ```
107
+
108
+ ### Labels
109
+
110
+ ```js
111
+ series.labels.template.setAll({
112
+ text: "{category}",
113
+ fontSize: 16,
114
+ fill: am5.color(0x000000),
115
+ textAlign: "center",
116
+ oversizedBehavior: "truncate" // "truncate" | "wrap" | "none"
117
+ });
118
+ ```
119
+
120
+ ### Custom colors
121
+
122
+ ```js
123
+ // Per-set colors from data
124
+ series.data.setAll([
125
+ { name: "Frontend", value: 100, fill: am5.color(0x264653) },
126
+ { name: "Backend", value: 80, fill: am5.color(0x2a9d8f) },
127
+ // ...
128
+ ]);
129
+
130
+ // Use fillField to map colors from data
131
+ am5venn.Venn.new(root, {
132
+ categoryField: "name",
133
+ valueField: "value",
134
+ intersectionsField: "sets",
135
+ fillField: "fill"
136
+ })
137
+ ```
138
+
139
+ ### Hide labels on intersections
140
+
141
+ ```js
142
+ series.labels.template.adapters.add("text", function(text, target) {
143
+ if (target.dataItem && target.dataItem.dataContext.sets) {
144
+ return ""; // hide label on intersections
145
+ }
146
+ return text;
147
+ });
148
+ ```
149
+
150
+ ## Click events
151
+
152
+ ```js
153
+ series.slices.template.events.on("click", function(ev) {
154
+ var dataItem = ev.target.dataItem;
155
+ console.log("Clicked:", dataItem.get("category"));
156
+ });
157
+ ```
158
+
159
+ ## Legend
160
+
161
+ ```js
162
+ // Add legend to the same container as the Venn series
163
+ const legend = container.children.push(am5.Legend.new(root, {
164
+ centerX: am5.percent(50),
165
+ x: am5.percent(50),
166
+ layout: root.horizontalLayout
167
+ }));
168
+
169
+ // Only show legend for main sets, not intersections
170
+ legend.data.setAll(series.dataItems.filter(function(di) {
171
+ return !di.dataContext.sets;
172
+ }));
173
+ ```
174
+
175
+ ## Two-set Venn example
176
+
177
+ ```js
178
+ series.data.setAll([
179
+ { name: "Frontend", value: 300 },
180
+ { name: "Backend", value: 250 },
181
+ { name: "Frontend ∩ Backend", value: 80, sets: ["Frontend", "Backend"] } // intersection — name must be unique
182
+ ]);
183
+ ```
184
+
185
+ ## Notes on sizing and positioning
186
+
187
+ - Circle sizes are proportional to `value`
188
+ - Intersection overlap is **approximate** — amCharts positions circles to visually suggest the declared intersection values, but exact area-proportional overlap is not guaranteed
189
+ - For best results, keep intersection values smaller than either parent set value
190
+ - Very small intersections relative to set sizes may not be visible
191
+
192
+ ---
193
+
194
+ ## Example: Technology skills Venn diagram
195
+
196
+ ```html
197
+ <!DOCTYPE html>
198
+ <html>
199
+ <head>
200
+ <meta charset="UTF-8">
201
+ <title>Venn Diagram</title>
202
+ <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
203
+ <script src="https://cdn.amcharts.com/lib/5/venn.js"></script>
204
+ <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
205
+ <style>
206
+ #chartdiv { width: 100%; height: 500px; }
207
+ </style>
208
+ </head>
209
+ <body>
210
+ <div id="chartdiv"></div>
211
+ <script>
212
+ var root = am5.Root.new("chartdiv");
213
+ root.setThemes([am5themes_Animated.new(root)]);
214
+
215
+ var container = root.container.children.push(am5.Container.new(root, {
216
+ width: am5.p100,
217
+ height: am5.p100,
218
+ layout: root.verticalLayout
219
+ }));
220
+
221
+ var series = container.children.push(
222
+ am5venn.Venn.new(root, {
223
+ categoryField: "name",
224
+ valueField: "value",
225
+ intersectionsField: "sets"
226
+ })
227
+ );
228
+
229
+ // Slice styling
230
+ series.slices.template.setAll({
231
+ fillOpacity: 0.6,
232
+ strokeWidth: 2,
233
+ stroke: am5.color(0xffffff),
234
+ tooltipText: "{category}: {value}"
235
+ });
236
+
237
+ series.slices.template.states.create("hover", {
238
+ fillOpacity: 0.8
239
+ });
240
+
241
+ // Label styling
242
+ series.labels.template.setAll({
243
+ text: "{category}",
244
+ fontSize: 14,
245
+ fill: am5.color(0x000000)
246
+ });
247
+
248
+ // Data
249
+ series.data.setAll([
250
+ { name: "Frontend", value: 120 },
251
+ { name: "Backend", value: 100 },
252
+ { name: "DevOps", value: 70 },
253
+ { name: "Frontend ∩ Backend", value: 40, sets: ["Frontend", "Backend"] },
254
+ { name: "Backend ∩ DevOps", value: 25, sets: ["Backend", "DevOps"] },
255
+ { name: "Frontend ∩ DevOps", value: 15, sets: ["Frontend", "DevOps"] },
256
+ { name: "Full Stack", value: 10, sets: ["Frontend", "Backend", "DevOps"] }
257
+ ]);
258
+
259
+ // Legend — only main sets
260
+ var legend = container.children.push(am5.Legend.new(root, {
261
+ centerX: am5.percent(50),
262
+ x: am5.percent(50)
263
+ }));
264
+ legend.data.setAll(series.dataItems.filter(function(di) {
265
+ return !di.dataContext.sets;
266
+ }));
267
+
268
+ series.appear(1000);
269
+ // Note: no chart.appear() needed — Venn is not a chart, just a series
270
+ </script>
271
+ </body>
272
+ </html>
273
+ ```
274
+
275
+ ## Example 2: Two-set Venn with custom colors and click handler
276
+
277
+ ```html
278
+ <!DOCTYPE html>
279
+ <html>
280
+ <head>
281
+ <meta charset="UTF-8">
282
+ <title>Two-Set Venn</title>
283
+ <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
284
+ <script src="https://cdn.amcharts.com/lib/5/venn.js"></script>
285
+ <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
286
+ <style>
287
+ #chartdiv { width: 100%; height: 500px; }
288
+ </style>
289
+ </head>
290
+ <body>
291
+ <div id="chartdiv"></div>
292
+ <script>
293
+ var root = am5.Root.new("chartdiv");
294
+ root.setThemes([am5themes_Animated.new(root)]);
295
+
296
+ var container = root.container.children.push(am5.Container.new(root, {
297
+ width: am5.p100,
298
+ height: am5.p100,
299
+ layout: root.verticalLayout
300
+ }));
301
+
302
+ var series = container.children.push(
303
+ am5venn.Venn.new(root, {
304
+ categoryField: "name",
305
+ valueField: "value",
306
+ intersectionsField: "sets",
307
+ fillField: "fill"
308
+ })
309
+ );
310
+
311
+ // Styling
312
+ series.slices.template.setAll({
313
+ fillOpacity: 0.65,
314
+ strokeWidth: 3,
315
+ stroke: am5.color(0xffffff),
316
+ tooltipText: "{category}: {value}"
317
+ });
318
+
319
+ series.slices.template.states.create("hover", {
320
+ fillOpacity: 0.85,
321
+ scale: 1.03
322
+ });
323
+
324
+ series.labels.template.setAll({
325
+ text: "{category}\n[bold]{value}[/]",
326
+ fontSize: 15,
327
+ fill: am5.color(0xffffff),
328
+ textAlign: "center"
329
+ });
330
+
331
+ // Hide labels on intersection
332
+ series.labels.template.adapters.add("text", function(text, target) {
333
+ if (target.dataItem && target.dataItem.dataContext.sets) {
334
+ return "[bold]{value}[/]";
335
+ }
336
+ return text;
337
+ });
338
+
339
+ // Click handler
340
+ series.slices.template.events.on("click", function(ev) {
341
+ var di = ev.target.dataItem;
342
+ alert(di.get("category") + ": " + di.get("value"));
343
+ });
344
+
345
+ // Data
346
+ series.data.setAll([
347
+ { name: "Mobile Users", value: 450, fill: am5.color(0x2196f3) },
348
+ { name: "Desktop Users", value: 380, fill: am5.color(0x4caf50) },
349
+ { name: "Both Platforms", value: 120, sets: ["Mobile Users", "Desktop Users"], fill: am5.color(0x9c27b0) }
350
+ ]);
351
+
352
+ // Legend — main sets only
353
+ var legend = container.children.push(am5.Legend.new(root, {
354
+ centerX: am5.percent(50),
355
+ x: am5.percent(50),
356
+ y: am5.percent(95),
357
+ centerY: am5.percent(100)
358
+ }));
359
+ legend.data.setAll(series.dataItems.filter(function(di) {
360
+ return !di.dataContext.sets;
361
+ }));
362
+
363
+ series.appear(1000);
364
+ // Note: no chart.appear() needed — Venn is not a chart, just a series
365
+ </script>
366
+ </body>
367
+ </html>
368
+ ```
@@ -0,0 +1,339 @@
1
+ # Word Cloud
2
+
3
+ Docs: https://www.amcharts.com/docs/v5/charts/word-cloud/
4
+
5
+ Word Cloud displays words/tags sized by their value/weight. It's a "container-less" chart — the series is pushed directly to `root.container.children` (no wrapper chart object).
6
+
7
+ ## Imports
8
+
9
+ ### ES modules / TypeScript
10
+ ```ts
11
+ import * as am5 from "@amcharts/amcharts5";
12
+ import * as am5wc from "@amcharts/amcharts5/wc";
13
+ import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
14
+ ```
15
+
16
+ ### CDN / script tags
17
+ ```html
18
+ <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
19
+ <script src="https://cdn.amcharts.com/lib/5/wc.js"></script>
20
+ <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
21
+ ```
22
+
23
+ ## Setup
24
+
25
+ ```js
26
+ const root = am5.Root.new("chartdiv");
27
+ root.setThemes([am5themes_Animated.new(root)]);
28
+
29
+ // WordCloud is pushed directly — no chart wrapper
30
+ const series = root.container.children.push(
31
+ am5wc.WordCloud.new(root, {
32
+ categoryField: "tag",
33
+ valueField: "weight",
34
+ maxFontSize: am5.percent(15), // relative to container
35
+ minFontSize: am5.percent(3),
36
+ })
37
+ );
38
+
39
+ // Data — LAST
40
+ series.data.setAll([
41
+ { tag: "JavaScript", weight: 64 },
42
+ { tag: "Python", weight: 48 },
43
+ { tag: "TypeScript", weight: 35 },
44
+ { tag: "Java", weight: 30 },
45
+ { tag: "React", weight: 28 },
46
+ { tag: "Node.js", weight: 22 },
47
+ { tag: "CSS", weight: 18 },
48
+ { tag: "SQL", weight: 15 }
49
+ ]);
50
+
51
+ series.appear(1000);
52
+ ```
53
+
54
+ ## Settings
55
+
56
+ | Setting | Type | Default | Description |
57
+ |---------|------|---------|-------------|
58
+ | `categoryField` | string | — | Data field for word text (required) |
59
+ | `valueField` | string | — | Data field for word weight/size (required) |
60
+ | `maxFontSize` | percent/number | `am5.percent(20)` | Maximum font size |
61
+ | `minFontSize` | percent/number | `am5.percent(2)` | Minimum font size |
62
+ | `angles` | number[] | `[0, -90]` | Allowed rotation angles for words |
63
+ | `randomness` | number (0–1) | `0.2` | Layout randomness (0 = ordered by value, 1 = fully random) |
64
+ | `minWordLength` | number | `1` | Skip words shorter than this |
65
+ | `maxCount` | number | — | Maximum number of words to display |
66
+ | `excludeWords` | string[] | `[]` | Words to exclude |
67
+ | `text` | string | — | Raw text to parse — words are extracted and weighted by frequency automatically |
68
+ | `colors` | ColorSet | — | Color set for words |
69
+
70
+ ### excludeWords example
71
+
72
+ ```js
73
+ am5wc.WordCloud.new(root, {
74
+ categoryField: "word",
75
+ valueField: "count",
76
+ excludeWords: ["the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "is", "it"]
77
+ });
78
+ ```
79
+
80
+ **Note:** amCharts WordCloud does not support mask/shape rendering (words constrained to a custom shape). Words are arranged in a rectangular area.
81
+
82
+ ## Customizing labels
83
+
84
+ ```js
85
+ series.labels.template.setAll({
86
+ fontFamily: "Courier New",
87
+ fontWeight: "bold",
88
+ paddingTop: 5,
89
+ paddingBottom: 5,
90
+ paddingLeft: 5,
91
+ paddingRight: 5,
92
+ tooltipText: "{category}: {value}",
93
+ cursorOverStyle: "pointer"
94
+ });
95
+ ```
96
+
97
+ ## Click events
98
+
99
+ ```js
100
+ series.labels.template.events.on("click", function(ev) {
101
+ var dataItem = ev.target.dataItem;
102
+ console.log("Clicked:", dataItem.get("category"), dataItem.get("value"));
103
+ });
104
+ ```
105
+
106
+ ## Custom colors
107
+
108
+ ```js
109
+ // From a fixed list
110
+ series.set("colors", am5.ColorSet.new(root, {
111
+ colors: [
112
+ am5.color(0x095256),
113
+ am5.color(0x087f8c),
114
+ am5.color(0x5aaa95),
115
+ am5.color(0x86a873),
116
+ am5.color(0xbb9f06)
117
+ ]
118
+ }));
119
+
120
+ // Or use color from data
121
+ series.labels.template.adapters.add("fill", function(fill, target) {
122
+ if (target.dataItem) {
123
+ return am5.color(target.dataItem.dataContext.color);
124
+ }
125
+ return fill;
126
+ });
127
+ ```
128
+
129
+ ## Sentence Cloud
130
+
131
+ Instead of individual words, you can display phrases by using multi-word category values:
132
+
133
+ ```js
134
+ series.data.setAll([
135
+ { tag: "Machine Learning", weight: 40 },
136
+ { tag: "Data Science", weight: 35 },
137
+ { tag: "Web Development", weight: 30 }
138
+ ]);
139
+ ```
140
+
141
+ ## Changing data dynamically
142
+
143
+ ```js
144
+ // Replace all data
145
+ series.data.setAll(newData);
146
+
147
+ // Add items
148
+ series.data.push({ tag: "Rust", weight: 20 });
149
+
150
+ // Remove by index
151
+ series.data.removeIndex(0);
152
+ ```
153
+
154
+ ---
155
+
156
+ ## Example: Interactive word cloud
157
+
158
+ ```html
159
+ <!DOCTYPE html>
160
+ <html>
161
+ <head>
162
+ <meta charset="UTF-8">
163
+ <title>Word Cloud</title>
164
+ <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
165
+ <script src="https://cdn.amcharts.com/lib/5/wc.js"></script>
166
+ <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
167
+ <style>
168
+ #chartdiv { width: 100%; height: 500px; }
169
+ </style>
170
+ </head>
171
+ <body>
172
+ <div id="chartdiv"></div>
173
+ <script>
174
+ var root = am5.Root.new("chartdiv");
175
+ root.setThemes([am5themes_Animated.new(root)]);
176
+
177
+ var series = root.container.children.push(
178
+ am5wc.WordCloud.new(root, {
179
+ categoryField: "tag",
180
+ valueField: "weight",
181
+ maxFontSize: am5.percent(15),
182
+ minFontSize: am5.percent(3),
183
+ angles: [0, -45, -90],
184
+ randomness: 0.3
185
+ })
186
+ );
187
+
188
+ // Custom colors
189
+ series.set("colors", am5.ColorSet.new(root, {
190
+ colors: [
191
+ am5.color(0x264653),
192
+ am5.color(0x2a9d8f),
193
+ am5.color(0xe9c46a),
194
+ am5.color(0xf4a261),
195
+ am5.color(0xe76f51)
196
+ ]
197
+ }));
198
+
199
+ // Label styling
200
+ series.labels.template.setAll({
201
+ fontFamily: "Arial",
202
+ tooltipText: "{category}: [bold]{value}[/]",
203
+ cursorOverStyle: "pointer"
204
+ });
205
+
206
+ // Click handler
207
+ series.labels.template.events.on("click", function(ev) {
208
+ var category = ev.target.dataItem.get("category");
209
+ alert("You clicked: " + category);
210
+ });
211
+
212
+ series.data.setAll([
213
+ { tag: "JavaScript", weight: 64 },
214
+ { tag: "Python", weight: 48 },
215
+ { tag: "TypeScript", weight: 35 },
216
+ { tag: "Java", weight: 30 },
217
+ { tag: "React", weight: 28 },
218
+ { tag: "Angular", weight: 22 },
219
+ { tag: "Vue", weight: 20 },
220
+ { tag: "Node.js", weight: 22 },
221
+ { tag: "CSS", weight: 18 },
222
+ { tag: "SQL", weight: 15 },
223
+ { tag: "Go", weight: 14 },
224
+ { tag: "Rust", weight: 12 },
225
+ { tag: "PHP", weight: 11 },
226
+ { tag: "Swift", weight: 10 },
227
+ { tag: "Kotlin", weight: 9 },
228
+ { tag: "Ruby", weight: 8 },
229
+ { tag: "C#", weight: 25 },
230
+ { tag: "C++", weight: 20 },
231
+ { tag: "Docker", weight: 16 },
232
+ { tag: "Kubernetes", weight: 14 }
233
+ ]);
234
+
235
+ series.appear(1000);
236
+ </script>
237
+ </body>
238
+ </html>
239
+ ```
240
+
241
+ ## Example 2: Sentence cloud with excludeWords and dynamic update
242
+
243
+ ```html
244
+ <!DOCTYPE html>
245
+ <html>
246
+ <head>
247
+ <meta charset="UTF-8">
248
+ <title>Sentence Cloud</title>
249
+ <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
250
+ <script src="https://cdn.amcharts.com/lib/5/wc.js"></script>
251
+ <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
252
+ <style>
253
+ #chartdiv { width: 100%; height: 450px; }
254
+ button { margin: 5px; padding: 8px 16px; cursor: pointer; }
255
+ </style>
256
+ </head>
257
+ <body>
258
+ <div>
259
+ <button onclick="showTech()">Tech Skills</button>
260
+ <button onclick="showBusiness()">Business Skills</button>
261
+ </div>
262
+ <div id="chartdiv"></div>
263
+ <script>
264
+ var root = am5.Root.new("chartdiv");
265
+ root.setThemes([am5themes_Animated.new(root)]);
266
+
267
+ var series = root.container.children.push(
268
+ am5wc.WordCloud.new(root, {
269
+ categoryField: "phrase",
270
+ valueField: "weight",
271
+ maxFontSize: am5.percent(12),
272
+ minFontSize: am5.percent(3),
273
+ angles: [0, -45, 45],
274
+ randomness: 0.4,
275
+ minWordLength: 2,
276
+ excludeWords: ["and", "the", "with", "for"]
277
+ })
278
+ );
279
+
280
+ // Custom color set
281
+ series.set("colors", am5.ColorSet.new(root, {
282
+ colors: [
283
+ am5.color(0x1a535c),
284
+ am5.color(0x4ecdc4),
285
+ am5.color(0xf7fff7),
286
+ am5.color(0xff6b6b),
287
+ am5.color(0xffe66d)
288
+ ]
289
+ }));
290
+
291
+ series.labels.template.setAll({
292
+ fontFamily: "Georgia, serif",
293
+ tooltipText: "{category}: [bold]{value}[/]",
294
+ cursorOverStyle: "pointer"
295
+ });
296
+
297
+ var techData = [
298
+ { phrase: "Machine Learning", weight: 50 },
299
+ { phrase: "Cloud Computing", weight: 45 },
300
+ { phrase: "Data Engineering", weight: 40 },
301
+ { phrase: "DevOps", weight: 35 },
302
+ { phrase: "Cybersecurity", weight: 33 },
303
+ { phrase: "API Design", weight: 28 },
304
+ { phrase: "Microservices", weight: 25 },
305
+ { phrase: "Containerization", weight: 22 },
306
+ { phrase: "CI/CD Pipelines", weight: 20 },
307
+ { phrase: "Edge Computing", weight: 18 },
308
+ { phrase: "Serverless", weight: 16 },
309
+ { phrase: "GraphQL", weight: 14 },
310
+ { phrase: "WebAssembly", weight: 12 },
311
+ { phrase: "Blockchain", weight: 10 }
312
+ ];
313
+
314
+ var businessData = [
315
+ { phrase: "Product Strategy", weight: 48 },
316
+ { phrase: "User Research", weight: 42 },
317
+ { phrase: "Agile Management", weight: 38 },
318
+ { phrase: "Stakeholder Communication", weight: 35 },
319
+ { phrase: "OKR Planning", weight: 30 },
320
+ { phrase: "Risk Assessment", weight: 27 },
321
+ { phrase: "Customer Journey", weight: 24 },
322
+ { phrase: "Market Analysis", weight: 22 },
323
+ { phrase: "Revenue Modeling", weight: 20 },
324
+ { phrase: "Team Leadership", weight: 18 },
325
+ { phrase: "Design Thinking", weight: 16 },
326
+ { phrase: "Data-Driven Decisions", weight: 14 }
327
+ ];
328
+
329
+ // Dynamic data swap functions
330
+ window.showTech = function() { series.data.setAll(techData); };
331
+ window.showBusiness = function() { series.data.setAll(businessData); };
332
+
333
+ // Initial data
334
+ series.data.setAll(techData);
335
+ series.appear(1000);
336
+ </script>
337
+ </body>
338
+ </html>
339
+ ```