3 Attachment(s)
Need to resize the window to make QwtPlotSpectrogram shows correctly
Hello,
I'm showing Qwt plots in different tabs of a QTabWidget :
Attachment 13158
The first tab is "Main" and contains two Qwt plots (curve & spectrogram, in a vertical layout with an exapanding horitzontal and vertical size policy otherwise the plots will not take all the available place - strange strange...).
Then, I go to another tab "Baseline" to load data from a file and replot all the tabs's plots.
My problem : the QwtSpectrogram of the main tab is not showing correctly, the yLeft axis title disappeared and the yRight axis are overflowing :
Attachment 13159
If I resize the window the plot will be repainted correctly :
Attachment 13160
How can I fix this ? I called repaint() after replot() but it doesn't fix the problem. It seems that the problem is that the replot is not well done if the plot belongs to a masked tab.
Thanks !
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
The geometry of a child is always the responsibility of the parent - the child is indicating that something relevant has changed by sending a QEvent::LayoutRequest.
From the screenshot I guess, that you are changing something behind the back of the intended Qwt API and the necessary QEvent::LayoutRequest is not sent to the plot widget.
If you know which operation is responsible you can try to manually call QwtPlot::updateLayout - or post a QEvent::LayoutRequest event to the plot widget, if you need an asynchronous update.
Uwe
3 Attachment(s)
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Hello Uwe,
I really didn't understand your explanation : the size of the spectrogram plot didn't change between the moment where I loaded the data and got back to the main plot (I didn't resize the window).
Let me give you another example, I noticed that if I don't show the empty plot that is in "Spectrum" before loading the data, it will be displayed correctly. But If I show the "Spectrum" tab then load the data then go back to it the plot will not be shown correctly :
Loading data then showing the "spectrum" tab (OK !)
Attachment 13161
Showing the "spectrum" tab, loading the datan getting back to "spectrum tab" (NOT OK)
This Attachment 13162 , loading data from "Baseline" tab then going back to "Spectrum", Attachment 13163
In fact, I'm changing my plotting API to Qwt. I didn't have this problem with QCP or VTK for example ! and as I mentionned before, I was obliged to apply an exapanding horizontal and vertical size policy for the Qwt widgets otherwise they are too small.
If I place directly in the tab widget, Qwt widgets in its layout, I can't resize the window no more (the maximize button disappears !!??!!!). That's why I'm obliged to put a Qwt widgets inside a QWidget. That's really weired (and of course I didn't have these bizarre issues with Qcp or VTK 2D plots).
UPDATE: looking back at the last screenshots, it appears that the axis labels are not scaling correctly or something like that.
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Quote:
Originally Posted by
embeddedmz
I really didn't understand your explanation : ...
As I don't have much information about your code I can only guess from the screenshots - and those look like the internal layout inside plot widget needs to be recalculated with QwtPlot::updateLayout.
Just to verify if I'm right you can set up a timer calling manually QwtPlot::updateLayout to see if this does the job.
If yes the next step is to find out, why updateLayout is not called.
The other reason I can imagine is, that the plot widget itself is not resized by its parent, what would be a bug in your layout code. You can overload QwtPlot::resizeEvent to see what size it gets and if this is the correct one. If this is your problem it might be related to your tab widget, that for some reason blocks layout calculations, when being on a different tab.
But if you can simplify your problem to a small compilable demo I can tell you what is going wrong.
Uwe
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Quote:
Just to verify if I'm right you can set up a timer calling manually QwtPlot::updateLayout to see if this does the job.
If yes the next step is to find out, why updateLayout is not called.
Calling updateLayout after replot (or with a timer) fixed the problem ! Does this mean updateLayout performs a second replot after the first one ?
I will try to produce a demo...
Thanks.
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Quote:
Originally Posted by
embeddedmz
Does this mean updateLayout performs a second replot after the first one ?
When updateLayout leads to a different size for the plot canvas, then the content of the canvas has to be recreated from scratch. This is not exactly the same as what replot ( no update of the scale ticks/intervals ) does, but as the heavy operation ( recalculation of the spectrogram image ) is done twice you should definitely understand and fix the problem.
Uwe
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Uwe,
I made a quick example here https://github.com/embeddedmz/qwt_sp..._issue_example
To reproduce the issue, show the "Plot" tab, then go back to the "Button" tab and click on its content (it's a button !), then go back to the "Plot" tab. You will see, for example, that the labels of the right y axis are overflowing.
If you press on the button without passing by the "Plot" tab, there will be no problem !
Maybe the problem is I'm setting an axis scale before rendering it ?
Quote:
d_plot->d_spectrogram->setData( new SpectrogramData() );
d_plot->setAxisScale( QwtPlot::yRight, 100000, 900000 ); // <==== ????
d_plot->replot();
You can also check that without fixing a size policy, the plots are small !
Regards.
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Any news concerning this subject ? Sorry of insisting, but I want to adopt Qwt as the plotting library in our products (and tools) and some of the issues it brings (unlike QCP) are really frustrating.
Thanks.
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Quote:
Any news concerning this subject ?
I had a quick look at your demo and the problem is related to the implementation of QWidget::updateGeometry().
When looking into the implementation you can see, that it blocks posting the LayoutRequest events, when the parent is not visible. In your situation updateGeometry is called from the scale widget and the parent is the plot widget being invisible. Not sure, why this is implemented like this in qwidget.cpp as updates are processed for QLayouts - so I'm tempted to call it a Qt bug.
A possible workaround for your demo would be:
Code:
QObject::connect(pushButton,
&QPushButton
::pressed,
[this]() {
d_plot->d_spectrogram->setData( new SpectrogramData() );
d_plot
->setAxisScale
( QwtPlot::yRight,
100000,
900000 );
if ( !d_plot->isVisible() )
d_plot->updateLayout(); // does not cause expensive operation, when being done before the replot
d_plot->replot();
});
A possible workaround in qwt_scale_widget.cpp would be:
Code:
{
....
if ( update_geometry )
{
updateGeometry();
if ( auto w = parentWidget() )
{
if ( !w->isVisible() )
}
update();
}
}
Quote:
Sorry of insisting, but I want to adopt Qwt as the plotting library in our products (and tools) and some of the issues it brings (unlike QCP) are really frustrating.
You would have a similar amount of problems when migrating the other way round. But QCP is a commercial product and you can pay for what you expect from me to do for free.
Uwe
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Hello Uwe,
First of all, thank you very much for your reply, that's very kind of you.
This workaround won't work. I have already tried it : calling updateLayout before replot won't fix the replot issue. However, I will use the condition to avoid updating the layout after the replot uselessly. I will try the second workaround another time (soon).
Code:
if ( !d_plot->isVisible() )
d_plot->updateLayout(); // does not cause expensive operation, when being done before the replot
Otherwise (in the same subject), I have an issue reploting the QwtPlotSpectrogram with a slider (screenshot in my second post) : I use the slider to rescale the data range and I am doing this :
Code:
// dLower, dUpper are double variables (new data range)
m_plot
->setAxisScale
(QwtPlot::yRight, dLower, dUpper
);
axis->setColorMap(QwtInterval(dLower, dUpper), new LinearColorMapRGB()); // I need to do this, otherwise, the color bar will change
//axis->setColorBarEnabled(true); // already done elsewhere
RawPlotData* spectroData = static_cast<RawPlotData*>(m_spectrogram.data());
if (spectroData)
{
spectroData->SetZRange(dLower, dUpper); // here I'm just calling setInterval(Qt::ZAxis, QwtInterval(dLower, dUpper) on the QwtMatrixRasterData object
}
m_plot->replot(); // I tried also to call repaint after it etc...
But the replot with or without updateLayout and/or repaint, doesn't update the shown result. Only resizing the window, replots the data with the new data range.
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Quote:
This workaround won't work. I have already tried it : calling updateLayout before replot won't fix the replot issue.
The problem is about a missing layout update - not replotting. And on my box the workaround solved it in the demo code ( note, that updateLayout needs to be alled after setAxisScale and before replot ). So maybe you are talking about a different situation/problem now ?
Quote:
Otherwise (in the same subject), I have an issue reploting the QwtPlotSpectrogram with a slider ...
Your code is changing attributes behind the back of the spectrogram item and therefore its internal cache is not invalidated. It is not wrong to do things this way, but then you have to help the spectrogram item by calling:
Code:
m_spectrogram->invalidateCache().
HTH,
Uwe
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Quote:
The problem is about a missing layout update - not replotting. And on my box the workaround solved it in the demo code ( note, that updateLayout needs to be alled after setAxisScale and before replot ). So maybe you are talking about a different situation/problem now ?
I called updateLayout just before replot, so after any eventual setAxisScale call. I even copied/pasted your code with the workaround in the demo and nothing changed !
My Qt version is 5.12.3 by the way and actually working under Ubuntu 18.04 (but will also run the program on Centos 7 later).
Like for the yRight axis's color bar issue (see the comment above), reassigning a new color map to the spectrogram object fixed my issue ! It's not pretty but it doesn't matter :p
Code:
m_spectrogram.setColorMap(new LinearColorMapRGB());
Invalidating the cache worked perfectly ! Awesome, thank you !
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Quote:
Originally Posted by
embeddedmz
I even copied/pasted your code with the workaround in the demo and nothing changed !!
Ah yes I only checked the other workaround. Calling updateLayout does not work because the missing LayoutRequest is from the autoscaler for the x axis, that happens in replot.
But this one should work:
Code:
QObject::connect(pushButton,
&QPushButton
::pressed,
[this]() {
d_plot->d_spectrogram->setData( new SpectrogramData() );
d_plot
->setAxisScale
( QwtPlot::yRight,
100000,
900000 );
d_plot->replot();
});
The situations is kind of specific as you need to do changes for an invisible plot, that has been shown before at least once. Sending the LayoutRequest manually is of course stupid and leads to a recalulation of the layout, that is not always necessary. But it doesn't result in recreating the image of your spectrogram, what is the heavy operation, that needs to be avoided.
The other workaround in qwt_scale_widget is a better one, as it avoids any pointless operation. I will add it as a fix to the Qwt code - something like this:
Code:
if ( update_geometry )
{
updateGeometry();
{
if ( !w->isVisible() && w->layout() == NULL )
{
if ( w->testAttribute( Qt::WA_WState_Polished ) )
}
}
update();
}
HTH,
Uwe
1 Attachment(s)
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Neat !
I have two more questions (I'm really curious) :
- What does "Qt::WA_WState_Polished" mean ? is this made to handle the case when a plot has already been shown but was reploted when it's hidden ?
- As mentionned somewhere in this thread : what do you think about the fact that I need to set an expanding vertical and horizontal size policy for the QwtPlot which is a child of another QWidget so that the QwtPlot takes all the available space (like in the screenshots) and not like this : Attachment 13164
I have also a suggestion : when changing the range of data of a spectrogram, I need also to rescale the color bar of the yRight axis :
Code:
axis->setColorMap(QwtInterval(dLower, dUpper), new LinearColorMapRGB());
The problem is that I need to make a memory allocation each time I need to rescale, whereas I only need to change the interval (first parameter). There's indeed this const method, but it returns a copy :
Code:
QwtInterval colorBarInterval() const;
It would be great if there's a non const method that returns a reference to the internal QwtInterval, so we can modify it without reallocating a new color map !
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Quote:
What does "Qt::WA_WState_Polished" mean ?
It is an attribute, that is set once the widget has received a QEvent::Polish event - see https://doc.qt.io/qt-5/qwidget.html#ensurePolished.
A widget always gets an initial resize event that leads in case of the plot widget to calling updateLayout and there is no reason to trigger extra updates before that. So checking for Qt::WA_WState_Polished is a minor optimization for this initial phase.
Quote:
what do you think about the fact that I need to set an expanding vertical and horizontal size policy for the QwtPlot which is a child of another QWidget so that the QwtPlot takes all the available space
A widget doesn't take any space it is always the parent that gives its children their geometries. So obviously your parent widget does this according to the size policies of its children. The default size policy of the plot widget is QSizePolicy::MinimumExpanding in both directions - why your parent does what it does then is hard to say without knowing your code.
Uwe
Re: Need to resize the window to make QwtPlotSpectrogram shows correctly
Hi all, first post in the forum. I had the same resize problem as the OP.
I wanted to show a bar plot:
Code:
BarChart
::BarChart(QWidget *parent
) : QwtCustomPlot(parent)
{
QwtColumnSymbol *columnSymbol;
columnSymbol = new QwtColumnSymbol(QwtColumnSymbol::Box);
columnSymbol->setLineWidth(0);
columnSymbol->setFrameStyle(QwtColumnSymbol::NoFrame);
columnSymbol
->setPalette
(QPalette("Red"));
_barChart = new QwtPlotBarChart();
_barChart->setLayoutPolicy(QwtPlotBarChart::AutoAdjustSamples);
_barChart->setSpacing(2);
_barChart->setMargin(0);
_barChart->setSymbol(columnSymbol);
_barChart->attach(this);
}
inherited from the custom plotter
Code:
QwtCustomPlot
::QwtCustomPlot(QWidget *parent
) :{
((QFrame *)canvas
())->setLineWidth
(0);
plotLayout()->setCanvasMargin(0);
setAttribute(Qt::WA_Hover);
setAutoFillBackground(true);
enableAxis
(QwtPlot::xBottom,
false);
setAxisTitle
(QwtPlot::xBottom, axisText
);
setAxisTitle
(QwtPlot::yLeft, axisText
);
}
which sets the canvas margin to 0, hence filling the canvas with the bar plot.
Since a bar is 1 unit wide, the x axis range of n bars goes from -0.5 to n-0.5. I scale it manually at each update:
Code:
void BarChart::setBars(const QVector<double> &values)
{
if(values.isEmpty())
return;
setAxisScale(
-0.5,
values.size()-0.5);
_barChart->setSamples(values);
}
This works as long as I don't resize the plot, with the bar at the extremes adjacent to the widget border.
However, resizing the plot resets the canvas margins to 0.5 units to the extremes, hence changing the layout.
The solution was to force the canvas margins to follow the scale
Code:
plotLayout()->setAlignCanvasToScales(true);
The resize now keeps the layout unaltered!