import matplotlib.pyplot as plt
import numpy as np
from io import StringIO

plt.rcParams.update({'text.color': '#808080', 'axes.labelcolor': '#808080', 'axes.edgecolor': '#999999',
                     'xtick.color': '#808080', 'ytick.color': '#808080'})

z = np.linspace(-5, 5, 401)
sig = 1 / (1 + np.exp(-z))
acts = [('sigmoid', sig, sig * (1 - sig), (-0.15, 1.15), 'largest slope 0.25'),
        ('tanh', np.tanh(z), 1 - np.tanh(z) ** 2, (-1.2, 1.2), 'largest slope 1'),
        ('ReLU', np.maximum(0, z), (z > 0).astype(float), (-0.5, 5.2), 'slope 1 for every z > 0')]

fig, axes = plt.subplots(1, 3, figsize=(9.5, 3.0))
for ax, (name, f, d, ylim, note) in zip(axes, acts):
    ax.axhline(0, color='gray', lw=0.6); ax.axvline(0, color='gray', lw=0.6)
    ax.plot(z, f, color='#58a6ff', lw=2.2, label=f'{name}(z)')
    if name == 'ReLU':                                  # the derivative jumps at 0: draw it in two pieces
        ax.plot(z[z < 0], d[z < 0], color='#f0883e', lw=1.8, ls='--', label='derivative')
        ax.plot(z[z > 0], d[z > 0], color='#f0883e', lw=1.8, ls='--')
    else:
        ax.plot(z, d, color='#f0883e', lw=1.8, ls='--', label='derivative')
    ax.set_ylim(*ylim)
    ax.set_title(f'{name} · {note}', fontsize=9)
    ax.set_xlabel('z', fontsize=9)
    ax.tick_params(labelsize=7.5)
    ax.legend(fontsize=7.5, loc='upper left', framealpha=0)
axes[0].axhline(0.25, color='#f0883e', lw=0.6, ls=':')
axes[0].text(2.2, 0.29, '0.25', color='#f0883e', fontsize=8)
plt.tight_layout()

buffer = StringIO()
plt.savefig(buffer, format="svg", transparent=True)
print(buffer.getvalue())

plt.close()
