Skip to content

Commit

Permalink
Plot: Respect the "Order by" clause when plotting
Browse files Browse the repository at this point in the history
The tables/queries sorted by X are drawn using QCPGraph as before.

Since QCPGraph does automatically sort by X, we change to QCPCurve that
requires a third data vector to reflect the order. We get that from the
current row order.

In the case of curves, only None and Line is supported as line style.

Since the order is now important for the plot, it is automatically updated
whenever the user sorts by another column in the browsed table.

This addresses issue #821 and indirectly fixes the problem of incorrect
point->row selection link when the table is not sorted by X, reported in
issue #838.
  • Loading branch information
mgrojo committed Jan 7, 2018
1 parent b99edac commit b08960f
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 14 deletions.
2 changes: 2 additions & 0 deletions src/MainWindow.cpp
Expand Up @@ -1635,6 +1635,8 @@ void MainWindow::browseTableHeaderClicked(int logicalindex)
// select the first item in the column so the header is bold
// we might try to select the last selected item
ui->dataTable->setCurrentIndex(ui->dataTable->currentIndex().sibling(0, logicalindex));

plotDock->updatePlot(m_browseTableModel, &browseTableSettings[currentlyBrowsedTableName()]);
}

void MainWindow::resizeEvent(QResizeEvent*)
Expand Down
75 changes: 61 additions & 14 deletions src/PlotDock.cpp
Expand Up @@ -195,7 +195,7 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett
QStringList yAxisLabels;

// Clear graphs and axis labels
ui->plotWidget->clearGraphs();
ui->plotWidget->clearPlottables();
ui->plotWidget->xAxis->setLabel(QString());
ui->plotWidget->yAxis->setLabel(QString());

Expand Down Expand Up @@ -231,17 +231,16 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett
// leading 16 bit are column index
uint itemdata = item->data(0, Qt::UserRole).toUInt();
int column = itemdata >> 16;
QCPGraph* graph = ui->plotWidget->addGraph();

graph->setPen(QPen(item->backgroundColor(PlotColumnY)));
graph->setSelectable (QCP::stDataRange);
bool isSorted = true;

// prepare the data vectors for qcustomplot
// possible improvement might be a QVector subclass that directly
// access the model data, to save memory, we are copying here
QVector<double> xdata(model->rowCount()), ydata(model->rowCount());
QVector<double> xdata(model->rowCount()), ydata(model->rowCount()), tdata(model->rowCount());
for(int i = 0; i < model->rowCount(); ++i)
{
tdata[i] = i;
// convert x type axis if it's datetime
if(xtype == QVariant::DateTime)
{
Expand All @@ -258,6 +257,9 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett
xdata[i] = model->data(model->index(i, x)).toDouble();
}

if (i != 0)
isSorted &= (xdata[i-1] <= xdata[i]);

// Get the y value for this point. If the selected column is -1, i.e. the row number, just use the current row number from the loop
// instead of retrieving some value from the model.
QVariant pointdata;
Expand All @@ -271,14 +273,38 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett
else
ydata[i] = pointdata.toDouble();
}

// set some graph styles
graph->setData(xdata, ydata);
graph->setLineStyle((QCPGraph::LineStyle) ui->comboLineType->currentIndex());
// WARN: ssDot is removed
int shapeIdx = ui->comboPointShape->currentIndex();
if (shapeIdx > 0) shapeIdx += 1;
graph->setScatterStyle(QCPScatterStyle((QCPScatterStyle::ScatterShape)shapeIdx, 5));
QCPScatterStyle scatterStyle = QCPScatterStyle(static_cast<QCPScatterStyle::ScatterShape>(shapeIdx), 5);

