Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

PyDataSource.cxx

Go to the documentation of this file.
00001 
00012 #ifdef HAVE_CONFIG_H
00013 #include "config.h"
00014 #endif
00015 
00016 // For truncation warning
00017 #ifdef _MSC_VER
00018 #include "msdevstudio/MSconfig.h"
00019 #endif
00020 
00021 #include "PyDataSource.h"
00022 
00023 #include "datasrcs/DataSourceController.h"
00024 #include "datasrcs/DataSourceException.h"
00025 #include "datasrcs/NTuple.h"
00026 #include "python/ListTuple.h"
00027 
00028 #ifdef HAVE_NUMARRAY
00029 #include "numarray/NumArrayTuple.h"
00030 #include "numarray/num_util.h"
00031 #endif
00032 
00033 #ifdef HAVE_CFITSIO
00034 #include "fits/FitsNTuple.h"
00035 #endif
00036 
00037 #ifdef HAVE_ROOT
00038 #include "root/QtRootNTuple.h"
00039 #endif
00040 
00041 #include <sstream>
00042 
00043 using namespace boost::python;
00044 
00045 namespace hippodraw {
00046 namespace Python {
00047 
00048 void PyDataSourceExceptionTranslator( const PyDataSource::StopIteration & e ) {
00049    PyErr_SetString ( PyExc_StopIteration, e.what() );
00050 }
00051 
00052 void
00053 export_DataArray()
00054 {
00055    class_ < PyDataSource >
00056      ( "DataArray",
00057        "A DataArray wraps a DataSource object so that numerical Python\n"
00058        "arrays can be used as both input and output.   The numerical array\n"
00059        "can be either a numarray.array or Numeric.array depending on\n"
00060        "how the hippo module was configured.\n"
00061        "\n"
00062        "Accees to the array is done like a Python list or dictionary.\n"
00063        "\tarray = my_data_array [ index ] # list form\n"
00064        "\tarray = my_data_array [ 'my_label' ] # dict form\n"
00065        "\n"
00066        "Storage to the array is also done like a Python list or dictionary.\n"
00067        "\tmy_data_array [ index ] = ... # list form\n"
00068        "\tmy_data_array [ 'my_label' ] = ... # dict form\n" )
00069 
00070       .def ( init < const std::string & > (
00071              "DataArray ( string ) -> DataArray\n"
00072              "\n"
00073              "Creates a DataArray.   The string can be one of\n"
00074              "\tListTuple\n"
00075              "\tNTuple\n"
00076              "\tNumArrayTuple" ) )
00077       
00078       .add_property ( "columns", 
00079                       &PyDataSource::columns )
00080       
00081       .add_property ( "rows",
00082                       &PyDataSource::rows )
00083 
00084      .def ( "dataSource",
00085             &PyDataSource::dataSource,
00086             return_value_policy < reference_existing_object > (),
00087             "dataSource () -> DataSource\n"
00088             "\n"
00089             "Returns reference to underlying DataSource"  )
00090 
00091       .def ( "getTitle", 
00092              &PyDataSource::getTitle,
00093              return_value_policy < copy_const_reference > (),
00094              "getTitle () -> string\n"
00095              "\n"
00096              "Returns title of the DataSource." )
00097 
00098       .def ( "setName",
00099              &PyDataSource::setName,
00100              "setName ( string ) -> None\n"
00101              "\n"
00102              "Sets the name of the DataSource. The name should be unique\n"
00103              "with one application and may appear in the Inspector panel." )
00104       
00105       .def ( "setTitle",
00106              &PyDataSource::setTitle,
00107              "setTitle ( string ) -> None\n"
00108              "\n"
00109              "Sets the title of the DataSource.  The title is what appears,\n"
00110              "by default, at the top of a Display." )
00111            
00112       .def ( "getLabels",
00113              &PyDataSource::getLabels,
00114              return_value_policy < copy_const_reference > (),
00115              "getLabels () -> list\n"
00116              "\n"
00117              "Returns the list of string objects of column labels." )
00118       
00119       .def ( "addColumn", 
00120              ( int (PyDataSource:: * )
00121                (const std::string &, const std::vector<double> &) )
00122              &PyDataSource::addColumn,
00123              "addColumn ( string, list ) -> value\n"
00124              "addColumn ( string, array ) -> value\n"
00125              "\n"
00126              "Adds a column. The string will be the label of the column.\n"
00127              "A copy of the list or array values will be the contents.\n"
00128              "The second form is only avalable if HippoDraw was configured\n"
00129              "with numerical Python support. Returns the new column's index." )
00130              
00131 #ifdef HAVE_NUMARRAY      
00132       .def ( "addColumn", 
00133              ( int (PyDataSource:: * )
00134                (const std::string &, boost::python::numeric::array) )
00135              &PyDataSource::addColumn )
00136 #endif
00137              
00138       .def ( "getColumn", 
00139              ( const std::vector < double > & (PyDataSource:: * ) // fptr
00140                ( unsigned int ) const) // function signature
00141              &PyDataSource::getColumn,
00142              return_value_policy < copy_const_reference> (),
00143              "getColumn ( value ) -> list\n"
00144              "\n"
00145              "Returns a column as list of floats.  'value' maybe either\n"
00146              "the column label or its index." )
00147 
00148       .def ( "getColumn", 
00149              ( const std::vector < double > & (PyDataSource:: * ) // fptr
00150                ( const std::string & ) const) // function signature
00151              &PyDataSource::getColumn,
00152              return_value_policy < copy_const_reference> () )
00153       
00154       .def ( "replaceColumn", 
00155              ( void (PyDataSource:: * )
00156                ( const std::string &, const std::vector<double> & ) )
00157              &PyDataSource::replaceColumn,
00158              "replaceColumn ( value, list ) -> None\n"
00159              "replaceColumn ( value, array ) -> None\n"
00160              "\n"
00161              "Replace column by its label or index.  The second form is \n"
00162              "only available if HippoDraw was configure with numerical\n"
00163              "arrays." )
00164       
00165       .def ( "replaceColumn", 
00166              ( void (PyDataSource:: * ) // fptr
00167                ( unsigned int index, const std::vector<double> & ) )
00168              &PyDataSource::replaceColumn )
00169 
00170 #ifdef HAVE_NUMARRAY      
00171       .def ( "replaceColumn", 
00172              ( void (PyDataSource:: * ) // fptr
00173                ( const std::string &, numeric::array ) ) // function signature
00174              &PyDataSource::replaceColumn )
00175       
00176       .def ( "replaceColumn", 
00177              ( void (PyDataSource:: * ) // fptr
00178                ( unsigned int index, numeric::array ) ) // function signature
00179              &PyDataSource::replaceColumn )
00180 #endif
00181 
00182 // comment out until implemented for ListTuple and NumArrayTuple
00183 //       .def ( "clear",
00184 //              &PyDataSource::clear,
00185 //              "Clears the data elements of the DataSource" )
00186 
00187       .def ("has_key",
00188             &PyDataSource::hasColumn,
00189             "has_key ( string ) -> boolean\n"
00190             "\n"
00191             "Returns True if column with label exists.")
00192 
00193       .def ( "keys",
00194              &PyDataSource::getLabels,
00195              return_value_policy < copy_const_reference > (),
00196              "keys () -> list\n"
00197              "\n"
00198              "Returns the list of column labels." )
00199       
00200       .def ( "register",
00201              ( void (PyDataSource:: * ) ( const std::string & ) )
00202              &PyDataSource::registerNTuple,
00203              "register ( string ) -> None\n"
00204              "register ( ) -> string\n"
00205              "\n"
00206              "Register the underlying DataSource with the\n"
00207              "DataSourceController. The first form registers it with the\n"
00208              "given name, while the second from returns a unique name\n"
00209              "generated by the controller." )
00210 
00211       .def ( "register",
00212              ( std::string (PyDataSource:: * ) () )
00213              &PyDataSource::registerNTuple )
00214 
00215 #ifdef HAVE_NUMARRAY
00216       .def ( "__getitem__", 
00217              ( numeric::array ( PyDataSource:: * )
00218                ( const std::string & ) const )
00219              &PyDataSource::columnAsNumArray,
00220              return_value_policy < return_by_value > (),
00221              "__getitem__ ( value ) -> array\n"
00222              "\n"
00223              "Returns a copy of the column as numerical array.   'value' can\n"
00224              "be either the column label or its index." )
00225 
00226       .def ( "__getitem__", 
00227              ( numeric::array ( PyDataSource:: * )
00228                ( unsigned int ) const )
00229              &PyDataSource::columnAsNumArray,
00230              return_value_policy < return_by_value > () )
00231 
00232       .def ( "__setitem__", 
00233              ( void ( PyDataSource:: * )
00234                ( const std::string &, numeric::array ) )
00235              &PyDataSource::saveColumnFromNumArray,
00236              return_value_policy < return_by_value > (),
00237              "__setitem__ ( value, array ) -> None\n"
00238              "\n"
00239              "Copies the constents of array.  If `'value' is an index, then\n"
00240              "replaces the contents of the existing column.   If 'value' is\n"
00241              "a label then either replaces existing column with that label\n"
00242              "or adds a new column." )
00243 
00244       .def ( "__setitem__", 
00245              ( void ( PyDataSource:: * )
00246                ( unsigned int, numeric::array ) )
00247              &PyDataSource::saveColumnFromNumArray,
00248              return_value_policy < return_by_value > () )
00249 #endif
00250       ;
00251    register_exception_translator<PyDataSource::StopIteration>
00252       (&PyDataSourceExceptionTranslator);
00253 }
00254    
00255 } // namespace Python
00256 } // namespace hippodraw
00257 
00258 PyDataSource::PyDataSource() {
00259    m_type = "NTuple";
00260    m_dataSource = new NTuple();
00261 }
00262 
00263 PyDataSource::
00264 PyDataSource ( const std::string & name, DataSource * source )
00265   : m_type ( name ),
00266     m_dataSource ( source )
00267 {
00268 }
00269 
00270 PyDataSource::
00271 PyDataSource(const std::string & dataSource) : m_type(dataSource) {
00272    if (dataSource == "ListTuple") {
00273       m_dataSource = new ListTuple();
00274    } else if (dataSource == "NTuple") {
00275       m_dataSource = new NTuple();
00276 #ifdef HAVE_NUMARRAY
00277    } else if (dataSource == "NumArrayTuple") {
00278       m_dataSource = new NumArrayTuple();
00279 #endif
00280    } else {
00281       throw std::runtime_error("Invalid DataSource: " + dataSource);
00282    }
00283 }
00284 
00285 PyDataSource::~PyDataSource() {
00286    delete m_dataSource;
00287 }
00288 
00289 
00290 unsigned int PyDataSource::columns() const {
00291    return m_dataSource->columns();
00292 }
00293 
00294 unsigned int PyDataSource::rows() const {
00295    return m_dataSource->rows();
00296 }
00297 
00298 const std::string & PyDataSource::getTitle() const {
00299    return m_dataSource->title();
00300 }
00301 
00302 void PyDataSource::setTitle(const std::string & title) {
00303    m_dataSource->setTitle(title);
00304 }
00305 
00306 void PyDataSource::setName(const std::string & name) {
00307    m_dataSource->setName(name);
00308 }
00309 
00310 const std::vector<std::string> & PyDataSource::getLabels() const {
00311    return m_dataSource->getLabels();
00312 }
00313 
00314 const std::vector<double> & 
00315 PyDataSource::getColumn(const std::string & name) const {
00316    return m_dataSource->getColumn(name);
00317 }
00318 
00319 const std::vector<double> & 
00320 PyDataSource::getColumn(unsigned int index) const {
00321    return m_dataSource->getColumn(index);
00322 }
00323 
00324 void
00325 PyDataSource::
00326 replaceColumn (const std::string & label,
00327                const std::vector < double > & col )
00328 {
00329    if (m_type == "NTuple") {
00330       NTuple * nt = dynamic_cast<NTuple *>(m_dataSource);
00331       nt->replaceColumn(label, col);
00332    } else if (m_type == "ListTuple") {
00333       ListTuple * nt = dynamic_cast<ListTuple *>(m_dataSource);
00334       boost::python::list seq(col);
00335       nt->replaceColumn(label, seq);
00336    } else {
00337       std::string what("Cannot replace a column of this type in a " + m_type);
00338       throw std::runtime_error(what);
00339    }
00340 }
00341 
00342 void
00343 PyDataSource::
00344 replaceColumn ( unsigned int index,
00345                 const std::vector < double > & col)
00346 {
00347    const std::vector<std::string> & names = m_dataSource->getLabels();
00348    if ( 0 <= index && index < names.size() ) {
00349       replaceColumn(names[index], col);
00350    } else {
00351       std::ostringstream what;
00352       what << "Invalid column index: " << index;
00353       throw std::runtime_error(what.str());
00354    }
00355 }
00356 
00357 #ifdef HAVE_NUMARRAY
00358 void
00359 PyDataSource::
00360 replaceColumn ( const std::string & label,
00361                 boost::python::numeric::array array)
00362 {
00363    NumArrayTuple * nt = dynamic_cast<NumArrayTuple *>(m_dataSource);
00364    if (!nt) {
00365       std::string what("Cannot replace a column of this type in a " + m_type);
00366       throw std::runtime_error(what);
00367    }
00368    nt->replaceColumn(label, array);
00369 }
00370 
00371 void
00372 PyDataSource::
00373 replaceColumn ( unsigned int index,
00374                 boost::python::numeric::array array )
00375 {
00376    NumArrayTuple * nt = dynamic_cast<NumArrayTuple *>(m_dataSource);
00377    if (!nt) {
00378       std::string what("Cannot replace a column of this type in a " + m_type);
00379       throw std::runtime_error(what);
00380    }
00381    nt->replaceColumn(index, array);
00382 }
00383 #endif
00384 
00385 int PyDataSource::addColumn( const std::string & label,
00386                              const std::vector<double> & col ) {
00387    if (m_type == "NTuple") {
00388       NTuple * nt = dynamic_cast<NTuple *>(m_dataSource);
00389       return nt->addColumn(label, col);
00390    } else if (m_type == "ListTuple") {
00391       ListTuple * nt = dynamic_cast<ListTuple *>(m_dataSource);
00392       boost::python::list seq(col);
00393       return nt->addColumn(label, seq);
00394    } else {
00395       std::string what("Cannot add a column of this type to a " + m_type);
00396       throw std::runtime_error(what);
00397    }
00398    return m_dataSource->columns();
00399 }
00400 
00401 #ifdef HAVE_NUMARRAY
00402 int PyDataSource::addColumn( const std::string & label, 
00403                              boost::python::numeric::array array ) {
00404    NumArrayTuple * nt = dynamic_cast<NumArrayTuple *>(m_dataSource);
00405    if (!nt) {
00406       std::string what("Cannot add a column of this type to a " + m_type);
00407       throw std::runtime_error(what);
00408    }
00409    return nt->addColumn(label, array);
00410 }
00411 #endif
00412 
00413 void PyDataSource::clear() {
00414    m_dataSource->clear();
00415 }
00416 
00417 bool PyDataSource::hasColumn(const std::string & colname) const {
00418    const std::vector<std::string> & names = getLabels();
00419    return std::find(names.begin(), names.end(), colname) != names.end();
00420 }
00421 
00422 void PyDataSource::registerNTuple( const std::string & name ) {
00423    m_dataSource->setName(name);
00424    DataSourceController * controller  = DataSourceController::instance();
00425    controller->registerNTuple(name, m_dataSource);
00426 }
00427 
00428 std::string PyDataSource::registerNTuple() {
00429    DataSourceController * controller  = DataSourceController::instance();
00430    return controller->registerNTuple(m_dataSource);
00431 }
00432 
00433 #ifdef HAVE_NUMARRAY
00434 boost::python::numeric::array
00435 PyDataSource::
00436 columnAsNumArray( const std::string & colname ) const {
00437    if (m_type == "NumArrayTuple") {
00438       NumArrayTuple * nt = dynamic_cast<NumArrayTuple *>(m_dataSource);
00439       return nt->getNumArray(colname);
00440    } 
00441    typedef std::vector<double> vec;
00442    const vec & array = m_dataSource->getColumn(colname);
00443    std::vector<int> shape(1);
00444    shape[0] = array.size();
00445    numeric::array na = num_util::makeNum(&const_cast<vec &>(array)[0], shape);
00446    return na;
00447 }
00448 boost::python::numeric::array
00449 PyDataSource::
00450 columnAsNumArray( unsigned int index ) const {
00451    if ( 0 <= index && index < columns() ) {
00452       if (m_type == "NumArrayTuple") {
00453          NumArrayTuple * nt = dynamic_cast<NumArrayTuple *>(m_dataSource);
00454          return nt->getNumArray(index);
00455       } 
00456       typedef std::vector<double> vec;
00457       const vec & array = m_dataSource->getColumn(index);
00458       std::vector<int> shape(1);
00459       shape[0] = array.size();
00460       numeric::array na = 
00461          num_util::makeNum(&const_cast<vec &>(array)[0], shape);
00462       return na;
00463    } else {
00464       throw StopIteration("index out-of-range");
00465    }
00466 }
00467 
00468 namespace {
00469    void extractVector(boost::python::numeric::array array,
00470                       std::vector<double> & col) {
00471       const numeric::array & my_array = array;
00472       int size = num_util::size( my_array );
00473       col.clear();
00474       col.reserve(size);
00475       for (int i = 0; i < size; i++) {
00476          boost::python::object result = my_array[i];
00477          col.push_back( boost::python::extract<double>(result) );
00478       }
00479    }
00480 }
00481 
00482 void PyDataSource::
00483 saveColumnFromNumArray( const std::string & label,
00484                         boost::python::numeric::array array ) {
00485    if (m_type == "NumArrayTuple") {
00486       if (hasColumn(label)) {
00487          replaceColumn(label, array);
00488       } else {
00489          addColumn(label, array);
00490       }
00491       return;
00492    }
00493 
00494    if (m_type == "ListTuple") {
00495       boost::python::list seq(array);
00496       ListTuple * nt = dynamic_cast<ListTuple *>(m_dataSource);
00497       if (hasColumn(label)) {
00498          nt->replaceColumn(label, seq);
00499       } else {
00500          nt->addColumn(label, seq);
00501       }
00502       return;
00503    }
00504 
00505    std::vector<double> col;
00506    ::extractVector(array, col);
00507 
00508    if (m_type == "NTuple") {
00509       NTuple * nt = dynamic_cast<NTuple *>(m_dataSource);
00510       if (hasColumn(label)) {
00511          nt->replaceColumn(label, col);
00512       } else {
00513          nt->addColumn(label, col);
00514       }
00515       return;
00516    }
00517 
00518 #ifdef HAVE_CFITSIO
00519    FitsNTuple * fnt = dynamic_cast < FitsNTuple * > ( m_dataSource );
00520    if ( fnt != 0 ) {
00521      if ( hasColumn ( label ) ) {
00522        fnt -> replaceColumn ( label, col );
00523      } else {
00524        fnt -> addColumn ( label, col );
00525      }
00526      return;
00527    }
00528 #endif
00529 
00530 #ifdef HAVE_ROOT
00531    QtRootNTuple * rnt = dynamic_cast < QtRootNTuple * > ( m_dataSource );
00532    if ( rnt != 0 ) {
00533      if ( hasColumn ( label ) ) {
00534        rnt -> replaceColumn ( label, col );
00535      } else {
00536        rnt -> addColumn ( label, col );
00537      }
00538      return;
00539    }
00540 #endif
00541 
00542    throw std::runtime_error("__setitem__ not supported for " + m_type);
00543 }
00544 
00545 void PyDataSource::
00546 saveColumnFromNumArray( unsigned int index,
00547                         boost::python::numeric::array array ) {
00548    if (0 <= index && index < columns()) {
00549       if (m_type == "NumArrayTuple") {
00550          replaceColumn(index, array);
00551       } else if (m_type == "NTuple") {
00552          std::vector<double> col;
00553          ::extractVector(array, col);
00554          NTuple * nt = dynamic_cast<NTuple *>(m_dataSource);
00555          nt->replaceColumn(index, col);
00556       } else if (m_type == "ListTuple") {
00557          boost::python::list seq(array);
00558          ListTuple * nt = dynamic_cast<ListTuple *>(m_dataSource);
00559          nt->replaceColumn(index, seq);
00560       } else {
00561          throw std::runtime_error
00562             ("__setitem__ by index is not supported for " + m_type);
00563       }
00564    } else {
00565       std::ostringstream what;
00566       what << "Invalid column index: " << index;
00567       throw std::runtime_error(what.str());
00568    }
00569 }
00570 #endif // HAVE_NUMARRAY

Generated for HippoDraw-1.14.8.5 by doxygen 1.4.3