PDA

View Full Version : QwtRasterData and values



DKL1972
19th July 2008, 16:57
Can someone explain to me why the QwtRasterData::value method (which returns the value at the specified raster position) has "doubles" as the x / y for the position. I think I understand that the position is the pixel position, but what is a fraction of a position? I am trying to map the value call to my data but I am not sure what the fractional positions are.

For example, I am creating a 100 x 100 QwtRasterData. I want to have a 100x100 array with values in it. How do I map the "value" call to my array?

By the way, I am using the Spectrogram example as a starting point.

Thanks.

Debilski
19th July 2008, 22:18
Hi,
as far as I’ve understood it, you’d give the boundaries when you’re initialising your subclassed QwtRasterData. Qwt would then call the value method with all numbers between those boundaries that are currently displayable. If you stretch the plot to a size of 200 pixels, this will mean that qwt asks for 200 values betwenn 0 and 100, so you will have to use a method to get appropriate integer numbers from those.



class SpectrogramData: public QwtRasterData
{
public:
SpectrogramData
: QwtRasterData(QwtDoubleRect(0., 0., 100., 100.))
{
}
virtual double value(double x, double y) const
{
return myDataArray[(unsigned int) floor(x)][(unsigned int) floor(y)];
}
};


You could also implement a QSize rasterHint() method which returns the maximal resolution possible, so that Qwt only asks for 100 values between 0 and 100 and not like 300-something or however large you drag your plot on screen.

Unfortunately, I do have issues with the code as well (especially when rasterHint is implemented), so it can only serve you as a first idea.

My problem is, that sometimes Qwt would call value(99,100) which of course yields an out-of-range value. And somehow the plot gets shifted in y-direction, too. Strangely, this does not happen in x direction, e.g. Qwt does not call value(100,99) or value(100,100). At least that is not what I observed.

Hopefully, someone could post an insightful solution to this and hint how Qwt determines which arguments it passes to the value(x, y) method.

Nontheless, I hope my first version is of some use for you anyway.

DKL1972
19th July 2008, 22:54
Thank you. This explains it well for me and is a great start!

Uwe
20th July 2008, 10:30
Can someone explain to me why the QwtRasterData::value method (which returns the value at the specified raster position) has "doubles" as the x / y for the position. I think I understand that the position is the pixel position, ...
No - Qwt has already translated the pixel positions into the coordinate system from the current scales. So you have to do some resampling (next neighbour, aggregation, accumulation or whatever) inside of YourRasterData::value ( or rebuild your matrix in QwtRasterData::initRaster() ).

Uwe

shargath
20th August 2008, 23:18
Hello everyone. I have the same problem with value method like Debilski. parameters of value function are bigger than for eg. 10 even if i set
QwtRasterData(QwtDoubleRect(0., 0., 10., 10.))
I tried to round somehow the parameters x and y but i failed.
In manual for QwtRasterData::initRaster() there is written:

Before the composition of an image QwtPlotSpectrogram calls initRaster, announcing the area and its resolution that will be requested. The default implementation does nothing, but for data sets that are stored in files, it might be good idea to reimplement initRaster, where the data is resampled and loaded into memory.
Does someone will be so kinde and give me example of QwtRasterData which returns value from 2 dimensional array of double.

Thank You very much.

Uwe
21st August 2008, 10:33
I tried to round somehow the parameters x and y but i failed
Your QwtRasterData implementation tells the spectrogram, that it has data in the area (0.0, 0.0, 10.0, 10.0). This is an area on the plot canvas according to the scales and has nothing to do with the resolution of your raster !