QCPAbstractPlottable* plottable;
// When it is already sorted by x, we draw a graph.
// When it is not sorted by x, we draw a curve, so the order selected by the user in the table or in the query is
// respected. In this case the line will have loops and only None and Line is supported as line style.
// TODO: how to make the user aware of this without disturbing.
if (isSorted) {
QCPGraph* graph = ui->plotWidget->addGraph();
plottable = graph;
graph->setData(xdata, ydata, /*alreadySorted*/ true);
// set some graph styles not supported by the abstract plottable
graph->setLineStyle((QCPGraph::LineStyle) ui->comboLineType->currentIndex());
graph->setScatterStyle(scatterStyle);

} else {
QCPCurve* curve = new QCPCurve(ui->plotWidget->xAxis, ui->plotWidget->yAxis);
plottable = curve;
curve->setData(tdata, xdata, ydata, /*alreadySorted*/ true);
// set some curve styles not supported by the abstract plottable
if (ui->comboLineType->currentIndex() == QCPCurve::lsNone)
curve->setLineStyle(QCPCurve::lsNone);
else
curve->setLineStyle(QCPCurve::lsLine);
curve->setScatterStyle(scatterStyle);
}

plottable->setPen(QPen(item->backgroundColor(PlotColumnY)));
plottable->setSelectable (QCP::stDataRange);

// gather Y label column names
if(column == RowNumId)
Expand Down Expand Up @@ -497,14 +523,28 @@ void PlotDock::on_comboLineType_currentIndexChanged(int index)
{
Q_ASSERT(index >= QCPGraph::lsNone &&
index <= QCPGraph::lsImpulse);

bool hasCurves = (ui->plotWidget->plottableCount() > ui->plotWidget->graphCount());
QCPGraph::LineStyle lineStyle = (QCPGraph::LineStyle) index;
if (lineStyle > QCPGraph::lsLine && hasCurves) {
QMessageBox::warning(this, qApp->applicationName(),
tr("There are curves in this plot and the selected line style can only be applied to graphs sorted by X. "
"Either sort the table or query by X to remove curves or select one of the styles supported by curves: "
"None or Line."));
return;
}
for (int i = 0, ie = ui->plotWidget->graphCount(); i < ie; ++i)
{
QCPGraph * graph = ui->plotWidget->graph(i);
if (graph)
graph->setLineStyle(lineStyle);
}
ui->plotWidget->replot();
// We have changed the style only for graphs, but not for curves.
// If there are any in the plot, we have to update it completely in order to apply the new style
if (hasCurves)
updatePlot(m_currentPlotModel, m_currentTableSettings, false);
else
ui->plotWidget->replot();

// Save settings for this table
if(m_currentTableSettings)
Expand All @@ -525,14 +565,21 @@ void PlotDock::on_comboPointShape_currentIndexChanged(int index)
if (index > 0) index += 1;
Q_ASSERT(index >= QCPScatterStyle::ssNone &&
index < QCPScatterStyle::ssPixmap);

bool hasCurves = (ui->plotWidget->plottableCount() > ui->plotWidget->graphCount());
QCPScatterStyle::ScatterShape shape = (QCPScatterStyle::ScatterShape) index;
for (int i = 0, ie = ui->plotWidget->graphCount(); i < ie; ++i)
{
QCPGraph * graph = ui->plotWidget->graph(i);
if (graph)
graph->setScatterStyle(QCPScatterStyle(shape, 5));
}
ui->plotWidget->replot();
// We have changed the style only for graphs, but not for curves.
// If there are any in the plot, we have to update it completely in order to apply the new style
if (hasCurves)
updatePlot(m_currentPlotModel, m_currentTableSettings, false);
else
ui->plotWidget->replot();

// Save settings for this table
if(m_currentTableSettings)
Expand Down Expand Up @@ -601,9 +648,9 @@ void PlotDock::fetchAllData()
void PlotDock::selectionChanged()
{

for (QCPGraph* graph : ui->plotWidget->selectedGraphs()) {
for (QCPAbstractPlottable* plottable : ui->plotWidget->selectedPlottables()) {

for (QCPDataRange dataRange : graph->selection().dataRanges()) {
for (QCPDataRange dataRange : plottable->selection().dataRanges()) {

int index = dataRange.begin();
if (dataRange.length() != 0) {
Expand Down

0 comments on commit b08960f

Please sign in to comment.