{"spec_id":"contour-filled","library":"echarts","language":"javascript","code":"// anyplot.ai\n// contour-filled: Filled Contour Plot\n// Library: echarts 6.1.0 | JavaScript 22.23.2\n// Quality: 85/100 | Created: 2026-09-04\n\n//# anyplot-orientation: square\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Combined rainfall-intensity field from two overlapping storm cells over a\n// 100 km x 100 km region, sampled on a regular grid.\nconst N = 70; // grid points per axis (spec range: 30-100)\nconst DOMAIN_MIN = -50;\nconst DOMAIN_MAX = 50;\nconst step = (DOMAIN_MAX - DOMAIN_MIN) / (N - 1);\nconst coords = Array.from({ length: N }, (_, i) => DOMAIN_MIN + i * step);\n\n// Two Gaussian storm cells: [centerX, centerY, sigma, peakIntensityMmPerHr]\n// Centers are far apart relative to sigma so the two peaks read as distinct\n// lobes rather than merging into one blob.\nconst storms = [\n  [-25, -18, 11, 45],\n  [25, 20, 13, 30],\n];\n\nfunction rainfallIntensity(x, y) {\n  return storms.reduce((sum, [cx, cy, sigma, peak]) => {\n    const d2 = (x - cx) ** 2 + (y - cy) ** 2;\n    return sum + peak * Math.exp(-d2 / (2 * sigma * sigma));\n  }, 0);\n}\n\nconst data = [];\nlet zMax = 0;\nfor (let i = 0; i < N; i++) {\n  for (let j = 0; j < N; j++) {\n    const z = rainfallIntensity(coords[i], coords[j]);\n    if (z > zMax) zMax = z;\n    data.push([i, j, Math.round(z * 10) / 10]);\n  }\n}\n\n// --- Axis labels (thin out to keep the grid readable) -----------------------\nconst axisLabels = coords.map((v) => Math.round(v).toString());\nconst tickInterval = Math.ceil(N / 8) - 1;\n\n// --- Title size (scale for length > 67 chars) --------------------------------\nconst titleText =\n  \"Storm Rainfall Intensity · contour-filled · javascript · echarts · anyplot.ai\";\nconst titleSize = Math.max(\n  15,\n  Math.round(22 * Math.min(1, 67 / titleText.length)),\n);\n\n// --- Render ------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\nchart.setOption({\n  animation: false,\n  backgroundColor: \"transparent\",\n\n  title: {\n    text: titleText,\n    left: \"center\",\n    top: 18,\n    textStyle: { color: t.ink, fontSize: titleSize, fontWeight: \"bold\" },\n  },\n\n  grid: { left: 140, right: 240, top: 130, bottom: 120 },\n\n  xAxis: {\n    type: \"category\",\n    data: axisLabels,\n    name: \"Distance East–West (km)\",\n    nameLocation: \"middle\",\n    nameGap: 45,\n    nameTextStyle: { color: t.ink, fontSize: 18 },\n    axisLabel: { color: t.inkSoft, fontSize: 14, interval: tickInterval },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { show: false },\n    splitLine: { show: false },\n  },\n\n  yAxis: {\n    type: \"category\",\n    data: axisLabels,\n    name: \"Distance North–South (km)\",\n    nameLocation: \"middle\",\n    nameGap: 55,\n    nameTextStyle: { color: t.ink, fontSize: 18 },\n    axisLabel: { color: t.inkSoft, fontSize: 14, interval: tickInterval },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { show: false },\n    splitLine: { show: false },\n  },\n\n  // Imprint sequential colormap banded into few, high-contrast levels — the\n  // filled-contour look. Every swatch is labeled with its own range so\n  // intermediate levels can be read off precisely, not just the extremes.\n  visualMap: {\n    type: \"piecewise\",\n    min: 0,\n    max: Math.ceil(zMax),\n    splitNumber: 9,\n    calculable: false,\n    orient: \"vertical\",\n    right: 30,\n    top: \"middle\",\n    itemWidth: 20,\n    itemHeight: 18,\n    itemGap: 8,\n    precision: 0,\n    formatter: (min, max) => `${Math.round(min)}–${Math.round(max)} mm/hr`,\n    textStyle: { color: t.inkSoft, fontSize: 12 },\n    inRange: { color: t.seq },\n    backgroundColor: \"transparent\",\n    borderWidth: 0,\n  },\n\n  series: [\n    {\n      type: \"heatmap\",\n      data: data,\n      itemStyle: { borderWidth: 0 },\n      emphasis: { disabled: true },\n      label: { show: false },\n    },\n  ],\n\n  tooltip: { show: false },\n});\n"}