QwtSpectrogram, Change axis numbers
I want to draw a spectrogram with size 2000*2000. However, i don't want the axis scale numbers to be from 0 to 2000, but rather a linear transformation, where 2000 is mapped to a certain number (e.g. 120), and the rest of the values are mapped accordingly.
I declare a
instance, and i use setData() function to pass a SpectrogramData instance:
Code:
private:
std::vector<std::vector<double>> data_;
public:
SpectrogramData();
~SpectrogramData();
void setData(std::vector<std::vector<double>> & data) { data_ = data; }
virtual double value(double x, double y) const{ return data_[x][y]; }
};
Then i initialize the QwtPlot:
Code:
...
spectrogram_data_ = new SpectrogramData();
...
spectrogram_->setData(spectrogram_data_);
spectrogram_->attach(plot_);
The problem is that when i draw something, i have to use setInterval() on the spectrogram_data object, but the values 0 and 2000, for min and max, that i pass in order to fully draw the 2000*2000 matrix, set the axis to 0-2000 as well. If i give smaller values to setInterval() then part of the matrix is not drawn.
What i tried is to use QwtTranform, since i want a linear transformation, but as i am given to understand, it does not behave the way i want:
Code:
class AxisTransformation : public QwtTransform {
private:
double prev_start_, prev_end_;
double new_start_, new_end_;
public:
AxisTransformation(double prev_start, double prev_end, double new_start, double new_end) : prev_start_(prev_start), prev_end_(prev_end), new_start_(new_start), new_end_(new_end) {}
virtual double transform(double value) const {
return new_value = new_start_ + (new_end_ - new_start_) * (value - prev_start_) / (prev_end_ - prev_start_);
}
virtual double invTransform(double value) const {
return new_value = prev_start_ + (prev_end_ - prev_start_) * (value - new_start_) / (new_end_ - new_start_);
}
AxisTransformation * copy() const {
return new AxisTransformation(*this);
}
};
along with
Code:
AxisTransformation * t = new AxisTransformation(0, 2000, 0, 120);
axis_x_bottom->setTransformation(t);
So how can i fully draw the 2000*2000 matrix, but specifying the axis numbers displayed to be from 0 to 120?
Re: QwtSpectrogram, Change axis numbers
Better remove all what you did so far and restart with something like that:
Code:
{
public:
SpectrogramData()
{
m_intervals[ Qt::XAxis ] = QwtInterval( 0, 120 );
m_intervals[ Qt::YAxis ] = QwtInterval( 0, 120 );
m_intervals[ Qt::ZAxis ] = ...
}
virtual QwtInterval interval( Qt::Axis axis ) const
{
if ( axis >= 0 && axis <= 2 )
return m_intervals[ axis ];
return QwtInterval();
}
virtual double value( double x, double y ) const
{
double value = ...; // find the value corresponding to x/y in your vector
return value;
}
private:
QwtInterval m_intervals[3];
};
If you don't insist on using std::vector you could use QwtMatrixRasterData like demonstrated in the rasterview example. You get at least bilinear interpolation and a valid pixel hint for free.
Uwe
Re: QwtSpectrogram, Change axis numbers
So, as i am given to understand, i should map the values myself into the data, which i did and it seems to work!
I thought that just changing what values are displayed in the x-axis should be much easier.
The problem with the rasterview example is that if i use setValueMatrix() to set the data, without subclassing and using value(x,y) overloading, then the rendering time is much higher, i think. The subclassing way seems to be the fastest way.
Also, how many values are picked in the QwtInterval 0-120, and how are they picked. I mean, i want to achieve a certain resolution based on the data and, obviously, 2000*2000 cannot be rendered in a small window.
Re: QwtSpectrogram, Change axis numbers
Quote:
Originally Posted by
kkaz
I thought that just changing what values are displayed in the x-axis should be much easier.
You can set the axes manually using QwtPlot::setAxisScale or you rely on autoscaling, what is based on the bounding rectangle of the plot items. In your case the bounding rectangle depends on the intervals returned by raster data.
So there is nothing difficult about this - beside, that you are not setting the proper intervals. Return [0,120] and that's it.
Quote:
Originally Posted by
kkaz
The problem with the rasterview example is that if i use setValueMatrix() to set the data, without subclassing and using value(x,y) overloading, then the rendering time is much higher, i think.
You might not want to copy your data only because of API reasons, but there is no performance benefit from not using it.
Quote:
Originally Posted by
kkaz
Also, how many values are picked in the QwtInterval 0-120, and how are they picked.
The spectrogram has to create a QImage from the data, what is a matrix of RGB values. Position and size are found from the resolution of the data ( YourRasterData::pixelHint() ) and the resolution of the target device ( usually the screen ). Then it simply runs over the pixels of the image, calculates the corresponding position in plot coordinates and requests the value by calling YourRasterData::value(). Finally it maps the value into a RGB value and stores it in the image.
Calculating the value for a given position usually requires some sort resampling - this is what needs to be done inside of QwtRasterData::value(). Most implementations do some sort of nearest neighbor ( = simple and fast ), but of course you might lose significant pixels when the resolution of the image is too low. If this is not acceptable in your case you need to do calculate the value by taking adjacent values into count. In the end it is performance vs. quality.
When using QwtMatrixRasterData the resolution of the data can be calculated on its own ( you don't need to implement a pixelHint ) and bilinear interpolation as resampling algo is available. Or in other words: this is the option, for everyone who is not interested in these details.
Uwe