I'm afraid that it's not really possible. numpy arrays view raw memory. Anything can change that memory without going through the numpy array object itself. The pattern we usually use is to reassign the whole array after doing the slice/index assignment.
import numpy as np
from traits.api import Array, HasTraits, NO_COMPARE
class C(HasTraits):
x = Array(comparison_mode=NO_COMPARE)
def _x_changed(self):
print 'Doing something'
c = C()
c.x = np.linspace(0, 1, 10)
# This does not trigger:
c.x[3] = 100
# This does:
c.x = c.x