{"spec_id":"quiver-basic","library":"echarts","language":"javascript","code":"// anyplot.ai\n// quiver-basic: Basic Quiver Plot\n// Library: echarts 6.1.0 | JavaScript 22.23.1\n// Quality: 90/100 | Created: 2026-07-24\n//# anyplot-orientation: landscape\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data: negative-gradient field over an elliptic loss bowl ---------------\n// Steepest-descent direction at each grid point of a toy 2-parameter loss\n// surface L(w1, w2) = A/2 * (w1 - MIN_W1)^2 + B/2 * (w2 - MIN_W2)^2.\nconst ARROW_SCALE = 0.28;\nconst A = 0.25;\nconst B = 0.5;\nconst MIN_W1 = 3;\nconst MIN_W2 = 1;\n\nconst arrows = [];\nfor (let w1 = -3; w1 <= 9; w1 += 1) {\n  for (let w2 = -5; w2 <= 5; w2 += 1) {\n    const gradW1 = A * (w1 - MIN_W1);\n    const gradW2 = B * (w2 - MIN_W2);\n    const u = -gradW1;\n    const v = -gradW2;\n    const magnitude = Math.hypot(gradW1, gradW2);\n    arrows.push([w1, w2, u, v, magnitude]);\n  }\n}\nconst maxMagnitude = Math.max(...arrows.map((d) => d[4]));\n\n// --- Render one arrow (shaft + arrowhead); a dot marks zero-gradient points -\nfunction renderArrow(_params, api) {\n  const w1 = api.value(0);\n  const w2 = api.value(1);\n  const u = api.value(2);\n  const v = api.value(3);\n  const color = api.visual(\"color\");\n\n  const start = api.coord([w1, w2]);\n  const end = api.coord([w1 + u * ARROW_SCALE, w2 + v * ARROW_SCALE]);\n  const dx = end[0] - start[0];\n  const dy = end[1] - start[1];\n  const length = Math.hypot(dx, dy);\n\n  if (length < 3) {\n    return {\n      type: \"circle\",\n      shape: { cx: start[0], cy: start[1], r: 4 },\n      style: { fill: color },\n    };\n  }\n\n  const angle = Math.atan2(dy, dx);\n  const headLength = Math.min(11, length * 0.4);\n  const headAngle = Math.PI / 7;\n  const left = [\n    end[0] - headLength * Math.cos(angle - headAngle),\n    end[1] - headLength * Math.sin(angle - headAngle),\n  ];\n  const right = [\n    end[0] - headLength * Math.cos(angle + headAngle),\n    end[1] - headLength * Math.sin(angle + headAngle),\n  ];\n\n  return {\n    type: \"group\",\n    children: [\n      {\n        type: \"line\",\n        shape: { x1: start[0], y1: start[1], x2: end[0], y2: end[1] },\n        style: { stroke: color, lineWidth: 2.5 },\n      },\n      {\n        type: \"polygon\",\n        shape: { points: [end, left, right] },\n        style: { fill: color },\n      },\n    ],\n  };\n}\n\n// --- Init ---------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Option ---------------------------------------------------------------\nchart.setOption({\n  animation: false,\n  backgroundColor: \"transparent\",\n  title: {\n    text: \"quiver-basic · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },\n  },\n  grid: { left: 90, right: 190, top: 100, bottom: 90 },\n  xAxis: {\n    type: \"value\",\n    name: \"Weight w1\",\n    nameLocation: \"middle\",\n    nameGap: 40,\n    nameTextStyle: { color: t.ink, fontSize: 16 },\n    min: -4,\n    max: 10,\n    axisLabel: { color: t.inkSoft, fontSize: 14 },\n    axisLine: { onZero: false, lineStyle: { color: t.inkSoft } },\n    splitLine: { lineStyle: { color: t.grid } },\n  },\n  yAxis: {\n    type: \"value\",\n    name: \"Weight w2\",\n    nameLocation: \"middle\",\n    nameGap: 55,\n    nameTextStyle: { color: t.ink, fontSize: 16 },\n    min: -6,\n    max: 6,\n    axisLabel: { color: t.inkSoft, fontSize: 14 },\n    axisLine: { onZero: false, lineStyle: { color: t.inkSoft } },\n    splitLine: { lineStyle: { color: t.grid } },\n  },\n  visualMap: {\n    type: \"continuous\",\n    dimension: 4,\n    seriesIndex: 0,\n    min: 0,\n    max: maxMagnitude,\n    right: 30,\n    top: \"middle\",\n    itemWidth: 18,\n    itemHeight: 280,\n    text: [\"Steep\", \"Flat\"],\n    textStyle: { color: t.inkSoft, fontSize: 14 },\n    inRange: { color: t.seq },\n  },\n  series: [\n    {\n      type: \"custom\",\n      renderItem: renderArrow,\n      data: arrows,\n      encode: { x: 0, y: 1 },\n    },\n  ],\n});\n"}