{"spec_id":"bifurcation-basic","library":"echarts","language":"javascript","code":"// anyplot.ai\n// bifurcation-basic: Bifurcation Diagram for Dynamical Systems\n// Library: echarts 5.5.1 | JavaScript 22.22.3\n// Quality: 91/100 | Created: 2026-06-17\n//# anyplot-orientation: landscape\n\nconst t = window.ANYPLOT_TOKENS;\nconst BRAND = t.palette[0]; // #009E73 — Imprint palette position 1 (first series)\n\n// --- Data: logistic map x(n+1) = r * x(n) * (1 - x(n)) ----------------------\n// For each growth rate r, iterate the map, discard the transient, and keep the\n// long-term orbit. Fully deterministic — no RNG needed.\nconst R_MIN = 2.5;\nconst R_MAX = 4.0;\nconst R_STEPS = 1500; // parameter resolution across [2.5, 4.0]\nconst TRANSIENT = 300; // iterations discarded before the orbit settles\nconst KEEP = 100; // long-term state values recorded per r\n\nconst points = [];\nfor (let i = 0; i < R_STEPS; i++) {\n  const r = R_MIN + ((R_MAX - R_MIN) * i) / (R_STEPS - 1);\n  let x = 0.5;\n  for (let n = 0; n < TRANSIENT; n++) {\n    x = r * x * (1 - x);\n  }\n  for (let n = 0; n < KEEP; n++) {\n    x = r * x * (1 - x);\n    points.push([r, x]);\n  }\n}\n// ~150,000 points — dense enough to resolve the period-doubling cascade.\n\n// Key period-doubling thresholds on the route to chaos.\n// Positions staggered (top/bottom alternating) so the three closely-spaced\n// labels near chaos onset (r ≈ 3.449 / 3.544 / 3.5699) don't crowd each other.\nconst bifurcations = [\n  { r: 3.0,    text: \"period-2\", position: \"insideStartTop\" },\n  { r: 3.449,  text: \"period-4\", position: \"insideEndBottom\" },\n  { r: 3.544,  text: \"period-8\", position: \"insideStartTop\" },\n  { r: 3.5699, text: \"chaos\",    position: \"insideEndBottom\" },\n];\n\n// --- Init -------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Option -----------------------------------------------------------------\nchart.setOption({\n  animation: false,\n  color: t.palette,\n  backgroundColor: \"transparent\",\n  title: {\n    text: \"bifurcation-basic · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    top: 18,\n    textStyle: { color: t.ink, fontSize: 22, fontWeight: \"bold\" },\n  },\n  grid: { left: 92, right: 56, top: 96, bottom: 84 },\n  xAxis: {\n    type: \"value\",\n    min: R_MIN,\n    max: R_MAX,\n    name: \"Growth rate  r\",\n    nameLocation: \"middle\",\n    nameGap: 46,\n    nameTextStyle: { color: t.ink, fontSize: 17 },\n    axisLabel: { color: t.inkSoft, fontSize: 14 },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { show: false },\n    splitLine: { show: false },\n  },\n  yAxis: {\n    type: \"value\",\n    min: 0,\n    max: 1,\n    name: \"Long-term state  x\",\n    nameLocation: \"middle\",\n    nameGap: 56,\n    nameTextStyle: { color: t.ink, fontSize: 17 },\n    axisLabel: { color: t.inkSoft, fontSize: 14 },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { show: false },\n    splitLine: { lineStyle: { color: t.grid } },\n  },\n  series: [\n    {\n      type: \"scatter\",\n      data: points,\n      symbolSize: 1.1, // very small points → density-based visualization\n      large: true, // optimised path for the 150k-point cloud\n      largeThreshold: 2000,\n      itemStyle: { color: BRAND, opacity: 0.34 },\n      markLine: {\n        symbol: \"none\",\n        silent: true,\n        lineStyle: { color: t.inkSoft, type: \"dashed\", width: 1.4, opacity: 0.7 },\n        // Per-item label overrides carry the position and text; fontSize 14 gives\n        // comfortable legibility at both full resolution and mobile thumbnail.\n        label: { color: t.inkSoft, fontSize: 14 },\n        data: bifurcations.map((b) => ({\n          xAxis: b.r,\n          label: { formatter: b.text, position: b.position },\n        })),\n      },\n    },\n  ],\n});\n"}