{"spec_id":"bar-permutation-importance","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// bar-permutation-importance: Permutation Feature Importance Plot\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 92/100 | Created: 2026-08-26\n\n//# anyplot-orientation: landscape\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Permutation importance for a random-forest classifier predicting loan\n// default risk (n_repeats = 30). Sorted by importance_mean, highest first.\nconst importance = [\n  { feature: \"Credit Score\", mean: 0.182, std: 0.021 },\n  { feature: \"Debt-to-Income Ratio\", mean: 0.146, std: 0.018 },\n  { feature: \"Previous Defaults\", mean: 0.121, std: 0.024 },\n  { feature: \"Annual Income\", mean: 0.098, std: 0.015 },\n  { feature: \"Credit Utilization\", mean: 0.084, std: 0.013 },\n  { feature: \"Loan Amount\", mean: 0.067, std: 0.011 },\n  { feature: \"Num. Late Payments\", mean: 0.055, std: 0.014 },\n  { feature: \"Employment Years\", mean: 0.041, std: 0.009 },\n  { feature: \"Recent Credit Inquiries\", mean: 0.033, std: 0.01 },\n  { feature: \"Num. Credit Lines\", mean: 0.024, std: 0.008 },\n  { feature: \"Savings Balance\", mean: 0.018, std: 0.007 },\n  { feature: \"Age\", mean: 0.012, std: 0.006 },\n  { feature: \"Loan Purpose Score\", mean: 0.007, std: 0.005 },\n  { feature: \"Home Ownership\", mean: 0.003, std: 0.004 },\n  { feature: \"Num. Dependents\", mean: -0.002, std: 0.003 },\n];\n\n// --- Sequential color gradient (Imprint imprint_seq), mapped to importance --\nfunction hexToRgb(hex) {\n  const n = parseInt(hex.slice(1), 16);\n  return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\nfunction lerpColor(hexA, hexB, frac) {\n  const a = hexToRgb(hexA);\n  const b = hexToRgb(hexB);\n  const rgb = a.map((v, i) => Math.round(v + (b[i] - v) * frac));\n  return `rgb(${rgb.join(\",\")})`;\n}\n\nconst meanValues = importance.map((d) => d.mean);\nconst minMean = Math.min(...meanValues);\nconst maxMean = Math.max(...meanValues);\nconst span = maxMean - minMean || 1;\n\nconst categories = importance.map((d) => d.feature);\nconst data = importance.map((d) => ({\n  name: d.feature,\n  y: d.mean,\n  color: lerpColor(t.seq[1], t.seq[0], (d.mean - minMean) / span),\n}));\n\n// --- Manual error-bar whiskers ------------------------------------------------\n// The core bundle has no highcharts-more, so there is no \"errorbar\" series\n// type. Draw real whiskers with the SVG renderer at each point's actual\n// axis-computed pixel position instead — this is the documented technique for\n// error bars on a plain bar/column series without the add-on module.\nlet errorBarGroup = null;\nfunction drawErrorBars(chart) {\n  if (errorBarGroup) errorBarGroup.destroy();\n  errorBarGroup = chart.renderer.g(\"error-bars\").add();\n  const yAxis = chart.yAxis[0];\n  const xAxis = chart.xAxis[0];\n  const capHalf = 9;\n  chart.series[0].points.forEach((point, i) => {\n    const d = importance[i];\n    const xPix = xAxis.toPixels(i, false);\n    const loPix = yAxis.toPixels(d.mean - d.std, false);\n    const hiPix = yAxis.toPixels(d.mean + d.std, false);\n    chart.renderer\n      .path([\"M\", loPix, xPix, \"L\", hiPix, xPix])\n      .attr({ \"stroke-width\": 2, stroke: t.ink, zIndex: 6 })\n      .add(errorBarGroup);\n    [loPix, hiPix].forEach((px) => {\n      chart.renderer\n        .path([\"M\", px, xPix - capHalf, \"L\", px, xPix + capHalf])\n        .attr({ \"stroke-width\": 2, stroke: t.ink, zIndex: 6 })\n        .add(errorBarGroup);\n    });\n  });\n}\n\n// --- Chart -------------------------------------------------------------------\nHighcharts.chart(\"container\", {\n  chart: {\n    type: \"bar\",\n    backgroundColor: \"transparent\",\n    animation: false,\n    style: { fontFamily: \"inherit\" },\n    events: {\n      render: function () {\n        drawErrorBars(this);\n      },\n    },\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: \"bar-permutation-importance · javascript · highcharts · anyplot.ai\",\n    style: { color: t.ink, fontSize: \"22px\", fontWeight: \"600\" },\n  },\n  subtitle: {\n    text: \"Random-forest loan-default classifier · error bars = ±1 SD across 30 permutation repeats\",\n    style: { color: t.inkSoft, fontSize: \"14px\" },\n  },\n  xAxis: {\n    categories,\n    reversed: true,\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n  },\n  yAxis: {\n    title: { text: \"Decrease in Model Score\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    gridLineColor: t.grid,\n    min: -0.03,\n    max: 0.22,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n    plotLines: [{ value: 0, color: t.inkSoft, width: 1.5, dashStyle: \"Dash\", zIndex: 5 }],\n  },\n  legend: { enabled: false },\n  plotOptions: {\n    series: { animation: false },\n    bar: { borderWidth: 0, pointPadding: 0.08, groupPadding: 0.1 },\n  },\n  series: [{ name: \"Importance\", data }],\n});\n"}