nav-left cat-right
cat-right
Matthias Pospiech > Programming > C++ > Qt > qwt spectrogramm plot with data arrays

qwt spectrogramm plot with data arrays

The following is a class using the qwt libary to generate a spectrogramm and/or a contour plot. In contrast to the example shipped with qwt it uses a data array instead of a hard coded function. QSpectrogramPlot.h
#ifndef QSPECTROGRAMPLOT_H_
#define QSPECTROGRAMPLOT_H_
 
#include "ExtFunctions.h"
 
#include <QtGui/QHBoxLayout>
#include <QtGui/QWidget>
 
#include <qwt_plot.h>
#include <qwt_color_map.h>
#include <qwt_plot_spectrogram.h>
#include <qwt_scale_widget.h>
#include <qwt_scale_draw.h>
#include <qwt_plot_zoomer.h>
#include <qwt_plot_panner.h>
#include <qwt_plot_layout.h>
 
 
/* -------------------------------------------
 * SpectrogramData derived from QwtRasterData
 * Saves the values for the plot
 * -------------------------------------------
*/
 
class SpectrogramData: public QwtRasterData
{
private:
	double * m_Array;
	double m_minValue;
	double m_maxValue;
 
	struct structMinMax{
		double min;
		double max;
	};
	structMinMax m_RangeX;
	structMinMax m_RangeY;
	struct structXY{
		double x;
		double y;
	};
	structXY m_DataSize;
	structXY m_RealToArray;
 
public:
	// Constructor giving back the QwtRasterData Constructor
    SpectrogramData(): QwtRasterData()
    {
		m_Array = NULL;
    }
 
    ~SpectrogramData()
    {
		if (m_Array != NULL)
			delete [] m_Array;
    }
 
    virtual QwtRasterData *copy() const
    {
        SpectrogramData *clone = new SpectrogramData();
		clone->setRangeX(m_RangeX.min, m_RangeX.max);
		clone->setRangeY(m_RangeY.min, m_RangeY.max);
		clone->setBoundingRect(QwtDoubleRect(m_RangeX.min, m_RangeY.min, m_RangeX.max, m_RangeY.max));
		clone->setData(m_Array, m_DataSize.x, m_DataSize.y);
		return clone;
    }
 
    virtual QwtDoubleInterval range() const
    {
        return QwtDoubleInterval(m_minValue, m_maxValue);
    }
 
    double value(double x, double y) const
    {
		int xpos = (int)((x - m_RangeX.min) / m_RealToArray.x);
		int ypos = (int)((y - m_RangeY.min) / m_RealToArray.y);
		int pos = ArrPos(xpos, ypos);
		double dvalue = m_Array[pos];
		return dvalue;
    }
 
	void setData(double * Array, int sizex, int sizey)
	{
		m_DataSize.x = sizex;
		m_DataSize.y = sizey;
		int size = sizex * sizey;
		MinMaxArrayValue(Array, size, &m_minValue, &m_maxValue);
		if (m_Array != NULL)
			delete [] m_Array;
		m_Array = new double [size];
		memcpy(m_Array, Array, size * sizeof(double));
 
		m_RealToArray.x = (m_RangeX.max - m_RangeX.min) / (m_DataSize.x - 1);
		m_RealToArray.y = (m_RangeY.max - m_RangeY.min) / (m_DataSize.y - 1);
	}
 
	void setRangeX(const double min, const double max)
	{
		m_RangeX.min = min;
		m_RangeX.max = max;
	}
 
	void setRangeY(const double min, const double max)
	{
		m_RangeY.min = min;
		m_RangeY.max = max;		
	}
 
	int ArrPos(const int x, const int y) const
	{
		return y + m_DataSize.y * x;
	}
 
};
 
 
class QSpectrogramPlot : public QWidget //, protected Ui_QSpectrogramPlot
{
	Q_OBJECT
public:
	QSpectrogramPlot(QWidget* parent = 0, Qt::WFlags flags = 0);
	virtual ~QSpectrogramPlot();
 
 
public:
    QHBoxLayout *hboxLayout;
    QwtPlot *qwtPlot;
 
    void setupUi(QWidget *widget)
    {
		QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
		sizePolicy.setHorizontalStretch(20);
		sizePolicy.setVerticalStretch(20);
		sizePolicy.setHeightForWidth(widget->sizePolicy().hasHeightForWidth());
		widget->setSizePolicy(sizePolicy);
		widget->setAutoFillBackground(false);
		hboxLayout = new QHBoxLayout(widget);
		qwtPlot = new QwtPlot(widget);
		qwtPlot->setSizePolicy(sizePolicy);
		hboxLayout->addWidget(qwtPlot);
 
		QMetaObject::connectSlotsByName(widget);
    } // setupUi
 
 
private:
	QwtLinearColorMap m_colorMap;
	QwtPlotSpectrogram * m_spectrogram;
	QwtScaleWidget * m_rightAxis;
	SpectrogramData m_RasterData;
	QwtDoubleInterval m_DataRange;
	QwtPlotZoomer * zoomer;
 
public slots:
    void showContour(bool on);
    void showSpectrogram(bool on);
 
 
private:
	void initColorMap();
	void initColorBar();
	void initZoomer();
 
public:
	enum colormap{standard, gray, jet};
 
