def f51(x, y): return -x + x*y
def g51(x, y): return -4*y + 8*x*y
lim = 2.0
x_g, y_g = np.meshgrid(np.linspace(-lim, lim, 24), np.linspace(-lim, lim, 24))
dx = f51(x_g, y_g); dy = g51(x_g, y_g)
nrm = np.sqrt(dx**2 + dy**2 + 1e-10)
fig, ax = plt.subplots(figsize=(8, 7))
ax.quiver(x_g, y_g, dx/nrm, dy/nrm, alpha=0.3, color='gray', scale=28)
# Nullclines
ax.axvline(0, color='steelblue', ls='--', lw=1.8, label=r"$x$-nullcline: $x=0$")
ax.axhline(1, color='steelblue', ls='--', lw=1.8, label=r"$x$-nullcline: $y=1$")
ax.axhline(0, color='crimson', ls='--', lw=1.8, label=r"$y$-nullcline: $y=0$")
ax.axvline(0.5,color='crimson', ls='--', lw=1.8, label=r"$y$-nullcline: $x=1/2$")
# Orbits
np.random.seed(7)
ics = [(1.5, 1.5), (1.5, 0.5), (1.5, -0.5), (1.5, -1.5),
(-1.5, 1.5), (-1.5, 0.5), (-1.5, -0.5), (-1.5, -1.5),
(0.3, 1.5), (0.8, 1.5), (-0.3, 0.5), (-0.8, 0.5),
(0.3, -0.5), (0.8, -0.5), (0.1, 0.1), (-0.1, 0.1)]
for x0, y0 in ics:
sol = solve_ivp(lambda t, z: [f51(z[0], z[1]), g51(z[0], z[1])],
(0, 6), [x0, y0], dense_output=True, max_step=0.02)
xy = sol.y; mask = np.all(np.abs(xy) < lim*1.35, axis=0)
ax.plot(xy[0, mask], xy[1, mask], 'k-', lw=1.0, alpha=0.55)
# Critical points
ax.plot(0, 0, 'o', color='steelblue', markersize=9, zorder=5, label='Stable node $(0,0)$')
ax.plot(0.5, 1, 's', color='crimson', markersize=9, zorder=5, label='Saddle $(1/2,1)$')
ax.set_xlim(-lim, lim); ax.set_ylim(-lim, lim)
ax.set_xlabel('$x$'); ax.set_ylabel('$y$')
ax.set_title(r"Example 5.1: $x'=-x+xy$, $y'=-4y+8xy$", fontsize=11)
ax.legend(fontsize=8, loc='lower right')
plt.tight_layout()
plt.show()