PDA

View Full Version : Arbitrary axis interval without affecting the plot



parasonic
19th September 2011, 21:59
I have been searching the forums for the past week on how to do this, so please excuse me if this question has been answered.

I have a QwtPlotSpectrogram attached to a QwtPlot, and I would like to scale the plot so that it spans the entire canvas. I would also like to arbitrarily set the axes regardless of how the data is on-screen. The following code sets up the scaling so that the plot spans the canvas. plot_2d is the QwtPlot widget.



// This is a hack to properly scale the plot. By default, the plot
// autoscales to values larger than the extent of the data, e.g. an axis
// with value 128 extends to 140, and an axis with value 16384 extends
// to 20000.
const unsigned x_length = data.size1();
const unsigned y_length = data.size2();
plot_2d->setAxisScale(QwtPlot::xBottom, 0, x_length - 1);
plot_2d->setAxisScale(QwtPlot::yLeft, 0, y_length - 1);
// Refresh the axes with the new scale values
plot_2d->updateAxes();
// Call replot the Qwt widget ("owner" of QwtPlotSpectrogram widget)
plot_2d->replot();


I have been wholly unsuccessful in setting the intervals for the axes. Most of the things which I have tried have not affected the rendering, and the few which have done something have changed the plot as well. For instance, calling the following code inverts the plot and axis.


plot_2d->axisScaleEngine(QwtPlot::xBottom)->setAttribute(QwtScaleEngine::Inverted);

Is there a way to change the axis interval, for instance, to [-1234.5, 12.345], without changing how the plot is rendered itself? Thank you.

FelixB
20th September 2011, 07:53
Is there a way to change the axis interval, for instance, to [-1234.5, 12.345], without changing how the plot is rendered itself? Thank you.

of course, but it's a little bit tricky. QwtPlotItems have a relevant x- and y-axis. these axes define how the item is plotted. so, when you change the scale of a relevant axÃ*s, the item gets painted differently than before.

If I understand your problem, you want (for example) change the x-axis to [10,100] and you want to keep your spectrogram as it is, let's say in the range [0,50]. Then you can't change the relevant axis since that would change the spectrogram. Assuming you want to have xBottom visible, you must define xTop as relevant x-axis. You set the scale of xTop to [0,50] and now you can set the scale of xBottom to any interval you want - the spectrogram always gets painted in an interval of [0,50]. Same applies to yLeft/yRight.

hope that helps...
Felix

Uwe
20th September 2011, 08:38
I have a QwtPlotSpectrogram attached to a QwtPlot, and I would like to scale the plot so that it spans the entire canvas.
You want to eliminate the margins at the ends of the scales, so that they are aligned with the canvas border ?


I would also like to arbitrarily set the axes regardless of how the data is on-screen.
Is this the question how to disable autoscaling ?

It would help if you try to use the terminology of the Qwt plot framework. Guess you mean your spectrogram item, when you write about "plot" otherwise a "plot that spans the canvas" doesn't make any sense at all.

Uwe

Spitfire
20th September 2011, 09:22
I will leech on the thread as it's of intrest to me too.

What parasonic wants is to be able to set the axis to arbitrary range without affecting how the plot is rendered.
That's exacly what I'm trying to do.
Suggestion made by FelixB would probably work if you don't need top axis, if you do - that's no-go.

So for example if plot item is build from points which x range is 0-100 how to set the axis to be 50-392 (or 0.001 to 0.107 etc) without affecting how the plot is displayed (zoomer has to work in that setup as well)?

FelixB
20th September 2011, 09:51
if you need both bottom and top axis, it gets very complicated.

maybe it is possible to create your own ScaleDraw and override the "label(double)"-method to draw any value you want. but I am not sure if that would affects other parts...

or you could set your axis invisible and paint an own axis under the plot (yes, that would be a very ugly workaround ;) ).

Uwe
20th September 2011, 09:52
What parasonic wants is to be able to set the axis to arbitrary range without affecting how the plot is rendered.
That's exacly what I'm trying to do.
What is the reason for binding a plot item to a coordinate system, when you don't want to have it rendered according to it ?


So for example if plot item is build from points which x range is 0-100 how to set the axis to be 50-392 (or 0.001 to 0.107 etc) without affecting how the plot is displayed (zoomer has to work in that setup as well)?
You can always overload the draw method of a plot item and manipulate the canvas maps.


