dataload_csv.cpp
Go to the documentation of this file.
00001 #include "dataload_csv.h"
00002 #include <QTextStream>
00003 #include <QFile>
00004 #include <QMessageBox>
00005 #include <QDebug>
00006 #include <QSettings>
00007 #include <QProgressDialog>
00008 #include "selectlistdialog.h"
00009 
00010 DataLoadCSV::DataLoadCSV()
00011 {
00012     _extensions.push_back( "csv");
00013 }
00014 
00015 const QRegExp csv_separator("(\\,|\\;|\\|)");
00016 
00017 const std::vector<const char*> &DataLoadCSV::compatibleFileExtensions() const
00018 {
00019     return _extensions;
00020 }
00021 
00022 QSize DataLoadCSV::parseHeader(QFile *file, std::vector<std::string>& ordered_names)
00023 {
00024     QTextStream inA(file);
00025 
00026     QString first_line = inA.readLine();
00027     QString second_line = inA.readLine();
00028 
00029     QStringList firstline_items = first_line.split(csv_separator);
00030 
00031     int linecount = 0;
00032     const int columncount = firstline_items.count();
00033 
00034     for (int i=0; i < firstline_items.size(); i++ )
00035     {
00036         // remove annoying prefix
00037         QString field_name ( firstline_items[i] );
00038 
00039         if( field_name.isEmpty())
00040         {
00041             field_name = QString("_Column_%1").arg(i);
00042         }
00043         ordered_names.push_back( field_name.toStdString() );
00044     }
00045 
00046     while (!inA.atEnd())
00047     {
00048         inA.readLine();
00049         linecount++;
00050     }
00051 
00052     QSize table_size;
00053     table_size.setWidth( columncount);
00054     table_size.setHeight( linecount );
00055     return table_size;
00056 }
00057 
00058 bool DataLoadCSV::readDataFromFile(FileLoadInfo* info, PlotDataMapRef& plot_data)
00059 {
00060     bool use_provided_configuration = false;
00061 
00062     if( info->plugin_config.hasChildNodes() )
00063     {
00064         use_provided_configuration = true;
00065         xmlLoadState( info->plugin_config.firstChildElement() );
00066     }
00067 
00068     const int TIME_INDEX_NOT_DEFINED = -2;
00069 
00070     int time_index = TIME_INDEX_NOT_DEFINED;
00071 
00072     QFile file( info->filename );
00073     file.open(QFile::ReadOnly);
00074 
00075     std::vector<std::string> column_names;
00076 
00077     const QSize table_size = parseHeader( &file, column_names);
00078     const int tot_lines   = table_size.height() -1;
00079     const int columncount = table_size.width();
00080 
00081     file.close();
00082     file.open(QFile::ReadOnly);
00083     QTextStream inB( &file );
00084 
00085     std::vector<PlotData*> plots_vector;
00086 
00087     bool interrupted = false;
00088 
00089     int linecount = 0;
00090 
00091     QProgressDialog progress_dialog;
00092     progress_dialog.setLabelText("Loading... please wait");
00093     progress_dialog.setWindowModality( Qt::ApplicationModal );
00094     progress_dialog.setRange(0, tot_lines -1);
00095     progress_dialog.setAutoClose( true );
00096     progress_dialog.setAutoReset( true );
00097     progress_dialog.show();
00098 
00099     // remove first line (header)
00100     inB.readLine();
00101 
00102     //---- build plots_vector from header  ------
00103     std::deque<std::string> valid_field_names;
00104 
00105     for (unsigned i=0; i < column_names.size(); i++ )
00106     {
00107         const std::string& field_name = ( column_names[i] );
00108 
00109         auto it = plot_data.addNumeric(field_name);
00110 
00111         valid_field_names.push_back( field_name );
00112         plots_vector.push_back( &(it->second) );
00113 
00114         if (time_index == TIME_INDEX_NOT_DEFINED && use_provided_configuration)
00115         {
00116             if( _default_time_axis == field_name )
00117             {
00118                 time_index = i ;
00119             }
00120         }
00121     }
00122 
00123     if( time_index == TIME_INDEX_NOT_DEFINED && !use_provided_configuration)
00124     {
00125         valid_field_names.push_front( "INDEX (auto-generated)" );
00126 
00127         SelectFromListDialog* dialog = new SelectFromListDialog( valid_field_names );
00128         dialog->setWindowTitle("Select the time axis");
00129         int res = dialog->exec();
00130 
00131         if (res == QDialog::Rejected )
00132         {
00133             return false;
00134         }
00135 
00136         const int selected_item = dialog->getSelectedRowNumber().at(0);
00137         if( selected_item > 0)
00138         {
00139           for (unsigned i=0; i< column_names.size(); i++)
00140           {
00141             if( column_names[i] == valid_field_names[selected_item ] )
00142             {
00143               _default_time_axis = column_names[i];
00144               time_index = selected_item -1;
00145               break;
00146             }
00147           }
00148         }
00149     }
00150 
00151     //-----------------
00152     double prev_time = - std::numeric_limits<double>::max();
00153     bool monotonic_warning = false;
00154 
00155     while (!inB.atEnd() )
00156     {
00157         QString line = inB.readLine();
00158 
00159         QStringList string_items = line.split(csv_separator);
00160         if( string_items.size() != columncount)
00161         {
00162           continue;
00163         }
00164         double t = linecount;
00165 
00166         if( time_index >= 0)
00167         {
00168             bool is_number = false;
00169             t = string_items[ time_index ].toDouble(&is_number);
00170 
00171             if( !is_number)
00172             {
00173                 QMessageBox::StandardButton reply;
00174                 reply = QMessageBox::warning(0, tr("Error reading file"),
00175                                               tr("One of the timestamps is not a valid number. Abort\n") );
00176 
00177                 return false;
00178             }
00179             if( t < prev_time )
00180             {
00181                 QMessageBox::StandardButton reply;
00182                 reply = QMessageBox::warning(0, tr("Error reading file"),
00183                                               tr("Selected time in not strictly monotonic. Loading will be aborted\n") );
00184 
00185                 return false;
00186             }
00187             else if (t == prev_time)
00188             {
00189                 monotonic_warning = true;
00190             }
00191 
00192             prev_time = t;
00193         }
00194 
00195         int index = 0;
00196         for (int i=0; i < string_items.size(); i++ )
00197         {
00198             bool is_number = false;
00199             double y = string_items[i].toDouble(&is_number);
00200             if( is_number )
00201             {
00202                 PlotData::Point point( t,y );
00203                 plots_vector[index]->pushBack( point );
00204             }
00205             index++;
00206         }
00207 
00208         if(linecount++ %100 == 0)
00209         {
00210             progress_dialog.setValue( linecount );
00211             QApplication::processEvents();
00212             if( progress_dialog.wasCanceled() ) {
00213                 interrupted = true;
00214                 break;
00215             }
00216         }
00217     }
00218     file.close();
00219 
00220     if(interrupted)
00221     {
00222         progress_dialog.cancel();
00223         plot_data.numeric.clear();
00224     }
00225 
00226     if( monotonic_warning )
00227     {
00228         QString message = "Two consecutive samples had the same X value (i.e. time).\n"
00229                           "Since PlotJuggler makes the assumption that timeseries are strictly monotonic, you "
00230                           "might experience undefined behaviours.\n\n"
00231                           "You have been warned...";
00232         QMessageBox::warning(0, tr("Warning"), message );
00233     }
00234 
00235     return true;
00236 }
00237 
00238 DataLoadCSV::~DataLoadCSV()
00239 {
00240 
00241 }
00242 
00243 bool DataLoadCSV::xmlSaveState(QDomDocument &doc, QDomElement &parent_element) const
00244 {
00245     QDomElement elem = doc.createElement("default");
00246     elem.setAttribute("time_axis", _default_time_axis.c_str() );
00247 
00248     parent_element.appendChild( elem );
00249     return true;
00250 }
00251 
00252 bool DataLoadCSV::xmlLoadState(const QDomElement &parent_element)
00253 {
00254     QDomElement elem = parent_element.firstChildElement( "default" );
00255     if( !elem.isNull()    )
00256     {
00257         if( elem.hasAttribute("time_axis") )
00258         {
00259             _default_time_axis = elem.attribute("time_axis").toStdString();
00260             return true;
00261         }
00262     }
00263     return false;
00264 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Wed Jul 3 2019 19:28:04