| |
- Data
- DataPosition
- Page
class Data |
|
Data class is the base class for generic data retrieving and
storing for displaying.
All operations needed for interfacing with displaying
classes should be coded in the base class. Derived classes
implement the specialized code to retrieve information from
different data sources.
Data objects are composed by a set of page objects. Each page has
a NumPy array that stores the actual data, and a dictionary, containing
information about this data and its source.
The items in the page's information dictionary are defined by
the derived data classes, but these keys in the dictionary are
standarized:
"SourceType": string, identify the type of data source of the page.
Each derived class have to define it's own.
"SourceName": the name of the data source of this page
"Key": the key for this actual data in the data source, which is
source dependent.
"Source": optional, represent the source object itself (if possible)
in order to allow the application to make direct calls to
low level funcionality.
Data class can add elements to this dictionary for internal purposes
(not to be considered by application of View objects).
In this case, the key starts by "_".
Data objects have a general dictionary containing global information
and, if needed, the relation between pages.
Base class objects can be created to manage direct NumPy arrays
manipulation, or to mix pages of different data sources.
Data objects have an EventHandler member (self.eh) through which
it sends "DataChange" and "DeleteEvent" events
Interface:
===========================
- __init__
- GetNumberPages
- AppendPage
- InsertPage
- GetSource
- GetSourceName
- GetInfo
- GetPageDimention
- GetPageSize
- GetPageArray
- GetPageInfo
- GetPageArrayRegion
- GetItemPageInfo
- GetPageArrayRegion
- IsCoordValid
- GetCoordValue
- CopyPages
- Delete
- Invalidate
- Refresh
- Destroy
- SetSource (virtual)
- GetSourceInfo (virtual)
- LoadSource (virtual)
In most of the cases the applications will deal just with the
second group of methods, they're a proposed way to have a
standarized and higher level interface to data sources.
SetSource, GetSourceInfo and LoadSource are the methods that derived
classes should override (a fourth is the RefreshPage it wants to
have automatic updating by polling). These three methods are signed as
virtuals, but there's a default implementation in the Data class
for loading numeric arrays (NumPy arrays can be handled by direct
calling AppendPage/InsertPage/Delete methods, of course, this
implementation is there as a simple example of what derived classes
should do).
New methods can be added to derived classes, but it's good to try to keep
the same philosophy, in order all the sources to have a similar interface:
1) SetSource links the Data object with a source, without actually loading
any data.
2) GetSourceInfo gets information about source. It returns at least a list
of keys to identify every readable item in the source.
3) LoadSource performs the reading of data. It indexes source's items with
the same keys received by GetSourceInfo.
If refresh_interval is not defined in the constructor, applications can
poll for changes in data calling Refresh (if RefreshPage has been coded).
Derived classes implement automatic refresh bahaviour by overriding
RefreshPage (see doc).
In automatic polling mode, if a GUI Binding is loaded then RefreshPage
is called from a timer, with interval defined as in the Data object
constructor. Otherwise, a thread is created to call RefreshPage.
In this case the base class creates a self.Semaphore property to synchronize
main thread. self.Semaphore.acquire() and self.Semaphore.release() are
called from the thread befire and after RefreshPage.
The base class doesn't take any other action about thread synchronization
it is up to derived classes to call pairs self.Semaphore.acquire() and
self.Semaphore.release() to protect concurrent code.
The lower level interface is not thread save, so if the derived class
is supposed to use thread, it is responsible to have a thread safe
interface.
The indexing of pages (see interface methods, index parameter) in a data
object can be done in two was:
- With a integer that represents the position of the page. This is
a simpler approach that suits for simpler applications.
- With a dictionary, that logically indexes the page based on a number of
keys (typically "SourceType", "SourceName" and "Key"). This is the
way applications should deal if they are going to delete pages from
a Data objects, in order to other objects to keep the link logically.
Internal Events:
===========================
Emits:
"DataChange"
"DeleteEvent" |
|
- AppendPage(self, info={}, array=None)
- Appends one page to the page list.
This method just stores a reference to info and array, does not perform
a deepcopy
Parameters:
info: Dictionary of the page
array: NumPy data of the page
- CopyPages(self, source_obj, index_list=0, position=None, synchronized=1, invalidate=1)
- Copies pages from other data object. This method makes a deepcopy operation.
Parameters:
source_obj: Source object of the copied pages
index_list: index or tuple of indexes to be copied
position: Position to be copied to. If None, it is appended
synchronized: if non-zero stores the location of the refresh method of the
original object for updating the page. Otherwise, is no more
updated.
invalidate: if non-zero performs an invalidade call after the operation
- Delete(self, index=None)
- Deletes a given page from the data object
Parameters:
index: Index of the page in the page list. If None, deletes all pages
- Destroy(self, source=None)
- Cleanup.
As event handlers and callbacks, by keeping a reference to other
objects, avoid them to be destroyed (and freed from memory), the
Destroy method has to be explicitly called for Data objects
before they get out of scope.
I had tried to use weak references in order not to need this method,
but this generated many other troubles (like impossibility to define
selections locally, difficult control of the destruction sequence,
not interceptable error mesassages...).
- GetCoordValue(self, coord)
- Returns the value of data in a gives coordinate.
Parameters:
coord: a DataPosition object
- GetInfo(self)
- Returns the general information about the object
- GetItemPageInfo(self, key, index=0)
- Returns the value of a given key in page's information
Parameters:
key: Key of page dictionary
index: Either an integer meaning the sequencial position of the page
or a dictionary that logically index the page based on keys of
the page's Info dictionary.
- GetNumberPages(self)
- Returns number of pages of the data object
- GetPageArray(self, index=0)
- Returns page's data (NumPy array)
Parameters:
index: Either an integer meaning the sequencial position of the page
or a dictionary that logically index the page based on keys of
the page's Info dictionary.
- GetPageArrayRegion(self, pos=None, size=None, index=0, return_dimention=None)
- Returns one slice of the data in a given page.
This method may be used by higher level selection functions (they
should manage selection in multiple pages)
Parameters:
pos: Tuple containing the coordinates of the beggining of the slice.
Coordinates must match the dimention of data:
(x,),(x,y,) or (x,y,z,),
If None,set to the beggining of the data (0,),(0,0,) or (0,0,0,),
according to the dimention of data.
size: Tuple containing the coordinates of the size of the slice.
Coordinates must match the dimention of data:
(x,),(x,y,) or (x,y,z,),
If None,set to the size from pos to the end of data in all dimentions
Any coordinate (x,y ou z) can be set to "ALL", which means up to the
end of data in this dimention.
index: Either an integer meaning the sequencial position of the page
or a dictionary that logically index the page based on keys of
the page's Info dictionary.
return_dimention: Defines the dimention of the returned array. For instance,
if accessing 3d data, but we want the result as a 2d
array, instead of a 3d array with z=1, we should set
this parameter to 2. If None, it keeps the original
dimention.
- GetPageDimention(self, index=0)
- Returns the dimention of a given page
Parameters:
index: Either an integer meaning the sequencial position of the page
or a dictionary that logically index the page based on keys of
the page's Info dictionary.
- GetPageInfo(self, index=0)
- Returns page's information (dictionary)
Parameters:
index: Either an integer meaning the sequencial position of the page
or a dictionary that logically index the page based on keys of
the page's Info dictionary.
- GetPageListIndex(self, index)
- Converts a physical or logical index, into a physical one
- GetPageSize(self, index=0)
- Returns a tuple containing the size of a page
Parameters:
index: Either an integer meaning the sequencial position of the page
or a dictionary that logically index the page based on keys of
the page's Info dictionary.
- GetSource(self)
- Returns source object
- GetSourceInfo(self)
- Virtual method, Returns information about source, to give
application possibility to know about it before loading.
Returns a dictionary. The minimum suggested keys in this
dictionary are "Size" (number of possible keys to this
source) and "KeyList" (list of all available keys in this
source).
Important: To be overridden
The default implementation works with a NumPy array
- GetSourceLoadedKeys(self, source_name)
- Returns the keys loaded for a given source name.
- GetSourceLoadedNames(self)
- Return a list of all different source name loaded
- GetSourceName(self)
- Returns source name
- InsertPage(self, info={}, array=None, index=None)
- Inserts one page in a given position of the page list.
This method just stores a reference to info and array, does not perform
a deepcopy
Parameters:
info: Dictionary of the page
array: NumPy data of the page
index: Either an integer meaning the sequencial position of the page
or a dictionary that logically index the page based on keys of
the page's Info dictionary.
- Invalidate(self, page_list='ALL')
- This method have to be called from the derived classes when there's a change
in the contents of data, in order to trigger the update events in all views
and select objects related to this data.
- IsCoordValid(self, coord)
- Returns if the coordinate is inside the data object
Parameters:
coord: a DataPosition object
- LoadSource(self, key_list='ALL', append=0, invalidate=1)
- Virtual method, creates a given number of pages, getting data
from the actual source (set by SetSource)
Parameters:
key_list: list of all keys to be read from source
append: If non-zero appends to the end of page list.
Otherwise, initializes the page list
invalidate: if non-zero performs an invalidate call after
loading
Important: To be overridden
The default implementation works with a NumPy array
- Refresh(self)
- The application calls this method in order to poll for data changes.
- RefreshPage(source_obj, self, page)
- Virtual method, implements seeking for changes in source for
"page".
Returns non-zero if the page was changed.
If not implemented in the derived class, this class doesn't
support dinamic changes monitoring.
As pages can be copied to different Data objects, and can
store the original RefreshPage method for updating, source_obj
refers to the object that was origin of the page data, while
self indicates the object that actually owns the page
with index page.
It was done this way because if it is stored the reference to
the unbound method, python doesn't allow you to call it with
an object of different data type.
Important:
Derived classes shall update the page: self.Pages[page]
but not: source_obj.Pages[page]
- SetSource(self, source_name=None)
- Virtual method, sets a new source for data retrieving.
Parameters:
source_name: name of the source
Important: To be overridden
The default implementation works with a NumPy array
- _Data__ThreadProc = __ThreadProc(self)
- The polling thread, active if no GUI is loaded
(otherwise a GUI Timer is used).
- __init__(self, refresh_interval=None, info={})
- Parameters:
refresh_interval: time in milisseconds the Data will be refreshed
if None, no polling for data changes
info: dictionary containing generic information about this object
|
class DataPosition |
|
Structure to store data coordinates.
Consists of:
page_index: the index of the page
page_coord: tuple with the coordinates in the page, (x,), (x,y) or (x,y,z)
according to the dimention of the page |
|
- __init__(self, page_index=None, page_coord=None)
|
class Page |
|
Page class defines a structure composed by a NumPy array and a dictionary.
Data objects contain a set of pages.
The array stores the actual data.
The dictionary contains variable information about the data in the array. |
|
- __init__(self, info={}, array=None)
- Constructor:
Pages can be initialized in the constructor, or be filled afterwards.
All pages must have a field in the info dictionary called "SourceType",
which indicates source type for this data. If not present in info,
it is initialized to "None". This field is going to be verified by
Data derived classes, in the method UpdatePage to control
updating of objects having pages with diferent source types.
| |