Isis 3 Programmer Reference
LoadCSV.cpp
Go to the documentation of this file.
1 
24 #include <QString>
25 #include <vector>
26 #include <numeric>
27 #include <iostream>
28 #include <sstream>
29 
30 #include "LoadCSV.h"
31 #include "FileName.h"
32 #include "IException.h"
33 
34 using namespace std;
35 
36 namespace Isis {
37 
38 
39  LoadCSV::LoadCSV() : _base(), _csvSpecs("LoadCSV"), _data(0,0), _history() { }
40 
41  LoadCSV::LoadCSV(const QString &base, const HiCalConf &conf,
42  const DbProfile &profile) : _base(), _csvSpecs("LoadCSV"),
43  _data(0,0), _history() {
44  load(base, conf, profile);
45  }
46 
47  void LoadCSV::load(const QString &base, const HiCalConf &conf,
48  const DbProfile &profile) {
49 
50  // Initialize the object with necessary info
51  init(base, conf, profile);
52 
53  // Set up access to the CSV table. Note that HiCalConf.getMatrixSource()
54  // method is typically used, but the parsing has been broken up here for
55  // implementation purposes.
56  QString csvfile(conf.filepath(getValue()));
57  addHistory("File", csvfile);
58  CSVReader csv;
59 
60  // Retrieve information regarding the format within the CSV
61  bool colHeader(IsEqual(ConfKey(_csvSpecs,makeKey("Header"), QString("FALSE")), "TRUE"));
62  bool rowHeader(colHeader); // Both default to state of the {BASE}Header
63  if (IsEqual(getValue("ColumnHeader"), "TRUE")) colHeader = true;
64  if (IsEqual(getValue("RowHeader"), "TRUE")) rowHeader = true;
65  if (_csvSpecs.exists(makeKey("ColumnName"))) colHeader = true;
66  if (_csvSpecs.exists(makeKey("RowName") )) rowHeader = true;
67 
68  // Skip lines, comment headers and separator
69  int skip = toInt(ConfKey(_csvSpecs, makeKey("SkipLines"), QString("0")));
70  addHistory("SkipLines", ToString(skip));
71  bool comments = IsEqual(ConfKey(_csvSpecs, makeKey("IgnoreComments"), QString("TRUE")));
72  QString separator = ConfKey(_csvSpecs, makeKey("Separator"), QString(","));
73  if (separator.isEmpty()) separator = ","; // Guarantees content
74 
75  // Apply conditions
76  csv.setComment(comments);
77  csv.setSkip(skip);
78  csv.setHeader(colHeader);
79  csv.setDelimiter(separator[0].toLatin1());
80  if (separator[0] == ' ') csv.setSkipEmptyParts();
81 
82  // Now read the file
83  FileName csvF(csvfile);
84  csvfile = csvF.expanded();
85  try {
86  csv.read(csvfile);
87  } catch (IException &ie) {
88  QString mess = "Could not read CSV file \'" + csvfile + "\'";
89  throw IException(ie, IException::User, mess, _FILEINFO_);
90  }
91 
92  // Now get the data from the CSV table
93  int ncols = csv.columns();
94  int nrows = csv.rows();
95 
96  // Initial conditions selects all rows and columns
97  int startColumn((rowHeader) ? 1 : 0), endColumn(ncols-1);
98  int startRow(0), endRow(nrows-1);
99 
100  // Update columns
101  QString colName(getValue("ColumnName"));
102  if (!colName.isEmpty()) {
103  addHistory("ColumnName", colName);
104  CSVReader::CSVAxis chead = csv.getHeader();
105  startColumn = getAxisIndex(colName, chead);
106  if (startColumn < 0) {
107  QString mess = "Column name " + colName +
108  " not found in CSV file " + csvfile;
109  throw IException(IException::User, mess, _FILEINFO_);
110  }
111  endColumn = startColumn;
112  addHistory("ColumnIndex", ToString(startColumn));
113  }
114  else if (!(getValue("ColumnIndex").isEmpty())) {
115  startColumn = ToInteger(getValue("ColumnIndex")) +
116  ((rowHeader) ? 1 : 0);
117  endColumn = startColumn;
118  addHistory("ColumnStart", ToString(startColumn));
119  addHistory("ColumnEnd", ToString(endColumn));
120  }
121 
122  // Update row indicies
123  QString rowName(getValue("RowName"));
124  if (!rowName.isEmpty()) {
125  addHistory("RowName", rowName);
126  if (!rowHeader) {
127  QString mess = "Row name given but config does not specify presence of row header!";
128  throw IException(IException::User, mess, _FILEINFO_);
129  }
130  CSVReader::CSVAxis rhead = csv.getColumn(0);
131  startRow = getAxisIndex(rowName, rhead);
132  if (startRow < 0) {
133  QString mess = "Row name " + rowName + " not found in CSV file " + csvfile;
134  throw IException(IException::User, mess, _FILEINFO_);
135  }
136  endRow = startRow;
137  addHistory("RowIndex", ToString(startRow));
138  }
139  else if (!(getValue("RowIndex").isEmpty())) {
140  startRow = ToInteger(getValue("RowIndex"));
141  if (rowHeader) startRow++;
142  endRow = startRow;
143  addHistory("RowStart", ToString(startRow));
144  addHistory("RowEnd", ToString(endRow));
145  }
146 
147  // Now ready to read all row/columns and convert to matrix
148  int drows(endRow-startRow+1);
149  int dcols(endColumn-startColumn+1);
150  HiMatrix d(drows, dcols);
151  vector<QString> errors;
152  for (int r = startRow, hr = 0 ; r <= endRow ; r++, hr++) {
153  CSVReader::CSVAxis row = csv.getRow(r);
154  for (int c = startColumn, hc = 0 ; c <= endColumn ; c++, hc++) {
155  try {
156  d[hr][hc] = ToDouble(row[c]);
157  }
158  catch (...) {
159  std::ostringstream mess;
160  mess << "Invalid real value (" << row[c] << ") in row index " << r;
161  if (!rowName.isEmpty()) mess << " (Name:" << rowName << ")";
162  mess << ", column index " << c;
163  if (!colName.isEmpty()) mess << " (Name:" << colName << ")";
164  errors.push_back(mess.str().c_str());
165  d[hr][hc] = Null;
166  }
167  }
168  }
169 
170  // Save data anyway
171  _data = d;
172 
173  // Check for errors
174  if (errors.size() > 0) {
175  //iException::Clear(); Not sure how this could ever do anything
176  std::ostringstream mess;
177  mess << "Conversion errors in CSV file " + csvfile + ": Errors: ";
178 
179  std::vector<QString>::const_iterator it = errors.begin();
180 
181  while (it != errors.end()) {
182  mess << *it << "; ";
183  it++;
184  }
185  throw IException(IException::User, mess.str().c_str(), _FILEINFO_);
186  }
187  return;
188  }
189 
190 
191  QString LoadCSV::filename() const {
192  return (getValue());
193  }
194 
195  int LoadCSV::size() const {
196  return (_data.dim1() * _data.dim2());
197  }
198 
199  bool LoadCSV::validateSize(const int &expected, const bool &throw_on_error)
200  const {
201  if (expected != size()) {
202  if (!throw_on_error) return (false);
203  ostringstream mess;
204  mess << "Invalid count (Expected: " << expected << ", Received: "
205  << size() << ") in CSV file " << getValue();
206  throw IException(IException::User, mess.str(), _FILEINFO_);
207  }
208  return (true);
209  }
210 
211  HiVector LoadCSV::getVector() const {
212  HiVector v(size(), const_cast<double *> (_data[0]));
213  return (v.copy());
214  }
215 
216  HiMatrix LoadCSV::getMatrix() const {
217  return (_data.copy());
218  }
219 
220 
221  void LoadCSV::History(HiHistory &history) const {
222  std::ostringstream mess;
223  mess << "LoadCSV(";
224  QString comma("");
225  for (unsigned int i = 0 ; i < _history.size() ; i++) {
226  mess << comma << _history[i];
227  comma = ",";
228  }
229  mess << ")";
230  history.add(mess.str().c_str());
231  return;
232  }
233 
234  void LoadCSV::init(const QString &base, const HiCalConf &conf,
235  const DbProfile &profile) {
236  _base = base;
237  _csvSpecs = ResolveKeys(base, conf, profile);
238  _history.clear();
239  return;
240  }
241 
242  void LoadCSV::addHistory(const QString &element,
243  const QString &desc) {
244  std::ostringstream mess;
245  mess << element << "[" << desc << "]";
246  _history.push_back(mess.str().c_str());
247  }
248 
249  void LoadCSV::getKeyList(const QString &base,
250  std::vector<QString> &keys) const {
251  keys.clear();
252  keys.push_back(base);
253  keys.push_back(base+"IgnoreComments");
254  keys.push_back(base+"ColumnHeader");
255  keys.push_back(base+"ColumnName");
256  keys.push_back(base+"ColumnIndex");
257  keys.push_back(base+"RowHeader");
258  keys.push_back(base+"RowName");
259  keys.push_back(base+"RowIndex");
260  keys.push_back(base+"SkipLines");
261  keys.push_back(base+"Header");
262  keys.push_back(base+"Separator");
263  return;
264  }
265 
266  DbProfile LoadCSV::ResolveKeys(const QString &base, const HiCalConf &conf,
267  const DbProfile &prof) const {
268  vector<QString> keys;
269  getKeyList(base, keys);
270  DbProfile keyprof("LoadCSV");
271  for (unsigned int i = 0 ; i < keys.size() ; i++) {
272  QString kvalue = ParsedKey(keys[i], conf, prof);
273  if (!kvalue.isEmpty()) keyprof.add(keys[i], kvalue);
274  }
275  return (keyprof);
276  }
277 
278  QString LoadCSV::ParsedKey(const QString &key, const HiCalConf &conf,
279  const DbProfile &prof) const {
280  QString value("");
281  if (prof.exists(key)) {
282  value = conf.resolve(prof(key), prof);
283  }
284  return (value);
285  }
286 
287  QString LoadCSV::makeKey(const QString &suffix) const {
288  QString key = _base + suffix;
289  return (key);
290  }
291 
292  QString LoadCSV::getValue(const QString &suffix) const {
293  QString key = makeKey(suffix);
294  QString value("");
295  if (_csvSpecs.exists(key)) value = _csvSpecs(key);
296  return (value);
297  }
298 
299  int LoadCSV::getAxisIndex(const QString &name,
300  const CSVReader::CSVAxis &header) const {
301  QString head = name.trimmed();
302  for (int i = 0 ; i < header.dim() ; i++) {
303  if (head.toLower() == header[i].toLower().trimmed()) {
304  return (i);
305  }
306  }
307  return (-1);
308  }
309 
310 } // namespace ISIS
const double Null
Value for an Isis Null pixel.
Definition: SpecialPixel.h:110
int toInt(const QString &string)
Global function to convert from a string to an integer.
Definition: IString.cpp:108
Namespace for the standard library.
bool IsEqual(const QString &v1, const QString &v2="TRUE")
Shortened string equality test.
Definition: HiCalUtil.h:272
int ToInteger(const T &value)
Helper function to convert values to Integers.
Definition: HiCalUtil.h:236
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
$Revision $Date$ $Id$
double ToDouble(const T &value)
Helper function to convert values to doubles.
Definition: HiCalUtil.h:248
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
T ConfKey(const DbProfile &conf, const QString &keyname, const T &defval, int index=0)
Find a keyword in a profile using default for non-existant keywords.
Definition: HiCalUtil.h:219
QString ToString(const T &value)
Helper function to convert values to strings.
Definition: HiCalUtil.h:260
TNT::Array2D< double > HiMatrix
2-D buffer
Definition: HiCalTypes.h:41
TNT::Array1D< double > HiVector
1-D Buffer
Definition: HiCalTypes.h:40