fig, axes = plt.subplots(1, 2, figsize=(11, 5))
# Left: solution comparison
ax = axes[0]
t_fine = np.linspace(0, 2, 400)
ax.plot(t_fine, x_exact1(t_fine), 'k-', lw=2.2, label='Exact', zorder=5)
ax.plot(t_e, X_e, 'o--', color='tomato', lw=1.5, ms=6, label='Euler ($h=0.5$)')
ax.plot(t_me, X_me, 's--', color='darkorange', lw=1.5, ms=6, label='Mod. Euler ($h=0.5$)')
ax.plot(t_rk, X_rk, '^--', color='steelblue', lw=1.5, ms=6, label='RK4 ($h=0.5$)')
ax.set_xlabel(r'$t$', fontsize=13)
ax.set_ylabel(r'$x$', fontsize=13)
ax.set_title(r"$x' = x - 2t$, $x(0) = 1$", fontsize=11)
ax.legend(fontsize=9)
# Right: error convergence
ax = axes[1]
hs = np.array([0.2, 0.1, 0.05, 0.025, 0.01])
err_e = []; err_me = []; err_rk = []
for h in hs:
_, Xe = euler(f1, t0, x0, T, h)
_, Xme = modified_euler(f1, t0, x0, T, h)
_, Xrk = rk4(f1, t0, x0, T, h)
err_e.append(abs(Xe[-1] - exact_T))
err_me.append(abs(Xme[-1] - exact_T))
err_rk.append(abs(Xrk[-1] - exact_T))
ax.loglog(hs, err_e, 'o-', color='tomato', lw=1.8, ms=7, label='Euler')
ax.loglog(hs, err_me, 's-', color='darkorange', lw=1.8, ms=7, label='Mod. Euler')
ax.loglog(hs, err_rk, '^-', color='steelblue', lw=1.8, ms=7, label='RK4')
# Reference slopes
ax.loglog(hs, 3*hs, 'k:', lw=1.2, label=r'$O(h)$')
ax.loglog(hs, 4*hs**2, 'k--', lw=1.2, label=r'$O(h^2)$')
ax.loglog(hs, 0.1*hs**4, 'k-.', lw=1.2, label=r'$O(h^4)$')
ax.set_xlabel(r'Step size $h$', fontsize=13)
ax.set_ylabel(r'$|X_N - x(2)|$', fontsize=13)
ax.set_title('Error convergence at $t=2$', fontsize=11)
ax.legend(fontsize=8)
plt.suptitle(r"Example 1: $x'=x-2t$, $x(0)=1$", fontsize=11)
plt.tight_layout()
plt.show()