{"spec_id":"recurrence-basic","library":"echarts","language":"javascript","code":"// anyplot.ai\n// recurrence-basic: Recurrence Plot for Nonlinear Time Series\n// Library: echarts 5.5.1 | JavaScript 22.22.3\n// Quality: 88/100 | Created: 2026-06-10\n//# anyplot-orientation: square\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Lorenz attractor (σ=10, ρ=28, β=8/3): deterministic chaotic time series\nconst dt = 0.02;\nlet lx = 1.0, ly = 0.0, lz = 0.0;\n\n// Burn-in: drive initial conditions onto the strange attractor\nfor (let k = 0; k < 300; k++) {\n  const dxk = 10 * (ly - lx);\n  const dyk = lx * (28 - lz) - ly;\n  const dzk = lx * ly - (8 / 3) * lz;\n  lx += dxk * dt;\n  ly += dyk * dt;\n  lz += dzk * dt;\n}\n\n// Time-delay embedding of x-component: state(i) = (x[i], x[i+DELAY])\n// Implements Takens' theorem reconstruction from a scalar observable\nconst DELAY = 8;\nconst NPTS = 300;\nconst N_TOTAL = NPTS + DELAY;\n\nconst lorenzX = [];\nfor (let k = 0; k < N_TOTAL; k++) {\n  const dxk = 10 * (ly - lx);\n  const dyk = lx * (28 - lz) - ly;\n  const dzk = lx * ly - (8 / 3) * lz;\n  lx += dxk * dt;\n  ly += dyk * dt;\n  lz += dzk * dt;\n  lorenzX.push(lx);\n}\n\nconst emX = lorenzX.slice(0, NPTS);\nconst emY = lorenzX.slice(DELAY, NPTS + DELAY);\n\n// Pairwise Euclidean distances in 2D embedded state space, normalized to [0, 1]\n// Main diagonal stays 0 (every state recurs with itself — Takens determinism)\nlet maxDist = 0;\nconst rawDist = new Float32Array(NPTS * NPTS);\nfor (let i = 0; i < NPTS; i++) {\n  for (let j = i + 1; j < NPTS; j++) {\n    const dx = emX[i] - emX[j];\n    const dy = emY[i] - emY[j];\n    const val = Math.sqrt(dx * dx + dy * dy);\n    rawDist[i * NPTS + j] = val;\n    rawDist[j * NPTS + i] = val;\n    if (val > maxDist) maxDist = val;\n  }\n}\n\n// Full recurrence distance matrix: [col, row, normalizedDist] for all N×N pairs\n// imprint_seq encoding: green (0=identical/recurrent) → blue (1=maximally distant)\nconst data = [];\nfor (let i = 0; i < NPTS; i++) {\n  for (let j = 0; j < NPTS; j++) {\n    data.push([j, i, rawDist[i * NPTS + j] / maxDist]);\n  }\n}\n\nconst timeLabels = Array.from({ length: NPTS }, (_, k) => k);\n\nconst chart = echarts.init(document.getElementById(\"container\"));\nchart.setOption({\n  animation: false,\n  backgroundColor: \"transparent\",\n  title: {\n    text: \"recurrence-basic · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    top: 18,\n    textStyle: { color: t.ink, fontSize: 22 },\n  },\n  // imprint_seq: brand green (near/recurrent) → blue (far/non-recurrent)\n  visualMap: {\n    min: 0,\n    max: 1,\n    show: true,\n    orient: \"vertical\",\n    right: 20,\n    top: \"middle\",\n    itemWidth: 16,\n    itemHeight: 160,\n    text: [\"Far\", \"Near\"],\n    textStyle: { color: t.inkSoft, fontSize: 12 },\n    inRange: { color: t.seq },\n  },\n  grid: { left: 90, right: 100, top: 76, bottom: 82 },\n  xAxis: {\n    type: \"category\",\n    data: timeLabels,\n    name: \"Time Index\",\n    nameLocation: \"center\",\n    nameGap: 38,\n    nameTextStyle: { color: t.inkSoft, fontSize: 16 },\n    axisLabel: { color: t.inkSoft, fontSize: 13, interval: 49 },\n    axisLine: { show: false },\n    axisTick: { show: false },\n    splitLine: { show: false },\n  },\n  yAxis: {\n    type: \"category\",\n    data: timeLabels,\n    name: \"Time Index\",\n    nameLocation: \"center\",\n    nameGap: 50,\n    nameTextStyle: { color: t.inkSoft, fontSize: 16 },\n    axisLabel: { color: t.inkSoft, fontSize: 13, interval: 49 },\n    axisLine: { show: false },\n    axisTick: { show: false },\n    splitLine: { show: false },\n  },\n  series: [\n    {\n      type: \"heatmap\",\n      data: data,\n      progressive: 0,\n      emphasis: { disabled: true },\n    },\n  ],\n});\n"}