Mantid
Loading...
Searching...
No Matches
ITableWorkspace.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
9#include "MantidAPI/Column.h"
10#include "MantidAPI/TableRow.h"
13#include "MantidKernel/V3D.h"
23
24#include <boost/preprocessor/list/for_each.hpp>
25#include <boost/preprocessor/tuple/to_list.hpp>
26#include <boost/python/class.hpp>
27#include <boost/python/converter/builtin_converters.hpp>
28#include <boost/python/dict.hpp>
29#include <boost/python/extract.hpp>
30#include <boost/python/list.hpp>
31#include <boost/python/make_constructor.hpp>
32#include <boost/python/overloads.hpp>
33
34// See
35// http://docs.scipy.org/doc/numpy/reference/c-api.array.html#PY_ARRAY_UNIQUE_SYMBOL
36#define PY_ARRAY_UNIQUE_SYMBOL API_ARRAY_API
37#define NO_IMPORT_ARRAY
38#include <numpy/ndarrayobject.h>
39
40using namespace Mantid::API;
45using namespace boost::python;
46
48
49namespace {
50
51// Numpy PyArray_IsIntegerScalar is broken for Python 3 for numpy < 1.11
52#define TO_LONG PyLong_AsLong
53#define STR_CHECK PyUnicode_Check
54#if NPY_API_VERSION < 0x0000000a //(1.11)
55#define IS_ARRAY_INTEGER(obj) (PyLong_Check(obj) || PyArray_IsScalar((obj), Integer))
56#else
57#define IS_ARRAY_INTEGER PyArray_IsIntegerScalar
58#endif
59
61#define BUILTIN_TYPES BOOST_PP_TUPLE_TO_LIST(8, (double, std::string, int, size_t, uint32_t, int64_t, float, uint64_t))
62#define USER_TYPES BOOST_PP_TUPLE_TO_LIST(1, (Mantid::Kernel::V3D))
63#define ARRAY_TYPES BOOST_PP_TUPLE_TO_LIST(2, (std::vector<int>, std::vector<double>))
64
73PyObject *getValue(const Mantid::API::Column_const_sptr &column, const std::type_info &typeID, const int row) {
74 if (typeID.hash_code() == typeid(Mantid::API::Boolean).hash_code()) {
75 bool res = column->cell<Mantid::API::Boolean>(row);
76 return to_python_value<const bool &>()(res);
77 }
78
79#define GET_BUILTIN(R, _, T) \
80 else if (typeID.hash_code() == typeid(T).hash_code()) { \
81 result = to_python_value<const T &>()(column->cell<T>(row)); \
82 }
83#define GET_USER(R, _, T) \
84 else if (typeID.hash_code() == typeid(T).hash_code()) { \
85 const converter::registration *entry = converter::registry::query(typeid(T)); \
86 if (!entry) \
87 throw std::invalid_argument("Cannot find converter from C++ type."); \
88 result = entry->to_python((const void *)&column->cell<T>(row)); \
89 }
90#define GET_ARRAY(R, _, T) \
91 else if (typeID.hash_code() == typeid(T).hash_code()) { \
92 result = Converters::Clone::apply<T::value_type>::create1D(column->cell<T>(row)); \
93 }
94
95 // -- Use the boost preprocessor to generate a list of else if clause to cut
96 // out copy and pasted code.
97 PyObject *result(nullptr);
98 if (false) {
99 } // So that it always falls through to the list checking
100 BOOST_PP_LIST_FOR_EACH(GET_BUILTIN, _, BUILTIN_TYPES)
101 BOOST_PP_LIST_FOR_EACH(GET_ARRAY, _, ARRAY_TYPES)
102 BOOST_PP_LIST_FOR_EACH(GET_USER, _, USER_TYPES)
103 else {
104 throw std::invalid_argument("Cannot convert C++ type to Python: " + column->type());
105 }
106 return result;
107}
108
115void setValue(const Column_sptr &column, const int row, const object &value) {
116 const auto &typeID = column->get_type_info();
117
118 // Special case: Treat Mantid Boolean as normal bool
119 if (typeID.hash_code() == typeid(Mantid::API::Boolean).hash_code()) {
120 column->cell<Mantid::API::Boolean>(row) = extract<bool>(value)();
121 return;
122 }
123
124 // Special case: Boost has issues with NumPy ints, so use Python API instead
125 // to check this first
126 if (typeID.hash_code() == typeid(int).hash_code() && IS_ARRAY_INTEGER(value.ptr())) {
127 column->cell<int>(row) = static_cast<int>(TO_LONG(value.ptr()));
128 return;
129 }
130
131// Macros for all other types
132#define SET_CELL(R, _, T) \
133 else if (typeID.hash_code() == typeid(T).hash_code()) { \
134 column->cell<T>(row) = extract<T>(value)(); \
135 }
136#define SET_VECTOR_CELL(R, _, T) \
137 else if (typeID.hash_code() == typeid(T).hash_code()) { \
138 if (!NDArray::check(value)) { \
139 column->cell<T>(row) = Converters::PySequenceToVector<T::value_type>(value)(); \
140 } else { \
141 column->cell<T>(row) = Converters::NDArrayToVector<T::value_type>(value)(); \
142 } \
143 }
144
145 // -- Use the boost preprocessor to generate a list of else if clause to cut
146 // out copy and pasted code.
147 if (false) {
148 } // So that it always falls through to the list checking
149 BOOST_PP_LIST_FOR_EACH(SET_CELL, _, BUILTIN_TYPES)
150 BOOST_PP_LIST_FOR_EACH(SET_CELL, _, USER_TYPES)
151 BOOST_PP_LIST_FOR_EACH(SET_VECTOR_CELL, _, ARRAY_TYPES)
152 else {
153 throw std::invalid_argument("Cannot convert Python type to C++: " + column->type());
154 }
155}
156
165bool addColumnPlotType(ITableWorkspace &self, const std::string &type, const std::string &name, int plottype) {
166 auto newColumn = self.addColumn(type, name);
167
168 if (newColumn)
169 newColumn->setPlotType(plottype);
170
171 return newColumn != nullptr;
172}
173
184bool addColumnSimple(ITableWorkspace &self, const std::string &type, const std::string &name) {
185 return self.addColumn(type, name) != nullptr;
186}
187
198bool addReadOnlyColumn(ITableWorkspace &self, const std::string &type, const std::string &name) {
199 auto newColumn = self.addColumn(type, name);
200 newColumn->setReadOnly(true);
201 return true;
202}
203
210int getPlotType(ITableWorkspace &self, const object &column) {
211 // Find the column
213 if (STR_CHECK(column.ptr())) {
214 colptr = self.getColumn(extract<std::string>(column)());
215 } else {
216 colptr = self.getColumn(extract<int>(column)());
217 }
218
219 return colptr->getPlotType();
220}
221
230void setPlotType(ITableWorkspace &self, const object &column, int ptype, int linkedCol = -1) {
231 // Find the column
233 if (STR_CHECK(column.ptr())) {
234 colptr = self.getColumn(extract<std::string>(column)());
235 } else {
236 colptr = self.getColumn(extract<int>(column)());
237 }
238 colptr->setPlotType(ptype);
239 if (linkedCol >= 0) {
240 colptr->setLinkedYCol(linkedCol);
241 }
242 self.modified();
243}
244
245GNU_DIAG_OFF("unused-local-typedef")
246// Ignore -Wconversion warnings coming from boost::python
247// Seen with GCC 7.1.1 and Boost 1.63.0
248GNU_DIAG_OFF("conversion")
249// cppcheck-suppress unknownMacro
250BOOST_PYTHON_FUNCTION_OVERLOADS(setPlotType_overloads, setPlotType, 3, 4)
251GNU_DIAG_ON("conversion")
252GNU_DIAG_ON("unused-local-typedef")
253
260int getLinkedYCol(ITableWorkspace &self, const object &column) {
261 // Find the column
263 if (STR_CHECK(column.ptr())) {
264 colptr = self.getColumn(extract<std::string>(column)());
265 } else {
266 colptr = self.getColumn(extract<int>(column)());
267 }
268
269 return colptr->getLinkedYCol();
270}
271
278void setLinkedYCol(ITableWorkspace &self, const object &errColumn, const int dataColomn) {
279 // Find the column
281 if (STR_CHECK(errColumn.ptr())) {
282 colptr = self.getColumn(extract<std::string>(errColumn)());
283 } else {
284 colptr = self.getColumn(extract<int>(errColumn)());
285 }
286
287 colptr->setLinkedYCol(dataColomn);
288}
289
296PyObject *column(const ITableWorkspace &self, const object &value) {
297 // Find the column and row
299 if (STR_CHECK(value.ptr())) {
300 column = self.getColumn(extract<std::string>(value)());
301 } else {
302 column = self.getColumn(extract<int>(value)());
303 }
304 const std::type_info &typeID = column->get_type_info();
305 const auto numRows = static_cast<int>(column->size());
306
307 PyObject *result = PyList_New(numRows);
308 for (int i = 0; i < numRows; i++) {
309 if (PyList_SetItem(result, i, getValue(column, typeID, i)))
310 throw std::runtime_error("Error while building list");
311 }
312
313 return result;
314}
315
320PyObject *stringNumpyArray(const Mantid::API::Column_const_sptr &column) {
321 // Find maximum string length in the column cells
322 size_t maxlen = 0;
323 for (size_t i = 0; i < column->size(); ++i) {
324 maxlen = std::max(maxlen, column->cell<std::string>(i).size());
325 }
326 // Create array descriptor
327 std::string dtype_str = "<U" + std::to_string(maxlen);
328 PyObject *dtype = Py_BuildValue("s", dtype_str.c_str());
329 PyArray_Descr *descr = nullptr;
330 if (!PyArray_DescrConverter(dtype, &descr)) {
331 Py_DECREF(dtype);
332 throw std::runtime_error("Failed to create Unicode dtype");
333 }
334 Py_DECREF(dtype);
335 npy_intp arrayDims[1] = {static_cast<npy_intp>(column->size())};
336 PyObject *nparray = PyArray_NewFromDescr(&PyArray_Type, descr, 1, arrayDims, nullptr, nullptr, 0, nullptr);
337 auto *dest = reinterpret_cast<PyArrayObject *>(nparray);
338 for (size_t i = 0; i < column->size(); ++i) {
339 // Create python string object and place it into array
340 PyObject *pystr = PyUnicode_FromString(column->cell<std::string>(i).c_str());
341 PyArray_SETITEM(dest, static_cast<char *>(PyArray_GETPTR1(dest, i)), pystr);
342 Py_DECREF(pystr);
343 }
344 return nparray;
345}
346
347size_t getStride(const Mantid::API::Column_const_sptr &column) {
348 const std::type_info &typeID = column->get_type_info();
349 if (typeID.hash_code() == typeid(Mantid::Kernel::V3D).hash_code()) {
350 return column->cell<Mantid::Kernel::V3D>(0).size();
351 }
352 if (typeID.hash_code() == typeid(std::vector<int>).hash_code()) {
353 return column->cell<std::vector<int>>(0).size();
354 }
355 if (typeID.hash_code() == typeid(std::vector<double>).hash_code()) {
356 return column->cell<std::vector<double>>(0).size();
357 }
358 return 1;
359}
360
361template <typename T, typename U> void copyTo1DArray(void *dest, const Mantid::API::Column_const_sptr &column) {
362 auto dest_p = static_cast<T *>(dest);
363 for (size_t i = 0; i < column->size(); ++i) {
364 dest_p[i] = column->cell<U>(i);
365 }
366}
367
368template <typename T, typename U> void copyTo2DArray(void *dest, const Mantid::API::Column_const_sptr &column) {
369 auto dest_p = static_cast<T *>(dest);
370 size_t stride = getStride(column);
371 for (size_t i = 0; i < column->size(); ++i) {
372 const auto src = static_cast<std::vector<T>>(column->cell<U>(i));
373 if (src.size() != stride) {
374 throw std::runtime_error(
375 "All rows in a vector column must have the same length to be converted into a numpy array");
376 }
377 std::copy(src.begin(), src.end(), dest_p + i * stride);
378 }
379 return;
380}
381
382const std::unordered_map<size_t, std::tuple<int, std::function<void(void *, Mantid::API::Column_const_sptr)>>>
383 array_handlers = {
384 {typeid(int).hash_code(), {NPY_INT, copyTo1DArray<int, int>}},
385 {typeid(Mantid::API::Boolean).hash_code(), {NPY_BOOL, copyTo1DArray<bool, Mantid::API::Boolean>}},
386 {typeid(int32_t).hash_code(), {NPY_INT32, copyTo1DArray<int32_t, int32_t>}},
387 {typeid(uint32_t).hash_code(), {NPY_UINT32, copyTo1DArray<uint32_t, uint32_t>}},
388 {typeid(int64_t).hash_code(), {NPY_INT64, copyTo1DArray<int64_t, int64_t>}},
389 {typeid(uint64_t).hash_code(), {NPY_UINT64, copyTo1DArray<uint64_t, uint64_t>}},
390 {typeid(double).hash_code(), {NPY_DOUBLE, copyTo1DArray<double, double>}},
391 {typeid(float).hash_code(), {NPY_FLOAT, copyTo1DArray<float, float>}},
392 {typeid(size_t).hash_code(),
393 {(sizeof(size_t) == 4) ? NPY_UINT32 : NPY_UINT64,
394 (sizeof(size_t) == 4) ? copyTo1DArray<uint32_t, uint32_t> : copyTo1DArray<uint64_t, uint64_t>}},
395 {typeid(std::vector<int>).hash_code(), {NPY_INT, copyTo2DArray<int, std::vector<int>>}},
396 {typeid(std::vector<double>).hash_code(), {NPY_DOUBLE, copyTo2DArray<double, std::vector<double>>}},
397 {typeid(Mantid::Kernel::V3D).hash_code(), {NPY_DOUBLE, copyTo2DArray<double, Mantid::Kernel::V3D>}}};
398
405PyObject *columnArray(const ITableWorkspace &self, const object &value) {
407 if (STR_CHECK(value.ptr())) {
408 column = self.getColumn(extract<std::string>(value)());
409 } else {
410 column = self.getColumn(extract<size_t>(value)());
411 }
412 const std::type_info &typeID = column->get_type_info();
413 if (typeID.hash_code() == typeid(std::string).hash_code()) {
414 return stringNumpyArray(column);
415 }
416
417 auto it = array_handlers.find(typeID.hash_code());
418 if (it == array_handlers.end()) {
419 throw std::invalid_argument(std::string("Column type not yet supported for array: ") + std::string(typeID.name()));
420 }
421 const size_t numRows = self.rowCount();
422 const size_t stride = getStride(column);
423 const bool isVectorLike = (stride != 1);
424 npy_intp arrayDims[2] = {static_cast<npy_intp>(numRows), static_cast<npy_intp>(isVectorLike ? stride : 0)};
425 const int nDims = isVectorLike ? 2 : 1;
426 auto &[npy_type, copy_func] = it->second;
427 PyObject *nparray = PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(npy_type), nDims, arrayDims, nullptr,
428 nullptr, 0, nullptr);
429 if (!nparray) {
430 throw std::runtime_error("Failed to allocate NumPy array");
431 }
432 void *dest = PyArray_DATA(reinterpret_cast<PyArrayObject *>(nparray)); // HEAD of the contiguous numpy data array
433 copy_func(dest, std::move(column));
434 return nparray;
435}
436
443PyObject *row(ITableWorkspace &self, int row) {
444 if (row < 0)
445 throw std::invalid_argument("Cannot specify negative row number");
446 if (row >= static_cast<int>(self.rowCount()))
447 throw std::invalid_argument("Cannot specify row larger than number of rows");
448
449 auto numCols = static_cast<int>(self.columnCount());
450
451 PyObject *result = PyDict_New();
452
453 for (int columnIndex = 0; columnIndex < numCols; columnIndex++) {
454 Mantid::API::Column_const_sptr col = self.getColumn(columnIndex);
455 const std::type_info &typeID = col->get_type_info();
456
457 if (PyDict_SetItemString(result, col->name().c_str(), getValue(col, typeID, row)))
458 throw std::runtime_error("Error while building dict");
459 }
460
461 return result;
462}
463
469boost::python::list columnTypes(ITableWorkspace &self) {
470 auto numCols = static_cast<int>(self.columnCount());
471
472 boost::python::list types;
473
474 for (int colIndex = 0; colIndex < numCols; colIndex++) {
475 const auto col = self.getColumn(colIndex);
476 const auto &type = col->type();
477 types.append(type);
478 }
479
480 return types;
481}
482
491void addRowFromDict(ITableWorkspace &self, const dict &rowItems) {
492 // rowItems must contain an entry for every column
493 auto nitems = boost::python::len(rowItems);
494 if (nitems != static_cast<decltype(nitems)>(self.columnCount())) {
495 throw std::invalid_argument("Number of values given does not match the number of columns. "
496 "Expected: " +
498 }
499
500 // Add a new row to populate with values
501 const auto rowIndex = static_cast<int>(self.rowCount());
502 self.appendRow();
503
504 // Declared in this scope so we can access them in catch block
505 Column_sptr col; // Column in table
506 object value; // Value from dictionary
507
508 try {
509 // Retrieve and set the value for each column
510 auto columns = self.getColumnNames();
511 for (auto &iter : columns) {
512 col = self.getColumn(iter);
513 value = rowItems[iter];
514 setValue(col, rowIndex, value);
515 }
516 } catch (error_already_set &) {
517 // One of the columns wasn't found in the dictionary
518 if (PyErr_ExceptionMatches(PyExc_KeyError)) {
519 std::ostringstream msg;
520 msg << "Missing key-value entry for column ";
521 msg << "<" << col->name() << ">";
522 PyErr_SetString(PyExc_KeyError, msg.str().c_str());
523 }
524
525 // Wrong type of data for one of the columns
526 if (PyErr_ExceptionMatches(PyExc_TypeError)) {
527 std::ostringstream msg;
528 msg << "Wrong datatype for column <" << col->name() << "> ";
529 msg << "(expected <" << col->type() << ">)";
530 PyErr_SetString(PyExc_TypeError, msg.str().c_str());
531 }
532
533 // Remove the new row since populating it has failed
534 self.removeRow(rowIndex);
535 throw;
536 }
537 self.modified();
538}
539
548void addRowFromSequence(ITableWorkspace &self, const object &rowItems) {
549 // rowItems must contain an entry for every column
550 auto nitems = boost::python::len(rowItems);
551 if (nitems != static_cast<decltype(nitems)>(self.columnCount())) {
552 throw std::invalid_argument("Number of values given does not match the number of columns. "
553 "Expected: " +
555 }
556
557 // Add a new row to populate with values
558 const auto rowIndex = static_cast<int>(self.rowCount());
559 self.appendRow();
560
561 // Loop over sequence and set each column value in same order
562 for (decltype(nitems) i = 0; i < nitems; ++i) {
563 auto col = self.getColumn(i);
564 auto value = rowItems[i];
565
566 try {
567 setValue(col, rowIndex, value);
568 } catch (error_already_set &) {
569 // Wrong type of data for one of the columns
570 if (PyErr_ExceptionMatches(PyExc_TypeError)) {
571 std::ostringstream msg;
572 msg << "Wrong datatype for column <" << col->name() << "> ";
573 msg << "(expected <" << col->type() << ">)";
574 PyErr_SetString(PyExc_TypeError, msg.str().c_str());
575 }
576
577 // Remove the new row since populating it has failed
578 self.removeRow(rowIndex);
579 throw;
580 }
581 }
582 self.modified();
583}
584
594void getCellLoc(ITableWorkspace &self, const object &col_or_row, const int row_or_col, Column_sptr &column,
595 int &rowIndex) {
596 if (STR_CHECK(col_or_row.ptr())) {
597 column = self.getColumn(extract<std::string>(col_or_row)());
598 rowIndex = row_or_col;
599 } else {
600 rowIndex = extract<int>(col_or_row)();
601 column = self.getColumn(row_or_col);
602 }
603}
604
613PyObject *cell(ITableWorkspace &self, const object &value, int row_or_col) {
614 // Find the column and row
616 int rowIndex;
617 getCellLoc(self, value, row_or_col, col, rowIndex);
618 const std::type_info &typeID = col->get_type_info();
619 return getValue(col, typeID, rowIndex);
620}
621
630void setCell(ITableWorkspace &self, const object &col_or_row, const int row_or_col, const object &value,
631 const bool &notify_replace) {
633 int rowIndex;
634 getCellLoc(self, col_or_row, row_or_col, col, rowIndex);
635 setValue(col, rowIndex, value);
636
637 if (notify_replace) {
638 self.modified();
639 }
640}
641
648bool isColumnReadOnly(ITableWorkspace &self, const object &column) {
649 // Find the column
651 if (STR_CHECK(column.ptr())) {
652 colptr = self.getColumn(extract<std::string>(column)());
653 } else {
654 colptr = self.getColumn(extract<int>(column)());
655 }
656 return colptr->getReadOnly();
657}
658
665void setColumnReadOnly(ITableWorkspace &self, const object &column, const bool readOnly) {
666 // Find the column
668 if (STR_CHECK(column.ptr())) {
669 colptr = self.getColumn(extract<std::string>(column)());
670 } else {
671 colptr = self.getColumn(extract<int>(column)());
672 }
673 colptr->setReadOnly(readOnly);
674 self.modified();
675}
676} // namespace
677
686dict toDict(const ITableWorkspace &self) {
687 dict result;
688
689 for (const auto &name : self.getColumnNames()) {
690 handle<> handle(column(self, object(name)));
691 object values(handle);
692 result[name] = values;
693 }
694
695 return result;
696}
697
698class ITableWorkspacePickleSuite : public boost::python::pickle_suite {
699public:
700 static dict getstate(const ITableWorkspace &ws) {
701 dict data;
702 data["data"] = toDict(ws);
703 data["meta_data"] = writeMetaData(ws);
704 return data;
705 }
706
707 static void setstate(ITableWorkspace &ws, const dict &state) {
708 readMetaData(ws, state);
709 readData(ws, state);
710 }
711
712private:
717 static dict writeMetaData(const ITableWorkspace &ws) {
718 list columnTypes;
719 list columnNames;
720
721 const auto &names = ws.getColumnNames();
722 for (const auto &name : names) {
723 const auto &column = ws.getColumn(name);
724 columnNames.append(name);
725 columnTypes.append(column->type());
726 }
727
728 dict metaData;
729 metaData["column_names"] = columnNames;
730 metaData["column_types"] = columnTypes;
731 return metaData;
732 }
733
742 static void readMetaData(ITableWorkspace &ws, const dict &state) {
743 const auto &metaData = state["meta_data"];
744 const auto &columnNames = metaData["column_names"];
745 const auto &columnTypes = metaData["column_types"];
746
747 auto numColumns = len(columnNames);
748 for (decltype(numColumns) colIndex = 0; colIndex < numColumns; ++colIndex) {
749 const auto &key = columnNames[colIndex];
750 const auto &value = columnTypes[colIndex];
751 const auto &name = extract<std::string>(key);
752 const auto &type = extract<std::string>(value);
753 ws.addColumn(type, name);
754 }
755 }
756
762 static void readData(ITableWorkspace &ws, const dict &state) {
763 const auto &data = state["data"];
764 const auto &names = ws.getColumnNames();
765
766 if (names.empty()) {
767 return;
768 }
769
770 auto numRows = len(data[names[0]]);
771 for (int rowIndex = 0; rowIndex < numRows; ++rowIndex) {
772 ws.appendRow();
773 for (const auto &name : names) {
774 setValue(ws.getColumn(name), static_cast<int>(rowIndex), data[name][rowIndex]);
775 }
776 }
777 }
778};
779
782
783 std::string iTableWorkspace_docstring = "Most of the information from a table workspace is returned ";
784 iTableWorkspace_docstring += "as native copies. All of the column accessors return lists while the ";
785 iTableWorkspace_docstring += "rows return dicts. This object does support the idom 'for row in ";
786 iTableWorkspace_docstring += "ITableWorkspace'.";
787
788 class_<ITableWorkspace, bases<Workspace>, boost::noncopyable>("ITableWorkspace", iTableWorkspace_docstring.c_str(),
789 no_init)
790 .def_pickle(ITableWorkspacePickleSuite())
791 .def("addColumn", &addColumnSimple, (arg("self"), arg("type"), arg("name")),
792 "Add a named column with the given type. Recognized types are: "
793 "int,float,double,bool,str,V3D,long64")
794
795 .def("addColumn", &addColumnPlotType, (arg("self"), arg("type"), arg("name"), arg("plottype")),
796 "Add a named column with the given datatype "
797 "(int,float,double,bool,str,V3D,long64) "
798 "\nand plottype "
799 "(0 = None, 1 = X, 2 = Y, 3 = Z, 4 = xErr, 5 = yErr, 6 = Label).")
800
801 .def("addReadOnlyColumn", &addReadOnlyColumn, (arg("self"), arg("type"), arg("name")),
802 "Add a read-only, named column with the given type. Recognized types are: "
803 "int,float,double,bool,str,V3D,long64")
804
805 .def("getPlotType", &getPlotType, (arg("self"), arg("column")),
806 "Get the plot type of given column as an integer. "
807 "Accepts column name or index. \nPossible return values: "
808 "(0 = None, 1 = X, 2 = Y, 3 = Z, 4 = xErr, 5 = yErr, 6 = Label).")
809
810 .def("setPlotType", setPlotType,
811 setPlotType_overloads((arg("self"), arg("column"), arg("ptype"), arg("linkedCol") = -1),
812 "Set the plot type of given column. "
813 "Accepts column name or index. \nPossible type values: "
814 "(0 = None, 1 = X, 2 = Y, 3 = Z, 4 = xErr, 5 = yErr, 6 = "
815 "Label)."))
816
817 .def("getLinkedYCol", &getLinkedYCol, (arg("self"), arg("column")),
818 "Get the data column associated with a given error column. ")
819
820 .def("setLinkedYCol", &setLinkedYCol, (arg("self"), arg("errColumn"), arg("dataColumn")),
821 "Set the data column associated with a given error column. ")
822
823 .def("removeColumn", &ITableWorkspace::removeColumn, (arg("self"), arg("name")), "Remove the named column.")
824
825 .def("columnCount", &ITableWorkspace::columnCount, arg("self"), "Returns the number of columns in the workspace.")
826
827 .def("rowCount", &ITableWorkspace::rowCount, arg("self"), "Returns the number of rows within the workspace.")
828
829 .def("setRowCount", &ITableWorkspace::setRowCount, (arg("self"), arg("count")),
830 "Resize the table to contain count rows.")
831
832 .def("__len__", &ITableWorkspace::rowCount, arg("self"), "Returns the number of rows within the workspace.")
833
834 .def("getColumnNames", &ITableWorkspace::getColumnNames, arg("self"),
835 boost::python::return_value_policy<VectorToNumpy>(), "Return a list of the column names.")
836
837 .def("keys", &ITableWorkspace::getColumnNames, arg("self"), boost::python::return_value_policy<VectorToNumpy>(),
838 "Return a list of the column names.")
839
840 .def("column", &column, (arg("self"), arg("column")), "Return all values of a specific column as a list.")
841
842 .def("columnArray", &columnArray, (arg("self"), arg("column")),
843 "Return all values of a specific column (either index or name) as a numpy array.")
844
845 .def("row", &row, (arg("self"), arg("row")), "Return all values of a specific row as a dict.")
846
847 .def("columnTypes", &columnTypes, arg("self"), "Return the types of the columns as a list")
848
849 // FromSequence must come first since it takes an object parameter
850 // Otherwise, FromDict will never be called as object accepts anything
851 .def("addRow", &addRowFromSequence, (arg("self"), arg("row_items_seq")),
852 "Appends a row with the values from the given sequence. "
853 "It it assumed that the items are in the correct order for the "
854 "defined columns.")
855
856 .def("addRow", &addRowFromDict, (arg("self"), arg("row_items_dict")),
857 "Appends a row with the values from the dictionary.")
858
859 .def("cell", &cell, (arg("self"), arg("value"), arg("row_or_column")),
860 "Return the value in the given cell. If the value argument is a "
861 "number then it is interpreted as a row otherwise it "
862 "is interpreted as a column name.")
863
864 .def("setCell", &setCell,
865 (arg("self"), arg("row_or_column"), arg("column_or_row"), arg("value"), arg("notify_replace") = true),
866 "Sets the value of a given cell. If the row_or_column argument is a "
867 "number then it is interpreted as a row otherwise it "
868 "is interpreted as a column name. If notify replace is false, then "
869 "the replace workspace event is not triggered.")
870
871 .def("toDict", &toDict, (arg("self")),
872 "Gets the values of this workspace as a dictionary. The keys of the "
873 "dictionary will be the names of the columns of the table. The "
874 "values of the entries will be lists of values for each column.")
875
876 .def("setColumnReadOnly", &setColumnReadOnly, (arg("self"), arg("column"), arg("read_only")),
877 "Sets whether or not a given column of this workspace should be read-only. Columns can be "
878 "selected by name or by index")
879
880 .def("isColumnReadOnly", &isColumnReadOnly, (arg("self"), arg("column")),
881 "Gets whether or not a given column of this workspace is be read-only. Columns can be "
882 "selected by name or by index");
883
884 //-------------------------------------------------------------------------------------------------
885
887}
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
#define GET_POINTER_SPECIALIZATION(TYPE)
Definition GetPointer.h:17
tagPyArrayObject PyArrayObject
_PyArray_Descr PyArray_Descr
void export_ITableWorkspace()
#define SET_VECTOR_CELL(R, _, T)
#define GET_BUILTIN(R, _, T)
#define USER_TYPES
#define ARRAY_TYPES
#define GET_ARRAY(R, _, T)
dict toDict(const ITableWorkspace &self)
Get the contents of the workspace as a python dictionary.
#define GET_USER(R, _, T)
#define SET_CELL(R, _, T)
#define BUILTIN_TYPES
Boost macro for "looping" over builtin types.
#define IS_ARRAY_INTEGER(obj)
#define TO_LONG
#define STR_CHECK
#define GNU_DIAG_ON(x)
#define GNU_DIAG_OFF(x)
This is a collection of macros for turning compiler warnings off in a controlled manner.
static void readMetaData(ITableWorkspace &ws, const dict &state)
Read the meta data from a python dict into the table workspace.
static void setstate(ITableWorkspace &ws, const dict &state)
static dict writeMetaData(const ITableWorkspace &ws)
Write the meta data from a table workspace to a python dict.
static dict getstate(const ITableWorkspace &ws)
static void readData(ITableWorkspace &ws, const dict &state)
Read the data from a python dict into the table workspace.
ITableWorkspace is an implementation of Workspace in which the data are organised in columns of same ...
virtual void removeColumn(const std::string &name)=0
Removes a column.
void modified()
If the workspace is the AnalysisDataService sends AfterReplaceNotification.
virtual void setRowCount(size_t count)=0
Resizes the workspace.
virtual Column_sptr getColumn(const std::string &name)=0
Gets the shared pointer to a column by name.
TableRowHelper appendRow()
Appends a row.
virtual void removeRow(size_t index)=0
Delets a row if it exists.
virtual Column_sptr addColumn(const std::string &type, const std::string &name)=0
Creates a new column.
virtual size_t columnCount() const =0
Number of columns in the workspace.
virtual std::vector< std::string > getColumnNames() const =0
Returns a vector of all column names.
virtual size_t rowCount() const =0
Number of rows in the workspace.
Class for 3D vectors.
Definition V3D.h:34
Thin object wrapper around a numpy array.
Definition NDArray.h:31
std::shared_ptr< Column > Column_sptr
Definition Column.h:232
std::shared_ptr< const Column > Column_const_sptr
Definition Column.h:233
std::string dtype(const Container< HeldType > &)
std::string to_string(const wide_integer< Bits, Signed > &n)
As TableColumn stores its data in a std::vector bool type cannot be used in the same way as the other...
Definition Column.h:213
Implements a return value policy that returns a numpy array from a function returning a std::vector b...
Encapsulates the registration required for an interface type T that sits on top of a Kernel::DataItem...