{"spec_id":"bar-pareto","library":"echarts","language":"javascript","code":"// anyplot.ai\n// bar-pareto: Pareto Chart with Cumulative Line\n// Library: echarts 5.5.1 | JavaScript 22.22.3\n// Quality: 91/100 | Created: 2026-06-20\n//# anyplot-orientation: landscape\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Customer complaint categories, pre-sorted descending by count\nconst rawData = [\n  { category: \"System Downtime\", count: 142 },\n  { category: \"Slow Performance\", count: 98 },\n  { category: \"Login Issues\", count: 76 },\n  { category: \"Data Loss\", count: 54 },\n  { category: \"UI Glitches\", count: 41 },\n  { category: \"Payment Errors\", count: 28 },\n  { category: \"Missing Features\", count: 19 },\n  { category: \"Poor Support\", count: 13 },\n];\n\nconst total = rawData.reduce((sum, d) => sum + d.count, 0);\nlet running = 0;\nconst cumulativePct = rawData.map((d) => {\n  running += d.count;\n  return parseFloat(((running / total) * 100).toFixed(1));\n});\n\nconst categories = rawData.map((d) => d.category);\nconst counts = rawData.map((d) => d.count);\n\n// Title font size scaled by length (67-char baseline at 22px)\nconst title =\n  \"Customer Complaints · bar-pareto · javascript · echarts · anyplot.ai\";\nconst titleFontSize =\n  title.length > 67 ? Math.round((22 * 67) / title.length) : 22;\n\nconst chart = echarts.init(document.getElementById(\"container\"));\n\nchart.setOption({\n  animation: false,\n  color: t.palette,\n  backgroundColor: \"transparent\",\n\n  title: {\n    text: title,\n    left: \"center\",\n    top: 22,\n    textStyle: { color: t.ink, fontSize: titleFontSize, fontWeight: \"500\" },\n  },\n\n  legend: {\n    data: [\"Count\", \"Cumulative %\"],\n    top: 68,\n    textStyle: { color: t.inkSoft, fontSize: 16 },\n    icon: \"roundRect\",\n  },\n\n  grid: { left: 100, right: 110, top: 120, bottom: 100 },\n\n  xAxis: {\n    type: \"category\",\n    data: categories,\n    axisLabel: {\n      color: t.inkSoft,\n      fontSize: 14,\n      rotate: 18,\n      margin: 14,\n    },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { show: false },\n    splitLine: { show: false },\n  },\n\n  yAxis: [\n    {\n      type: \"value\",\n      name: \"Count\",\n      nameTextStyle: { color: t.inkSoft, fontSize: 14, padding: [0, 8, 0, 0] },\n      axisLabel: { color: t.inkSoft, fontSize: 14 },\n      axisLine: { show: true, lineStyle: { color: t.inkSoft } },\n      axisTick: { show: false },\n      splitLine: { lineStyle: { color: t.grid } },\n    },\n    {\n      type: \"value\",\n      name: \"Cumulative %\",\n      min: 0,\n      max: 100,\n      nameTextStyle: { color: t.inkSoft, fontSize: 14, padding: [0, 0, 0, 8] },\n      axisLabel: {\n        color: t.inkSoft,\n        fontSize: 14,\n        formatter: \"{value}%\",\n      },\n      axisLine: { show: true, lineStyle: { color: t.inkSoft } },\n      axisTick: { show: false },\n      splitLine: { show: false },\n    },\n  ],\n\n  series: [\n    {\n      name: \"Count\",\n      type: \"bar\",\n      data: counts,\n      yAxisIndex: 0,\n      itemStyle: { color: t.palette[0] },\n      barMaxWidth: 72,\n    },\n    {\n      name: \"Cumulative %\",\n      type: \"line\",\n      data: cumulativePct,\n      yAxisIndex: 1,\n      symbol: \"circle\",\n      symbolSize: 12,\n      lineStyle: { color: t.palette[1], width: 3 },\n      itemStyle: { color: t.palette[1] },\n      // 80% Pareto threshold reference line (amber = warning/threshold semantic anchor)\n      markLine: {\n        silent: true,\n        symbol: [\"none\", \"none\"],\n        lineStyle: { color: \"#DDCC77\", type: \"dashed\", width: 2 },\n        data: [{ yAxis: 80 }],\n        label: {\n          show: true,\n          formatter: \"80% threshold\",\n          color: \"#DDCC77\",\n          fontSize: 13,\n          position: \"insideEndTop\",\n        },\n      },\n    },\n  ],\n});\n"}