{"spec_id":"phase-diagram-pt","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// phase-diagram-pt: Thermodynamic Phase Diagram (Pressure-Temperature)\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 93/100 | Created: 2026-08-20\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data: water's P-T phase boundaries -------------------------------------\n// Reference points (well-known constants for water):\n//   triple point:  273.16 K,   611.73 Pa\n//   critical point: 647.1 K,   22.064 MPa\n//   ice Ih/III/liquid triple point: 251.165 K, 209.9 MPa (fusion curve terminus)\nconst R = 8.314; // gas constant, J/(mol*K)\n\nconst TRIPLE_T = 273.16;\nconst TRIPLE_P = 611.73;\nconst CRITICAL_T = 647.1;\nconst CRITICAL_P = 22.064e6;\nconst ICE_III_T = 251.165;\nconst ICE_III_P = 209.9e6;\n\n// Liquid-gas boundary: Clausius-Clapeyron, latent heat calibrated so the curve\n// passes exactly through the triple point and the critical point.\nconst L_VAP = (-R * Math.log(CRITICAL_P / TRIPLE_P)) / (1 / CRITICAL_T - 1 / TRIPLE_T);\nconst VAPORIZATION_POINTS = 80;\nconst vaporizationCurve = [];\nfor (let i = 0; i <= VAPORIZATION_POINTS; i++) {\n  const temperature = TRIPLE_T + (i / VAPORIZATION_POINTS) * (CRITICAL_T - TRIPLE_T);\n  const pressure = TRIPLE_P * Math.exp((-L_VAP / R) * (1 / temperature - 1 / TRIPLE_T));\n  vaporizationCurve.push([temperature, pressure]);\n}\n\n// Solid-gas boundary: Clausius-Clapeyron with the standard latent heat of\n// sublimation for ice, anchored at the triple point.\nconst L_SUB = 51100; // J/mol\nconst SUB_T_MIN = 210;\nconst SUBLIMATION_POINTS = 70;\nconst sublimationCurve = [];\nfor (let i = 0; i <= SUBLIMATION_POINTS; i++) {\n  const temperature = SUB_T_MIN + (i / SUBLIMATION_POINTS) * (TRIPLE_T - SUB_T_MIN);\n  const pressure = TRIPLE_P * Math.exp((-L_SUB / R) * (1 / temperature - 1 / TRIPLE_T));\n  sublimationCurve.push([temperature, pressure]);\n}\n\n// Solid-liquid boundary: water's anomalous negative slope (melting point drops\n// as pressure rises), a linear-in-temperature approximation anchored at the\n// triple point and the ice Ih/III/liquid triple point.\nconst FUSION_SLOPE = (ICE_III_P - TRIPLE_P) / (ICE_III_T / TRIPLE_T - 1);\nconst FUSION_POINTS = 60;\nconst fusionCurve = [];\nfor (let i = 0; i <= FUSION_POINTS; i++) {\n  const temperature = TRIPLE_T + (i / FUSION_POINTS) * (ICE_III_T - TRIPLE_T);\n  const pressure = TRIPLE_P + FUSION_SLOPE * (temperature / TRIPLE_T - 1);\n  fusionCurve.push([temperature, pressure]);\n}\n\n// Phase region labels — literal chart text, always visible (not hover-dependent).\nconst regionLabels = [\n  { x: 225, y: 1e5, text: \"Solid\" },\n  { x: 320, y: 1e6, text: \"Liquid\" },\n  { x: 420, y: 1e3, text: \"Gas\" },\n  { x: 695, y: 3e7, text: \"Supercritical Fluid\" },\n];\n\nconst referencePoints = [\n  { x: TRIPLE_T, y: TRIPLE_P, name: \"Triple Point\", dataLabels: { align: \"left\", x: 10, y: -6 } },\n  { x: CRITICAL_T, y: CRITICAL_P, name: \"Critical Point\", dataLabels: { align: \"right\", x: -12, y: -10 } },\n];\n\n// --- Title (fontsize scales down when the string runs past the 67-char baseline) ---\nconst TITLE = \"Water Phase Diagram · phase-diagram-pt · javascript · highcharts · anyplot.ai\";\nconst TITLE_DEFAULT_PX = 22;\nconst titleFontSize = Math.max(14, Math.round(TITLE_DEFAULT_PX * Math.min(1, 67 / TITLE.length)));\n\n// --- Chart -------------------------------------------------------------------\nHighcharts.chart(\"container\", {\n  chart: {\n    type: \"line\",\n    backgroundColor: \"transparent\",\n    animation: false,\n    style: { fontFamily: \"inherit\" },\n    events: {\n      // Soft background tint for the Supercritical Fluid corner (T > critical T\n      // AND P > critical P) — the one region whose boundary is a straight\n      // rectangle rather than a curve, so a flat shade stays physically honest.\n      render() {\n        if (this.supercriticalShade) return;\n        const left = this.xAxis[0].toPixels(CRITICAL_T, false);\n        const right = this.plotLeft + this.plotWidth;\n        const plotAreaTop = this.plotTop;\n        const criticalPTop = this.yAxis[0].toPixels(CRITICAL_P, false);\n        if (right > left && criticalPTop > plotAreaTop) {\n          this.supercriticalShade = this.renderer\n            .rect(left, plotAreaTop, right - left, criticalPTop - plotAreaTop)\n            .attr({ fill: Highcharts.color(t.ink).setOpacity(0.08).get(), zIndex: -1 })\n            .add();\n        }\n      },\n    },\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: TITLE,\n    style: { color: t.ink, fontSize: `${titleFontSize}px`, fontWeight: \"600\" },\n  },\n  subtitle: {\n    text: \"Triple point 273.16 K / 611.73 Pa · Critical point 647.1 K / 22.064 MPa\",\n    style: { color: t.inkSoft, fontSize: \"14px\" },\n  },\n  xAxis: {\n    title: { text: \"Temperature (K)\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    min: 190,\n    max: 720,\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    gridLineWidth: 0,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n  },\n  yAxis: {\n    type: \"logarithmic\",\n    title: { text: \"Pressure (Pa)\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    min: 0.1,\n    max: 5e8,\n    gridLineColor: t.grid,\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n  },\n  legend: {\n    itemStyle: { color: t.inkSoft, fontSize: \"14px\" },\n    itemHoverStyle: { color: t.ink },\n  },\n  plotOptions: {\n    series: { animation: false },\n  },\n  series: [\n    {\n      name: \"Solid-Liquid boundary\",\n      type: \"line\",\n      data: fusionCurve,\n      color: t.palette[0],\n      lineWidth: 3,\n      marker: { enabled: false },\n      zIndex: 3,\n    },\n    {\n      name: \"Liquid-Gas boundary\",\n      type: \"line\",\n      data: vaporizationCurve,\n      color: t.palette[1],\n      lineWidth: 3,\n      marker: { enabled: false },\n      zIndex: 3,\n    },\n    {\n      name: \"Solid-Gas boundary\",\n      type: \"line\",\n      data: sublimationCurve,\n      color: t.palette[2],\n      lineWidth: 3,\n      marker: { enabled: false },\n      zIndex: 3,\n    },\n    {\n      name: \"Phase regions\",\n      type: \"scatter\",\n      data: regionLabels.map((r) => ({ x: r.x, y: r.y, name: r.text })),\n      color: t.inkSoft,\n      showInLegend: false,\n      marker: { enabled: false },\n      dataLabels: {\n        enabled: true,\n        format: \"{point.name}\",\n        style: { color: t.inkSoft, fontSize: \"18px\", fontStyle: \"italic\", textOutline: \"none\" },\n      },\n      zIndex: 1,\n    },\n    {\n      name: \"Reference points\",\n      type: \"scatter\",\n      data: referencePoints.map((p) => ({\n        x: p.x,\n        y: p.y,\n        name: p.name,\n        dataLabels: p.dataLabels,\n      })),\n      color: t.ink,\n      showInLegend: false,\n      marker: { enabled: true, symbol: \"diamond\", radius: 7, lineWidth: 1.5, lineColor: t.pageBg },\n      dataLabels: {\n        enabled: true,\n        allowOverlap: true,\n        format: \"{point.name}\",\n        style: { color: t.ink, fontSize: \"14px\", fontWeight: \"600\", textOutline: \"none\" },\n      },\n      zIndex: 4,\n    },\n  ],\n});\n"}