r_val, K_val = 1.0, 4.0
f_log = lambda x: r_val * x * (1 - x / K_val)
x_arr = np.linspace(-0.5, 6.5, 400)
f_arr = f_log(x_arr)
fig = plt.figure(figsize=(11, 5))
gs = fig.add_gridspec(2, 2, width_ratios=[1.8, 1], hspace=0.5, wspace=0.35)
ax_f = fig.add_subplot(gs[0, 0])
ax_pl = fig.add_subplot(gs[1, 0])
ax_t = fig.add_subplot(gs[:, 1])
# ── f(x) graph ──────────────────────────────────────────────
ax_f.plot(x_arr, f_arr, color='steelblue', lw=2.5)
ax_f.axhline(0, color='k', lw=0.8)
ax_f.fill_between(x_arr, 0, f_arr, where=(f_arr > 0),
alpha=0.15, color='seagreen', label='$f>0$ (increasing)')
ax_f.fill_between(x_arr, 0, f_arr, where=(f_arr < 0),
alpha=0.15, color='crimson', label='$f<0$ (decreasing)')
ax_f.plot([0, K_val], [0, 0], 'ko', markersize=8, zorder=5)
ax_f.set_xlabel('$x$'); ax_f.set_ylabel("$f(x)$")
ax_f.set_title(r"$f(x)=x(1-x/4)$"); ax_f.legend(fontsize=8)
ax_f.set_xlim(-0.5, 6.5)
# ── Phase line ───────────────────────────────────────────────
ax_pl.axhline(0, color='k', lw=1.2)
ax_pl.plot(0, 0, 'o', markersize=12, color='crimson', zorder=5)
ax_pl.plot(K_val, 0, 'o', markersize=12, color='seagreen', zorder=5)
ax_pl.annotate('', xy=(-0.3, 0), xytext=(0.3, 0),
arrowprops=dict(arrowstyle='<-', color='crimson', lw=2))
for xm in [1.5, 2.5]:
ax_pl.annotate('', xy=(xm+0.5, 0), xytext=(xm-0.5, 0),
arrowprops=dict(arrowstyle='->', color='seagreen', lw=2))
for xm in [5.0, 5.8]:
ax_pl.annotate('', xy=(xm-0.5, 0), xytext=(xm+0.5, 0),
arrowprops=dict(arrowstyle='<-', color='crimson', lw=2))
ax_pl.text(0, 0.25, '$x^*=0$\n(unstable)', ha='center', fontsize=9, color='crimson')
ax_pl.text(K_val, 0.25, f'$x^*={K_val}$\n(stable)', ha='center', fontsize=9, color='seagreen')
ax_pl.set_xlim(-0.8, 7); ax_pl.set_ylim(-0.6, 0.7)
ax_pl.set_yticks([]); ax_pl.set_xlabel('$x$')
ax_pl.set_title('Phase line')
# ── Solution curves ──────────────────────────────────────────
t_eval = np.linspace(0, 8, 400)
f_ode = lambda t, x: [r_val * x[0] * (1 - x[0] / K_val)]
colors_t = plt.cm.viridis(np.linspace(0.1, 0.9, 6))
for x0, color in zip([0.3, 1.0, 2.0, 3.0, 6.0, 8.0], colors_t):
sol = solve_ivp(f_ode, (0, 8), [x0], t_eval=t_eval, max_step=0.05)
ax_t.plot(sol.t, sol.y[0], color=color, lw=2, label=f'$x_0={x0}$')
ax_t.axhline(K_val, color='seagreen', ls='--', lw=1.8, label=f'$K={K_val}$')
ax_t.axhline(0, color='crimson', ls='--', lw=1.2)
ax_t.set_xlabel('$t$'); ax_t.set_ylabel('$x(t)$')
ax_t.set_title('Solutions vs. time')
ax_t.legend(fontsize=7, ncol=2)
plt.suptitle(r"Logistic: $x' = x(1-x/4)$", fontsize=12, y=1.01)
plt.tight_layout()
plt.show()