Skip to content

Commit

Permalink
Add an 'update' method to AbstractPlotData. General clean-up of Array…
Browse files Browse the repository at this point in the history
…PlotData.
  • Loading branch information
corranwebster committed May 16, 2013
1 parent 91e900a commit 7007efb
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 37 deletions.
64 changes: 54 additions & 10 deletions chaco/abstract_plot_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,25 +49,52 @@ def get_data(self, name):
raise NotImplementedError


def set_data(self, name, new_data, generate_name=False):
def del_data(self, name):
""" Deletes the array specified by *name*, or raises a KeyError if
the named array does not exist.
If the instance is not writable, then this must do nothing.
"""
Returns the new data's name.
If **writable** is True, then this method sets the data associated
with the given name to the new value.
raise NotImplementedError

If **writable** is False, then this method must do nothing.
def set_data(self, name, new_data, generate_name=False):
""" Sets the specified array as the value for either the specified
name or a generated name.
If *generate_name* is True, then the data source must
create a new name to bind to the data, and return it.
If the instance's `writable` attribute is True, then this method sets
the data associated with the given name to the new value, otherwise it
does nothing.
If the name does not exist, then the method attaches a new data entry
to this PlotData.
Parameters
----------
name : string
The name of the array whose value is to be set.
new_data : array
The array to set as the value of *name*.
generate_name : Boolean
If True, a unique name of the form 'seriesN' is created for the
array, and is used in place of *name*. The 'N' in 'seriesN' is
one greater the largest N already used.
Returns
-------
The name under which the array was set.
"""
raise NotImplementedError


def update_data(self, data):
"""
Update a set of data values, firing only one data_changed event.
The *data* argument should be a dictionary whose keys are data names
and whose values are the data objects.
"""
raise NotImplementedError

def set_selection(self, name, selection):
""" Sets the selection on the specified data.
Expand All @@ -83,3 +110,20 @@ def set_selection(self, name, selection):
array named by *name* is selected.
"""
raise NotImplementedError

#------------------------------------------------------------------------
# Dictionary Interface
#------------------------------------------------------------------------

def __getitem__(self, name):
return self.arrays.get(name, None)

def __setitem__(self, name, value):
return self.set_data(name, value)

def __delitem__(self, name):
return self.del_data(name)

def update(self, data):
self.update_data(data)

99 changes: 72 additions & 27 deletions chaco/array_plot_data.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
""" Defines ArrayPlotData.
"""

from numpy import array
from numpy import array, ndarray

# Enthought library imports
from traits.api import Dict
Expand Down Expand Up @@ -60,25 +60,15 @@ def __init__(self, *data, **kw):
of this class is convenience.
"""
super(AbstractPlotData, self).__init__()
self.arrays.update(kw)
for i in range(1, len(data)+1):
self.arrays['series'+str(i)] = data[i-1]
return
self._update_data(kw)
data = dict(zip(self._generate_names(len(data)), data))
self._update_data(data)


#------------------------------------------------------------------------
# Dictionary Interface
# AbstractPlotData Interface
#------------------------------------------------------------------------

def __getitem__(self, name):
return self.arrays.get(name, None)

def __setitem__(self, name, value):
return self.set_data(name, value)

def __delitem__(self, name):
return self.del_data(name)


def list_data(self):
""" Returns a list of the names of the arrays managed by this instance.
"""
Expand All @@ -92,10 +82,14 @@ def get_data(self, name):
"""
return self.arrays.get(name, None)


def del_data(self, name):
""" Deletes the array specified by *name*, or raises a KeyError if
the named array does not exist.
"""
if not self.writable:
return None

if name in self.arrays:
del self.arrays[name]
else:
Expand All @@ -106,7 +100,9 @@ def set_data(self, name, new_data, generate_name=False):
""" Sets the specified array as the value for either the specified
name or a generated name.
Implements AbstractPlotData.
If the instance's `writable` attribute is True, then this method sets
the data associated with the given name to the new value, otherwise it
does nothing.
Parameters
----------
Expand All @@ -122,13 +118,14 @@ def set_data(self, name, new_data, generate_name=False):
Returns
-------
The name under which the array was set.
"""
if not self.writable:
return None

if generate_name:
# Find all 'series*' and increment
candidates = [n[6:] for n in self.arrays.keys() if n.startswith('series')]
candidates = [n[6:] for n in self.list_data() if n.startswith('series')]
max_int = 0
for c in candidates:
try:
Expand All @@ -137,24 +134,72 @@ def set_data(self, name, new_data, generate_name=False):
except ValueError:
pass
name = "series%d" % (max_int + 1)
self.update_data({name: new_data})
return self.name

event = {}
if name in self.arrays:
event['changed'] = [name]
else:
event['added'] = [name]

if isinstance(new_data, list) or isinstance(new_data, tuple):
new_data = array(new_data)
def update_data(self, data):
""" Sets the specified array as the value for either the specified
name or a generated name.
Implements AbstractPlotData.
self.arrays[name] = new_data
Parameters
----------
data : dict of str: array
The name of the array whose value is to be set.
"""
if not self.writable:
return None

event = {}
for name in data:
if name in self.arrays:
event.setdefault('changed', []).append(name)
else:
event.setdefault('added', []).append(name)

self._update_data(data)
self.data_changed = event
return name


def set_selection(self, name, selection):
""" Overrides AbstractPlotData to do nothing and not raise an error.
"""
pass

#------------------------------------------------------------------------
# Private methods
#------------------------------------------------------------------------

def _generate_names(self, n):
""" Generate n new names
"""
max_index = max(self._generate_indices())
names = ["series{d}".format(n) for n in range(max_index+1, max_index+n+1)]
return names

def _generate_indices(self):
""" Generator that yields all integers that match "series%d" in keys
"""
for names in self.list_data():
if n.startswith('series'):
try:
v = int(n[6:])
except ValueError:
continue
yield v

def _update_data(self, data):
""" Update the array, ensuring that data is an array
"""
new_data = {}
for name, iterable in data:
if not isinstance(iterable, ndarray):
new_data[name] = array(iterable)
else:
new_data[name] = iterable

self.arrays.update(new_data)

0 comments on commit 7007efb

Please sign in to comment.