The ‘
Microarray
’ class
Now we come to define the Microarray class of object. This is specified according to the
principles discussed in
Chapter 8
. The __init__ constructor, which is called each time an
object of this type is made, requires a sample name and a NumPy array of data. We can
also pass in values for the row and column data labels. These are not mandatory, and if not
set they will be filled with sequential integer numbers for each row and column. Note that
the def keyword is indented relative to the class keyword, to specify that the function
definition is inside, and thus part of, the class specification.
class Microarray(object):
def __init__(self, name, data, rowData=None, colData=None):
Firstly, inside the constructor function we store the name for the microarray data by
assigning it to self.name. Recall that self. arguments are used so that variables are tied to
the Microarray object, so that when a particular instance of a microarray object is made
the self will represent that actual object, rather than the abstract specification stated within
the class construction. Then we make a copy of the input data (using array() will make a
copy as a NumPy array), which converts any input lists or tuples and means the original
input won’t be changed if it is used elsewhere.
self.name = name
data = array(data)
Next the sizes of axes in the array data are extracted with the .shape attribute. If there
are three axes in the data we assume these represent the respective data channels (e.g.
colours), rows and columns. Otherwise if there are two data axes we assume there is only
one channel and we re-cast the data array as a single element within a larger array, so that
it is forced to have three axes (i.e. shape is (1, nCols, nRows)) even though there is only
one layer of data.
shape = data.shape
if len(shape) == 3:
self.nChannels, self.nRows, self.nCols = shape
elif len(shape) == 2:
self.nRows, self.nCols = shape
self.nChannels = 1
data = array([data]) # or data.reshape((1, self.nRows, self.nCols))
If the number of data axes doesn’t fit what we require an error exception is triggered so
the program will stop (if the exception is not handled).
else:
raise Exception('Array data must have either 2 or 3 axes.')
With the data now potentially adjusted, to ensure that it has three axes, we associate it
with a self. variable so that it is tied to the object. Also we take a copy of the data which
will be left in its original form, so that at any point in the future we can revert to the
original state if we wish,
self.data = data
self.origData = array(data)
Lastly in the constructor function the row and column labels are associated with the
object, noting that the or keyword is used so that if either list of labels is None (empty or
otherwise logically false) then they are defined as a sequential range of integer numbers,
one for each row or column.
self.rowData = rowData or range(self.nRows)
self.colData = colData or range(self.nCols)
This example is somewhat lazy, given that we have not made any checks to ensure that
the data is of the correct type or that the rowData or colData is the correct size (if set).
Naturally these checks should be made in real-world applications.
As a very simple example in the toolkit of functions for Microarray we create a method
so we can revert the self.data array back to the original values, if we want. The function
takes the self as its argument, which at run time will be filled with a particular occurrence
of the object, so that it can then access all of the attributes (and other functions) linked to
that object; in other words we can use self. inside this function. The function simply works
by assigning self.data to a copy of the original data and resetting self.nChannels, in case
that had changed.
def resetData(self):
self.data = array(self.origData)
self.nChannels = len(self.data)
Do'stlaringiz bilan baham: |