	void setData(double * Array, int sizex, int sizey);
	void setRangeX(const double min, const double max);
	void setRangeY(const double min, const double max);
	void setDataRange(double min, double max);
	void setDataAutoRange();
	void setColorMap(colormap map);
 
 
private:
	colormap m_colormap;
};
#endif
QSpectrogramPlot.cpp
#include "QSpectrogramPlot.h"
 
/* --------------------------------------
 * Zoomer Class, used in QSpectrogramPlot
 * --------------------------------------
*/
class MyZoomer: public QwtPlotZoomer
{
public:
    MyZoomer(QwtPlotCanvas* canvas): QwtPlotZoomer(canvas)
    {
        setTrackerMode(QwtPicker::AlwaysOn);
    }
 
protected:
    virtual QwtText trackerText( const QwtDoublePoint& p ) const 
    {
        QwtText t( QwtPlotPicker::trackerText( p ));
 
        QColor c(Qt::white);
        c.setAlpha(180);
        t.setBackgroundBrush( QBrush(c) );
 
        return t;
    }
};
 
 
/* --------------------------------------
 * QSpectrogramPlot Class
 * --------------------------------------
*/
 
QSpectrogramPlot::QSpectrogramPlot(QWidget* parent /*= 0*/, Qt::WFlags flags /*= 0*/) : QWidget(parent, flags)
{
	setupUi(this);
	m_spectrogram = new QwtPlotSpectrogram();
	m_RasterData = SpectrogramData();
	setColorMap(gray);
	//initColorMap();	
	m_spectrogram->attach(qwtPlot);
	qwtPlot->plotLayout()->setAlignCanvasToScales(true);			
	initColorBar();
	zoomer = NULL;
}
 
 
QSpectrogramPlot::~QSpectrogramPlot()
{
}
 
void QSpectrogramPlot::setData(double * Array, int sizex, int sizey)
{
	m_RasterData.setData(Array, sizex, sizey);
	m_spectrogram->setData(m_RasterData);
	setDataAutoRange();
	initColorBar();
	initZoomer();
}
 
void QSpectrogramPlot::setRangeX(const double min, const double max)
{
	m_RasterData.setRangeX(min, max);
	qwtPlot->setAxisScale(QwtPlot::xBottom, min, max);	
}
 
void QSpectrogramPlot::setRangeY(const double min, const double max)
{
	m_RasterData.setRangeY(min, max);
	qwtPlot->setAxisScale(QwtPlot::yLeft, min, max);
}
 
 
void QSpectrogramPlot::showContour(bool on)
{
    m_spectrogram->setDisplayMode(QwtPlotSpectrogram::ContourMode, on);
}
 
void QSpectrogramPlot::showSpectrogram(bool on)
{
    m_spectrogram->setDisplayMode(QwtPlotSpectrogram::ImageMode, on);
    m_spectrogram->setDefaultContourPen(on ? QPen() : QPen(Qt::NoPen));
}
 
void QSpectrogramPlot::setColorMap(colormap map)
{
	m_colormap = map;
	initColorMap();
	initColorBar();
}
 
void QSpectrogramPlot::initColorMap()
{
	switch (m_colormap)
	{
		case standard:
			m_colorMap = QwtLinearColorMap(Qt::darkCyan, Qt::red);
			m_colorMap.addColorStop(0.1, Qt::cyan);
			m_colorMap.addColorStop(0.6, Qt::green);
			m_colorMap.addColorStop(0.95, Qt::yellow);
			break;
		case gray:
		    m_colorMap = QwtLinearColorMap(Qt::black, Qt::white);
			break;
		case jet:
			double pos;
			m_colorMap = QwtLinearColorMap(QColor(0,0,189), QColor(132,0,0));
			pos = 1.0/13.0*1.0; m_colorMap.addColorStop(pos, QColor(0,0,255));
			pos = 1.0/13.0*2.0; m_colorMap.addColorStop(pos, QColor(0,66,255));
			pos = 1.0/13.0*3.0; m_colorMap.addColorStop(pos, QColor(0,132,255));
			pos = 1.0/13.0*4.0; m_colorMap.addColorStop(pos, QColor(0,189,255));
			pos = 1.0/13.0*5.0; m_colorMap.addColorStop(pos, QColor(0,255,255));
			pos = 1.0/13.0*6.0; m_colorMap.addColorStop(pos, QColor(66,255,189));
			pos = 1.0/13.0*7.0; m_colorMap.addColorStop(pos, QColor(132,255,132));
			pos = 1.0/13.0*8.0; m_colorMap.addColorStop(pos, QColor(189,255,66));
			pos = 1.0/13.0*9.0; m_colorMap.addColorStop(pos, QColor(255,255,0));
			pos = 1.0/13.0*10.0; m_colorMap.addColorStop(pos, QColor(255,189,0));
			pos = 1.0/13.0*12.0; m_colorMap.addColorStop(pos, QColor(255,66,0));
			pos = 1.0/13.0*13.0; m_colorMap.addColorStop(pos, QColor(189,0,0));
			break;	
	}
	m_spectrogram->setColorMap(m_colorMap);
}
 
