import numpy as np
import matplotlib.pyplot as plt

#plt.xkcd()
fig = plt.figure( figsize=(3.5,3.7) )
ax = fig.add_subplot(1, 1, 1)

def gaussian(x, y) :
    return np.exp(-0.5*(x*x+y*y))

def gaussiangradient(x, y) :
    return np.asarray([-x*np.exp(-0.5*(x*x+y*y)), -y*np.exp(-0.5*(x*x+y*y))])

# Gauss contour lines:
x1 = -2.0
x2 = 2.0
x = np.linspace(x1, x2, 200)
y = np.linspace(x1, x2, 200)
X, Y = np.meshgrid(x, y)
Z = gaussian(X, Y)
ax.set_xlabel('x')
ax.set_ylabel('y', rotation='horizontal')
ax.set_xticks(np.arange(x1, x2+0.1, 1.0))
ax.set_yticks(np.arange(x1, x2+0.1, 1.0))
ax.contour(X, Y, Z, linewidths=2, zorder=0)

# gradients:
xxg = [-1.1, 1.4, -1.0]
yyg = [-1.1, 0.6, 0.75]
for xg, yg in zip(xxg, yyg) :
    zg = gaussian(xg, yg)
    g = gaussiangradient(xg, yg)
    ax.scatter(xg, yg, c='k', s=100, zorder=10)
    ax.quiver([xg, xg], [yg, yg], [g[0], 0.0], [0.0, g[1]], units='xy', angles='uv', scale_units='x', scale=0.5, zorder=10)
    ax.quiver([xg], [yg], [g[0]], [g[1]], units='xy', angles='uv', scale_units='x', scale=0.5, zorder=10, lw=2)
ax.text(-0.8, -1.5, '$\partial f/\partial x$', ha='center', zorder=20)
ax.text(-1.55, -0.8, '$\partial f/\partial y$', va='center', rotation='vertical', zorder=20)
ax.text(-0.4, -0.8, r'$\nabla f$', ha='left', zorder=20)

plt.tight_layout();
plt.savefig('gradient.pdf')
#plt.show();
