diff --git a/src/blackgui/graphs/barchart.cpp b/src/blackgui/graphs/barchart.cpp new file mode 100644 index 000000000..6023a3930 --- /dev/null +++ b/src/blackgui/graphs/barchart.cpp @@ -0,0 +1,180 @@ +/* Copyright (C) 2019 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "barchart.h" +#include +#include +#include +#include +#include +#include +#include + +namespace BlackGui +{ + namespace Graphs + { + CBarChart::CBarChart(QWidget *parent): QwtPlot(parent) + { + this->setAutoFillBackground(true); + this->setPalette(Qt::white); + this->canvas()->setPalette(QColor("LemonChiffon")); + + this->setTitle("Bar Chart"); + // setAxisTitle(QwtPlot::yLeft, "Whatever"); + // setAxisTitle(QwtPlot::xBottom, "Whatever"); + + m_barChartItem.reset(new QwtPlotMultiBarChart("Bar Chart ")); + m_barChartItem->setLayoutPolicy(QwtPlotMultiBarChart::AutoAdjustSamples); + m_barChartItem->setSpacing(5); + m_barChartItem->setMargin(3); + m_barChartItem->attach(this); + + // this->insertLegend(new QwtLegend()); + // this->setAutoReplot(true); + // this->setOrientation(Qt::Vertical); + } + + void CBarChart::setStyle(QwtPlotMultiBarChart::ChartStyle style) + { + m_barChartItem->setStyle(style); + } + + void CBarChart::setOrientation(Qt::Orientation orientation, const QStringList &labels) + { + QwtPlot::Axis axis1, axis2; + CTextScaleDraw *scaleDraw = labels.isEmpty() ? nullptr : new CTextScaleDraw(labels); + + if (orientation == Qt::Vertical) + { + axis1 = QwtPlot::xBottom; + axis2 = QwtPlot::yLeft; + + m_barChartItem->setOrientation(Qt::Vertical); + if (scaleDraw) + { + scaleDraw->setLabelRotation(90); + scaleDraw->setLabelAlignment(Qt::AlignRight); + } + } + else + { + axis1 = QwtPlot::yLeft; + axis2 = QwtPlot::xBottom; + + m_barChartItem->setOrientation(Qt::Horizontal); + if (scaleDraw) + { + scaleDraw->setLabelRotation(0); + scaleDraw->setLabelAlignment(Qt::AlignLeft); + } + } + + setAxisScale(axis1, 0, m_barChartItem->dataSize() - 1, 1.0); + setAxisAutoScale(axis2); + + QwtScaleDraw *scaleDraw1 = axisScaleDraw(axis1); + scaleDraw1->enableComponent(QwtScaleDraw::Backbone, true); + scaleDraw1->enableComponent(QwtScaleDraw::Ticks, false); + + QwtScaleDraw *scaleDraw2 = axisScaleDraw(axis2); + scaleDraw2->enableComponent(QwtScaleDraw::Backbone, true); + scaleDraw2->enableComponent(QwtScaleDraw::Ticks, false); + + this->setAxisScaleDraw(axis1, scaleDraw ? scaleDraw : new QwtScaleDraw()); + this->setAxisScaleDraw(axis2, new QwtScaleDraw()); + + plotLayout()->setAlignCanvasToScale(axis1, true); + plotLayout()->setAlignCanvasToScale(axis2, true); + + plotLayout()->setCanvasMargin(0); + this->updateCanvasMargins(); + + this->replot(); + } + + void CBarChart::setSymbols(const QString &title, const QString &color) + { + const QStringList titles({ title }); + const QStringList colors({ color }); + this->setSymbols(titles, colors); + } + + void CBarChart::setSymbols(const QStringList &titles, const QStringList &colors) + { + Q_ASSERT_X(titles.size() > 0, Q_FUNC_INFO, "Need titles"); + Q_ASSERT_X(titles.size() == colors.size(), Q_FUNC_INFO, "Need same size"); + + int i = 0; + m_barChartItem->resetSymbolMap(); + for (const QString &color : colors) + { + QwtColumnSymbol *symbol = new QwtColumnSymbol(QwtColumnSymbol::Box); + symbol->setLineWidth(2); + symbol->setFrameStyle(QwtColumnSymbol::Raised); + symbol->setPalette(QPalette(color)); + m_barChartItem->setSymbol(i++, symbol); + } + + QList qwtTitles; + for (const QString &title : titles) + { + qwtTitles << title; + } + m_barChartItem->setBarTitles(qwtTitles); + m_barChartItem->setLegendIconSize(QSize(10, 14)); + } + + void CBarChart::setSamples1Bar(const QList &samples, const QStringList &labels, Qt::Orientation orientation) + { + QVector< QVector > series; + for (double d : samples) + { + QVector values; + values << d; + series << values; + } + + if (orientation == Qt::Vertical) + { + int w = samples.size() * 10; + if (w < 200) w = 200; + this->setMinimumWidth(w); + this->setMinimumHeight(0); + } + else + { + int h = samples.size() * 10; + if (h < 200) h = 200; + this->setMinimumHeight(h); + this->setMinimumWidth(0); + } + + m_barChartItem->setSamples(series); + this->setOrientation(orientation, labels); + } + + CTextScaleDraw::CTextScaleDraw(const QStringList &texts) : m_labels(texts) + { + this->setLabelRotation(0); + this->setLabelAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + this->setSpacing(5); + } + + QwtText CTextScaleDraw::label(double v) const + { + if (m_labels.isEmpty()) { return QString::number(v); } + const int i = qRound(v); + if (i < 0 || m_labels.size() <= i) { return QwtText("invalid"); } + return m_labels.at(i); + } + + } // ns +} // ns + diff --git a/src/blackgui/graphs/barchart.h b/src/blackgui/graphs/barchart.h new file mode 100644 index 000000000..e21836a99 --- /dev/null +++ b/src/blackgui/graphs/barchart.h @@ -0,0 +1,81 @@ +/* Copyright (C) 2019 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKGUI_GRAPH_BARCHART_H +#define BLACKGUI_GRAPH_BARCHART_H + +#include "blackgui/blackguiexport.h" + +#include +#include +#include + +#include +#include +#include + +namespace BlackGui +{ + namespace Graphs + { + /** + * For axis labels + */ + class CTextScaleDraw: public QwtScaleDraw + { + public: + //! Constructorxs + CTextScaleDraw(const QStringList &texts); + + //! Value to label + virtual QwtText label(double v) const override; + + //! Labels + void setLabels(const QStringList &labels) { m_labels = labels; } + + //! Any labels? + bool hasLabels() const { return !m_labels.isEmpty(); } + + private: + QStringList m_labels; + }; + + /** + * Bar chart, modified version of QWT examples + */ + class BLACKGUI_EXPORT CBarChart: public QwtPlot + { + public: + //! Constructor + CBarChart(QWidget * = nullptr); + + //! Style + void setStyle(QwtPlotMultiBarChart::ChartStyle style); + + //! Set number of symbols + void setSymbols(const QString &title, const QString &color); + + //! Set number of symbols + void setSymbols(const QStringList &titles, const QStringList &colors); + + //! Samples with 1 bar per sample + void setSamples1Bar(const QList &samples, const QStringList &labels, Qt::Orientation orientation); + + private: + //! Orientation + void setOrientation(Qt::Orientation, const QStringList &labels); + + QScopedPointer m_barChartItem; + }; + } // ns +} // ns + +#endif