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/list.hpp>
30#include <boost/python/make_constructor.hpp>
31#include <boost/python/overloads.hpp>
32
33#include <cstring>
34#include <vector>
35
36// See
37// http://docs.scipy.org/doc/numpy/reference/c-api.array.html#PY_ARRAY_UNIQUE_SYMBOL
38#define PY_ARRAY_UNIQUE_SYMBOL API_ARRAY_API
39#define NO_IMPORT_ARRAY
40#include <numpy/arrayobject.h>
41
42using namespace Mantid::API;
47using namespace boost::python;
48
50
51namespace {
52
53// Numpy PyArray_IsIntegerScalar is broken for Python 3 for numpy < 1.11
54#define TO_LONG PyLong_AsLong
55#define STR_CHECK PyUnicode_Check
56#if NPY_API_VERSION < 0x0000000a //(1.11)
57#define IS_ARRAY_INTEGER(obj) (PyLong_Check(obj) || PyArray_IsScalar((obj), Integer))
58#else
59#define IS_ARRAY_INTEGER PyArray_IsIntegerScalar
60#endif
61
63#define BUILTIN_TYPES BOOST_PP_TUPLE_TO_LIST(8, (double, std::string, int, size_t, uint32_t, int64_t, float, uint64_t))
64#define USER_TYPES BOOST_PP_TUPLE_TO_LIST(1, (Mantid::Kernel::V3D))
65#define ARRAY_TYPES BOOST_PP_TUPLE_TO_LIST(2, (std::vector<int>, std::vector<double>))
66
75PyObject *getValue(const Mantid::API::Column_const_sptr &column, const std::type_info &typeID, const int row) {
76 if (typeID.hash_code() == typeid(Mantid::API::Boolean).hash_code()) {
77 bool res = column->cell<Mantid::API::Boolean>(row);
78 return to_python_value<const bool &>()(res);
79 }
80
81#define GET_BUILTIN(R, _, T) \
82 else if (typeID.hash_code() == typeid(T).hash_code()) { \
83 result = to_python_value<const T &>()(column->cell<T>(row)); \
84 }
85#define GET_USER(R, _, T) \
86 else if (typeID.hash_code() == typeid(T).hash_code()) { \
87 const converter::registration *entry = converter::registry::query(typeid(T)); \
88 if (!entry) \
89 throw std::invalid_argument("Cannot find converter from C++ type."); \
90 result = entry->to_python((const void *)&column->cell<T>(row)); \
91 }
92#define GET_ARRAY(R, _, T) \
93 else if (typeID.hash_code() == typeid(T).hash_code()) { \
94 result = Converters::Clone::apply<T::value_type>::create1D(column->cell<T>(row)); \
95 }
96
97 // -- Use the boost preprocessor to generate a list of else if clause to cut
98 // out copy and pasted code.
99 PyObject *result(nullptr);
100 if (false) {
101 } // So that it always falls through to the list checking
102 BOOST_PP_LIST_FOR_EACH(GET_BUILTIN, _, BUILTIN_TYPES)
103 BOOST_PP_LIST_FOR_EACH(GET_ARRAY, _, ARRAY_TYPES)
104 BOOST_PP_LIST_FOR_EACH(GET_USER, _, USER_TYPES)
105 else {
106 throw std::invalid_argument("Cannot convert C++ type to Python: " + column->type());
107 }
108 return result;
109}
110
117void setValue(const Column_sptr &column, const int row, const object &value) {
118 const auto &typeID = column->get_type_info();
119
120 // Special case: Treat Mantid Boolean as normal bool
121 if (typeID.hash_code() == typeid(Mantid::API::Boolean).hash_code()) {
122 column->cell<Mantid::API::Boolean>(row) = extract<bool>(value)();
123 return;
124 }
125
126 // Special case: Boost has issues with NumPy ints, so use Python API instead
127 // to check this first
128 if (typeID.hash_code() == typeid(int).hash_code() && IS_ARRAY_INTEGER(value.ptr())) {
129 column->cell<int>(row) = static_cast<int>(TO_LONG(value.ptr()));
130 return;
131 }
132
133// Macros for all other types
134#define SET_CELL(R, _, T) \
135 else if (typeID.hash_code() == typeid(T).hash_code()) { \
136 column->cell<T>(row) = extract<T>(value)(); \
137 }
138#define SET_VECTOR_CELL(R, _, T) \
139 else if (typeID.hash_code() == typeid(T).hash_code()) { \
140 if (!NDArray::check(value)) { \
141 column->cell<T>(row) = Converters::PySequenceToVector<T::value_type>(value)(); \
142 } else { \
143 column->cell<T>(row) = Converters::NDArrayToVector<T::value_type>(value)(); \
144 } \
145 }
146
147 // -- Use the boost preprocessor to generate a list of else if clause to cut
148 // out copy and pasted code.
149 if (false) {
150 } // So that it always falls through to the list checking
151 BOOST_PP_LIST_FOR_EACH(SET_CELL, _, BUILTIN_TYPES)
152 BOOST_PP_LIST_FOR_EACH(SET_CELL, _, USER_TYPES)
153 BOOST_PP_LIST_FOR_EACH(SET_VECTOR_CELL, _, ARRAY_TYPES)
154 else {
155 throw std::invalid_argument("Cannot convert Python type to C++: " + column->type());
156 }
157}
158
167bool addColumnPlotType(ITableWorkspace &self, const std::string &type, const std::string &name, int plottype) {
168 auto newColumn = self.addColumn(type, name);
169
170 if (newColumn)
171 newColumn->setPlotType(plottype);
172
173 return newColumn != nullptr;
174}
175
186bool addColumnSimple(ITableWorkspace &self, const std::string &type, const std::string &name) {
187 return self.addColumn(type, name) != nullptr;
188}
189
200bool addReadOnlyColumn(ITableWorkspace &self, const std::string &type, const std::string &name) {
201 auto newColumn = self.addColumn(type, name);
202 newColumn->setReadOnly(true);
203 return true;
204}
205
212int getPlotType(ITableWorkspace &self, const object &column) {
213 // Find the column
215 if (STR_CHECK(column.ptr())) {
216 colptr = self.getColumn(extract<std::string>(column)());
217 } else {
218 colptr = self.getColumn(extract<int>(column)());
219 }
220
221 return colptr->getPlotType();
222}
223
232void setPlotType(ITableWorkspace &self, const object &column, int ptype, int linkedCol = -1) {
233 // Find the column
235 if (STR_CHECK(column.ptr())) {
236 colptr = self.getColumn(extract<std::string>(column)());
237 } else {
238 colptr = self.getColumn(extract<int>(column)());
239 }
240 colptr->setPlotType(ptype);
241 if (linkedCol >= 0) {
242 colptr->setLinkedYCol(linkedCol);
243 }
244 self.modified();
245}
246
247GNU_DIAG_OFF("unused-local-typedef")
248// Ignore -Wconversion warnings coming from boost::python
249// Seen with GCC 7.1.1 and Boost 1.63.0
250GNU_DIAG_OFF("conversion")
251BOOST_PYTHON_FUNCTION_OVERLOADS(setPlotType_overloads, setPlotType, 3, 4)
252GNU_DIAG_ON("conversion")
253GNU_DIAG_ON("unused-local-typedef")
254
261int getLinkedYCol(ITableWorkspace &self, const object &column) {
262 // Find the column
264 if (STR_CHECK(column.ptr())) {
265 colptr = self.getColumn(extract<std::string>(column)());
266 } else {
267 colptr = self.getColumn(extract<int>(column)());
268 }
269
270 return colptr->getLinkedYCol();
271}
272
279void setLinkedYCol(ITableWorkspace &self, const object &errColumn, const int dataColomn) {
280 // Find the column
282 if (STR_CHECK(errColumn.ptr())) {
283 colptr = self.getColumn(extract<std::string>(errColumn)());
284 } else {
285 colptr = self.getColumn(extract<int>(errColumn)());
286 }
287
288 colptr->setLinkedYCol(dataColomn);
289}
290
297PyObject *column(const ITableWorkspace &self, const object &value) {
298 // Find the column and row
300 if (STR_CHECK(value.ptr())) {
301 column = self.getColumn(extract<std::string>(value)());
302 } else {
303 column = self.getColumn(extract<int>(value)());
304 }
305 const std::type_info &typeID = column->get_type_info();
306 const auto numRows = static_cast<int>(column->size());
307
308 PyObject *result = PyList_New(numRows);
309 for (int i = 0; i < numRows; i++) {
310 if (PyList_SetItem(result, i, getValue(column, typeID, i)))
311 throw std::runtime_error("Error while building list");
312 }
313
314 return result;
315}
316
323PyObject *row(ITableWorkspace &self, int row) {
324 if (row < 0)
325 throw std::invalid_argument("Cannot specify negative row number");
326 if (row >= static_cast<int>(self.rowCount()))
327 throw std::invalid_argument("Cannot specify row larger than number of rows");
328
329 auto numCols = static_cast<int>(self.columnCount());
330
331 PyObject *result = PyDict_New();
332
333 for (int columnIndex = 0; columnIndex < numCols; columnIndex++) {
334 Mantid::API::Column_const_sptr col = self.getColumn(columnIndex);
335 const std::type_info &typeID = col->get_type_info();
336
337 if (PyDict_SetItemString(result, col->name().c_str(), getValue(col, typeID, row)))
338 throw std::runtime_error("Error while building dict");
339 }
340
341 return result;
342}
343
349boost::python::list columnTypes(ITableWorkspace &self) {
350 auto numCols = static_cast<int>(self.columnCount());
351
352 boost::python::list types;
353
354 for (int colIndex = 0; colIndex < numCols; colIndex++) {
355 const auto col = self.getColumn(colIndex);
356 const auto &type = col->type();
357 types.append(type);
358 }
359
360 return types;
361}
362
371void addRowFromDict(ITableWorkspace &self, const dict &rowItems) {
372 // rowItems must contain an entry for every column
373 auto nitems = boost::python::len(rowItems);
374 if (nitems != static_cast<decltype(nitems)>(self.columnCount())) {
375 throw std::invalid_argument("Number of values given does not match the number of columns. "
376 "Expected: " +
378 }
379
380 // Add a new row to populate with values
381 const auto rowIndex = static_cast<int>(self.rowCount());
382 self.appendRow();
383
384 // Declared in this scope so we can access them in catch block
385 Column_sptr col; // Column in table
386 object value; // Value from dictionary
387
388 try {
389 // Retrieve and set the value for each column
390 auto columns = self.getColumnNames();
391 for (auto &iter : columns) {
392 col = self.getColumn(iter);
393 value = rowItems[iter];
394 setValue(col, rowIndex, value);
395 }
396 } catch (error_already_set &) {
397 // One of the columns wasn't found in the dictionary
398 if (PyErr_ExceptionMatches(PyExc_KeyError)) {
399 std::ostringstream msg;
400 msg << "Missing key-value entry for column ";
401 msg << "<" << col->name() << ">";
402 PyErr_SetString(PyExc_KeyError, msg.str().c_str());
403 }
404
405 // Wrong type of data for one of the columns
406 if (PyErr_ExceptionMatches(PyExc_TypeError)) {
407 std::ostringstream msg;
408 msg << "Wrong datatype for column <" << col->name() << "> ";
409 msg << "(expected <" << col->type() << ">)";
410 PyErr_SetString(PyExc_TypeError, msg.str().c_str());
411 }
412
413 // Remove the new row since populating it has failed
414 self.removeRow(rowIndex);
415 throw;
416 }
417 self.modified();
418}
419
428void addRowFromSequence(ITableWorkspace &self, const object &rowItems) {
429 // rowItems must contain an entry for every column
430 auto nitems = boost::python::len(rowItems);
431 if (nitems != static_cast<decltype(nitems)>(self.columnCount())) {
432 throw std::invalid_argument("Number of values given does not match the number of columns. "
433 "Expected: " +
435 }
436
437 // Add a new row to populate with values
438 const auto rowIndex = static_cast<int>(self.rowCount());
439 self.appendRow();
440
441 // Loop over sequence and set each column value in same order
442 for (decltype(nitems) i = 0; i < nitems; ++i) {
443 auto col = self.getColumn(i);
444 auto value = rowItems[i];
445
446 try {
447 setValue(col, rowIndex, value);
448 } catch (error_already_set &) {
449 // Wrong type of data for one of the columns
450 if (PyErr_ExceptionMatches(PyExc_TypeError)) {
451 std::ostringstream msg;
452 msg << "Wrong datatype for column <" << col->name() << "> ";
453 msg << "(expected <" << col->type() << ">)";
454 PyErr_SetString(PyExc_TypeError, msg.str().c_str());
455 }
456
457 // Remove the new row since populating it has failed
458 self.removeRow(rowIndex);
459 throw;
460 }
461 }
462 self.modified();
463}
464
474void getCellLoc(ITableWorkspace &self, const object &col_or_row, const int row_or_col, Column_sptr &column,
475 int &rowIndex) {
476 if (STR_CHECK(col_or_row.ptr())) {
477 column = self.getColumn(extract<std::string>(col_or_row)());
478 rowIndex = row_or_col;
479 } else {
480 rowIndex = extract<int>(col_or_row)();
481 column = self.getColumn(row_or_col);
482 }
483}
484
493PyObject *cell(ITableWorkspace &self, const object &value, int row_or_col) {
494 // Find the column and row
496 int rowIndex;
497 getCellLoc(self, value, row_or_col, col, rowIndex);
498 const std::type_info &typeID = col->get_type_info();
499 return getValue(col, typeID, rowIndex);
500}
501
510void setCell(ITableWorkspace &self, const object &col_or_row, const int row_or_col, const object &value,
511 const bool &notify_replace) {
513 int rowIndex;
514 getCellLoc(self, col_or_row, row_or_col, col, rowIndex);
515 setValue(col, rowIndex, value);
516
517 if (notify_replace) {
518 self.modified();
519 }
520}
521
528bool isColumnReadOnly(ITableWorkspace &self, const object &column) {
529 // Find the column
531 if (STR_CHECK(column.ptr())) {
532 colptr = self.getColumn(extract<std::string>(column)());
533 } else {
534 colptr = self.getColumn(extract<int>(column)());
535 }
536 return colptr->getReadOnly();
537}
538
545void setColumnReadOnly(ITableWorkspace &self, const object &column, const bool readOnly) {
546 // Find the column
548 if (STR_CHECK(column.ptr())) {
549 colptr = self.getColumn(extract<std::string>(column)());
550 } else {
551 colptr = self.getColumn(extract<int>(column)());
552 }
553 colptr->setReadOnly(readOnly);
554 self.modified();
555}
556} // namespace
557
566dict toDict(const ITableWorkspace &self) {
567 dict result;
568
569 for (const auto &name : self.getColumnNames()) {
570 handle<> handle(column(self, object(name)));
571 object values(handle);
572 result[name] = values;
573 }
574
575 return result;
576}
577
578class ITableWorkspacePickleSuite : public boost::python::pickle_suite {
579public:
580 static dict getstate(const ITableWorkspace &ws) {
581 dict data;
582 data["data"] = toDict(ws);
583 data["meta_data"] = writeMetaData(ws);
584 return data;
585 }
586
587 static void setstate(ITableWorkspace &ws, const dict &state) {
588 readMetaData(ws, state);
589 readData(ws, state);
590 }
591
592private:
597 static dict writeMetaData(const ITableWorkspace &ws) {
598 list columnTypes;
599 list columnNames;
600
601 const auto &names = ws.getColumnNames();
602 for (const auto &name : names) {
603 const auto &column = ws.getColumn(name);
604 columnNames.append(name);
605 columnTypes.append(column->type());
606 }
607
608 dict metaData;
609 metaData["column_names"] = columnNames;
610 metaData["column_types"] = columnTypes;
611 return metaData;
612 }
613
622 static void readMetaData(ITableWorkspace &ws, const dict &state) {
623 const auto &metaData = state["meta_data"];
624 const auto &columnNames = metaData["column_names"];
625 const auto &columnTypes = metaData["column_types"];
626
627 auto numColumns = len(columnNames);
628 for (decltype(numColumns) colIndex = 0; colIndex < numColumns; ++colIndex) {
629 const auto &key = columnNames[colIndex];
630 const auto &value = columnTypes[colIndex];
631 const auto &name = extract<std::string>(key);
632 const auto &type = extract<std::string>(value);
633 ws.addColumn(type, name);
634 }
635 }
636
642 static void readData(ITableWorkspace &ws, const dict &state) {
643 const auto &data = state["data"];
644 const auto &names = ws.getColumnNames();
645
646 if (names.empty()) {
647 return;
648 }
649
650 auto numRows = len(data[names[0]]);
651 for (int rowIndex = 0; rowIndex < numRows; ++rowIndex) {
652 ws.appendRow();
653 for (const auto &name : names) {
654 setValue(ws.getColumn(name), static_cast<int>(rowIndex), data[name][rowIndex]);
655 }
656 }
657 }
658};
659
662
663 std::string iTableWorkspace_docstring = "Most of the information from a table workspace is returned ";
664 iTableWorkspace_docstring += "as native copies. All of the column accessors return lists while the ";
665 iTableWorkspace_docstring += "rows return dicts. This object does support the idom 'for row in ";
666 iTableWorkspace_docstring += "ITableWorkspace'.";
667
668 class_<ITableWorkspace, bases<Workspace>, boost::noncopyable>("ITableWorkspace", iTableWorkspace_docstring.c_str(),
669 no_init)
670 .def_pickle(ITableWorkspacePickleSuite())
671 .def("addColumn", &addColumnSimple, (arg("self"), arg("type"), arg("name")),
672 "Add a named column with the given type. Recognized types are: "
673 "int,float,double,bool,str,V3D,long64")
674
675 .def("addColumn", &addColumnPlotType, (arg("self"), arg("type"), arg("name"), arg("plottype")),
676 "Add a named column with the given datatype "
677 "(int,float,double,bool,str,V3D,long64) "
678 "\nand plottype "
679 "(0 = None, 1 = X, 2 = Y, 3 = Z, 4 = xErr, 5 = yErr, 6 = Label).")
680
681 .def("addReadOnlyColumn", &addReadOnlyColumn, (arg("self"), arg("type"), arg("name")),
682 "Add a read-only, named column with the given type. Recognized types are: "
683 "int,float,double,bool,str,V3D,long64")
684
685 .def("getPlotType", &getPlotType, (arg("self"), arg("column")),
686 "Get the plot type of given column as an integer. "
687 "Accepts column name or index. \nPossible return values: "
688 "(0 = None, 1 = X, 2 = Y, 3 = Z, 4 = xErr, 5 = yErr, 6 = Label).")
689
690 .def("setPlotType", setPlotType,
691 setPlotType_overloads((arg("self"), arg("column"), arg("ptype"), arg("linkedCol") = -1),
692 "Set the plot type of given column. "
693 "Accepts column name or index. \nPossible type values: "
694 "(0 = None, 1 = X, 2 = Y, 3 = Z, 4 = xErr, 5 = yErr, 6 = "
695 "Label)."))
696
697 .def("getLinkedYCol", &getLinkedYCol, (arg("self"), arg("column")),
698 "Get the data column associated with a given error column. ")
699
700 .def("setLinkedYCol", &setLinkedYCol, (arg("self"), arg("errColumn"), arg("dataColumn")),
701 "Set the data column associated with a given error column. ")
702
703 .def("removeColumn", &ITableWorkspace::removeColumn, (arg("self"), arg("name")), "Remove the named column.")
704
705 .def("columnCount", &ITableWorkspace::columnCount, arg("self"), "Returns the number of columns in the workspace.")
706
707 .def("rowCount", &ITableWorkspace::rowCount, arg("self"), "Returns the number of rows within the workspace.")
708
709 .def("setRowCount", &ITableWorkspace::setRowCount, (arg("self"), arg("count")),
710 "Resize the table to contain count rows.")
711
712 .def("__len__", &ITableWorkspace::rowCount, arg("self"), "Returns the number of rows within the workspace.")
713
714 .def("getColumnNames", &ITableWorkspace::getColumnNames, arg("self"),
715 boost::python::return_value_policy<VectorToNumpy>(), "Return a list of the column names.")
716
717 .def("keys", &ITableWorkspace::getColumnNames, arg("self"), boost::python::return_value_policy<VectorToNumpy>(),
718 "Return a list of the column names.")
719
720 .def("column", &column, (arg("self"), arg("column")), "Return all values of a specific column as a list.")
721
722 .def("row", &row, (arg("self"), arg("row")), "Return all values of a specific row as a dict.")
723
724 .def("columnTypes", &columnTypes, arg("self"), "Return the types of the columns as a list")
725
726 // FromSequence must come first since it takes an object parameter
727 // Otherwise, FromDict will never be called as object accepts anything
728 .def("addRow", &addRowFromSequence, (arg("self"), arg("row_items_seq")),
729 "Appends a row with the values from the given sequence. "
730 "It it assumed that the items are in the correct order for the "
731 "defined columns.")
732
733 .def("addRow", &addRowFromDict, (arg("self"), arg("row_items_dict")),
734 "Appends a row with the values from the dictionary.")
735
736 .def("cell", &cell, (arg("self"), arg("value"), arg("row_or_column")),
737 "Return the value in the given cell. If the value argument is a "
738 "number then it is interpreted as a row otherwise it "
739 "is interpreted as a column name.")
740
741 .def("setCell", &setCell,
742 (arg("self"), arg("row_or_column"), arg("column_or_row"), arg("value"), arg("notify_replace") = true),
743 "Sets the value of a given cell. If the row_or_column argument is a "
744 "number then it is interpreted as a row otherwise it "
745 "is interpreted as a column name. If notify replace is false, then "
746 "the replace workspace event is not triggered.")
747
748 .def("toDict", &toDict, (arg("self")),
749 "Gets the values of this workspace as a dictionary. The keys of the "
750 "dictionary will be the names of the columns of the table. The "
751 "values of the entries will be lists of values for each column.")
752
753 .def("setColumnReadOnly", &setColumnReadOnly, (arg("self"), arg("column"), arg("read_only")),
754 "Sets whether or not a given column of this workspace should be read-only. Columns can be "
755 "selected by name or by index")
756
757 .def("isColumnReadOnly", &isColumnReadOnly, (arg("self"), arg("column")),
758 "Gets whether or not a given column of this workspace is be read-only. Columns can be "
759 "selected by name or by index");
760
761 //-------------------------------------------------------------------------------------------------
762
764}
double value
The value of the point.
Definition: FitMW.cpp:51
#define GET_POINTER_SPECIALIZATION(TYPE)
Definition: GetPointer.h:17
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
Definition: VersionCompat.h:24
#define STR_CHECK
Definition: VersionCompat.h:25
#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.
Thin object wrapper around a numpy array.
Definition: NDArray.h:31
std::shared_ptr< Column > Column_sptr
Definition: Column.h:228
std::shared_ptr< const Column > Column_const_sptr
Definition: Column.h:229
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:209
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...