{"spec_id":"mohr-circle","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nmohr-circle: Mohr's Circle for Stress Analysis\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-30\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom matplotlib.lines import Line2D\n\n\n# Theme tokens\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 — canonical order, first series always #009E73\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\"]\nCOLOR_CIRCLE = IMPRINT_PALETTE[0]  # brand green — Mohr's circle boundary\nCOLOR_STATE = IMPRINT_PALETTE[1]  # lavender — stress state points A, B\nCOLOR_SIGMA = IMPRINT_PALETTE[2]  # blue — principal stresses σ₁, σ₂\nCOLOR_SHEAR = IMPRINT_PALETTE[3]  # ochre — max shear τmax\nCOLOR_ANGLE = IMPRINT_PALETTE[4]  # matte red — principal angle 2θp arc\n\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.12,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Data — stress state for a shaft under combined torsion and bending\nsigma_x = 70\nsigma_y = -50\ntau_xy = 35\n\n# Mohr's circle parameters\ncenter = (sigma_x + sigma_y) / 2\nradius = np.sqrt(((sigma_x - sigma_y) / 2) ** 2 + tau_xy**2)\nsigma_1 = center + radius\nsigma_2 = center - radius\ntau_max = radius\ntwo_theta_p = np.degrees(np.arctan2(tau_xy, (sigma_x - sigma_y) / 2))\n\n# Circle coordinates\ntheta = np.linspace(0, 2 * np.pi, 360)\ncircle_sigma = center + radius * np.cos(theta)\ncircle_tau = radius * np.sin(theta)\n\n# Key points DataFrame for seaborn semantic mapping\npoints_df = pd.DataFrame(\n    {\n        \"sigma\": [sigma_x, sigma_y, sigma_1, sigma_2, center, center],\n        \"tau\": [tau_xy, -tau_xy, 0, 0, tau_max, -tau_max],\n        \"Element\": [\n            \"Stress State (A, B)\",\n            \"Stress State (A, B)\",\n            \"Principal Stress (σ₁, σ₂)\",\n            \"Principal Stress (σ₁, σ₂)\",\n            \"Max Shear (τmax)\",\n            \"Max Shear (τmax)\",\n        ],\n    }\n)\n\nelement_palette = {\n    \"Stress State (A, B)\": COLOR_STATE,\n    \"Principal Stress (σ₁, σ₂)\": COLOR_SIGMA,\n    \"Max Shear (τmax)\": COLOR_SHEAR,\n}\nelement_markers = {\"Stress State (A, B)\": \"o\", \"Principal Stress (σ₁, σ₂)\": \"D\", \"Max Shear (τmax)\": \"s\"}\n\n# Plot — square canvas for equal-aspect Mohr's circle (2400×2400 px)\nfig, ax = plt.subplots(figsize=(6, 6), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Mohr's circle with subtle fill\nax.plot(circle_sigma, circle_tau, color=COLOR_CIRCLE, linewidth=2.5, zorder=3)\nax.fill(circle_sigma, circle_tau, color=COLOR_CIRCLE, alpha=0.05, zorder=1)\n\n# Reference lines through center\nax.axhline(y=0, color=INK_SOFT, linewidth=1.0, zorder=2)\nax.axvline(x=center, color=INK_MUTED, linewidth=0.8, linestyle=\"--\", alpha=0.6, zorder=2)\n\n# Diameter line connecting A and B\nax.plot([sigma_x, sigma_y], [tau_xy, -tau_xy], color=COLOR_STATE, linewidth=1.5, linestyle=\"--\", alpha=0.5, zorder=3)\n\n# Key points via seaborn scatterplot with hue + style semantic mapping\nsns.scatterplot(\n    data=points_df,\n    x=\"sigma\",\n    y=\"tau\",\n    hue=\"Element\",\n    style=\"Element\",\n    markers=element_markers,\n    palette=element_palette,\n    s=220,\n    edgecolor=PAGE_BG,\n    linewidth=1.5,\n    zorder=5,\n    ax=ax,\n    legend=False,\n)\n\n# Center point\nax.scatter([center], [0], s=100, color=INK_SOFT, edgecolors=PAGE_BG, linewidth=1.5, zorder=5)\n\n# Annotations — graduated visual hierarchy matching the spec requirements\n\n# Input stress state info box (tertiary — small, monospace)\ninfo_text = f\"σx = {sigma_x} MPa\\nσy = {sigma_y} MPa\\nτxy = {tau_xy} MPa\"\nax.text(\n    0.98,\n    0.98,\n    info_text,\n    transform=ax.transAxes,\n    fontsize=7,\n    verticalalignment=\"top\",\n    horizontalalignment=\"right\",\n    family=\"monospace\",\n    color=INK_SOFT,\n    bbox={\"boxstyle\": \"round,pad=0.4\", \"facecolor\": ELEVATED_BG, \"edgecolor\": INK_MUTED, \"alpha\": 0.9},\n    linespacing=1.5,\n)\n\n# Center label (tertiary)\nax.annotate(\n    f\"C ({center:.0f}, 0)\",\n    xy=(center, 0),\n    xytext=(center - 6, -radius * 0.26),\n    fontsize=7,\n    color=INK_SOFT,\n    ha=\"right\",\n    arrowprops={\"arrowstyle\": \"->\", \"color\": INK_SOFT, \"lw\": 1.0},\n    zorder=6,\n)\n\n# Stress point A (secondary)\nax.annotate(\n    f\"A ({sigma_x}, {tau_xy})\",\n    xy=(sigma_x, tau_xy),\n    xytext=(sigma_x + 10, tau_xy + 18),\n    fontsize=8,\n    fontweight=\"bold\",\n    color=COLOR_STATE,\n    ha=\"left\",\n    arrowprops={\"arrowstyle\": \"->\", \"color\": COLOR_STATE, \"lw\": 1.3},\n    zorder=6,\n)\n\n# Stress point B (secondary)\nax.annotate(\n    f\"B ({sigma_y}, {-tau_xy})\",\n    xy=(sigma_y, -tau_xy),\n    xytext=(sigma_y - 12, -tau_xy - 18),\n    fontsize=8,\n    fontweight=\"bold\",\n    color=COLOR_STATE,\n    ha=\"right\",\n    arrowprops={\"arrowstyle\": \"->\", \"color\": COLOR_STATE, \"lw\": 1.3},\n    zorder=6,\n)\n\n# Principal stresses (primary — boxed, bold, prominent arrows)\nax.annotate(\n    f\"σ₁ = {sigma_1:.1f} MPa\",\n    xy=(sigma_1, 0),\n    xytext=(center + radius * 0.42, -radius * 0.46),\n    fontsize=8,\n    fontweight=\"bold\",\n    color=COLOR_SIGMA,\n    ha=\"center\",\n    arrowprops={\"arrowstyle\": \"-|>\", \"color\": COLOR_SIGMA, \"lw\": 1.5, \"mutation_scale\": 12},\n    bbox={\"boxstyle\": \"round,pad=0.25\", \"facecolor\": ELEVATED_BG, \"edgecolor\": COLOR_SIGMA, \"alpha\": 0.92},\n    zorder=6,\n)\n\nax.annotate(\n    f\"σ₂ = {sigma_2:.1f} MPa\",\n    xy=(sigma_2, 0),\n    xytext=(center - radius * 0.42, -radius * 0.46),\n    fontsize=8,\n    fontweight=\"bold\",\n    color=COLOR_SIGMA,\n    ha=\"center\",\n    arrowprops={\"arrowstyle\": \"-|>\", \"color\": COLOR_SIGMA, \"lw\": 1.5, \"mutation_scale\": 12},\n    bbox={\"boxstyle\": \"round,pad=0.25\", \"facecolor\": ELEVATED_BG, \"edgecolor\": COLOR_SIGMA, \"alpha\": 0.92},\n    zorder=6,\n)\n\n# Max shear stress (secondary)\nax.annotate(\n    f\"τmax = {tau_max:.1f} MPa\",\n    xy=(center, tau_max),\n    xytext=(center + radius * 0.52, tau_max + 6),\n    fontsize=8,\n    fontweight=\"bold\",\n    color=COLOR_SHEAR,\n    arrowprops={\"arrowstyle\": \"->\", \"color\": COLOR_SHEAR, \"lw\": 1.3},\n    zorder=6,\n)\n\n# 2θp angle arc (from positive x-axis to the stress state point A direction)\narc_angles = np.linspace(0, np.radians(two_theta_p), 50)\narc_r = radius * 0.3\narc_x = center + arc_r * np.cos(arc_angles)\narc_y = arc_r * np.sin(arc_angles)\nax.plot(arc_x, arc_y, color=COLOR_ANGLE, linewidth=2.0, zorder=4)\n\nmid_angle = np.radians(two_theta_p / 2)\nax.text(\n    center + arc_r * 1.5 * np.cos(mid_angle),\n    arc_r * 1.5 * np.sin(mid_angle),\n    f\"2θp = {two_theta_p:.1f}°\",\n    fontsize=7,\n    fontweight=\"bold\",\n    color=COLOR_ANGLE,\n    ha=\"left\",\n    va=\"bottom\",\n)\n\n# Legend\nlegend_handles = [\n    Line2D([0], [0], color=COLOR_CIRCLE, linewidth=2.5, label=\"Mohr's Circle\"),\n    Line2D(\n        [0],\n        [0],\n        marker=\"o\",\n        color=\"w\",\n        markerfacecolor=COLOR_STATE,\n        markersize=8,\n        markeredgecolor=PAGE_BG,\n        markeredgewidth=1.2,\n        label=\"Stress State (A, B)\",\n    ),\n    Line2D(\n        [0],\n        [0],\n        marker=\"D\",\n        color=\"w\",\n        markerfacecolor=COLOR_SIGMA,\n        markersize=8,\n        markeredgecolor=PAGE_BG,\n        markeredgewidth=1.2,\n        label=\"Principal Stress (σ₁, σ₂)\",\n    ),\n    Line2D(\n        [0],\n        [0],\n        marker=\"s\",\n        color=\"w\",\n        markerfacecolor=COLOR_SHEAR,\n        markersize=8,\n        markeredgecolor=PAGE_BG,\n        markeredgewidth=1.2,\n        label=\"Max Shear (τmax)\",\n    ),\n    Line2D([0], [0], color=COLOR_ANGLE, linewidth=2.0, label=\"Principal Angle (2θp)\"),\n]\nax.legend(handles=legend_handles, fontsize=7, loc=\"lower left\", framealpha=0.9, edgecolor=INK_SOFT)\n\n# Style\ntitle = \"mohr-circle · python · seaborn · anyplot.ai\"\nax.set_xlabel(\"Normal Stress σ (MPa)\", fontsize=10, color=INK)\nax.set_ylabel(\"Shear Stress τ (MPa)\", fontsize=10, color=INK)\nax.set_title(title, fontsize=12, fontweight=\"medium\", color=INK, pad=12)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\nax.set_aspect(\"equal\")\n\n# Grid — both axes for this engineering coordinate diagram\nax.yaxis.grid(True, alpha=0.12, linewidth=0.7, color=INK)\nax.xaxis.grid(True, alpha=0.12, linewidth=0.7, color=INK)\nsns.despine(ax=ax)\n\n# Save — no bbox_inches to preserve exact 2400×2400 canvas\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\nplt.close()\n"}