import numpy as np, matplotlib.pyplot as plt
from scipy.spatial import cKDTree
rng = np.random.default_rng(0)
sm = lambda z: np.exp(z-z.max(-1,keepdims=True))/np.exp(z-z.max(-1,keepdims=True)).sum(-1,keepdims=True)
centers = np.array([[3,3],[-3,3],[0,-3]], float)
Xtr = np.vstack([rng.normal(c, 0.7, (150,2)) for c in centers])
gx, gy = np.meshgrid(np.linspace(-9,9,120), np.linspace(-9,9,120)); G = np.c_[gx.ravel(), gy.ravel()]
conf = sm(-0.5*((G[:,None,:]-centers[None])**2).sum(-1)).max(1).reshape(gx.shape) # max-softmax
dist = cKDTree(Xtr).query(G, k=1)[0].reshape(gx.shape) # distance to data
fig, ax = plt.subplots(1, 2, figsize=(6.6, 2.9))
for a, M, t, cm in [(ax[0], conf, "max-softmax confidence", "viridis"),
(ax[1], -dist, "distance-to-data (OOD score)", "magma")]:
a.contourf(gx, gy, M, levels=20, cmap=cm); a.scatter(Xtr[:,0], Xtr[:,1], s=2, c="w")
a.set_title(t, fontsize=8); a.set_xticks([]); a.set_yticks([])
plt.tight_layout(); plt.show()