{"spec_id":"phase-diagram-pt","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nphase-diagram-pt: Thermodynamic Phase Diagram (Pressure-Temperature)\nLibrary: letsplot 4.10.1 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-06-08\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    flavor_high_contrast_dark,\n    flavor_high_contrast_light,\n    geom_area,\n    geom_line,\n    geom_point,\n    geom_text,\n    ggplot,\n    ggsize,\n    labs,\n    layer_tooltips,\n    scale_color_manual,\n    scale_x_continuous,\n    scale_y_log10,\n    theme,\n    theme_minimal,\n)\nfrom lets_plot.export import ggsave\n\n\nLetsPlot.setup_html()\n\n# Imprint palette — canonical order (hybrid-v3)\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\"]\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Phase region fill colors — theme-adaptive subtle backgrounds\nFILL_GAS = \"#FFF8E1\" if THEME == \"light\" else \"#302C00\"\nFILL_SOLID = \"#EDE9F8\" if THEME == \"light\" else \"#1E1930\"\nFILL_LIQUID = \"#E0F2F1\" if THEME == \"light\" else \"#00302E\"\n\n# Water phase diagram — physically accurate (Clausius-Clapeyron equations)\n# Triple point: 273.16 K, 611.73 Pa | Critical point: 647.1 K, 22.064 MPa\ntriple_t, triple_p = 273.16, 611.73\ncritical_t, critical_p = 647.1, 22.064e6\n\n# Solid-gas boundary (sublimation curve)\ntemp_solid_gas = np.linspace(200, triple_t, 80)\nL_sub = 51059.0\nR = 8.314\npressure_solid_gas = triple_p * np.exp((L_sub / R) * (1 / triple_t - 1 / temp_solid_gas))\n\n# Liquid-gas boundary (vaporization curve — triple point to critical point)\ntemp_liquid_gas = np.linspace(triple_t, critical_t, 100)\nL_vap = 40660.0\npressure_liquid_gas = triple_p * np.exp((L_vap / R) * (1 / triple_t - 1 / temp_liquid_gas))\n\n# Solid-liquid boundary (melting curve — negative slope, water anomaly)\ntemp_solid_liquid = np.linspace(200, 273.16, 80)\npressure_solid_liquid = triple_p + (temp_solid_liquid - triple_t) * (-13.5e6)\npressure_solid_liquid = np.clip(pressure_solid_liquid, triple_p, 1e9)\n\n# DataFrames for boundary curves\ndf_sublimation = pd.DataFrame(\n    {\"temperature\": temp_solid_gas, \"pressure\": pressure_solid_gas, \"boundary\": \"Solid–Gas (Sublimation)\"}\n)\ndf_vaporization = pd.DataFrame(\n    {\"temperature\": temp_liquid_gas, \"pressure\": pressure_liquid_gas, \"boundary\": \"Liquid–Gas (Vaporization)\"}\n)\ndf_melting = pd.DataFrame(\n    {\"temperature\": temp_solid_liquid, \"pressure\": pressure_solid_liquid, \"boundary\": \"Solid–Liquid (Melting)\"}\n)\ndf_boundaries = pd.concat([df_sublimation, df_vaporization, df_melting], ignore_index=True)\n\n# Phase region fill areas\ngas_temp = np.concatenate([temp_solid_gas, temp_liquid_gas])\ngas_pressure_upper = np.concatenate([pressure_solid_gas, pressure_liquid_gas])\ndf_gas_fill = pd.DataFrame({\"temperature\": gas_temp, \"ymax\": gas_pressure_upper, \"ymin\": 0.01, \"phase\": \"Gas\"})\ndf_solid_fill = pd.DataFrame(\n    {\"temperature\": temp_solid_liquid, \"ymax\": 2e9, \"ymin\": pressure_solid_liquid, \"phase\": \"Solid\"}\n)\ndf_liquid_fill = pd.DataFrame(\n    {\"temperature\": temp_liquid_gas, \"ymax\": 2e9, \"ymin\": pressure_liquid_gas, \"phase\": \"Liquid\"}\n)\n\n# Special points — triple point and critical point\ndf_points = pd.DataFrame(\n    {\n        \"temperature\": [triple_t, critical_t],\n        \"pressure\": [triple_p, critical_p],\n        \"label\": [\"Triple Point\\n(273.16 K, 611.73 Pa)\", \"Critical Point\\n(647.1 K, 22.06 MPa)\"],\n        \"point_type\": [\"Triple Point\", \"Critical Point\"],\n    }\n)\n\n# Phase region labels\ndf_labels = pd.DataFrame(\n    {\"temperature\": [225.0, 450.0, 450.0], \"pressure\": [5e7, 5e8, 500.0], \"text\": [\"SOLID\", \"LIQUID\", \"GAS\"]}\n)\n\n# Boundary curve colors — first 3 Imprint palette positions\nboundary_colors = IMPRINT_PALETTE[:3]\n\nanyplot_theme = theme(\n    plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n    panel_background=element_rect(fill=PAGE_BG),\n    panel_grid_major=element_line(color=INK_SOFT, size=0.3),\n    panel_grid_minor=element_blank(),\n    axis_title=element_text(size=12, color=INK),\n    axis_text=element_text(size=10, color=INK_SOFT),\n    axis_line=element_line(color=INK_SOFT),\n    plot_title=element_text(size=16, color=INK, margin=[0, 0, 8, 0]),\n    legend_text=element_text(size=10, color=INK_SOFT),\n    legend_title=element_text(size=12, color=INK),\n    legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n    legend_position=\"bottom\",\n)\n\nplot = (\n    ggplot()\n    # Subtle phase region fills\n    + geom_area(data=df_gas_fill, mapping=aes(x=\"temperature\", y=\"ymax\"), fill=FILL_GAS, alpha=0.6, inherit_aes=False)\n    + geom_area(\n        data=df_solid_fill, mapping=aes(x=\"temperature\", y=\"ymax\"), fill=FILL_SOLID, alpha=0.5, inherit_aes=False\n    )\n    + geom_area(\n        data=df_liquid_fill, mapping=aes(x=\"temperature\", y=\"ymax\"), fill=FILL_LIQUID, alpha=0.5, inherit_aes=False\n    )\n    # Phase boundary curves with interactive tooltips (lets-plot distinctive)\n    + geom_line(\n        data=df_boundaries,\n        mapping=aes(x=\"temperature\", y=\"pressure\", color=\"boundary\"),\n        size=1.2,\n        tooltips=layer_tooltips().line(\"@boundary\").line(\"T = @temperature K\").line(\"P = @pressure Pa\"),\n    )\n    # Special points with diamond markers\n    + geom_point(\n        data=df_points,\n        mapping=aes(x=\"temperature\", y=\"pressure\"),\n        color=INK,\n        size=4,\n        shape=18,\n        inherit_aes=False,\n        tooltips=layer_tooltips().line(\"@point_type\"),\n    )\n    # Triple point annotation\n    + geom_text(\n        data=df_points.iloc[[0]],\n        mapping=aes(x=\"temperature\", y=\"pressure\", label=\"label\"),\n        color=INK,\n        size=6,\n        nudge_x=50,\n        nudge_y=0.5,\n        label_padding=0.3,\n        inherit_aes=False,\n    )\n    # Critical point annotation\n    + geom_text(\n        data=df_points.iloc[[1]],\n        mapping=aes(x=\"temperature\", y=\"pressure\", label=\"label\"),\n        color=INK,\n        size=6,\n        nudge_x=-55,\n        nudge_y=0.7,\n        label_padding=0.3,\n        inherit_aes=False,\n    )\n    # Phase region labels — bold, subdued\n    + geom_text(\n        data=df_labels,\n        mapping=aes(x=\"temperature\", y=\"pressure\", label=\"text\"),\n        color=INK_MUTED,\n        size=9,\n        fontface=\"bold\",\n        alpha=0.85,\n        inherit_aes=False,\n    )\n    + scale_color_manual(values=boundary_colors)\n    + scale_y_log10()\n    + scale_x_continuous(breaks=[200, 300, 400, 500, 600, 700])\n    + labs(\n        x=\"Temperature (K)\",\n        y=\"Pressure (Pa)\",\n        title=\"phase-diagram-pt · python · letsplot · anyplot.ai\",\n        color=\"Phase Boundary\",\n    )\n    + theme_minimal()\n    + (flavor_high_contrast_light() if THEME == \"light\" else flavor_high_contrast_dark())\n    + anyplot_theme\n    + ggsize(800, 450)\n)\n\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}