PDA

View Full Version : qwtplotgrid and qwtscalediv problem



tangtao_xp
12th June 2013, 17:41
Hi,

I plan to write a function for the plot user to customize the style of grids. That is to say, the user can explicitly assign the number of the minor and major grid line. For example, a scale is 150(only considering X-axis) : major ticks is 0, 75, 150, medium ticks is 15, 30, 45, 60, 90, 105, 120, 135, minor ticks is 5, 10, 20, 25, 35, 40... 130, 140, 145 user only is needed to give the number of ticker(3 major ticks, 8 medium ticks and 20 minor tickes)

I met two problem:

1. for the style

grid line of major ticks should be painted in style of Qt::black, 1, Qt::SolidLine, and the medium ticks should be Qt::gray, 1, Qt::DashLine.

I use the qwtplotgrid member function setMajorPen()/setMinorPen() to apply the above style to the grid line, however it shows a unexpected plot grid line. Neither major lines nor minor lines are in correct postions. pls help to find the attchments.

what i get
9151

what i want
9152

2. for the number(or steps, stepsize)

I use QwtScaleEngine(QwtLinearScaleEngine/QwtLogScaleEngine), but it cannot work out the my ideal tickes as I metioned below.


------------------code------------------


plots[i] = new QwtPlot(mainFrame);

plots[i]->enableAxis(QwtPlot::xBottom, false);
plots[i]->enableAxis(QwtPlot::yRight, false);
plots[i]->enableAxis(QwtPlot::xTop, true);
plots[i]->enableAxis(QwtPlot::yLeft,true);

// grid
grids[i] = new QwtPlotGrid();
grids[i]->enableX(true);
grids[i]->enableXMin(true);

// for major grid line
grids[i]->setMajorPen(Qt::black, 1, Qt::SolidLine);
// for minor grid line
grids[i]->setMinorPen(Qt::gray, 1, Qt::DashLine);

QwtScaleDiv div;
QwtLinearScaleEngine *lineSE = new QwtLinearScaleEngine();
div = lineSE->divideScale(0, 150, 2, 5, 15);

plots[i]->setAxisScaleDiv(QwtPlot::xTop, div);

grids[i]->attach(plots[i]);



Thank you in advance.



Tang Tao

tangtao_xp
13th June 2013, 03:40
In my case, scale is 150, I want:

major ticks: (0, 75, 150) --> QPen(Qt::black, 1, Qt::SolidLine)
medium tickes: (15, 30, 45, 60, 90, 105, 120, 135) --> QPen(Qt::gray, 1, Qt::DashLine)
minor tickes: (5, 10, 20, 25, 35, 40, 50, 55, 65, 70, 80, 85, 95, 100, 110, 115, 125, 130) --> no painted grid lines

I tried:



QList<double> majorTicks;
majorTicks << 0 << 75 << 150;

QList<double> mediumTicks;
mediumTicks << 15 << 30 << 45 << 60 << 90 << 105 << 120 << 135;

QList<double> minorTicks;
minorTicks << 5 << 10 << 20 << 25 << 35 << 40 << 50 << 55 << 65
<< 70 << 80 << 85 << 95 << 100 << 110 << 115 << 125 << 130;

div.setTicks(QwtScaleDiv::MajorTick, majorTicks);
div.setTicks(QwtScaleDiv::MediumTick, mediumTicks);
div.setTicks(QwtScaleDiv::MinorTick, minorTicks);

plots[i]->setAxisScale(QwtPlot::xTop, 0, 150);
//plots[i]->setAxisScaleDiv(QwtPlot::xTop, div);
grids[i]->setXDiv(div);


still failed. Need helps!


Tang Tao

Uwe
13th June 2013, 07:05
The idea of using setAxisScaleDiv is the right one, but now the answer depends on what Qwt version you are using. When using Qwt < 6.1 you always have to use the following constructor:


QwtScaleDiv::QwtScaleDiv( const QwtInterval &, QList<double> ticks[NTickTypes] );This is the only way to have an object where isValid() is true.

