{"spec_id":"energy-level-atomic","library":"echarts","language":"javascript","code":"// anyplot.ai\n// energy-level-atomic: Atomic Energy Level Diagram\n// Library: echarts 6.1.0 | JavaScript 22.23.2\n// Quality: 91/100 | Updated: 2026-08-25\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data: hydrogen atom energy levels (Bohr model, E_n = -13.6/n^2 eV) -----\n// Real eV spacing collapses near the ionization limit (n=4,5,6 sit within\n// 0.5 eV of each other), so levels are plotted on a schematic index scale —\n// evenly spaced, labeled with their true energy — a standard convention for\n// diagrams where high-n levels converge. See specification.md \"Notes\".\nconst LEVELS = [\n  { n: 1, energy: -13.6 },\n  { n: 2, energy: -3.4 },\n  { n: 3, energy: -1.51 },\n  { n: 4, energy: -0.85 },\n  { n: 5, energy: -0.54 },\n  { n: 6, energy: -0.38 },\n];\nconst INDEX_BY_N = Object.fromEntries(LEVELS.map((l, i) => [l.n, i]));\nconst LEVEL_X0 = 1;\nconst LEVEL_X1 = 9;\nconst IONIZATION_INDEX = LEVELS.length + 1.4; // extra gap = \"levels converge\"\n\n// Lyman series (emission to n=1, ultraviolet) and Balmer series (emission to\n// n=2, visible) — wavelengths from the hydrogen spectral line tables.\nconst TRANSITIONS = [\n  { from: 2, to: 1, x: 2.0, wavelength: 121.6, name: \"Lyman-α\" },\n  { from: 3, to: 1, x: 3.0, wavelength: 102.6, name: \"Lyman-β\" },\n  { from: 4, to: 1, x: 4.0, wavelength: 97.3, name: \"Lyman-γ\" },\n  { from: 3, to: 2, x: 5.5, wavelength: 656.3, name: \"Balmer Hα\" },\n  { from: 4, to: 2, x: 6.5, wavelength: 486.1, name: \"Balmer Hβ\" },\n  { from: 5, to: 2, x: 7.5, wavelength: 434.0, name: \"Balmer Hγ\" },\n];\nconst WAVELENGTHS = TRANSITIONS.map((tr) => tr.wavelength);\n\n// Energy value shown on the y-axis tick at each schematic index.\nconst AXIS_ENERGY_LABEL = Object.fromEntries(LEVELS.map((l, i) => [i, `${l.energy.toFixed(2)} eV`]));\n\n// --- Init --------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Option --------------------------------------------------------------\nconst title = \"Hydrogen Atom Energy Levels · energy-level-atomic · javascript · echarts · anyplot.ai\";\nconst titleFontSize = Math.round(22 * Math.min(1, 67 / title.length));\n\nchart.setOption({\n  animation: false,\n  backgroundColor: \"transparent\",\n  title: {\n    text: title,\n    left: \"center\",\n    top: 24,\n    textStyle: { color: t.ink, fontSize: titleFontSize, fontWeight: 500 },\n  },\n  grid: { left: 140, right: 260, top: 120, bottom: 60 },\n  xAxis: { type: \"value\", min: 0, max: 12, show: false },\n  yAxis: {\n    type: \"value\",\n    min: -1,\n    max: IONIZATION_INDEX + 1,\n    interval: 1,\n    name: \"Energy (eV)\",\n    nameLocation: \"middle\",\n    nameGap: 90,\n    nameTextStyle: { color: t.ink, fontSize: 16 },\n    axisLabel: { color: t.inkSoft, fontSize: 14, formatter: (value) => AXIS_ENERGY_LABEL[Math.round(value)] || \"\" },\n    axisLine: { show: true, lineStyle: { color: t.inkSoft } },\n    axisTick: { show: false },\n    splitLine: { show: false },\n  },\n  visualMap: {\n    show: true,\n    min: Math.min(...WAVELENGTHS),\n    max: Math.max(...WAVELENGTHS),\n    seriesIndex: 3,\n    orient: \"vertical\",\n    right: 60,\n    top: \"middle\",\n    itemWidth: 16,\n    itemHeight: 220,\n    text: [`${Math.max(...WAVELENGTHS).toFixed(0)} nm (visible)`, `${Math.min(...WAVELENGTHS).toFixed(0)} nm (UV)`],\n    textGap: 14,\n    textStyle: { color: t.inkSoft, fontSize: 13 },\n    inRange: { color: t.seq },\n    calculable: false,\n    hoverLink: false,\n  },\n  graphic: [\n    {\n      type: \"text\",\n      right: 40,\n      top: 84,\n      style: { text: \"Wavelength\", fill: t.inkSoft, fontSize: 14, fontWeight: \"bold\" },\n    },\n  ],\n  series: [\n    {\n      // Energy level lines — structural reference elements, theme ink.\n      name: \"Energy levels\",\n      type: \"lines\",\n      coordinateSystem: \"cartesian2d\",\n      silent: true,\n      z: 2,\n      lineStyle: { color: t.ink, width: 3 },\n      label: {\n        show: true,\n        position: \"end\",\n        align: \"left\",\n        color: t.ink,\n        fontSize: 16,\n        formatter: (params) => `n = ${params.data.n}`,\n      },\n      data: LEVELS.map((l, i) => ({\n        coords: [\n          [LEVEL_X0, i],\n          [LEVEL_X1, i],\n        ],\n        n: l.n,\n      })),\n    },\n    {\n      // Convergence marker — many closely-spaced levels omitted for clarity.\n      name: \"Convergence\",\n      type: \"scatter\",\n      coordinateSystem: \"cartesian2d\",\n      silent: true,\n      symbolSize: 0,\n      label: {\n        show: true,\n        position: \"right\",\n        color: t.inkSoft,\n        fontSize: 15,\n        formatter: \"⋮  levels converge as n → ∞\",\n      },\n      data: [{ value: [LEVEL_X0, (LEVELS.length - 1 + IONIZATION_INDEX) / 2] }],\n    },\n    {\n      // Ionization limit — dashed reference line at E = 0.\n      name: \"Ionization limit\",\n      type: \"lines\",\n      coordinateSystem: \"cartesian2d\",\n      silent: true,\n      z: 2,\n      lineStyle: { color: t.inkSoft, width: 2, type: \"dashed\" },\n      label: {\n        show: true,\n        position: \"end\",\n        align: \"left\",\n        color: t.inkSoft,\n        fontSize: 15,\n        formatter: \"Ionization limit (0 eV)\",\n      },\n      data: [\n        {\n          coords: [\n            [LEVEL_X0, IONIZATION_INDEX],\n            [LEVEL_X1, IONIZATION_INDEX],\n          ],\n        },\n      ],\n    },\n    {\n      // Transitions — downward arrows, colored by wavelength (imprint_seq).\n      name: \"Transitions\",\n      type: \"lines\",\n      coordinateSystem: \"cartesian2d\",\n      z: 3,\n      symbol: [\"none\", \"arrow\"],\n      symbolSize: [0, 16],\n      lineStyle: { width: 3, opacity: 0.9 },\n      tooltip: {\n        formatter: (params) => `${params.data.name}: n=${params.data.from} → n=${params.data.to} (${params.value.toFixed(1)} nm)`,\n      },\n      data: TRANSITIONS.map((tr) => ({\n        coords: [\n          [tr.x, INDEX_BY_N[tr.from]],\n          [tr.x, INDEX_BY_N[tr.to]],\n        ],\n        value: tr.wavelength,\n        name: tr.name,\n        from: tr.from,\n        to: tr.to,\n      })),\n    },\n    {\n      // Wavelength labels — offset beside each arrow (not rotated onto it).\n      name: \"Transition labels\",\n      type: \"scatter\",\n      coordinateSystem: \"cartesian2d\",\n      silent: true,\n      symbolSize: 0,\n      label: {\n        show: true,\n        position: \"right\",\n        color: t.inkSoft,\n        fontSize: 13,\n        formatter: (params) => `${params.data.wavelength.toFixed(0)} nm`,\n      },\n      data: TRANSITIONS.map((tr) => ({\n        value: [tr.x, (INDEX_BY_N[tr.from] + INDEX_BY_N[tr.to]) / 2],\n        wavelength: tr.wavelength,\n      })),\n    },\n  ],\n});\n"}