dataload_csv.cpp
Go to the documentation of this file.
1 #include "dataload_csv.h"
2 #include <QTextStream>
3 #include <QFile>
4 #include <QMessageBox>
5 #include <QDebug>
6 #include <QSettings>
7 #include <QProgressDialog>
8 #include "selectlistdialog.h"
9 
11 {
12  _extensions.push_back( "csv");
13 }
14 
15 const QRegExp csv_separator("(\\,|\\;|\\|)");
16 
17 const std::vector<const char*> &DataLoadCSV::compatibleFileExtensions() const
18 {
19  return _extensions;
20 }
21 
22 QSize DataLoadCSV::parseHeader(QFile *file, std::vector<std::string>& ordered_names)
23 {
24  QTextStream inA(file);
25 
26  QString first_line = inA.readLine();
27  QString second_line = inA.readLine();
28 
29  QStringList firstline_items = first_line.split(csv_separator);
30 
31  int linecount = 0;
32  const int columncount = firstline_items.count();
33 
34  for (int i=0; i < firstline_items.size(); i++ )
35  {
36  // remove annoying prefix
37  QString field_name ( firstline_items[i] );
38 
39  if( field_name.isEmpty())
40  {
41  field_name = QString("_Column_%1").arg(i);
42  }
43  ordered_names.push_back( field_name.toStdString() );
44  }
45 
46  while (!inA.atEnd())
47  {
48  inA.readLine();
49  linecount++;
50  }
51 
52  QSize table_size;
53  table_size.setWidth( columncount);
54  table_size.setHeight( linecount );
55  return table_size;
56 }
57 
59 {
60  bool use_provided_configuration = false;
61 
62  if( info->plugin_config.hasChildNodes() )
63  {
64  use_provided_configuration = true;
65  xmlLoadState( info->plugin_config.firstChildElement() );
66  }
67 
68  const int TIME_INDEX_NOT_DEFINED = -2;
69 
70  int time_index = TIME_INDEX_NOT_DEFINED;
71 
72  QFile file( info->filename );
73  file.open(QFile::ReadOnly);
74 
75  std::vector<std::string> column_names;
76 
77  const QSize table_size = parseHeader( &file, column_names);
78  const int tot_lines = table_size.height() -1;
79  const int columncount = table_size.width();
80 
81  file.close();
82  file.open(QFile::ReadOnly);
83  QTextStream inB( &file );
84 
85  std::vector<PlotData*> plots_vector;
86 
87  bool interrupted = false;
88 
89  int linecount = 0;
90 
91  QProgressDialog progress_dialog;
92  progress_dialog.setLabelText("Loading... please wait");
93  progress_dialog.setWindowModality( Qt::ApplicationModal );
94  progress_dialog.setRange(0, tot_lines -1);
95  progress_dialog.setAutoClose( true );
96  progress_dialog.setAutoReset( true );
97  progress_dialog.show();
98 
99  // remove first line (header)
100  inB.readLine();
101 
102  //---- build plots_vector from header ------
103  std::deque<std::string> valid_field_names;
104 
105  for (unsigned i=0; i < column_names.size(); i++ )
106  {
107  const std::string& field_name = ( column_names[i] );
108 
109  auto it = plot_data.addNumeric(field_name);
110 
111  valid_field_names.push_back( field_name );
112  plots_vector.push_back( &(it->second) );
113 
114  if (time_index == TIME_INDEX_NOT_DEFINED && use_provided_configuration)
115  {
116  if( _default_time_axis == field_name )
117  {
118  time_index = i ;
119  }
120  }
121  }
122 
123  if( time_index == TIME_INDEX_NOT_DEFINED && !use_provided_configuration)
124  {
125  valid_field_names.push_front( "INDEX (auto-generated)" );
126 
127  SelectFromListDialog* dialog = new SelectFromListDialog( valid_field_names );
128  dialog->setWindowTitle("Select the time axis");
129  int res = dialog->exec();
130 
131  if (res == QDialog::Rejected )
132  {
133  return false;
134  }
135 
136  const int selected_item = dialog->getSelectedRowNumber().at(0);
137  if( selected_item > 0)
138  {
139  for (unsigned i=0; i< column_names.size(); i++)
140  {
141  if( column_names[i] == valid_field_names[selected_item ] )
142  {
143  _default_time_axis = column_names[i];
144  time_index = selected_item -1;
145  break;
146  }
147  }
148  }
149  }
150 
151  //-----------------
152  double prev_time = - std::numeric_limits<double>::max();
153  bool monotonic_warning = false;
154 
155  while (!inB.atEnd() )
156  {
157  QString line = inB.readLine();
158 
159  QStringList string_items = line.split(csv_separator);
160  if( string_items.size() != columncount)
161  {
162  continue;
163  }
164  double t = linecount;
165 
166  if( time_index >= 0)
167  {
168  bool is_number = false;
169  t = string_items[ time_index ].toDouble(&is_number);
170 
171  if( !is_number)
172  {
173  QMessageBox::StandardButton reply;
174  reply = QMessageBox::warning(0, tr("Error reading file"),
175  tr("One of the timestamps is not a valid number. Abort\n") );
176 
177  return false;
178  }
179  if( t < prev_time )
180  {
181  QMessageBox::StandardButton reply;
182  reply = QMessageBox::warning(0, tr("Error reading file"),
183  tr("Selected time in not strictly monotonic. Loading will be aborted\n") );
184 
185  return false;
186  }
187  else if (t == prev_time)
188  {
189  monotonic_warning = true;
190  }
191 
192  prev_time = t;
193  }
194 
195  int index = 0;
196  for (int i=0; i < string_items.size(); i++ )
197  {
198  bool is_number = false;
199  double y = string_items[i].toDouble(&is_number);
200  if( is_number )
201  {
202  PlotData::Point point( t,y );
203  plots_vector[index]->pushBack( point );
204  }
205  index++;
206  }
207 
208  if(linecount++ %100 == 0)
209  {
210  progress_dialog.setValue( linecount );
211  QApplication::processEvents();
212  if( progress_dialog.wasCanceled() ) {
213  interrupted = true;
214  break;
215  }
216  }
217  }
218  file.close();
219 
220  if(interrupted)
221  {
222  progress_dialog.cancel();
223  plot_data.numeric.clear();
224  }
225 
226  if( monotonic_warning )
227  {
228  QString message = "Two consecutive samples had the same X value (i.e. time).\n"
229  "Since PlotJuggler makes the assumption that timeseries are strictly monotonic, you "
230  "might experience undefined behaviours.\n\n"
231  "You have been warned...";
232  QMessageBox::warning(0, tr("Warning"), message );
233  }
234 
235  return true;
236 }
237 
239 {
240 
241 }
242 
243 bool DataLoadCSV::xmlSaveState(QDomDocument &doc, QDomElement &parent_element) const
244 {
245  QDomElement elem = doc.createElement("default");
246  elem.setAttribute("time_axis", _default_time_axis.c_str() );
247 
248  parent_element.appendChild( elem );
249  return true;
250 }
251 
252 bool DataLoadCSV::xmlLoadState(const QDomElement &parent_element)
253 {
254  QDomElement elem = parent_element.firstChildElement( "default" );
255  if( !elem.isNull() )
256  {
257  if( elem.hasAttribute("time_axis") )
258  {
259  _default_time_axis = elem.attribute("time_axis").toStdString();
260  return true;
261  }
262  }
263  return false;
264 }
virtual bool xmlSaveState(QDomDocument &doc, QDomElement &parent_element) const override
std::unordered_map< std::string, PlotData > numeric
Definition: plotdata.h:144
const QRegExp csv_separator("(\\,|\\;|\\|)")
QString filename
std::vector< const char * > _extensions
Definition: dataload_csv.h:33
TFSIMD_FORCE_INLINE const tfScalar & y() const
virtual ~DataLoadCSV()
std::vector< int > getSelectedRowNumber() const
QSize parseHeader(QFile *file, std::vector< std::string > &ordered_names)
virtual bool readDataFromFile(FileLoadInfo *fileload_info, PlotDataMapRef &destination) override
virtual bool xmlLoadState(const QDomElement &parent_element) override
std::unordered_map< std::string, PlotData >::iterator addNumeric(const std::string &name)
Definition: plotdata.h:147
std::string _default_time_axis
Definition: dataload_csv.h:35
virtual const std::vector< const char * > & compatibleFileExtensions() const override
int i
QDomDocument plugin_config


plotjuggler
Author(s): Davide Faconti
autogenerated on Sat Jul 6 2019 03:44:17