void QSpectrogramPlot::setDataRange(double min, double max)
{
	m_DataRange = QwtDoubleInterval(min, max);
}
 
void QSpectrogramPlot::setDataAutoRange()
{
	m_DataRange = m_spectrogram->data().range();
	if (m_DataRange.minValue() == m_DataRange.maxValue())
		m_DataRange = QwtDoubleInterval(m_DataRange.minValue(), m_DataRange.minValue() + 1);
}
 
void QSpectrogramPlot::initColorBar()
{
    m_rightAxis = qwtPlot->axisWidget(QwtPlot::yRight);
    m_rightAxis->setColorBarEnabled(true);
    m_rightAxis->setColorMap(m_DataRange, m_spectrogram->colorMap());
 
    qwtPlot->setAxisScale(QwtPlot::yRight, 
        m_DataRange.minValue(),
        m_DataRange.maxValue() );
    qwtPlot->enableAxis(QwtPlot::yRight);
 
}
 
void QSpectrogramPlot::initZoomer()
{
    // LeftButton for the zooming
    // MidButton for the panning
    // RightButton: zoom out by 1
    // Ctrl+RighButton: zoom out to full size
 
	if (zoomer != NULL)
		delete zoomer;
	zoomer = new MyZoomer(qwtPlot->canvas());
    zoomer->setMousePattern(QwtEventPattern::MouseSelect2,
        Qt::RightButton, Qt::ControlModifier);
    zoomer->setMousePattern(QwtEventPattern::MouseSelect3,
        Qt::RightButton);
 
    QwtPlotPanner *panner = new QwtPlotPanner(qwtPlot->canvas());
    panner->setAxisEnabled(QwtPlot::yRight, false);
    panner->setMouseButton(Qt::MidButton);
 
    // Avoid jumping when labels with more/less digits
    // appear/disappear when scrolling vertically
 
    const QFontMetrics fm(qwtPlot->axisWidget(QwtPlot::yLeft)->font());
    QwtScaleDraw *sd = qwtPlot->axisScaleDraw(QwtPlot::yLeft);
    sd->setMinimumExtent( fm.width("100.00") );
 
    const QColor c(Qt::darkBlue);
    zoomer->setRubberBandPen(c);
    zoomer->setTrackerPen(c);
}

12 Antworten : “qwt spectrogramm plot with data arrays”

  1. pospiech sagt:

    Sorry, but I have not been using this code or even any C++ or Qt code within the last years. I do not even have a running code example anymore.

  2. Mary sagt:

    Could you please add ExtFunction.h and main.cpp files.

  3. pospiech sagt:

    Unfortunately I have not worked on or with this project since a few years and currently do not plan to do so. Therefore it would be quite naturally that this code does not compile anymore with recent versions of Qt and qwt.

  4. sztibi82 sagt:

    Dear Sir,

    Please could you upload to this site the entire project as a zip or rar file, because I tried to reproduce your program, and it gives a lot of errors.

    Thanks

  5. pospiech sagt:

    I plan to release a complete set of classes as a whole project. If version 6.0 is released in the next month I would port the whole code first and then finish it. If it comes to late it will be a release for 5.x. However you should not expect anything before the end of the year. And currently I have not even taken a look at 6.0.

  6. Fran sagt:

    Isn’t there a version for qwt 6.0.0 ?

  7. Alexey sagt:

    It needs to call setRangeX and setRangeY before setData.

  8. Sorry, but I do not use Linux for C++ Development. Therefore I have no idea where your problem is. Anyway asking such questions is not what this comment section is meant for.

    I strongly recommand, that you ask on the qwt and qt-interest mailinglist or on qtcentre.org your question.

    Matthias

  9. ignacio sagt:

    Man, I have problem with the library qwt. I can’t use it. I don’t why!
    I downloaded, then i run qmake, make and make install. So, I think that in some place there is a folder with the includes and the libs. I told ubuntu too that this library is shared library, so i added to the PATH LIBRARY. But, any way I can’t use it. My compiler says that the header (qwt_) don’t exist. Please, help.. I need to draw a function for this Monday.

    Thanks

  10. Dean sagt:

    Very useful! This should be part of the Qwt examples.

  11. Extfunctions.h only provides MinMaxArrayValue which you can easily write on you own.

    the main.cpp would more or less look like in the original qwt example.

    The a setData with an additional qwtplot->replot() call should be enough to get the data displayed.

  12. Yuho sagt:

    Great, this is what I really wanna do! But could you kindly show me some missing source files, ExtFunction.h and main.cpp ?

Einen Kommentar schreiben

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

*