Getting axis rescaler to work while rending chart via QwtPlotRenderer
I use PlotRescaler to get my axis displayed proportionally, regardless of the plot size (currently I'm using the X-Axis as reference):
Code:
PlotRescaler
::PlotRescaler(QwtPlot * chart
) : QwtPlotRescaler(chart->canvas())
{
setRescalePolicy(QwtPlotRescaler::Fitting);
setAspectRatio(0.0);
setAspectRatio
(QwtPlot::yLeft,
1.0);
}
When I resize my chart widget, the y-axis limits get updated accordingly to keep the aspect ratio.
However, when I render my chart to bitmap/vector via QwtPlotRenderer, for example with:
Code:
QPdfWriter pdfWriter( fname );
pdfWriter.setPageSizeMM( sizeMM );
pdfWriter.setTitle( title );
pdfWriter.setPageMargins( QMarginsF() );
pdfWriter.setResolution( resolution );
renderer.render( m_chart, &painter, documentRect );
hereby using arbitrary target sizes that differ from the current screen ratio, the aspect ratio is not maintained. Apparently, the rescaler is not notified of the chart/plot layout dimension change during the rendering.
Is there a workaround/easy fix for that or do I have to modify QwtPlotRenderer to manually apply the rescaling after the plot layout update?
Thanks,
Andreas
Re: Getting axis rescaler to work while rending chart via QwtPlotRenderer
Hi there,
since there wasn't a single reply since last summer, this seems to be a rather unpopular feature :-)
Anyway, diggin into the code I found no easy way to implement this - the current API doesn't offer a convenient choice. Anyhow, here's what I've come up with so far:
The current QwtPlotRescaler operates on the chart canvas size:
Code:
//! Adjust the plot axes scales
void QwtPlotRescaler::rescale() const
{
// here we get the size of the plot canvas and use this to adjust the axes
const QSize size
= canvas
()->contentsRect
().
size();
rescale( size, size );
}
Now, within the plot renderer, we cannot use the canvas size, so the first change to implement was to make the
Code:
// should be public instead of protected
void QwtPlotRescaler::rescale(
const QSize &oldSize,
const QSize &newSize
) const
public. So now it can be called from within the plot renderer.
Also, the plot renderer needs to know about the rescaler, so an additional (optional) argument is added.
Code:
// render() function of QwtPlotRenderer get's an optional 4th argument
QPainter *,
const QRectF &rect , QwtPlotRescaler
*plotRescaler
= NULL) const;
Lastly, we call the plotRescaler after having adjusted the layout:
Code:
void QwtPlotRenderer
::render( QwtPlot *plot,
QPainter *painter,
const QRectF &plotRect, QwtPlotRescaler
* plotRescaler
) const {
...
// adjust plot axes based on layoutRect dimensions
if (plotRescaler) {
QSize s
= layoutRect.
size().
toSize();
plotRescaler->rescale(s,s);
}
...
this does the trick (almost). Unfortunately, the desired aspect ratio is only kept approximately. So, probably layoutRect() and contentsRect() are not the same here or the scaling within the plot rescaler still does something different. I'll try to track that down...
@Uwe: do you see a way to get this proportionality feature formally into the QwtPlotRenderer... my variant is certainly a hack and probably not what you would want to have in the official sources, right? :-)
Bye,
Andreas
Added after 10 minutes:
Update: seems things are not so easy after all - QwtPlotRescaler::updateScales() draws upon the scale div objects in the plot - thus using dimensions of the plot object (that will naturally differ) from the target render rectangle and thus there's a lot of garbage when the original plot dimensions do not match those of the target plot... So I guess implementing the whole scale adjustment stuff anew in the plot render will be necessary :-(
Does anyone have a better idea?
-Andreas
Re: Getting axis rescaler to work while rending chart via QwtPlotRenderer
Actually the problem is how QwtPlotLayout works: it subtracts title + footer + legend + axes from the given geometry and the rest goes to the canvas.
That makes sense, as the canvas is the element, that accepts any type of geometry - beside getting too small.
But if you need a specific aspect ratio it has be done the other way round: you start with the canvas and then attach the other elements accepting, that the plot does not fill the given geometry completely. If you want to try this you could overload QwtPlotLayout::activate, where you calculate the geometries like described.
Uwe
PS: what happened to QwtPlotVectorField - would be nice to have this class being complete ?