55# Copyright (c) 2015 Pierre Raybaut, for the Python translation/optimization
66# (see LICENSE file for more details)
77
8+ """
9+ QwtPlotRenderer
10+ ---------------
11+
12+ .. autoclass:: QwtPlotRenderer
13+ :members:
14+ """
15+
816from __future__ import division
917
1018from qwt .painter import QwtPainter
2533
2634
2735def qwtCanvasClip (canvas , canvasRect ):
36+ """
37+ The clip region is calculated in integers
38+ To avoid too much rounding errors better
39+ calculate it in target device resolution
40+ """
2841 x1 = np .ceil (canvasRect .left ())
2942 x2 = np .floor (canvasRect .right ())
3043 y1 = np .ceil (canvasRect .top ())
@@ -39,6 +52,30 @@ def __init__(self):
3952 self .layoutFlags = QwtPlotRenderer .DefaultLayout
4053
4154class QwtPlotRenderer (QObject ):
55+ """
56+ Renderer for exporting a plot to a document, a printer
57+ or anything else, that is supported by QPainter/QPaintDevice
58+
59+ Discard flags:
60+
61+ * `QwtPlotRenderer.DiscardNone`: Render all components of the plot
62+ * `QwtPlotRenderer.DiscardBackground`: Don't render the background of the plot
63+ * `QwtPlotRenderer.DiscardTitle`: Don't render the title of the plot
64+ * `QwtPlotRenderer.DiscardLegend`: Don't render the legend of the plot
65+ * `QwtPlotRenderer.DiscardCanvasBackground`: Don't render the background of the canvas
66+ * `QwtPlotRenderer.DiscardFooter`: Don't render the footer of the plot
67+ * `QwtPlotRenderer.DiscardCanvasFrame`: Don't render the frame of the canvas
68+
69+ .. note::
70+
71+ The `QwtPlotRenderer.DiscardCanvasFrame` flag has no effect when using
72+ style sheets, where the frame is part of the background
73+
74+ Layout flags:
75+
76+ * `QwtPlotRenderer.DefaultLayout`: Use the default layout as on screen
77+ * `QwtPlotRenderer.FrameWithScales`: Instead of the scales a box is painted around the plot canvas, where the scale ticks are aligned to.
78+ """
4279
4380 # enum DiscardFlag
4481 DiscardNone = 0x00
@@ -58,37 +95,123 @@ def __init__(self, parent=None):
5895 self .__data = QwtPlotRenderer_PrivateData ()
5996
6097 def setDiscardFlag (self , flag , on ):
98+ """
99+ Change a flag, indicating what to discard from rendering
100+
101+ :param int flag: Flag to change
102+ :param bool on: On/Off
103+
104+ .. seealso::
105+
106+ :py:meth:`testDiscardFlag()`, :py:meth:`setDiscardFlags()`,
107+ :py:meth:`discardFlags()`
108+ """
61109 if on :
62110 self .__data .discardFlags |= flag
63111 else :
64112 self .__data .discardFlags &= ~ flag
65113
66114 def testDiscardFlag (self , flag ):
115+ """
116+ :param int flag: Flag to be tested
117+ :return: True, if flag is enabled.
118+
119+ .. seealso::
120+
121+ :py:meth:`setDiscardFlag()`, :py:meth:`setDiscardFlags()`,
122+ :py:meth:`discardFlags()`
123+ """
67124 return self .__data .discardFlags & flag
68125
69126 def setDiscardFlags (self , flags ):
127+ """
128+ Set the flags, indicating what to discard from rendering
129+
130+ :param int flags: Flags
131+
132+ .. seealso::
133+
134+ :py:meth:`testDiscardFlag()`, :py:meth:`setDiscardFlag()`,
135+ :py:meth:`discardFlags()`
136+ """
70137 self .__data .discardFlags = flags
71138
72139 def discardFlags (self ):
140+ """
141+ :return: Flags, indicating what to discard from rendering
142+
143+ .. seealso::
144+
145+ :py:meth:`setDiscardFlag()`, :py:meth:`setDiscardFlags()`,
146+ :py:meth:`testDiscardFlag()`
147+ """
73148 return self .__data .discardFlags
74149
75150 def setLayoutFlag (self , flag , on ):
151+ """
152+ Change a layout flag
153+
154+ :param int flag: Flag to change
155+
156+ .. seealso::
157+
158+ :py:meth:`testLayoutFlag()`, :py:meth:`setLayoutFlags()`,
159+ :py:meth:`layoutFlags()`
160+ """
76161 if on :
77162 self .__data .layoutFlags |= flag
78163 else :
79164 self .__data .layoutFlags &= ~ flag
80165
81166 def testLayoutFlag (self , flag ):
167+ """
168+ :param int flag: Flag to be tested
169+ :return: True, if flag is enabled.
170+
171+ .. seealso::
172+
173+ :py:meth:`setLayoutFlag()`, :py:meth:`setLayoutFlags()`,
174+ :py:meth:`layoutFlags()`
175+ """
82176 return self .__data .layoutFlags & flag
83177
84178 def setLayoutFlags (self , flags ):
179+ """
180+ Set the layout flags
181+
182+ :param int flags: Flags
183+
184+ .. seealso::
185+
186+ :py:meth:`setLayoutFlag()`, :py:meth:`testLayoutFlag()`,
187+ :py:meth:`layoutFlags()`
188+ """
85189 self .__data .layoutFlags = flags
86190
87191 def layoutFlags (self ):
192+ """
193+ :return: Layout flags
194+
195+ .. seealso::
196+
197+ :py:meth:`setLayoutFlags()`, :py:meth:`setLayoutFlag()`,
198+ :py:meth:`testLayoutFlag()`
199+ """
88200 return self .__data .layoutFlags
89201
90202 def renderDocument (self , plot , filename , sizeMM = (300 , 200 ), resolution = 85 ,
91203 format_ = None ):
204+ """
205+ Render a plot to a file
206+
207+ The format of the document will be auto-detected from the
208+ suffix of the file name.
209+
210+ :param qwt.plot.QwtPlot plot: Plot widget
211+ :param str fileName: Path of the file, where the document will be stored
212+ :param QSizeF sizeMM: Size for the document in millimeters
213+ :param int resolution: Resolution in dots per Inch (dpi)
214+ """
92215 if isinstance (sizeMM , tuple ):
93216 sizeMM = QSizeF (* sizeMM )
94217 if format_ is None :
@@ -144,6 +267,30 @@ def renderDocument(self, plot, filename, sizeMM=(300, 200), resolution=85,
144267 raise TypeError ("Unsupported file format '%s'" % fmt )
145268
146269 def renderTo (self , plot , dest ):
270+ """
271+ Render a plot to a file
272+
273+ Supported formats are:
274+
275+ - pdf: Portable Document Format PDF
276+ - ps: Postcript
277+ - svg: Scalable Vector Graphics SVG
278+ - all image formats supported by Qt, see QImageWriter.supportedImageFormats()
279+
280+ Scalable vector graphic formats like PDF or SVG are superior to
281+ raster graphics formats.
282+
283+ :param qwt.plot.QwtPlot plot: Plot widget
284+ :param str fileName: Path of the file, where the document will be stored
285+ :param str format: Format for the document
286+ :param QSizeF sizeMM: Size for the document in millimeters.
287+ :param int resolution: Resolution in dots per Inch (dpi)
288+
289+ .. seealso::
290+
291+ :py:meth:`renderTo()`, :py:meth:`render()`,
292+ :py:meth:`qwt.painter.QwtPainter.setRoundingAlignment()`
293+ """
147294 if isinstance (dest , QPaintDevice ):
148295 w = dest .width ()
149296 h = dest .height ()
@@ -165,12 +312,28 @@ def renderTo(self, plot, dest):
165312 self .render (plot , p , rect )
166313
167314 def render (self , plot , painter , plotRect ):
315+ """
316+ Paint the contents of a QwtPlot instance into a given rectangle.
317+
318+ :param qwt.plot.QwtPlot plot: Plot to be rendered
319+ :param QPainter painter: Painter
320+ :param str format: Format for the document
321+ :param QRectF plotRect: Bounding rectangle
322+
323+ .. seealso::
324+
325+ :py:meth:`renderDocument()`, :py:meth:`renderTo()`,
326+ :py:meth:`qwt.painter.QwtPainter.setRoundingAlignment()`
327+ """
168328 if painter == 0 or not painter .isActive () or not plotRect .isValid ()\
169329 or plot .size ().isNull ():
170330 return
171331 if not self .__data .discardFlags & self .DiscardBackground :
172332 QwtPainter .drawBackground (painter , plotRect , plot )
173333
334+ # The layout engine uses the same methods as they are used
335+ # by the Qt layout system. Therefore we need to calculate the
336+ # layout in screen coordinates and paint with a scaled painter.
174337 transform = QTransform ()
175338 transform .scale (float (painter .device ().logicalDpiX ())/ plot .logicalDpiX (),
176339 float (painter .device ().logicalDpiY ())/ plot .logicalDpiY ())
@@ -194,6 +357,9 @@ def render(self, plot, painter, plotRect):
194357 scaleWidget .setMargin (0 )
195358 if not plot .axisEnabled (axisId ):
196359 left , right , top , bottom = 0 , 0 , 0 , 0
360+ # When we have a scale the frame is painted on
361+ # the position of the backbone - otherwise we
362+ # need to introduce a margin around the canvas
197363 if axisId == QwtPlot .yLeft :
198364 layoutRect .adjust (1 , 0 , 0 , 0 )
199365 elif axisId == QwtPlot .yRight :
@@ -204,6 +370,7 @@ def render(self, plot, painter, plotRect):
204370 layoutRect .adjust (0 , 0 , 0 , - 1 )
205371 layoutRect .adjust (left , top , right , bottom )
206372
373+ # Calculate the layout for the document.
207374 layoutOptions = QwtPlotLayout .IgnoreScrollbars
208375
209376 if self .__data .layoutFlags & self .FrameWithScales or \
@@ -221,6 +388,8 @@ def render(self, plot, painter, plotRect):
221388
222389 maps = self .buildCanvasMaps (plot , layout .canvasRect ())
223390 if self .updateCanvasMargins (plot , layout .canvasRect (), maps ):
391+ # recalculate maps and layout, when the margins
392+ # have been changed
224393 layout .activate (plot , layoutRect , layoutOptions )
225394 maps = self .buildCanvasMaps (plot , layout .canvasRect ())
226395
@@ -261,24 +430,57 @@ def render(self, plot, painter, plotRect):
261430 layout .invalidate ()
262431
263432 def renderTitle (self , plot , painter , rect ):
433+ """
434+ Render the title into a given rectangle.
435+
436+ :param qwt.plot.QwtPlot plot: Plot widget
437+ :param QPainter painter: Painter
438+ :param QRectF rect: Bounding rectangle
439+ """
264440 painter .setFont (plot .titleLabel ().font ())
265441 color = plot .titleLabel ().palette ().color (QPalette .Active , QPalette .Text )
266442 painter .setPen (color )
267443 plot .titleLabel ().text ().draw (painter , rect )
268444
269445 def renderFooter (self , plot , painter , rect ):
446+ """
447+ Render the footer into a given rectangle.
448+
449+ :param qwt.plot.QwtPlot plot: Plot widget
450+ :param QPainter painter: Painter
451+ :param QRectF rect: Bounding rectangle
452+ """
270453 painter .setFont (plot .footerLabel ().font ())
271454 color = plot .footerLabel ().palette ().color (QPalette .Active , QPalette .Text )
272455 painter .setPen (color )
273456 plot .footerLabel ().text ().draw (painter , rect )
274457
275458 def renderLegend (self , plot , painter , rect ):
459+ """
460+ Render the legend into a given rectangle.
461+
462+ :param qwt.plot.QwtPlot plot: Plot widget
463+ :param QPainter painter: Painter
464+ :param QRectF rect: Bounding rectangle
465+ """
276466 if plot .legend ():
277467 fillBackground = not self .__data .discardFlags & self .DiscardBackground
278468 plot .legend ().renderLegend (painter , rect , fillBackground )
279469
280470 def renderScale (self , plot , painter , axisId , startDist , endDist ,
281471 baseDist , rect ):
472+ """
473+ Paint a scale into a given rectangle.
474+ Paint the scale into a given rectangle.
475+
476+ :param qwt.plot.QwtPlot plot: Plot widget
477+ :param QPainter painter: Painter
478+ :param int axisId: Axis
479+ :param int startDist: Start border distance
480+ :param int endDist: End border distance
481+ :param int baseDist: Base distance
482+ :param QRectF rect: Bounding rectangle
483+ """
282484 if not plot .axisEnabled (axisId ):
283485 return
284486 scaleWidget = plot .axisWidget (axisId )
@@ -322,6 +524,14 @@ def renderScale(self, plot, painter, axisId, startDist, endDist,
322524 painter .restore ()
323525
324526 def renderCanvas (self , plot , painter , canvasRect , maps ):
527+ """
528+ Render the canvas into a given rectangle.
529+
530+ :param qwt.plot.QwtPlot plot: Plot widget
531+ :param QPainter painter: Painter
532+ :param qwt.scale_map.QwtScaleMap maps: mapping between plot and paint device coordinates
533+ :param QRectF rect: Bounding rectangle
534+ """
325535 canvas = plot .canvas ()
326536 r = canvasRect .adjusted (0. , 0. , - 1. , 1. )
327537 if self .__data .layoutFlags & self .FrameWithScales :
@@ -385,6 +595,13 @@ def renderCanvas(self, plot, painter, canvasRect, maps):
385595 painter .restore ()
386596
387597 def buildCanvasMaps (self , plot , canvasRect ):
598+ """
599+ Calculated the scale maps for rendering the canvas
600+
601+ :param qwt.plot.QwtPlot plot: Plot widget
602+ :param QRectF canvasRect: Target rectangle
603+ :return: Calculated scale maps
604+ """
388605 maps = []
389606 for axisId in range (QwtPlot .axisCnt ):
390607 map_ = QwtScaleMap ()
@@ -426,6 +643,19 @@ def updateCanvasMargins(self, plot, canvasRect, maps):
426643 return marginsChanged
427644
428645 def exportTo (self , plot , documentname , sizeMM = None , resolution = 85 ):
646+ """
647+ Execute a file dialog and render the plot to the selected file
648+
649+ :param qwt.plot.QwtPlot plot: Plot widget
650+ :param str documentName: Default document name
651+ :param QSizeF sizeMM: Size for the document in millimeters
652+ :param int resolution: Resolution in dots per Inch (dpi)
653+ :return: True, when exporting was successful
654+
655+ .. seealso::
656+
657+ :py:meth:`renderDocument()`
658+ """
429659 if plot is None :
430660 return
431661 if sizeMM is None :
0 commit comments