In Qwt 6.1 this nasty valid flag ( better don't ask what it was good for ) has been moved to where it belongs and you can use QwtScaleDiv like everyone expects that it can be used.

Uwe

tangtao_xp
13th June 2013, 08:57
Hi, Uwe

I really appreciate your reply. I am using the latest version of qwt (v6.1).
However, I am still confused about you answer. Are you glad to explain more clear for me?

And why I set the right div-object(in post #2) and it doesn't take effect?


Tang Tao

Uwe
13th June 2013, 09:41
Fixing the code from your second posting:


QwtScaleDiv div( 0, 150 );
div.setTicks(QwtScaleDiv::MajorTick, majorTicks);
div.setTicks(QwtScaleDiv::MediumTick, mediumTicks);
div.setTicks(QwtScaleDiv::MinorTick, minorTicks);
plots[i]->setAxisScaleDiv(QwtPlot::xTop, div);

When you want to have the grid lines independent from the scale ticks you have to set the QwtPlotItem::ScaleInterest flag of the grid item to false. Then the settings done for the grid won't be overwritten by the next replot.

Uwe

tangtao_xp
13th June 2013, 10:54
hi, Uwe

Sorry for late reply.

I think I want the grid to be decided by the QwtPlot::xTop scale. As your told, my plot has the right ticks at the xTop-scale now.

But the action of grid line is not what I expect.

9153

You can see that, in the picture:

at x = 15, 45, 105, 135, the vertical grid lines is the minor grid lines(gray, dashline).

at x = 30, 60, 90, 120, the vertical grid lines is the major grid lines(black, soildline).

what I want is:

at x = 15, 30, 45, 60, 90, 105, 135, the vertical grid lines is the minor grid lines(gray, dashline)
at x = 0, 75, 150, the vertical grid lines is the major grid lines(black, soildline)


does that mean I should overload QwtPlotGrid::draw()?


Thank you!


Tang Tao

Uwe
13th June 2013, 11:12
at x = 15, 30, 45, 60, 90, 105, 135, the vertical grid lines is the minor grid lines(gray, dashline)
at x = 0, 75, 150, the vertical grid lines is the major grid lines(black, soildline)
When using setAxisScaleDiv() the ticks will be exactly, where you have defined them. Of course another call of setAxisScale() or setAxisAutoScale() for the same axis will overwrite your definition.


does that mean I should overload QwtPlotGrid::draw()?
No all what needs to done is to define range and ticks in a QwtScaleDiv object and assign it to the scale. The grid will be synchronized to it in the next replot.

Uwe

tangtao_xp
13th June 2013, 12:23
hi, Uwe



When using setAxisScaleDiv() the ticks will be exactly, where you have defined them. Of course another call of setAxisScale() or setAxisAutoScale() for the same axis will overwrite your definition.


I checked my code again and I do not found another call of div defining function(so my definition won't be overwrited). I will give all code below.
And the grid lines are never synchronized to the scale. And plot picture is the same with post#6

my code:



void MainWindow::setWidget()
{
for (int i = 0; i < 1; i++)
{
plots[i] = new QwtPlot(mainFrame);

plots[i]->plotLayout()->setAlignCanvasToScales(true);

for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
plots[i]->axisWidget(axis)->setMargin( 0 );

QwtPlotCanvas *canvas = new QwtPlotCanvas();
canvas->setFrameStyle(QFrame::Plain | QFrame::NoFrame);
plots[i]->setCanvas(canvas);

plots[i]->enableAxis(QwtPlot::xBottom, false);
plots[i]->enableAxis(QwtPlot::yRight, false);
plots[i]->enableAxis(QwtPlot::xTop, true);
plots[i]->enableAxis(QwtPlot::yLeft,true);

grids[i] = new QwtPlotGrid();
grids[i]->enableX(true);
grids[i]->enableXMin(true);

grids[i]->setMajorPen(Qt::black, 1, Qt::SolidLine);
grids[i]->setMinorPen(Qt::gray, 1, Qt::DashLine);

QwtScaleDiv div(0, 150);

QList<double> majorTicks;
majorTicks << 0 << 75 << 150;

QList<double> mediumTicks;
mediumTicks << 15 << 30 << 45 << 60 << 90 << 105 << 120 << 135;

div.setTicks(QwtScaleDiv::MajorTick, majorTicks);
div.setTicks(QwtScaleDiv::MediumTick, mediumTicks);

plots[i]->setAxisScaleDiv(QwtPlot::xTop, div);

grids[i]->attach(plots[i]);

// picker
pickers[i] = new QwtPlotPicker(plots[i]->canvas());
pickers[i]->setTrackerMode(QwtPlotPicker::AlwaysOn);
}
}






No all what needs to done is to define range and ticks in a QwtScaleDiv object and assign it to the scale. The grid will be synchronized to it in the next replot.


Yes, I agree with you. In my code, I just want to simplify the problem for better understanding, for that english is not my mother tongue.

As far as I know, in qwt, we can take advantage of setAxisAutoScale() and QwtScaleEnginee class to auto-calculate the tricks. (I wish discuss with you after the first problem done)


Thank you for your patient help.



Tang Tao

Uwe
14th June 2013, 08:50
I modified the bode example this way:

In plot.cpp I added the following lines:


enableAxis( QwtPlot::xTop );
grid->setXAxis( QwtPlot::xTop ); // did you miss this one ???
In mainwindow.cpp I replaced the implementation of MainWindow::print():


void MainWindow::print()
{
QList<double> majorTicks;
majorTicks << 0 << 75 << 150;

QList<double> mediumTicks;
mediumTicks << 15 << 30 << 45 << 60 << 90 << 105 << 120 << 135;

QList<double> minorTicks;
minorTicks << 5 << 10 << 20 << 25 << 35 << 40 << 50 << 55 << 65
<< 70 << 80 << 85 << 95 << 100 << 110 << 115 << 125 << 130;

QwtScaleDiv div( 0, 150 );
div.setTicks(QwtScaleDiv::MajorTick, majorTicks);
div.setTicks(QwtScaleDiv::MediumTick, mediumTicks);
div.setTicks(QwtScaleDiv::MinorTick, minorTicks);
d_plot->setAxisScaleDiv(QwtPlot::xTop, div);
}
When pressing "Print" the scale looks like expected and the grid lines are aligned to the ticks.

Uwe

tangtao_xp
15th June 2013, 07:02
I modified the bode example this way:

In plot.cpp I added the following lines:


enableAxis( QwtPlot::xTop );
grid->setXAxis( QwtPlot::xTop ); // did you miss this one ???
In mainwindow.cpp I replaced the implementation of MainWindow::print():


It works! Thank you, Uwe!

I think the reason why code does not take effect is that the grid synchronizes with the x-bottom axis by default.
And I should change this default action of grid by setXAxis(QwtPlot::xTop) .

Now, I move to how to auto-calculate the ticks both in linearscale and logscale. If I had a trouble with that, I will post out.

Thank you again!



Tang Tao