{"spec_id":"mohr-circle","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nmohr-circle: Mohr's Circle for Stress Analysis\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-05-30\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\n\n\n# Theme tokens — Imprint palette 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\"\nGRID = \"rgba(26,26,23,0.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\n\n# Imprint palette — differentiated roles for Mohr's circle elements\nCIRCLE_COLOR = \"#009E73\"  # brand green — primary structural element\nPOINT_COLOR = \"#AE3030\"  # matte red — given stress state (A, B)\nSIGMA_COLOR = \"#4467A3\"  # blue — principal stresses σ1, σ2\nTAU_COLOR = \"#BD8233\"  # ochre — maximum shear stress\nARC_COLOR = \"#C475FD\"  # lavender — principal plane angle arc\n\n# Data — stress state (MPa)\nsigma_x = 80\nsigma_y = -40\ntau_xy = 30\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\n\n# Circle points\ntheta = np.linspace(0, 2 * np.pi, 360)\nsigma_circle = center + radius * np.cos(theta)\ntau_circle = radius * np.sin(theta)\n\n# Stress points\npoint_a = (sigma_x, tau_xy)\npoint_b = (sigma_y, -tau_xy)\n\n# Principal plane angle (2θp)\ntheta_2p = np.degrees(np.arctan2(tau_xy, (sigma_x - sigma_y) / 2))\n\n# Plot\nfig = go.Figure()\n\n# Reference lines through center\naxis_pad = radius * 0.3\nfig.add_shape(\n    type=\"line\",\n    x0=sigma_2 - axis_pad,\n    y0=0,\n    x1=sigma_1 + axis_pad,\n    y1=0,\n    line={\"color\": GRID, \"width\": 1.5},\n    layer=\"below\",\n)\nfig.add_shape(\n    type=\"line\",\n    x0=center,\n    y0=-radius - axis_pad,\n    x1=center,\n    y1=radius + axis_pad,\n    line={\"color\": GRID, \"width\": 1.5},\n    layer=\"below\",\n)\n\n# Mohr's circle — brand green with subtle fill\ncircle_fill = \"rgba(0,158,115,0.07)\" if THEME == \"light\" else \"rgba(0,158,115,0.13)\"\nfig.add_trace(\n    go.Scatter(\n        x=sigma_circle,\n        y=tau_circle,\n        mode=\"lines\",\n        line={\"color\": CIRCLE_COLOR, \"width\": 3.5},\n        showlegend=False,\n        fill=\"toself\",\n        fillcolor=circle_fill,\n    )\n)\n\n# Diameter line connecting A and B\nfig.add_trace(\n    go.Scatter(\n        x=[point_a[0], point_b[0]],\n        y=[point_a[1], point_b[1]],\n        mode=\"lines\",\n        line={\"color\": CIRCLE_COLOR, \"width\": 2, \"dash\": \"dash\"},\n        showlegend=False,\n        hoverinfo=\"skip\",\n    )\n)\n\n# Stress points A and B — given state (red)\nfig.add_trace(\n    go.Scatter(\n        x=[point_a[0]],\n        y=[point_a[1]],\n        mode=\"markers\",\n        marker={\"size\": 14, \"color\": POINT_COLOR, \"line\": {\"color\": PAGE_BG, \"width\": 2}},\n        showlegend=False,\n        hovertext=f\"A (σx={sigma_x}, τxy={tau_xy})\",\n        hoverinfo=\"text\",\n    )\n)\nfig.add_trace(\n    go.Scatter(\n        x=[point_b[0]],\n        y=[point_b[1]],\n        mode=\"markers\",\n        marker={\"size\": 14, \"color\": POINT_COLOR, \"line\": {\"color\": PAGE_BG, \"width\": 2}},\n        showlegend=False,\n        hovertext=f\"B (σy={sigma_y}, τxy={-tau_xy})\",\n        hoverinfo=\"text\",\n    )\n)\n\n# Principal stresses σ1, σ2 — derived results (blue diamonds)\nfig.add_trace(\n    go.Scatter(\n        x=[sigma_1, sigma_2],\n        y=[0, 0],\n        mode=\"markers\",\n        marker={\"size\": 14, \"color\": SIGMA_COLOR, \"symbol\": \"diamond\", \"line\": {\"color\": PAGE_BG, \"width\": 2}},\n        showlegend=False,\n        hovertext=[f\"σ₁ = {sigma_1:.1f} MPa\", f\"σ₂ = {sigma_2:.1f} MPa\"],\n        hoverinfo=\"text\",\n    )\n)\n\n# Maximum shear stress top — ochre triangle-up\nfig.add_trace(\n    go.Scatter(\n        x=[center],\n        y=[tau_max],\n        mode=\"markers\",\n        marker={\"size\": 14, \"color\": TAU_COLOR, \"symbol\": \"triangle-up\", \"line\": {\"color\": PAGE_BG, \"width\": 2}},\n        showlegend=False,\n        hovertext=[f\"τmax = {tau_max:.1f} MPa\"],\n        hoverinfo=\"text\",\n    )\n)\n\n# Maximum shear stress bottom — ochre triangle-down\nfig.add_trace(\n    go.Scatter(\n        x=[center],\n        y=[-tau_max],\n        mode=\"markers\",\n        marker={\"size\": 14, \"color\": TAU_COLOR, \"symbol\": \"triangle-down\", \"line\": {\"color\": PAGE_BG, \"width\": 2}},\n        showlegend=False,\n        hovertext=[f\"−τmax = {-tau_max:.1f} MPa\"],\n        hoverinfo=\"text\",\n    )\n)\n\n# Center point\nfig.add_trace(\n    go.Scatter(\n        x=[center],\n        y=[0],\n        mode=\"markers\",\n        marker={\"size\": 10, \"color\": CIRCLE_COLOR, \"symbol\": \"x\", \"line\": {\"width\": 2}},\n        showlegend=False,\n        hovertext=f\"C ({center:.0f}, 0)\",\n        hoverinfo=\"text\",\n    )\n)\n\n# Principal plane angle arc (2θp) — lavender\narc_r = radius * 0.28\narc_angles = np.linspace(0, np.radians(theta_2p), 50)\narc_x = center + arc_r * np.cos(arc_angles)\narc_y = arc_r * np.sin(arc_angles)\nfig.add_trace(\n    go.Scatter(\n        x=arc_x, y=arc_y, mode=\"lines\", line={\"color\": ARC_COLOR, \"width\": 2.5}, showlegend=False, hoverinfo=\"skip\"\n    )\n)\n\n# Annotations\nfig.add_annotation(\n    x=point_a[0],\n    y=point_a[1],\n    text=f\"A ({sigma_x}, {tau_xy})\",\n    showarrow=True,\n    arrowhead=0,\n    arrowcolor=POINT_COLOR,\n    ax=40,\n    ay=-35,\n    font={\"size\": 12, \"color\": POINT_COLOR},\n)\nfig.add_annotation(\n    x=point_b[0],\n    y=point_b[1],\n    text=f\"B ({sigma_y}, {-tau_xy})\",\n    showarrow=True,\n    arrowhead=0,\n    arrowcolor=POINT_COLOR,\n    ax=-40,\n    ay=35,\n    font={\"size\": 12, \"color\": POINT_COLOR},\n)\nfig.add_annotation(\n    x=sigma_1, y=0, text=f\"σ₁ = {sigma_1:.1f}\", showarrow=False, yshift=-28, font={\"size\": 12, \"color\": SIGMA_COLOR}\n)\nfig.add_annotation(\n    x=sigma_2, y=0, text=f\"σ₂ = {sigma_2:.1f}\", showarrow=False, yshift=-28, font={\"size\": 12, \"color\": SIGMA_COLOR}\n)\nfig.add_annotation(\n    x=center, y=tau_max, text=f\"τmax = {tau_max:.1f}\", showarrow=False, yshift=18, font={\"size\": 12, \"color\": TAU_COLOR}\n)\nfig.add_annotation(\n    x=center,\n    y=-tau_max,\n    text=f\"−τmax = {-tau_max:.1f}\",\n    showarrow=False,\n    yshift=-18,\n    font={\"size\": 12, \"color\": TAU_COLOR},\n)\nfig.add_annotation(\n    x=center,\n    y=0,\n    text=f\"C ({center:.0f}, 0)\",\n    showarrow=False,\n    xshift=35,\n    yshift=-18,\n    font={\"size\": 12, \"color\": INK_SOFT},\n)\n\n# 2θp label near arc midpoint\nmid_angle = np.radians(theta_2p / 2)\nfig.add_annotation(\n    x=center + arc_r * 1.4 * np.cos(mid_angle),\n    y=arc_r * 1.4 * np.sin(mid_angle),\n    text=f\"2θp = {theta_2p:.1f}°\",\n    showarrow=False,\n    font={\"size\": 11, \"color\": ARC_COLOR},\n)\n\n# Layout\ntitle_text = \"mohr-circle · python · plotly · anyplot.ai\"\nn = len(title_text)\ntitle_fontsize = round(16 * 67 / n) if n > 67 else 16\n\nfig.update_layout(\n    autosize=False,\n    title={\"text\": title_text, \"font\": {\"size\": title_fontsize, \"color\": INK}, \"x\": 0.5},\n    xaxis={\n        \"title\": {\"text\": \"Normal 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\": True,\n        \"zerolinecolor\": INK_SOFT,\n        \"zerolinewidth\": 1.5,\n        \"linecolor\": INK_SOFT,\n        \"scaleanchor\": \"y\",\n        \"scaleratio\": 1,\n    },\n    yaxis={\n        \"title\": {\"text\": \"Shear 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\": True,\n        \"zerolinecolor\": INK_SOFT,\n        \"zerolinewidth\": 1.5,\n        \"linecolor\": INK_SOFT,\n    },\n    plot_bgcolor=PAGE_BG,\n    paper_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    showlegend=False,\n    margin={\"l\": 65, \"r\": 65, \"t\": 80, \"b\": 60},\n)\n\n# Save\nfig.write_image(f\"plot-{THEME}.png\", width=600, height=600, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}