I'm using Python's traits package, and I'm trying to figure out the right way to use the traits.trait_numeric.Array class. It's straightforward to write a subclass of traits.api.HasTraits with an Array trait, so that when the Array changes, an on_trait_change is triggered, but I can't figure out how to trigger any sort of event when elements of the array are modified in place. Here is a minimal example:
from traits.api import HasTraits
from traits.trait_numeric import Array
import numpy as np
class C(HasTraits):
x = Array
def __init__(self):
self.on_trait_event(self.do_something, 'x')
def do_something(self):
print 'Doing something'
c = C()
# This line calls do_something()
c.x = np.linspace(0,1,10)
# This one doesn't, and I wish it did
c.x[3] = 100
# Same with this one
c.x[:] = np.ones(c.x.shape)
I'm hoping there is some built in feature of traits.trait_numeric.Array that I don't know about, since detecting when part of an array has changed seems like a very standard thing to need.
Barring that, I think the problem might be solvable by making a custom trait class that also inherits numpy.array, then changing the [] operator so that it explicitly triggers the right kind of trait events. But hopefully that is a can of worms I won't have to open.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With