Basic Quiver Plot — Apache ECharts

A quiver plot displays vector fields using arrows positioned at grid points. Each arrow represents a vector at that location, with direction indicating the vector's angle and length proportional to its magnitude. This visualization reveals flow patterns, gradients, and field structure in two-dimensional data.

Basic Quiver Plot rendered with Apache ECharts

Renders

JavaScript source (Apache ECharts)

// anyplot.ai
// quiver-basic: Basic Quiver Plot
// Library: echarts 6.1.0 | JavaScript 22.23.1
// Quality: 90/100 | Created: 2026-07-24
//# anyplot-orientation: landscape

const t = window.ANYPLOT_TOKENS;

// --- Data: negative-gradient field over an elliptic loss bowl ---------------
// Steepest-descent direction at each grid point of a toy 2-parameter loss
// surface L(w1, w2) = A/2 * (w1 - MIN_W1)^2 + B/2 * (w2 - MIN_W2)^2.
const ARROW_SCALE = 0.28;
const A = 0.25;
const B = 0.5;
const MIN_W1 = 3;
const MIN_W2 = 1;

const arrows = [];
for (let w1 = -3; w1 <= 9; w1 += 1) {
  for (let w2 = -5; w2 <= 5; w2 += 1) {
    const gradW1 = A * (w1 - MIN_W1);
    const gradW2 = B * (w2 - MIN_W2);
    const u = -gradW1;
    const v = -gradW2;
    const magnitude = Math.hypot(gradW1, gradW2);
    arrows.push([w1, w2, u, v, magnitude]);
  }
}
const maxMagnitude = Math.max(...arrows.map((d) => d[4]));

// --- Render one arrow (shaft + arrowhead); a dot marks zero-gradient points -
function renderArrow(_params, api) {
  const w1 = api.value(0);
  const w2 = api.value(1);
  const u = api.value(2);
  const v = api.value(3);
  const color = api.visual("color");

  const start = api.coord([w1, w2]);
  const end = api.coord([w1 + u * ARROW_SCALE, w2 + v * ARROW_SCALE]);
  const dx = end[0] - start[0];
  const dy = end[1] - start[1];
  const length = Math.hypot(dx, dy);

  if (length < 3) {
    return {
      type: "circle",
      shape: { cx: start[0], cy: start[1], r: 4 },
      style: { fill: color },
    };
  }

  const angle = Math.atan2(dy, dx);
  const headLength = Math.min(11, length * 0.4);
  const headAngle = Math.PI / 7;
  const left = [
    end[0] - headLength * Math.cos(angle - headAngle),
    end[1] - headLength * Math.sin(angle - headAngle),
  ];
  const right = [
    end[0] - headLength * Math.cos(angle + headAngle),
    end[1] - headLength * Math.sin(angle + headAngle),
  ];

  return {
    type: "group",
    children: [
      {
        type: "line",
        shape: { x1: start[0], y1: start[1], x2: end[0], y2: end[1] },
        style: { stroke: color, lineWidth: 2.5 },
      },
      {
        type: "polygon",
        shape: { points: [end, left, right] },
        style: { fill: color },
      },
    ],
  };
}

// --- Init ---------------------------------------------------------------
const chart = echarts.init(document.getElementById("container"));

// --- Option ---------------------------------------------------------------
chart.setOption({
  animation: false,
  backgroundColor: "transparent",
  title: {
    text: "quiver-basic · javascript · echarts · anyplot.ai",
    left: "center",
    textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },
  },
  grid: { left: 90, right: 190, top: 100, bottom: 90 },
  xAxis: {
    type: "value",
    name: "Weight w1",
    nameLocation: "middle",
    nameGap: 40,
    nameTextStyle: { color: t.ink, fontSize: 16 },
    min: -4,
    max: 10,
    axisLabel: { color: t.inkSoft, fontSize: 14 },
    axisLine: { onZero: false, lineStyle: { color: t.inkSoft } },
    splitLine: { lineStyle: { color: t.grid } },
  },
  yAxis: {
    type: "value",
    name: "Weight w2",
    nameLocation: "middle",
    nameGap: 55,
    nameTextStyle: { color: t.ink, fontSize: 16 },
    min: -6,
    max: 6,
    axisLabel: { color: t.inkSoft, fontSize: 14 },
    axisLine: { onZero: false, lineStyle: { color: t.inkSoft } },
    splitLine: { lineStyle: { color: t.grid } },
  },
  visualMap: {
    type: "continuous",
    dimension: 4,
    seriesIndex: 0,
    min: 0,
    max: maxMagnitude,
    right: 30,
    top: "middle",
    itemWidth: 18,
    itemHeight: 280,
    text: ["Steep", "Flat"],
    textStyle: { color: t.inkSoft, fontSize: 14 },
    inRange: { color: t.seq },
  },
  series: [
    {
      type: "custom",
      renderItem: renderArrow,
      data: arrows,
      encode: { x: 0, y: 1 },
    },
  ],
});

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/quiver-basic/echarts/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.

{
  "spec_id": "quiver-basic",
  "language": "javascript",
  "library": "echarts",
  "page": "https://anyplot.ai/quiver-basic/javascript/echarts",
  "hub": "https://anyplot.ai/quiver-basic",
  "code_json": "https://api.anyplot.ai/specs/quiver-basic/echarts/code",
  "spec_json": "https://api.anyplot.ai/specs/quiver-basic",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/quiver-basic/javascript/echarts/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/quiver-basic/javascript/echarts/plot-dark.png",
  "interactive_light_html": "https://storage.googleapis.com/anyplot-images/plots/quiver-basic/javascript/echarts/plot-light.html",
  "interactive_dark_html": "https://storage.googleapis.com/anyplot-images/plots/quiver-basic/javascript/echarts/plot-dark.html",
  "quality_score": 90.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of Basic Quiver Plot on anyplot.ai.

Other implementations