Stacked or grouped bars and plot legend

Two new options added to the context menu of the plot:

- Stacked bars: switches between stacked bars or grouped bars. The former
overlapped layout is avoided since it doesn't make much sense.

- Show legend: toggles the display of a plot legend with a translucent
background. Possible future improvement is dragging the legend with the
mouse.
This commit is contained in:
mgrojo
2018-01-21 17:00:45 +01:00
parent 175407645b
commit c5ec23e92e
2 changed files with 103 additions and 30 deletions

View File

@@ -9,7 +9,9 @@ PlotDock::PlotDock(QWidget* parent)
: QDialog(parent),
ui(new Ui::PlotDock),
m_currentPlotModel(nullptr),
m_currentTableSettings(nullptr)
m_currentTableSettings(nullptr),
m_showLegend(false),
m_stackedBars(false)
{
ui->setupUi(this);
@@ -50,6 +52,18 @@ PlotDock::PlotDock(QWidget* parent)
copy();
});
QAction* showLegendAction = new QAction(tr("Show legend"), m_contextMenu);
showLegendAction->setCheckable(true);
m_contextMenu->addAction(showLegendAction);
connect(showLegendAction, SIGNAL(toggled(bool)), this, SLOT(toggleLegendVisible(bool)));
QAction* stackedBarsAction = new QAction(tr("Stacked bars"), m_contextMenu);
stackedBarsAction->setCheckable(true);
m_contextMenu->addAction(stackedBarsAction);
connect(stackedBarsAction, SIGNAL(toggled(bool)), this, SLOT(toggleStackedBars(bool)));
connect(ui->plotWidget, &QTableView::customContextMenuRequested,
[=](const QPoint& pos) {
// Show menu
@@ -225,6 +239,8 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett
int x = xitem->data(PlotColumnField, Qt::UserRole).toInt();
int xtype = xitem->data(PlotColumnType, Qt::UserRole).toInt();
ui->plotWidget->xAxis->setTickLabelRotation(0);
// check if we have a x axis with datetime data
switch (xtype) {
case QVariant::Date: {
@@ -247,6 +263,8 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett
break;
}
case QVariant::String: {
// Ticker is set when we have got the labels
ui->plotWidget->xAxis->setTickLabelRotation(60);
break;
}
default: {
@@ -334,6 +352,7 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett
QCPScatterStyle scatterStyle = QCPScatterStyle(static_cast<QCPScatterStyle::ScatterShape>(shapeIdx), 5);
QCPAbstractPlottable* plottable;
// When the X type is String, we draw a bar chart.
// 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.
@@ -342,38 +361,39 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett
QCPBars* bars = new QCPBars(ui->plotWidget->xAxis, ui->plotWidget->yAxis);
plottable = bars;
bars->setData(xdata, ydata);
QColor brush = item->backgroundColor(PlotColumnY);
if (ui->plotWidget->plottableCount() > 1)
brush.setAlpha(124);
bars->setBrush(brush);
QSharedPointer<QCPAxisTickerText> ticker(new QCPAxisTickerText);
ticker->addTicks(xdata, labels);
ui->plotWidget->xAxis->setTicker(ticker);
ui->plotWidget->xAxis->setTickLabelRotation(60);
} else 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);
ui->plotWidget->xAxis->setTickLabelRotation(0);
// Set ticker once
if (ui->plotWidget->plottableCount() == 1) {
QSharedPointer<QCPAxisTickerText> ticker(new QCPAxisTickerText);
ticker->addTicks(xdata, labels);
ui->plotWidget->xAxis->setTicker(ticker);
}
QColor color = item->backgroundColor(PlotColumnY);
bars->setBrush(color);
plottable->setPen(QPen(color.darker(150)));
} 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);
ui->plotWidget->xAxis->setTickLabelRotation(0);
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->setPen(QPen(item->backgroundColor(PlotColumnY)));
plottable->setSelectable(QCP::stDataRange);
plottable->setName(item->text(PlotColumnField));
// gather Y label column names
if(column == RowNumId)
@@ -384,6 +404,9 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett
}
ui->plotWidget->rescaleAxes(true);
ui->plotWidget->legend->setVisible(m_showLegend);
// Legend with slightly transparent background brush:
ui->plotWidget->legend->setBrush(QColor(255, 255, 255, 150));
// set axis labels
if(x == RowNumId)
@@ -392,6 +415,8 @@ void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* sett
ui->plotWidget->xAxis->setLabel(model->headerData(x, Qt::Horizontal).toString());
ui->plotWidget->yAxis->setLabel(yAxisLabels.join("|"));
}
adjustBars();
ui->plotWidget->replot();
// Warn user if not all data has been fetched and hint about the button for loading all the data
@@ -789,3 +814,47 @@ void PlotDock::copy()
{
QApplication::clipboard()->setPixmap(ui->plotWidget->toPixmap());
}
void PlotDock::toggleLegendVisible(bool visible)
{
m_showLegend = visible;
ui->plotWidget->legend->setVisible(m_showLegend);
ui->plotWidget->replot();
}
// Stack or group bars and set the appropiate bar width (since it is not automatically done by QCustomPlot).
void PlotDock::adjustBars()
{
const double padding = 0.15;
const double groupedWidth = ui->plotWidget->plottableCount()? 1.0 / ui->plotWidget->plottableCount() : 0.0;
QCPBars* previousBar = nullptr;
QCPBarsGroup* barsGroup = m_stackedBars? nullptr : new QCPBarsGroup(ui->plotWidget);
for (int i = 0, ie = ui->plotWidget->plottableCount(); i < ie; ++i)
{
QCPBars* bar = qobject_cast<QCPBars*>(ui->plotWidget->plottable(i));
if (bar) {
if (m_stackedBars) {
// Ungroup if grouped
bar->setBarsGroup(nullptr);
if (previousBar)
bar->moveAbove(previousBar);
// Set width to ocuppy the full coordinate space, less padding
bar->setWidth(1.0 - padding);
} else {
// Unstack if stacked
bar->moveAbove(nullptr);
bar->setBarsGroup(barsGroup);
// Set width to a plot coordinate width, less padding
bar->setWidth(groupedWidth - padding);
}
previousBar = bar;
}
}
}
void PlotDock::toggleStackedBars(bool stacked)
{
m_stackedBars = stacked;
adjustBars();
ui->plotWidget->replot();
}

View File

@@ -85,6 +85,8 @@ private:
SqliteTableModel* m_currentPlotModel;
BrowseDataTableSettings* m_currentTableSettings;
QMenu* m_contextMenu;
bool m_showLegend;
bool m_stackedBars;
/*!
* \brief guessdatatype try to parse the first 10 rows and decide the datatype
@@ -93,6 +95,7 @@ private:
* \return the guessed datatype
*/
QVariant::Type guessDataType(SqliteTableModel* model, int column);
void adjustBars();
private slots:
void on_treePlotColumns_itemChanged(QTreeWidgetItem* item, int column);
@@ -104,7 +107,8 @@ private slots:
void mousePress();
void mouseWheel();
void copy();
void toggleLegendVisible(bool visible);
void toggleStackedBars(bool stacked);
};
#endif