{"spec_id":"phase-diagram","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nphase-diagram: Phase Diagram (State Space Plot)\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-14\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\n# Theme tokens\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\"\n\n# Okabe-Ito palette\nBRAND = \"#009E73\"\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\"]\n\n# Damped harmonic oscillator: m*x'' + c*x' + k*x = 0\n# Using underdamped solution: x(t) = A*exp(-gamma*t)*cos(omega_d*t + phi)\ngamma = 0.15  # Damping coefficient\nomega0 = 1.0  # Natural frequency\nomega_d = np.sqrt(omega0**2 - gamma**2)  # Damped frequency (underdamped case)\n\n# Time array\nt = np.linspace(0, 50, 2000)\n\n# Multiple trajectories from different initial conditions\n# Format: (A, phi) - amplitude and phase for analytical solution\ninitial_params = [(3.0, 0.0), (3.0, 0.5), (2.5, 2.5), (2.0, 4.0)]\n\n# Compute trajectories using analytical solution\n# x(t) = A * exp(-gamma*t) * cos(omega_d*t + phi)\n# v(t) = dx/dt = A * exp(-gamma*t) * (-gamma*cos(omega_d*t + phi) - omega_d*sin(omega_d*t + phi))\ntrajectories = []\nfor A, phi in initial_params:\n    exp_decay = A * np.exp(-gamma * t)\n    x = exp_decay * np.cos(omega_d * t + phi)\n    v = exp_decay * (-gamma * np.cos(omega_d * t + phi) - omega_d * np.sin(omega_d * t + phi))\n    trajectories.append((x, v, A, phi))\n\n# Create figure\nfig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Plot each trajectory\nfor i, (x, v, A, _phi) in enumerate(trajectories):\n    # Plot trajectory line\n    ax.plot(x, v, color=IMPRINT[i], linewidth=2.5, alpha=0.8, label=f\"Trajectory {i + 1} (A={A:.1f})\")\n\n    # Mark start point with larger marker\n    ax.scatter(x[0], v[0], s=250, color=IMPRINT[i], edgecolor=PAGE_BG, linewidth=2, zorder=5, marker=\"o\")\n\n    # Add arrows to show direction along trajectory\n    n_points = len(x)\n    n_arrows = 4\n    arrow_indices = np.linspace(100, n_points - 200, n_arrows, dtype=int)\n    for idx in arrow_indices:\n        dx = x[idx + 10] - x[idx]\n        dv = v[idx + 10] - v[idx]\n        length = np.sqrt(dx**2 + dv**2)\n        if length > 0.01:\n            ax.annotate(\n                \"\",\n                xy=(x[idx + 10], v[idx + 10]),\n                xytext=(x[idx], v[idx]),\n                arrowprops={\"arrowstyle\": \"->\", \"color\": IMPRINT[i], \"lw\": 2.5, \"mutation_scale\": 20},\n            )\n\n# Mark the equilibrium point (stable fixed point at origin)\nax.scatter(0, 0, s=400, color=INK_SOFT, marker=\"x\", linewidth=4, zorder=10, label=\"Equilibrium (stable)\")\n\n# Add reference lines for axes\nax.axhline(y=0, color=INK_SOFT, linewidth=1.5, linestyle=\"--\", alpha=0.4)\nax.axvline(x=0, color=INK_SOFT, linewidth=1.5, linestyle=\"--\", alpha=0.4)\n\n# Labels and styling\nax.set_xlabel(\"Position x (arbitrary units)\", fontsize=20, color=INK)\nax.set_ylabel(\"Velocity dx/dt (arbitrary units)\", fontsize=20, color=INK)\nax.set_title(\"Damped Oscillator · phase-diagram · matplotlib · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT, labelcolor=INK_SOFT)\nax.legend(fontsize=16, loc=\"upper right\", framealpha=0.9)\nfor s in (\"left\", \"bottom\"):\n    ax.spines[s].set_color(INK_SOFT)\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.grid(True, alpha=0.15, linestyle=\"-\", color=INK_SOFT, linewidth=0.8)\n\n# Set equal aspect ratio for proper visualization\nax.set_aspect(\"equal\", adjustable=\"box\")\n\n# Adjust axis limits for better visualization\nax.set_xlim(-4, 4)\nax.set_ylim(-3.5, 3.5)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}