Depending on the current scales and the resolution of your paint device the spectrogram requests values ( you don't know them in advance ! ) in this area from your data class. In most situations your data doesn't have a value for exactly this position. That's why you have to calculate one ( this is called resampling ) from the existing values.

How to do it depends completely on the organization of your data and the type of resampling you prefer.

Uwe

shargath
21st August 2008, 12:41
My data is stored in two dimensional array of doubles. In first version I want program to plot all values from this data array where cell [x][y] of array corespond to (x,y) pixel position on the canvas. What else and how should i implement besides QwtRasterData::value method.

Thank You for reply.

Uwe
21st August 2008, 19:57
YourRasterData::YourRasterData():
QwtRasterData(QwtDoubleRect(0.0, 0.0, 9.0, 9.0)
{
...
}

double YourRasterData::value(double x, double y) const
{
int ix = qRound(x);
int iy = qRound(y);
if ( ix >= 0 && ix < 10 && iy >= 0 && iy < 10 )
return _values[ix][iy];

return ...; // shouldn't happen
}

But from your previous postings I'm not sure that you really want what QwtPlotSpectrogram offers.

Uwe

shargath
21st August 2008, 23:29
Here is my code as simple as possible, also i applied your last suggestions but despite i got segmentation fault. Please help.


Plot.h



#ifndef PLOT_DATA_H
#define PLOT_DATA_H

#include "qwt_raster_data.h"

class plot_data: public QwtRasterData
{

private:
double ** d_DataArray;

public:
plot_data();
~plot_data();

virtual QwtRasterData *copy() const;
virtual QwtDoubleInterval range() const;
virtual double value(double x, double y) const;
void setData();
};

#endif // PLOT_DATA_H



Plot.cpp



#include "plot_data.h"
#include <QDebug>
#include <cmath>
plot_data::plot_data():
QwtRasterData(QwtDoubleRect(0., 0., 9.0, 9.0))
{
d_DataArray = NULL;
}

plot_data::~plot_data()
{
if (d_DataArray != NULL ){
for(int i = 0; i < 10; i ++)
{
delete [] d_DataArray[i];

}
delete [] d_DataArray;
}
}


QwtDoubleInterval plot_data::range() const
{
return QwtDoubleInterval(0., 10);

}

QwtRasterData* plot_data::copy() const
{
plot_data *clone = new plot_data();
return clone;
}


double plot_data::value(double x, double y) const
{

int xpos = qRound(x);
int ypos = qRound(y);
if (xpos >= 0 || xpos < 10 || ypos >= 0 || ypos < 10 )
{
//here is still segmentation fault;
return d_DataArray[xpos][ypos];
}
qDebug() << "it happened";
return 0.0;
}

void plot_data::setData()
{
//here i'm generating some test data.
//help values to random data;
int XMin = 0, XMax = 10, size = 100;


if (d_DataArray != NULL )
{
for(int i = 0; i < 10; i ++)
{
delete [] d_DataArray[i];
}
delete [] d_DataArray;
qDebug()<< "Deleted";
}

d_DataArray = new double* [10];
if (d_DataArray == NULL)
{
qDebug() << "BAd initialization";
}
for(int i = 0; i < 10; i ++)
{
d_DataArray[i] = new double [10];
if (d_DataArray[i] == NULL)
qDebug() << "Something Wrong with allocation";
}

for(int x = 0; x < 10; x ++)
for(int y = 0; y < 10; y ++){
d_DataArray[x][y] = XMin + rand() * (XMax - XMin) / RAND_MAX;

//qDebug() << d_DataArray[0][9] << "\n";
//WHEN I CALL HERE SOMETHING LIKE THIS IT ALSO YELDS SEGFAULT
}

}



Regarding the way how i would like to use the SpectrogramPlot. I'm working on 2 dimmensional Lattice boltzman method, and i want to visualise my results using SpectrogramPlot. It is simulation of fluid over discrete space. Results are values of speed in each cell of space. So i want to represent the data in 2D array. I think it's natural

Uwe
24th August 2008, 12:31
Your copy method returns a data object with an empty matrix. No surprise, that the (unprotected) value method runs into a segfault. I recommend to use one of the implicitely shared QTL containers, because it makes the implementation of the copy operation easier.

Uwe

jcox23
9th March 2010, 14:44
:
aaaahh.. I should have wait a little more before posting that...
turns out it's a similar problem as the op had...
x ,y values being asked outside the container...
SORRY....

Hi,
I'm reviving an old thread... I just stumbled upon this while trying to solve a pb of mine using QwtRasterData...

I have a QMap container filled with data created somewhere else in the program...
the following class is used like this
d_spectrogram->setData(SpectrogramData(&data));

this code:

class SpectrogramData: public QwtRasterData
{
public:
SpectrogramData(QMap<int, double*>* points):
QwtRasterData(QwtDoubleRect(0.0, 0.0, 1999.0, 1999.0))
{
datas = points;
}

virtual SpectrogramData *copy() const
{
SpectrogramData* spec_data = new SpectrogramData(datas);
return spec_data;
}

virtual QwtDoubleInterval range() const
{
return QwtDoubleInterval(0.0, 1000.0);
}

virtual double value(double x, double y) const
{

int X = qRound(x);
int Y = qRound(y);
return (datas->value(X))[Y];
}

private:
QMap<int, double*> *datas;

};

This consistently giving a segentation fault...happening when the object returned by the copy method is used...
Leave alone the fact that I dont understand why 2 SpectrogramData objects are used,

it seems that the copied object will contain a non null pointer to a non-empty container, as its parent...

If somebody can shed some light on the silly mistake I made!

Uwe
9th March 2010, 16:03
The map is somewhere allocated in your application code. It's up to the application code to take care of its lifetime. Also check the indices before accessing your map and double arrays - without setting the bounding rect you can be sure to see requests for positions you don't have.

Note, that SpectrogramData::value() is called very often ( for each pixel of your plot canvas: width * height ). So better don't use a QMap. Returning a rasterHint should be useful as well.

Uwe

jcox23
10th March 2010, 10:53
The map is somewhere allocated in your application code. It's up to the application code to take care of its lifetime.
Yes it is created outside the code, I cant afford copying it around, it can be big, and there's several of them...RAM usage could quickly explode...



Also check the indices before accessing your map and double arrays - without setting the bounding rect you can be sure to see requests for positions you don't have.

Yes turns out it was just that, a position request was outside the boundaries of my map...



Note, that SpectrogramData::value() is called very often ( for each pixel of your plot canvas: width * height ). So better don't use a QMap. Returning a rasterHint should be useful as well.
Uwe

I know, but QMap is just very convenient in my case, i have series of vectors (double) keyed by integers that are not linearly increasing....
QHash would be probably a bit faster, is that what you were thinking about or even going further than that by using a more low level container... like a long flatten array for example?