Commit cd785b3d authored by pixhawk's avatar pixhawk

Almost finished flexible data view, only minor improvements needed

parent 263cb7c1
......@@ -34,6 +34,8 @@ QGCDataPlot2D::QGCDataPlot2D(QWidget *parent) :
connect(ui->reloadButton, SIGNAL(clicked()), this, SLOT(reloadFile()));
connect(ui->savePlotButton, SIGNAL(clicked()), this, SLOT(savePlot()));
connect(ui->printButton, SIGNAL(clicked()), this, SLOT(print()));
connect(ui->legendCheckBox, SIGNAL(clicked(bool)), plot, SLOT(showLegend(bool)));
connect(ui->style, SIGNAL(currentIndexChanged(QString)), plot, SLOT(setStyleText(QString)));
}
void QGCDataPlot2D::reloadFile()
......@@ -214,6 +216,24 @@ void QGCDataPlot2D::loadRawLog(QString file, QString xAxisName, QString yAxisFil
loadCsvLog(logFile->fileName(), xAxisName, yAxisFilter);
}
/**
* This function loads a CSV file into the plot. It tries to assign the dimension names
* based on the first data row and tries to guess the separator char.
*
* @param file Name of the file to open
* @param xAxisName Optional paramater. If given, the x axis dimension will be selected to match this string
* @param yAxisFilter Optional parameter. If given, only data dimension names present in the filter string will be
* plotted
*
* @code
*
* QString file = "/home/user/datalog.txt"; // With header: x<tab>y<tab>z
* QString xAxis = "x";
* QString yAxis = "z";
*
* // Plotted result will be x vs z with y ignored.
* @endcode
*/
void QGCDataPlot2D::loadCsvLog(QString file, QString xAxisName, QString yAxisFilter)
{
if (logFile != NULL)
......@@ -235,9 +255,44 @@ void QGCDataPlot2D::loadCsvLog(QString file, QString xAxisName, QString yAxisFil
// First line is header
QString header = in.readLine();
QString separator = "\t";
qDebug() << "READING CSV:" << header;
bool charRead = false;
QString separator = "";
QList<QChar> sepCandidates;
sepCandidates << '\t';
sepCandidates << ',';
sepCandidates << ';';
sepCandidates << ' ';
sepCandidates << '~';
sepCandidates << '|';
// Iterate until separator is found
// or full header is parsed
for (int i = 0; i < header.length(); i++)
{
if (sepCandidates.contains(header.at(i)))
{
// Separator found
if (charRead)
{
separator += header[i];
}
}
else
{
// Char found
charRead = true;
// If the separator is not empty, this char
// has been read after a separator, so detection
// is now complete
if (separator != "") break;
}
}
QString out = separator;
out.replace("\t", "<tab>");
ui->filenameLabel->setText(file.split("/").last().split("\\").last()+" Separator: \""+out+"\"");
//qDebug() << "READING CSV:" << header;
// Clear plot
plot->removeData();
......@@ -245,7 +300,7 @@ void QGCDataPlot2D::loadCsvLog(QString file, QString xAxisName, QString yAxisFil
QVector<double> xValues;
QMap<QString, QVector<double>* > yValues;
QStringList curveNames = header.split(separator);
QStringList curveNames = header.split(separator, QString::SkipEmptyParts);
QString curveName;
// Clear UI elements
......@@ -254,73 +309,89 @@ void QGCDataPlot2D::loadCsvLog(QString file, QString xAxisName, QString yAxisFil
int curveNameIndex = 0;
int xValueIndex = curveNames.indexOf(xAxisName);
if (xValueIndex < 0 || xValueIndex > (curveNames.size() - 1)) xValueIndex = 0;
//int xValueIndex = curveNames.indexOf(xAxisName);
QString xAxisFilter;
if (xAxisName == "")
{
xAxisFilter = curveNames.first();
}
else
{
xAxisFilter = xAxisName;
}
foreach(curveName, curveNames)
{
if (curveNameIndex != xValueIndex)
ui->xAxis->addItem(curveName);
if (curveName != xAxisFilter)
{
// FIXME Add check for y value filter
if ((ui->yAxis->text() == "") && yValues.contains(curveName))
if ((yAxisFilter == "") || yAxisFilter.contains(curveName))
{
yValues.insert(curveName, new QVector<double>());
ui->xAxis->addItem(curveName);
// Add separator starting with second item
if (curveNameIndex > 0 && curveNameIndex < curveNames.size())
{
ui->yAxis->setText(ui->yAxis->text()+"|");
}
ui->yAxis->setText(ui->yAxis->text()+curveName);
curveNameIndex++;
}
}
curveNameIndex++;
}
// Select current axis in UI
ui->xAxis->setCurrentIndex(curveNames.indexOf(xAxisFilter));
// Read data
double x,y;
while (!in.atEnd()) {
while (!in.atEnd())
{
QString line = in.readLine();
QStringList values = line.split(separator);
QStringList values = line.split(separator, QString::SkipEmptyParts);
bool okx;
x = values.at(xValueIndex).toDouble(&okx);
if(okx)
foreach(curveName, curveNames)
{
// Append X value
xValues.append(x);
QString yStr;
bool oky;
bool okx;
if (curveName == xAxisFilter)
{
// X AXIS HANDLING
int yCount = 0;
foreach(yStr, values)
// Take this value as x if it is selected
x = values.at(curveNames.indexOf(curveName)).toDouble(&okx);
xValues.append(x - 1270125570000LL);
qDebug() << "x" << x - 1270125570000LL;
}
else
{
// We have already x, so only handle
// true y values
if (yCount != xValueIndex && yCount < curveNames.size())
// Y AXIS HANDLING
if(yAxisFilter == "" || yAxisFilter.contains(curveName))
{
y = yStr.toDouble(&oky);
// Append one of the Y values
yValues.value(curveNames.at(yCount))->append(y);
// Only append y values where a valid x value is present
if (yValues.value(curveName)->size() == xValues.size() - 1)
{
bool oky;
int curveNameIndex = curveNames.indexOf(curveName);
if (values.size() > curveNameIndex)
{
y = values.at(curveNameIndex).toDouble(&oky);
yValues.value(curveName)->append(y);
}
}
}
yCount++;
}
}
}
QVector<double>* yCurve;
int yCurveIndex = 0;
foreach(yCurve, yValues)
// Add data array of each curve to the plot at once (fast)
// Iterates through all x-y curve combinations
for (int i = 0; i < yValues.size(); i++)
{
plot->appendData(yValues.keys().at(yCurveIndex), xValues.data(), yCurve->data(), xValues.size());
yCurveIndex++;
plot->appendData(yValues.keys().at(i), xValues.data(), yValues.values().at(i)->data(), xValues.size());
}
}
......@@ -339,7 +410,7 @@ void QGCDataPlot2D::loadCsvLog(QString file, QString xAxisName, QString yAxisFil
* the match of the regression.
* @return 1 on success, 0 on failure (e.g. because of infinite slope)
*/
int QGCDataPlot2D::linearRegression(double *x,double *y,int n,double *a,double *b,double *r)
int QGCDataPlot2D::linearRegression(double* x,double* y,int n,double* a,double* b,double* r)
{
int i;
double sumx=0,sumy=0,sumx2=0,sumy2=0,sumxy=0;
......
......@@ -6,14 +6,14 @@
<rect>
<x>0</x>
<y>0</y>
<width>736</width>
<width>807</width>
<height>308</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="2,10,2,0,0,0,0,0,0,0,0,0">
<layout class="QGridLayout" name="gridLayout" columnstretch="2,10,2,0,0,0,0,0,0,0,0,0,0">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
......@@ -43,24 +43,74 @@
</item>
<item>
<property name="text">
<string>Dots</string>
<string>Only crosses</string>
</property>
</item>
<item>
<property name="text">
<string>Lines</string>
<string>Only circles</string>
</property>
</item>
<item>
<property name="text">
<string>Only dots</string>
</property>
</item>
<item>
<property name="text">
<string>Lines and crosses</string>
</property>
</item>
<item>
<property name="text">
<string>Lines and circles</string>
</property>
</item>
<item>
<property name="text">
<string>Lines and dots</string>
</property>
</item>
<item>
<property name="text">
<string>Dotted lines and crosses</string>
</property>
</item>
<item>
<property name="text">
<string>Dotted lines and circles</string>
</property>
</item>
<item>
<property name="text">
<string>Dotted lines and dots</string>
</property>
</item>
<item>
<property name="text">
<string>Dashed lines and crosses</string>
</property>
</item>
<item>
<property name="text">
<string>Dashed lines and circles</string>
</property>
</item>
<item>
<property name="text">
<string>Dashed lines and dots</string>
</property>
</item>
</widget>
</item>
<item row="0" column="8">
<item row="0" column="9">
<widget class="QPushButton" name="reloadButton">
<property name="text">
<string>Reload</string>
</property>
</widget>
</item>
<item row="0" column="9">
<item row="0" column="10">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
......@@ -73,14 +123,14 @@
</property>
</spacer>
</item>
<item row="0" column="10">
<item row="0" column="11">
<widget class="QPushButton" name="savePlotButton">
<property name="text">
<string>Save Plot</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="12">
<item row="1" column="0" colspan="13">
<widget class="QFrame" name="plotFrame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
......@@ -123,7 +173,7 @@
</property>
</widget>
</item>
<item row="2" column="9">
<item row="2" column="10">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
......@@ -136,21 +186,21 @@
</property>
</spacer>
</item>
<item row="0" column="11">
<item row="0" column="12">
<widget class="QPushButton" name="printButton">
<property name="text">
<string>Print</string>
</property>
</widget>
</item>
<item row="2" column="11">
<item row="2" column="12">
<widget class="QPushButton" name="saveCsvButton">
<property name="text">
<string>Save CSV</string>
</property>
</widget>
</item>
<item row="2" column="8">
<item row="2" column="9">
<widget class="QPushButton" name="selectFileButton">
<property name="text">
<string>Select file</string>
......@@ -164,6 +214,13 @@
</property>
</widget>
</item>
<item row="0" column="8">
<widget class="QCheckBox" name="legendCheckBox">
<property name="text">
<string>Legend</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
......
......@@ -62,6 +62,7 @@ IncrementalPlot::IncrementalPlot(QWidget *parent):
setFrameStyle(QFrame::NoFrame);
setLineWidth(0);
setStyleText("solid crosses");
setCanvasLineWidth(2);
plotLayout()->setAlignCanvasToScales(true);
......@@ -84,6 +85,7 @@ IncrementalPlot::IncrementalPlot(QWidget *parent):
zoomer->setRubberBandPen(QPen(Qt::red, 2, Qt::DotLine));
zoomer->setTrackerPen(QPen(Qt::red));
//zoomer->setZoomBase(QwtDoubleRect());
legend = NULL;
colors = QList<QColor>();
nextColor = 0;
......@@ -117,6 +119,75 @@ IncrementalPlot::~IncrementalPlot()
}
void IncrementalPlot::showLegend(bool show)
{
if (show)
{
if (legend == NULL)
{
legend = new QwtLegend;
legend->setFrameStyle(QFrame::Box);
}
insertLegend(legend, QwtPlot::RightLegend);
}
else
{
delete legend;
legend = NULL;
}
replot();
}
/**
* Set datapoint and line style. This interface is intented
* to be directly connected to the UI and allows to parse
* human-readable, textual descriptions into plot specs.
*
* Data points: Either "circles", "crosses" or the default "dots"
* Lines: Either "dotted", ("solid"/"line") or no lines if not used
*
* No special formatting is needed, as long as the keywords are contained
* in the string. Lower/uppercase is ignored as well.
*
* @param style Formatting string for line/data point style
*/
void IncrementalPlot::setStyleText(QString style)
{
foreach (QwtPlotCurve* curve, d_curve)
{
// Style of datapoints
if (style.toLower().contains("circles"))
{
curve->setSymbol(QwtSymbol(QwtSymbol::Ellipse,
QBrush(curve->pen().color()), curve->pen(), QSize(5, 5)) );
}
else if (style.toLower().contains("crosses"))
{
curve->setSymbol(QwtSymbol(QwtSymbol::XCross,
QBrush(curve->pen().color()), curve->pen(), QSize(5, 5)) );
}
else // Always show dots (style.toLower().contains("dots"))
{
curve->setSymbol(QwtSymbol(QwtSymbol::Rect,
QBrush(curve->pen().color()), curve->pen(), QSize(1, 1)) );
}
// Style of lines
if (style.toLower().contains("dotted"))
{
curve->setStyle(QwtPlotCurve::Dots);
}
else if (style.toLower().contains("line") || style.toLower().contains("solid"))
{
curve->setStyle(QwtPlotCurve::Lines);
}
else
{
curve->setStyle(QwtPlotCurve::NoCurve);
}
}
}
void IncrementalPlot::resetScaling()
{
xmin = 0;
......@@ -233,11 +304,11 @@ void IncrementalPlot::appendData(QString key, double *x, double *y, int size)
canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
// FIXME Check if here all curves should be drawn
// QwtPlotCurve* plotCurve;
// foreach(plotCurve, d_curve)
// {
// plotCurve->draw(0, curve->dataSize()-1);
// }
// QwtPlotCurve* plotCurve;
// foreach(plotCurve, d_curve)
// {
// plotCurve->draw(0, curve->dataSize()-1);
// }
curve->draw(curve->dataSize() - size, curve->dataSize() - 1);
canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, cacheMode);
......
......@@ -4,6 +4,7 @@
#include <QTimer>
#include <qwt_array.h>
#include <qwt_plot.h>
#include <qwt_legend.h>
#include <QMap>
#include "ScrollZoomer.h"
......@@ -38,12 +39,6 @@ public:
IncrementalPlot(QWidget *parent = NULL);
virtual ~IncrementalPlot();
void appendData(QString key, double x, double y);
void appendData(QString key, double *x, double *y, int size);
void resetScaling();
void removeData();
/** @brief Get color map of this plot */
QList<QColor> IncrementalPlot::getColorMap();
/** @brief Get next color of color map */
......@@ -51,10 +46,22 @@ public:
/** @brief Get color for curve id */
QColor IncrementalPlot::getColorForCurve(QString id);
public slots:
void appendData(QString key, double x, double y);
void appendData(QString key, double *x, double *y, int size);
void resetScaling();
void removeData();
/** @brief Show the plot legend */
void showLegend(bool show);
/** @brief Set new plot style */
void setStyleText(QString style);
protected:
QList<QColor> colors;
int nextColor;
ScrollZoomer* zoomer;
QwtLegend* legend;
double xmin;
double xmax;
double ymin;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment