{"spec_id":"line-stress-strain","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nline-stress-strain: Engineering Stress-Strain Curve\nLibrary: matplotlib 3.11.0 | Python 3.13.14\nQuality: 87/100 | Updated: 2026-06-21\n\"\"\"\n\nimport os\n\nimport matplotlib.patheffects as pe\nimport matplotlib.pyplot as plt\nimport numpy as np\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\"\n\n# Imprint palette — data colors, theme-independent\nBRAND = \"#009E73\"  # position 1 — always first series (main curve)\nLAVENDER = \"#C475FD\"  # position 2 — yield point marker\nBLUE = \"#4467A3\"  # position 3 — fracture marker\nRED = \"#AE3030\"  # position 5 — UTS marker (semantic limit anchor)\n\n# Data — Mild steel tensile test (realistic stress-strain behavior)\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\nstrain_elastic = np.linspace(0, yield_strain, 60)\nstress_elastic = youngs_modulus * strain_elastic\n\n# Yield plateau (Lüders band, mild steel specific)\nstrain_plateau = np.linspace(yield_strain, 0.02, 30)\nstress_plateau = np.full_like(strain_plateau, yield_stress) + np.random.normal(0, 1, len(strain_plateau))\n\n# Strain hardening region\nstrain_hardening = np.linspace(0.02, uts_strain, 120)\nt = (strain_hardening - 0.02) / (uts_strain - 0.02)\nstress_hardening = yield_stress + (uts - yield_stress) * (1 - (1 - t) ** 2.5)\n\n# Necking region (stress drops after UTS)\nstrain_necking = np.linspace(uts_strain, fracture_strain, 60)\nt_neck = (strain_necking - uts_strain) / (fracture_strain - uts_strain)\nstress_necking = uts - (uts - 300) * 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# 0.2% offset yield point construction\noffset = 0.002\noffset_line_strain = np.linspace(offset, offset + yield_stress / youngs_modulus + 0.003, 50)\noffset_line_stress = youngs_modulus * (offset_line_strain - offset)\noffset_yield_strain = offset + yield_stress / youngs_modulus\noffset_yield_stress = yield_stress\n\n# Plot — landscape 3200×1800 px (figsize=(8,4.5) × dpi=400)\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Main stress-strain curve — Imprint brand green (position 1)\nax.fill_between(strain, stress, alpha=0.06, color=BRAND, zorder=2)\nax.plot(\n    strain,\n    stress,\n    linewidth=2.5,\n    color=BRAND,\n    zorder=5,\n    path_effects=[pe.Stroke(linewidth=4, foreground=PAGE_BG), pe.Normal()],\n)\n\n# 0.2% offset reference line\nax.plot(\n    offset_line_strain,\n    offset_line_stress,\n    linewidth=1.5,\n    color=INK_SOFT,\n    linestyle=\"--\",\n    zorder=4,\n    label=\"0.2% Offset Line\",\n)\n\n# Yield point marker and annotation\nax.plot(\n    offset_yield_strain,\n    offset_yield_stress,\n    \"o\",\n    markersize=8,\n    color=LAVENDER,\n    markeredgecolor=PAGE_BG,\n    markeredgewidth=1.5,\n    zorder=6,\n)\nax.annotate(\n    \"Yield Point\\n(0.2% Offset)\",\n    xy=(offset_yield_strain, offset_yield_stress),\n    xytext=(0.06, yield_stress + 70),\n    fontsize=7,\n    color=LAVENDER,\n    fontweight=\"bold\",\n    arrowprops={\"arrowstyle\": \"->\", \"color\": LAVENDER, \"lw\": 1.2},\n    bbox={\"boxstyle\": \"round,pad=0.25\", \"facecolor\": ELEVATED_BG, \"edgecolor\": LAVENDER, \"alpha\": 0.85},\n)\n\n# UTS marker and annotation\nax.plot(uts_strain, uts, \"o\", markersize=8, color=RED, markeredgecolor=PAGE_BG, markeredgewidth=1.5, zorder=6)\nax.annotate(\n    \"UTS\",\n    xy=(uts_strain, uts),\n    xytext=(uts_strain + 0.02, uts + 20),\n    fontsize=7,\n    color=RED,\n    fontweight=\"bold\",\n    arrowprops={\"arrowstyle\": \"->\", \"color\": RED, \"lw\": 1.2},\n)\n\n# Fracture marker and annotation\nfracture_stress = stress_necking[-1]\nax.plot(\n    fracture_strain,\n    fracture_stress,\n    \"X\",\n    markersize=10,\n    color=BLUE,\n    markeredgecolor=PAGE_BG,\n    markeredgewidth=1.5,\n    zorder=6,\n)\nax.annotate(\n    \"Fracture\",\n    xy=(fracture_strain, fracture_stress),\n    xytext=(fracture_strain - 0.01, fracture_stress - 50),\n    fontsize=7,\n    color=BLUE,\n    fontweight=\"bold\",\n    arrowprops={\"arrowstyle\": \"->\", \"color\": BLUE, \"lw\": 1.2},\n)\n\n# Region shading (axvspan) with Imprint palette colors at low alpha\nregion_bounds = [(0, yield_strain), (yield_strain, 0.02), (0.02, uts_strain), (uts_strain, fracture_strain)]\nregion_colors = [BRAND, LAVENDER, BRAND, BLUE]\nregion_alphas = [0.07, 0.05, 0.04, 0.04]\n\nfor (x0, x1), color, alpha in zip(region_bounds, region_colors, region_alphas, strict=False):\n    ax.axvspan(x0, x1, alpha=alpha, color=color, zorder=1)\n\n# Region labels — elastic zone is too narrow for direct label, use annotate with arc arrow\nax.annotate(\n    \"Elastic\",\n    xy=(yield_strain / 2, 125),\n    xytext=(0.025, 60),\n    fontsize=7,\n    color=BRAND,\n    fontstyle=\"italic\",\n    fontweight=\"semibold\",\n    arrowprops={\"arrowstyle\": \"->\", \"color\": BRAND, \"lw\": 0.8, \"connectionstyle\": \"arc3,rad=0.2\"},\n)\nax.text(0.011, 50, \"Yield\\nPlateau\", fontsize=7, ha=\"center\", color=LAVENDER, fontstyle=\"italic\", alpha=0.9)\nax.text(0.12, 30, \"Strain Hardening\", fontsize=7, ha=\"center\", color=BRAND, fontstyle=\"italic\", alpha=0.9)\nax.text(0.29, 30, \"Necking\", fontsize=7, ha=\"center\", color=BLUE, fontstyle=\"italic\", alpha=0.9)\n\n# Elastic modulus annotation box\nmid_elastic = len(strain_elastic) // 3\nax.annotate(\n    f\"E = {youngs_modulus:,} MPa\",\n    xy=(strain_elastic[mid_elastic], stress_elastic[mid_elastic]),\n    xytext=(0.03, 150),\n    fontsize=7,\n    color=INK,\n    fontweight=\"semibold\",\n    arrowprops={\"arrowstyle\": \"->\", \"color\": INK_SOFT, \"lw\": 1.0},\n    bbox={\"boxstyle\": \"round,pad=0.3\", \"facecolor\": ELEVATED_BG, \"edgecolor\": INK_SOFT, \"alpha\": 0.9},\n)\n\n# Style — axis labels, title, ticks, spines, grid\ntitle = \"line-stress-strain · python · matplotlib · anyplot.ai\"\nax.set_xlabel(\"Engineering Strain (mm/mm)\", fontsize=10, color=INK)\nax.set_ylabel(\"Engineering Stress (MPa)\", fontsize=10, color=INK)\nax.set_title(title, fontsize=12, fontweight=\"medium\", pad=20, color=INK)\nax.text(\n    0.5,\n    1.015,\n    \"Mild Steel Tensile Test — E = 210 GPa, σᵧ = 250 MPa, UTS = 400 MPa\",\n    transform=ax.transAxes,\n    fontsize=8,\n    ha=\"center\",\n    color=INK_MUTED,\n    fontstyle=\"italic\",\n)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT, labelcolor=INK_SOFT)\nfor spine in [\"top\", \"right\"]:\n    ax.spines[spine].set_visible(False)\nfor spine in [\"bottom\", \"left\"]:\n    ax.spines[spine].set_linewidth(0.8)\n    ax.spines[spine].set_color(INK_SOFT)\nax.yaxis.grid(True, alpha=0.15, linewidth=0.8, color=INK)\nax.xaxis.grid(True, alpha=0.08, linewidth=0.5, color=INK)\nax.set_xlim(-0.01, 0.40)\nax.set_ylim(-10, 470)\n\nleg = ax.legend(fontsize=8, loc=\"center right\", framealpha=0.9)\nif leg:\n    leg.get_frame().set_facecolor(ELEVATED_BG)\n    leg.get_frame().set_edgecolor(INK_SOFT)\n    plt.setp(leg.get_texts(), color=INK_SOFT)\n\nfig.subplots_adjust(left=0.09, right=0.97, top=0.87, bottom=0.12)\n\n# Save — no bbox_inches='tight' (would trim canvas away from 3200×1800 target)\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}