00001
00012 #ifdef HAVE_CONFIG_H
00013 #include "config.h"
00014 #endif
00015
00016
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:: * )
00140 ( unsigned int ) const)
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:: * )
00150 ( const std::string & ) const)
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:: * )
00167 ( unsigned int index, const std::vector<double> & ) )
00168 &PyDataSource::replaceColumn )
00169
00170 #ifdef HAVE_NUMARRAY
00171 .def ( "replaceColumn",
00172 ( void (PyDataSource:: * )
00173 ( const std::string &, numeric::array ) )
00174 &PyDataSource::replaceColumn )
00175
00176 .def ( "replaceColumn",
00177 ( void (PyDataSource:: * )
00178 ( unsigned int index, numeric::array ) )
00179 &PyDataSource::replaceColumn )
00180 #endif
00181
00182
00183
00184
00185
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 }
00256 }
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