{"spec_id":"bar-feature-importance","library":"echarts","language":"javascript","code":"// anyplot.ai\n// bar-feature-importance: Feature Importance Bar Chart\n// Library: echarts 6.1.0 | JavaScript 22.23.2\n// Quality: 91/100 | Created: 2026-09-02\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Gradient-boosting churn model — feature_importances_ + per-tree std, ascending\n// by importance so the category axis (bottom-to-top) puts the top driver on top.\nconst features = [\n  \"Partner Status\",\n  \"Senior Citizen\",\n  \"Dependents Count\",\n  \"Paperless Billing\",\n  \"Internet Service Type\",\n  \"Tech Support Access\",\n  \"Total Charges\",\n  \"Payment Delay Days\",\n  \"Support Tickets\",\n  \"Monthly Charges\",\n  \"Tenure Months\",\n  \"Contract Length\",\n];\nconst importance = [0.013, 0.017, 0.020, 0.027, 0.034, 0.042, 0.058, 0.076, 0.099, 0.134, 0.208, 0.272];\nconst std = [0.006, 0.007, 0.008, 0.009, 0.010, 0.011, 0.014, 0.016, 0.019, 0.022, 0.028, 0.031];\nconst errorBarData = features.map((name, i) => [name, importance[i] - std[i], importance[i] + std[i]]);\n\n// --- Init ---------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Error bar renderer (ECharts has no built-in error-bar series) ----------\n// The precision label lives here, anchored past the high cap, so its position\n// always clears the error bar regardless of how wide the std interval is.\nfunction renderErrorBar(params, api) {\n  const category = api.value(0);\n  const centerValue = importance[params.dataIndex];\n  const lowPoint = api.coord([api.value(1), category]);\n  const highPoint = api.coord([api.value(2), category]);\n  const capHalf = 7;\n  const style = api.style({ stroke: t.ink, fill: undefined, lineWidth: 1.5 });\n  return {\n    type: \"group\",\n    children: [\n      { type: \"line\", shape: { x1: lowPoint[0], y1: lowPoint[1], x2: highPoint[0], y2: highPoint[1] }, style },\n      { type: \"line\", shape: { x1: lowPoint[0], y1: lowPoint[1] - capHalf, x2: lowPoint[0], y2: lowPoint[1] + capHalf }, style },\n      { type: \"line\", shape: { x1: highPoint[0], y1: highPoint[1] - capHalf, x2: highPoint[0], y2: highPoint[1] + capHalf }, style },\n      {\n        type: \"text\",\n        style: {\n          x: highPoint[0] + 12,\n          y: highPoint[1],\n          text: `${(centerValue * 100).toFixed(1)}%`,\n          fill: t.inkSoft,\n          fontSize: 14,\n          verticalAlign: \"middle\",\n          align: \"left\",\n        },\n      },\n    ],\n  };\n}\n\n// --- Option -------------------------------------------------------------------\nchart.setOption({\n  animation: false,\n  backgroundColor: \"transparent\",\n  title: {\n    text: \"bar-feature-importance · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    textStyle: { color: t.ink, fontSize: 22 },\n  },\n  tooltip: {\n    trigger: \"axis\",\n    axisPointer: { type: \"shadow\" },\n    valueFormatter: (v) => `${(v * 100).toFixed(1)}%`,\n  },\n  grid: { left: 24, right: 150, top: 100, bottom: 130, containLabel: true },\n  xAxis: {\n    type: \"value\",\n    name: \"Relative importance\",\n    nameLocation: \"middle\",\n    nameGap: 36,\n    nameTextStyle: { color: t.inkSoft, fontSize: 14 },\n    axisLabel: { color: t.inkSoft, fontSize: 14, formatter: (v) => `${Math.round(v * 100)}%` },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { show: false },\n    splitLine: { lineStyle: { color: t.grid } },\n  },\n  yAxis: {\n    type: \"category\",\n    data: features,\n    axisLabel: { color: t.inkSoft, fontSize: 14 },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { show: false },\n    splitLine: { show: false },\n  },\n  visualMap: {\n    type: \"continuous\",\n    dimension: 0,\n    min: 0,\n    max: Math.max(...importance) * 1.05,\n    calculable: false,\n    orient: \"horizontal\",\n    left: \"center\",\n    bottom: 24,\n    // Under orient:\"horizontal\" ECharts swaps the usual meaning: itemHeight is\n    // the bar's length, itemWidth its thickness — the reverse of \"vertical\".\n    itemWidth: 14,\n    itemHeight: 260,\n    text: [\"High\", \"Low\"],\n    textStyle: { color: t.inkSoft, fontSize: 14 },\n    inRange: { color: t.seq },\n  },\n  series: [\n    {\n      type: \"bar\",\n      data: importance,\n      barWidth: \"62%\",\n    },\n    {\n      type: \"custom\",\n      renderItem: renderErrorBar,\n      encode: { x: [1, 2], y: 0 },\n      data: errorBarData,\n      z: 10,\n      silent: true,\n    },\n  ],\n});\n\nchart.on(\"finished\", () => {\n  window.__anyplotReady = true;\n});\n"}