{"spec_id":"line-stress-strain","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nline-stress-strain: Engineering Stress-Strain Curve\nLibrary: plotly 6.8.0 | Python 3.13.14\nQuality: 89/100 | Updated: 2026-06-21\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\n\n\n# Theme tokens — Imprint palette, theme-adaptive chrome\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\"\nGRID = \"rgba(26,26,23,0.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\n\n# Imprint palette — selected positions for semantic roles\nBRAND = \"#009E73\"  # Imprint position 1 — main curve (Mild Steel)\nBLUE = \"#4467A3\"  # Imprint position 3 — 0.2% offset reference line\nOCHRE = \"#BD8233\"  # Imprint position 4 — UTS marker\nRED = \"#AE3030\"  # Imprint position 5 — fracture (semantic: failure)\nAMBER = \"#DDCC77\"  # semantic anchor — yield point (warning threshold)\n\n# Data — Mild steel tensile test simulation\nnp.random.seed(42)\n\nyoungs_modulus = 210000  # MPa\nyield_stress = 250  # MPa\nuts = 400  # MPa\nfracture_strain = 0.35\nuts_strain = 0.22\nyield_strain = yield_stress / youngs_modulus\n\n# Elastic region (steep linear rise)\nstrain_elastic = np.linspace(0, yield_strain, 50)\nstress_elastic = youngs_modulus * strain_elastic\n\n# Yield plateau and early plastic deformation\nstrain_plateau = np.linspace(yield_strain, 0.02, 20)\nstress_plateau = yield_stress + 5000 * (strain_plateau - yield_strain)\n\n# Strain hardening (concave down curve toward UTS)\nstrain_hardening = np.linspace(0.02, uts_strain, 100)\nt = (strain_hardening - 0.02) / (uts_strain - 0.02)\nstress_hardening = stress_plateau[-1] + (uts - stress_plateau[-1]) * (1 - (1 - t) ** 2)\n\n# Necking (stress drops from UTS to fracture)\nstrain_necking = np.linspace(uts_strain, fracture_strain, 50)\nt_neck = (strain_necking - uts_strain) / (fracture_strain - uts_strain)\nfracture_stress = 310\nstress_necking = uts - (uts - fracture_stress) * t_neck**1.5\n\n# Combine all regions\nstrain = np.concatenate([strain_elastic, strain_plateau, strain_hardening, strain_necking])\nstress = np.concatenate([stress_elastic, stress_plateau, stress_hardening, stress_necking])\n\n# Add slight noise for realism (skip elastic region for clean slope)\nnoise = np.random.normal(0, 1.0, len(strain))\nnoise[:50] = 0\nstress = stress + noise\nstress = np.maximum(stress, 0)\n\n# 0.2% offset line for yield determination\noffset_line_strain = np.linspace(0.002, 0.002 + yield_strain * 1.3, 50)\noffset_line_stress = youngs_modulus * (offset_line_strain - 0.002)\n\n# Key point coordinates\noffset_yield_strain = yield_stress / youngs_modulus + 0.002\noffset_yield_stress = yield_stress\nuts_plot_strain = uts_strain\nuts_plot_stress = uts\nfracture_plot_strain = strain[-1]\nfracture_plot_stress = stress[-1]\n\n# Plot\nfig = go.Figure()\n\n# Main stress-strain curve — Imprint position 1 (brand green)\nfig.add_trace(\n    go.Scatter(\n        x=strain,\n        y=stress,\n        mode=\"lines\",\n        line={\"color\": BRAND, \"width\": 3.5},\n        name=\"Mild Steel\",\n        hovertemplate=\"Strain: %{x:.4f}<br>Stress: %{y:.1f} MPa<extra></extra>\",\n    )\n)\n\n# 0.2% offset line — Imprint position 3 (blue reference line)\nfig.add_trace(\n    go.Scatter(\n        x=offset_line_strain,\n        y=offset_line_stress,\n        mode=\"lines\",\n        line={\"color\": BLUE, \"width\": 2, \"dash\": \"dash\"},\n        name=\"0.2% Offset Line\",\n        hoverinfo=\"skip\",\n    )\n)\n\n# Yield point marker — amber (semantic: warning threshold)\nfig.add_trace(\n    go.Scatter(\n        x=[offset_yield_strain],\n        y=[offset_yield_stress],\n        mode=\"markers\",\n        marker={\"size\": 14, \"color\": AMBER, \"symbol\": \"diamond\", \"line\": {\"color\": INK, \"width\": 1.5}},\n        name=\"Yield Point\",\n        hovertemplate=\"Yield Point<br>Strain: %{x:.4f}<br>Stress: %{y:.1f} MPa<extra></extra>\",\n    )\n)\n\n# UTS marker — Imprint position 4 (ochre)\nfig.add_trace(\n    go.Scatter(\n        x=[uts_plot_strain],\n        y=[uts_plot_stress],\n        mode=\"markers\",\n        marker={\"size\": 14, \"color\": OCHRE, \"symbol\": \"star\", \"line\": {\"color\": INK, \"width\": 1.5}},\n        name=\"Ultimate Tensile Strength\",\n        hovertemplate=\"UTS<br>Strain: %{x:.4f}<br>Stress: %{y:.1f} MPa<extra></extra>\",\n    )\n)\n\n# Fracture point marker — Imprint position 5 / semantic red (failure)\nfig.add_trace(\n    go.Scatter(\n        x=[fracture_plot_strain],\n        y=[fracture_plot_stress],\n        mode=\"markers\",\n        marker={\"size\": 14, \"color\": RED, \"symbol\": \"x\", \"line\": {\"color\": INK, \"width\": 2}},\n        name=\"Fracture Point\",\n        hovertemplate=\"Fracture<br>Strain: %{x:.4f}<br>Stress: %{y:.1f} MPa<extra></extra>\",\n    )\n)\n\n# Young's modulus annotation — offset up-right to avoid crowding near origin\nfig.add_annotation(\n    x=yield_strain * 0.45,\n    y=youngs_modulus * yield_strain * 0.45,\n    text=f\"E = {youngs_modulus // 1000} GPa\",\n    showarrow=True,\n    arrowhead=2,\n    arrowcolor=BRAND,\n    ax=60,\n    ay=-35,\n    font={\"size\": 12, \"color\": BRAND},\n    bgcolor=PAGE_BG,\n    borderpad=2,\n)\n\n# Yield point annotation — offset up-right to avoid overlap with E annotation\nfig.add_annotation(\n    x=offset_yield_strain,\n    y=offset_yield_stress,\n    text=\"Yield Point<br>(0.2% offset)\",\n    showarrow=True,\n    arrowhead=2,\n    arrowcolor=AMBER,\n    ax=70,\n    ay=-50,\n    font={\"size\": 12, \"color\": AMBER},\n    bgcolor=PAGE_BG,\n    borderpad=2,\n)\n\n# UTS annotation\nfig.add_annotation(\n    x=uts_plot_strain,\n    y=uts_plot_stress,\n    text=f\"UTS = {uts} MPa\",\n    showarrow=True,\n    arrowhead=2,\n    arrowcolor=OCHRE,\n    ax=-50,\n    ay=-35,\n    font={\"size\": 12, \"color\": OCHRE},\n    bgcolor=PAGE_BG,\n    borderpad=2,\n)\n\n# Fracture annotation\nfig.add_annotation(\n    x=fracture_plot_strain,\n    y=fracture_plot_stress,\n    text=\"Fracture\",\n    showarrow=True,\n    arrowhead=2,\n    arrowcolor=RED,\n    ax=-55,\n    ay=30,\n    font={\"size\": 12, \"color\": RED},\n    bgcolor=PAGE_BG,\n    borderpad=2,\n)\n\n# Region labels — tertiary ink for structural readability\nfig.add_annotation(x=0.007, y=95, text=\"Elastic\", showarrow=False, font={\"size\": 11, \"color\": INK_MUTED})\nfig.add_annotation(x=0.12, y=320, text=\"Strain Hardening\", showarrow=False, font={\"size\": 11, \"color\": INK_MUTED})\nfig.add_annotation(x=0.295, y=430, text=\"Necking\", showarrow=False, font={\"size\": 11, \"color\": INK_MUTED})\n\n# Title — mandatory format with length-aware font scaling\ntitle = \"Mild Steel Tensile Test · line-stress-strain · python · plotly · anyplot.ai\"\ntitle_fontsize = round(16 * 67 / max(67, len(title)))\n\nfig.update_layout(\n    autosize=False,\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    title={\"text\": title, \"font\": {\"size\": title_fontsize, \"color\": INK}},\n    xaxis={\n        \"title\": {\"text\": \"Engineering Strain\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"showgrid\": False,\n        \"zeroline\": False,\n        \"showline\": True,\n        \"mirror\": False,\n        \"linecolor\": INK_SOFT,\n        \"range\": [-0.01, 0.38],\n    },\n    yaxis={\n        \"title\": {\"text\": \"Engineering Stress (MPa)\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"showgrid\": True,\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"zeroline\": False,\n        \"showline\": True,\n        \"mirror\": False,\n        \"linecolor\": INK_SOFT,\n        \"range\": [-10, 460],\n    },\n    legend={\n        \"font\": {\"size\": 10, \"color\": INK_SOFT},\n        \"x\": 0.98,\n        \"y\": 0.05,\n        \"xanchor\": \"right\",\n        \"yanchor\": \"bottom\",\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n    },\n    updatemenus=[\n        {\n            \"type\": \"buttons\",\n            \"direction\": \"right\",\n            \"x\": 0.0,\n            \"y\": 1.10,\n            \"xanchor\": \"left\",\n            \"yanchor\": \"top\",\n            \"showactive\": True,\n            \"bgcolor\": ELEVATED_BG,\n            \"bordercolor\": INK_SOFT,\n            \"borderwidth\": 1,\n            \"font\": {\"color\": INK_SOFT, \"size\": 10},\n            \"buttons\": [\n                {\n                    \"label\": \"Full Curve\",\n                    \"method\": \"relayout\",\n                    \"args\": [{\"xaxis.range\": [-0.01, 0.38], \"yaxis.range\": [-10, 460]}],\n                },\n                {\n                    \"label\": \"Elastic Detail\",\n                    \"method\": \"relayout\",\n                    \"args\": [{\"xaxis.range\": [-0.0001, 0.0015], \"yaxis.range\": [-10, 300]}],\n                },\n            ],\n        }\n    ],\n    margin={\"l\": 80, \"r\": 40, \"t\": 100, \"b\": 60},\n    width=800,\n    height=450,\n)\n\n# Save — 3200×1800 px landscape (width=800 × scale=4, height=450 × scale=4)\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}