{"spec_id":"spectrum-nmr","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nspectrum-nmr: NMR Spectrum (Nuclear Magnetic Resonance)\nLibrary: plotnine 0.15.5 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-06-03\n\"\"\"\n\nimport os\nimport sys\n\n\n# This file is named 'plotnine.py' — remove its directory from sys.path so the\n# 'plotnine' library is found in site-packages instead of looping back here.\n_d = os.path.dirname(os.path.abspath(__file__))\nif _d in sys.path:\n    sys.path.remove(_d)\ndel _d\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    annotate,\n    coord_cartesian,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_area,\n    geom_line,\n    geom_point,\n    geom_segment,\n    geom_text,\n    geom_vline,\n    ggplot,\n    labs,\n    scale_x_reverse,\n    scale_y_continuous,\n    theme,\n    theme_minimal,\n)\n\n\n# Theme tokens — Imprint palette, theme-adaptive chrome\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\nBRAND = \"#009E73\"  # Imprint palette position 1 — ALWAYS first series\n\n# Title with length-aware fontsize\ntitle = \"\\xb9H NMR of Ethanol · spectrum-nmr · python · plotnine · anyplot.ai\"\nn = len(title)\ntitle_fontsize = max(8, round(12 * 67 / n)) if n > 67 else 12\n\n# Data — synthetic 1H NMR spectrum of ethanol (CH3CH2OH)\nnp.random.seed(42)\nchemical_shift = np.linspace(-0.5, 5.0, 6000)\n\nw = 0.015  # default Lorentzian peak width\nintensity = np.zeros_like(chemical_shift)\n\n# TMS reference peak at 0 ppm (singlet)\nw_tms = 0.012\nintensity += 0.4 * w_tms**2 / ((chemical_shift - 0.0) ** 2 + w_tms**2)\n\n# CH3 triplet near 1.18 ppm (ratio 1:2:1)\ntriplet_center = 1.18\nj_coupling = 0.07\nintensity += 0.7 * w**2 / ((chemical_shift - (triplet_center - j_coupling)) ** 2 + w**2)\nintensity += 1.4 * w**2 / ((chemical_shift - triplet_center) ** 2 + w**2)\nintensity += 0.7 * w**2 / ((chemical_shift - (triplet_center + j_coupling)) ** 2 + w**2)\n\n# CH2 quartet near 3.69 ppm (ratio 1:3:3:1)\nquartet_center = 3.69\nintensity += 0.35 * w**2 / ((chemical_shift - (quartet_center - 1.5 * j_coupling)) ** 2 + w**2)\nintensity += 1.05 * w**2 / ((chemical_shift - (quartet_center - 0.5 * j_coupling)) ** 2 + w**2)\nintensity += 1.05 * w**2 / ((chemical_shift - (quartet_center + 0.5 * j_coupling)) ** 2 + w**2)\nintensity += 0.35 * w**2 / ((chemical_shift - (quartet_center + 1.5 * j_coupling)) ** 2 + w**2)\n\n# OH singlet near 2.61 ppm\nintensity += 0.55 * w**2 / ((chemical_shift - 2.61) ** 2 + w**2)\n\n# Slight baseline noise\nintensity += np.random.normal(0, 0.003, len(chemical_shift))\nintensity = np.maximum(intensity, 0)\n\ndf = pd.DataFrame({\"chemical_shift\": chemical_shift, \"intensity\": intensity})\n\n# Peak annotation data\nlabels_df = pd.DataFrame(\n    {\n        \"x\": [triplet_center, quartet_center, 2.61, 0.0],\n        \"y\": [1.52, 1.17, 0.67, 0.45],\n        \"peak_y\": [1.40, 1.05, 0.55, 0.40],\n        \"label\": [\"CH₃ (triplet)\\n1.18 ppm\", \"CH₂ (quartet)\\n3.69 ppm\", \"OH (singlet)\\n2.61 ppm\", \"TMS\\n0.00\"],\n        \"group\": [\"main\", \"main\", \"main\", \"ref\"],\n    }\n)\n\nmain_labels = labels_df[labels_df[\"group\"] == \"main\"]\nref_labels = labels_df[labels_df[\"group\"] == \"ref\"]\n\nvline_df = pd.DataFrame({\"xintercept\": [triplet_center, quartet_center, 2.61]})\n\n# Plot\nplot = (\n    ggplot(df, aes(x=\"chemical_shift\", y=\"intensity\"))\n    + geom_area(fill=BRAND, alpha=0.08)\n    + geom_vline(\n        data=vline_df,\n        mapping=aes(xintercept=\"xintercept\"),\n        color=BRAND,\n        alpha=0.12,\n        size=0.5,\n        linetype=\"dashed\",\n        inherit_aes=False,\n    )\n    + geom_line(color=BRAND, size=1.0)\n    + geom_point(data=labels_df, mapping=aes(x=\"x\", y=\"peak_y\"), color=BRAND, size=2.5, shape=\"o\", inherit_aes=False)\n    + geom_segment(\n        data=labels_df,\n        mapping=aes(x=\"x\", xend=\"x\", y=\"peak_y\", yend=\"y\"),\n        color=INK_SOFT,\n        size=0.4,\n        linetype=\"dotted\",\n        inherit_aes=False,\n    )\n    + geom_text(\n        data=main_labels,\n        mapping=aes(x=\"x\", y=\"y\", label=\"label\"),\n        size=3.5,\n        color=INK,\n        fontweight=\"bold\",\n        va=\"bottom\",\n        ha=\"center\",\n        inherit_aes=False,\n    )\n    + geom_text(\n        data=ref_labels,\n        mapping=aes(x=\"x\", y=\"y\", label=\"label\"),\n        size=3.0,\n        color=INK_SOFT,\n        va=\"bottom\",\n        ha=\"center\",\n        inherit_aes=False,\n    )\n    + annotate(\"text\", x=4.6, y=0.03, label=\"baseline\", size=2.5, color=INK_MUTED, fontstyle=\"italic\")\n    + scale_x_reverse(limits=(5.0, -0.5), breaks=[0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0])\n    + scale_y_continuous(breaks=[], limits=(-0.05, 1.72))\n    + coord_cartesian(expand=False)\n    + labs(x=\"Chemical Shift (ppm)\", y=\"Intensity\", title=title)\n    + theme_minimal()\n    + theme(\n        figure_size=(8, 4.5),\n        text=element_text(size=7, color=INK_SOFT),\n        axis_title_x=element_text(size=10, color=INK, margin={\"t\": 8}),\n        axis_title_y=element_text(size=10, color=INK_MUTED),\n        axis_text_x=element_text(size=8, color=INK_SOFT),\n        axis_text_y=element_blank(),\n        axis_ticks_major_y=element_blank(),\n        axis_line_x=element_line(color=INK_SOFT, size=0.6),\n        axis_line_y=element_blank(),\n        plot_title=element_text(size=title_fontsize, color=INK, margin={\"b\": 8}),\n        panel_background=element_rect(fill=PAGE_BG, color=\"none\"),\n        plot_background=element_rect(fill=PAGE_BG, color=\"none\"),\n        panel_border=element_blank(),\n        panel_grid_major_x=element_line(color=INK, size=0.3, alpha=0.15),\n        panel_grid_major_y=element_blank(),\n        panel_grid_minor=element_blank(),\n        plot_margin=0.04,\n    )\n)\n\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5, units=\"in\", verbose=False)\n"}