class YourCurve: public QwtPlotCurve // could be any other plot item too
{
YourCurve()
{
setItemAttribute( QwtPlotItem::AutoScale, false );
}

virtual void draw( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect ) const
{
QwtScaleMap yourXMap;
yourXMap.setPaintInterval( xMap.p1(), xMap.p2() ); // widget coordinates
yourXMap.setScaleInterval( ... );

QwtScaleMap yourYMap;
yourYMap.setPaintInterval( yMap.p1(), yMap.p2() ); // widget coordinates
yourYMap.setScaleInterval( ... );

QwtPlotCurve::draw( painter, yourXMap, yourYMap, canvasRect );
}
};

HTH,
Uwe

FelixB
20th September 2011, 10:15
What is the reason for binding a plot item to a coordinate system, when you don't want to have it rendered according to it ?

In my case:
I'm working on an application that displays images created by an electron microscope as spectrogram. depending on the analysis method, the user wants to have the axes labelled with pixel of the original image or the physical unit (i.e. mm) . So, I need to switch the visible axes between two scales without changing the spectrogram. So, I use the invisible axes as "relevant" axes and can switch the visible "irrelevant" axes to whatever the user wants to see.

Spitfire
20th September 2011, 11:24
What is the reason for binding a plot item to a coordinate system, when you don't want to have it rendered according to it ?

There's several reasons, for example you may want to display 'low/medium/high/very high' descriptions on the axis, but you can't have x value of 'high' :)
In my case the x value of the points is just an array index (0-n).
If I keep it this way then the bottom axis shows me a range 0-n when I want it to be a time (I know that the points represents certain span of time, ie 20ms).
I know I could convert x value to time value but when zooming in/out I would like to be able to change the values displayed on the axis as it doesn't make much sense to show 0.00002ms, 20ns would be much nicer.

I'm fairly new to Qwt so I may be missing something obvious here.
What about QwtScaleEngine? Not sure what it does as documentation is bit vague, but it can be applied to the axis on the plot.

Uwe
20th September 2011, 11:51
In my case the x value of the points is just an array index (0-n).
If I keep it this way then the bottom axis shows me a range 0-n when I want it to be a time (I know that the points represents certain span of time, ie 20ms).
I know I could convert x value to time value but when zooming in/out I would like to be able to change the values displayed on the axis as it doesn't make much sense to show 0.00002ms, 20ns would be much nicer.
0.00002ms, 20ns are different representations of the same value.
Changing the tick values, when you want to change its representation only is somehow "von hinten durch die Brust ins Auge".


I'm fairly new to Qwt so I may be missing something obvious here.
See http://qwt.sourceforge.net/class_qwt_abstract_scale_draw.html#a4ff88bc827dd6c 6ca9298de13483b61f.

Check the cpuplot example how to use it.

Uwe

parasonic
20th September 2011, 21:43
Thank you for your replies. My task is to create a clone for the Matlab imagesc() which has one form where one can specify the axis extents in the arguments.

Would the following code theoretically change the x-axis to range from -100 to 20? As it is, the code here still allows the x-axis to be drawn from 0 to 127, and the plot shows up compressed and on the right hand side.


class RD_Qwt_Plot : public QwtPlotSpectrogram
{
public:
RD_Qwt_Plot()
{
setItemAttribute(QwtPlotItem::AutoScale, false);
}

~RD_Qwt_Plot()
{
}

virtual void draw(QPainter* painter, const QwtScaleMap &xMap,
const QwtScaleMap &yMap, const QRectF &canvasRect) const
{
QwtScaleMap cust_x_map;
cust_x_map.setPaintInterval(xMap.p1(), xMap.p2());
// Matrix spans 128 for the X direction
// cust_x_map.setScaleInterval(0, 127);
cust_x_map.setScaleInterval(-100, 20);

QwtScaleMap cust_y_map;
cust_y_map.setPaintInterval(yMap.p1(), yMap.p2());
// Matrix spans 16384 for the Y direction
cust_y_map.setScaleInterval(0, 16383);

QwtPlotSpectrogram::draw(painter, cust_x_map, cust_y_map, canvasRect);

}

/*
// This method is referenced when checking to see what data to be plotted.
// If you set the interval here, it changes both the axis and the
// data plotted.
QwtInterval interval(Qt::Axis axis) const
{
const QwtInterval interv(-34, 67);
return interv;
}
*/
};


Here is a screen shot of what currently happens.
6868

Thanks

Uwe
21st September 2011, 08:03
My task is to create a clone for the Matlab imagesc() which has one form where one can specify the axis extents in the arguments.

See QwtPlot::setAxisScale() and check the spectrogram example how to eliminate the margins. If you want to limit the area, where to display your spectrogram see QwtRasterData::setInterval().

What the heck is your motivation to manipulate the canvas maps ?

Uwe