Repotrlab 2.0
bzr revid: pinky-b8333ccaab5dad8ff965b6c380fadadf30d5212a
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
#Copyright ReportLab Europe Ltd. 2000-2004
|
||||
#see license.txt for license details
|
||||
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/graphguide/ch1_intro.py
|
||||
from reportlab.tools.docco.rl_doc_utils import *
|
||||
import reportlab
|
||||
|
||||
title("Graphics Guide")
|
||||
centred('ReportLab Version ' + reportlab.Version)
|
||||
|
||||
nextTemplate("Normal")
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Chapter 1
|
||||
#
|
||||
########################################################################
|
||||
|
||||
|
||||
heading1("Introduction")
|
||||
|
||||
|
||||
heading2("About this document")
|
||||
disc("""
|
||||
This document is intended to be a helpful and reasonably full
|
||||
introduction to the use of the ReportLab Graphics sub-package.
|
||||
Starting with simple drawings and shapes, we will take you through the
|
||||
slightly more complex reusable widgets all the way through to our
|
||||
powerful and flexible chart library. You will see examples of using
|
||||
reportlab/graphics to make bar charts, line charts, line plots, pie
|
||||
charts... and a smiley face.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
We presume that you have already installed both the Python programming
|
||||
language and the core ReportLab library. If you have not done either
|
||||
of these, look in the ReportLab User Guide where chapter one
|
||||
talks you through all the required steps.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
We recommend that you read some or all of the User Guide and have at
|
||||
least a basic understanding of how the ReportLab library works before
|
||||
you start getting to grips with ReportLab Graphics.
|
||||
""")
|
||||
|
||||
disc("")
|
||||
todo("""
|
||||
Be warned! This document is in a <em>very</em> preliminary form. We need
|
||||
your help to make sure it is complete and helpful. Please send any
|
||||
feedback to our user mailing list, reportlab-users@reportlab.com.
|
||||
""")
|
||||
|
||||
heading2("What is ReportLab?")
|
||||
disc("""ReportLab is a software library that lets you directly
|
||||
create documents in Adobe's Portable Document Format (PDF) using
|
||||
the Python programming language. """)
|
||||
|
||||
disc("""The ReportLab library directly creates PDF based on
|
||||
your graphics commands. There are no intervening steps. Your applications
|
||||
can generate reports extremely fast - sometimes orders
|
||||
of magnitude faster than traditional report-writing
|
||||
tools.""")
|
||||
|
||||
heading2("What is ReportLab Graphics?")
|
||||
disc("""
|
||||
ReportLab Graphics is one of the sub-packages to the ReportLab
|
||||
library. It started off as a stand-alone set of programs, but is now a
|
||||
fully integrated part of the ReportLab toolkit that allows you to use
|
||||
its powerful charting and graphics features to improve your PDF forms
|
||||
and reports.
|
||||
""")
|
||||
|
||||
heading2("Getting Involved")
|
||||
disc("""ReportLab is an Open Source project. Although we are
|
||||
a commercial company we provide the core PDF generation
|
||||
sources freely, even for commercial purposes, and we make no income directly
|
||||
from these modules. We also welcome help from the community
|
||||
as much as any other Open Source project. There are many
|
||||
ways in which you can help:""")
|
||||
|
||||
bullet("""General feedback on the core API. Does it work for you?
|
||||
Are there any rough edges? Does anything feel clunky and awkward?""")
|
||||
|
||||
bullet("""New objects to put in reports, or useful utilities for the library.
|
||||
We have an open standard for report objects, so if you have written a nice
|
||||
chart or table class, why not contribute it?""")
|
||||
|
||||
bullet("""Demonstrations and Case Studies: If you have produced some nice
|
||||
output, send it to us (with or without scripts). If ReportLab solved a
|
||||
problem for you at work, write a little 'case study' and send it in.
|
||||
And if your web site uses our tools to make reports, let us link to it.
|
||||
We will be happy to display your work (and credit it with your name
|
||||
and company) on our site!""")
|
||||
|
||||
bullet("""Working on the core code: we have a long list of things
|
||||
to refine or to implement. If you are missing some features or
|
||||
just want to help out, let us know!""")
|
||||
|
||||
disc("""The first step for anyone wanting to learn more or
|
||||
get involved is to join the mailing list. To Subscribe visit
|
||||
$http://two.pairlist.net/mailman/listinfo/reportlab-users$.
|
||||
From there you can also browse through the group's archives
|
||||
and contributions. The mailing list is
|
||||
the place to report bugs and get support. """)
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
#Copyright ReportLab Europe Ltd. 2000-2004
|
||||
#see license.txt for license details
|
||||
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/graphguide/ch2_concepts.py
|
||||
from reportlab.tools.docco.rl_doc_utils import *
|
||||
|
||||
heading1("General Concepts")
|
||||
|
||||
disc("""
|
||||
In this chapter we will present some of the more fundamental principles of
|
||||
the graphics library, which will show-up later in various places.
|
||||
""")
|
||||
|
||||
|
||||
heading2("Drawings and Renderers")
|
||||
|
||||
disc("""
|
||||
A <i>Drawing</i> is a platform-independent description of a collection of
|
||||
shapes.
|
||||
It is not directly associated with PDF, Postscript or any other output
|
||||
format.
|
||||
Fortunately, most vector graphics systems have followed the Postscript
|
||||
model and it is possible to describe shapes unambiguously.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
A drawing contains a number of primitive <i>Shapes</i>.
|
||||
Normal shapes are those widely known as rectangles, circles, lines,
|
||||
etc.
|
||||
One special (logic) shape is a <i>Group</i>, which can hold other
|
||||
shapes and apply a transformation to them.
|
||||
Groups represent composites of shapes and allow to treat the
|
||||
composite as if it were a single shape.
|
||||
Just about anything can be built up from a small number of basic
|
||||
shapes.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
The package provides several <i>Renderers</i> which know how to draw a
|
||||
drawing into different formats.
|
||||
These include PDF (of course), Postscript, and bitmap output.
|
||||
The bitmap renderer uses Raph Levien's <i>libart</i> rasterizer
|
||||
and Fredrik Lundh's <i>Python Imaging Library</i> (PIL).
|
||||
Very recently, an experimental SVG renderer was also added.
|
||||
It makes use of Python's standard library XML modules, so you don't
|
||||
need to install the XML-SIG's additional package named PyXML.
|
||||
If you have the right extensions installed, you can generate drawings
|
||||
in bitmap form for the web as well as vector form for PDF documents,
|
||||
and get "identical output".
|
||||
""")
|
||||
|
||||
disc("""
|
||||
The PDF renderer has special "privileges" - a Drawing object is also
|
||||
a <i>Flowable</i> and, hence, can be placed directly in the story
|
||||
of any Platypus document, or drawn directly on a <i>Canvas</i> with
|
||||
one line of code.
|
||||
In addition, the PDF renderer has a utility function to make
|
||||
a one-page PDF document quickly.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
The SVG renderer is special as it is still pretty experimental.
|
||||
The SVG code it generates is not really optimised in any way and
|
||||
maps only the features available in ReportLab Graphics (RLG) to
|
||||
SVG. This means there is no support for SVG animation, interactivity,
|
||||
scripting or more sophisticated clipping, masking or graduation
|
||||
shapes.
|
||||
So, be careful, and please report any bugs you find!
|
||||
""")
|
||||
|
||||
disc("""
|
||||
We expect to add both input and output filters for many vector
|
||||
graphics formats in future.
|
||||
SVG was the most prominent first one to start with for which there
|
||||
is now an output filter in the graphics package.
|
||||
An SVG input filter will probably become available in Summer 2002
|
||||
as an additional module.
|
||||
GUIs will be able to obtain screen images from the bitmap output
|
||||
filter working with PIL, so a chart could appear in a Tkinter
|
||||
GUI window.
|
||||
""")
|
||||
|
||||
|
||||
heading2("Coordinate System")
|
||||
|
||||
disc("""
|
||||
The Y-direction in our X-Y coordinate system points from the
|
||||
bottom <i>up</i>.
|
||||
This is consistent with PDF, Postscript and mathematical notation.
|
||||
It also appears to be more natural for people, especially when
|
||||
working with charts.
|
||||
Note that in other graphics models (such as SVG) the Y-coordinate
|
||||
points <i>down</i>.
|
||||
For the SVG renderer this is actually no problem as it will take
|
||||
your drawings and flip things as needed, so your SVG output looks
|
||||
just as expected.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
The X-coordinate points, as usual, from left to right.
|
||||
So far there doesn't seem to be any model advocating the opposite
|
||||
direction - at least not yet (with interesting exceptions, as it
|
||||
seems, for Arabs looking at time series charts...).
|
||||
""")
|
||||
|
||||
|
||||
heading2("Getting Started")
|
||||
|
||||
disc("""
|
||||
Let's create a simple drawing containing the string "Hello World",
|
||||
displayed on top of a coloured rectangle.
|
||||
After creating it we will save the drawing to a standalone PDF file.
|
||||
""")
|
||||
|
||||
eg("""
|
||||
from reportlab.lib import colors
|
||||
from reportlab.graphics.shapes import *
|
||||
|
||||
d = Drawing(400, 200)
|
||||
d.add(Rect(50, 50, 300, 100, fillColor=colors.yellow))
|
||||
d.add(String(150,100, 'Hello World',
|
||||
fontSize=18, fillColor=colors.red))
|
||||
|
||||
from reportlab.graphics import renderPDF
|
||||
renderPDF.drawToFile(d, 'example1.pdf', 'My First Drawing')
|
||||
""")
|
||||
|
||||
disc("This will produce a PDF file containing the following graphic:")
|
||||
|
||||
from reportlab.graphics.shapes import *
|
||||
from reportlab.graphics import testshapes
|
||||
t = testshapes.getDrawing01()
|
||||
draw(t, "'Hello World'")
|
||||
|
||||
disc("""
|
||||
Each renderer is allowed to do whatever is appropriate for its format,
|
||||
and may have whatever API is needed.
|
||||
If it refers to a file format, it usually has a $drawToFile$ function,
|
||||
and that's all you need to know about the renderer.
|
||||
Let's save the same drawing in Encapsulated Postscript format:
|
||||
""")
|
||||
|
||||
##eg("""
|
||||
## from reportlab.graphics import renderPS
|
||||
## renderPS.drawToFile(D, 'example1.eps', 'My First Drawing')
|
||||
##""")
|
||||
eg("""
|
||||
from reportlab.graphics import renderPS
|
||||
renderPS.drawToFile(d, 'example1.eps')
|
||||
""")
|
||||
|
||||
disc("""
|
||||
This will produce an EPS file with the identical drawing, which
|
||||
may be imported into publishing tools such as Quark Express.
|
||||
If we wanted to generate the same drawing as a bitmap file for
|
||||
a website, say, all we need to do is write code like this:
|
||||
""")
|
||||
|
||||
eg("""
|
||||
from reportlab.graphics import renderPM
|
||||
renderPM.saveToFile(d, 'example1.png', 'PNG')
|
||||
""")
|
||||
|
||||
disc("""
|
||||
Many other bitmap formats, like GIF, JPG, TIFF, BMP and PPN are
|
||||
genuinely available, making it unlikely you'll need to add external
|
||||
postprocessing steps to convert to the final format you need.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
To produce an SVG file containing the identical drawing, which
|
||||
may be imported into graphical editing tools such as Illustrator
|
||||
all we need to do is write code like this:
|
||||
""")
|
||||
|
||||
eg("""
|
||||
from reportlab.graphics import renderSVG
|
||||
renderSVG.drawToFile(d, 'example1.svg')
|
||||
""")
|
||||
|
||||
|
||||
heading2("Attribute Verification")
|
||||
|
||||
disc("""
|
||||
Python is very dynamic and lets us execute statements at run time that
|
||||
can easily be the source for unexpected behaviour.
|
||||
One subtle 'error' is when assigning to an attribute that the framework
|
||||
doesn't know about because the used attribute's name contains a typo.
|
||||
Python lets you get away with it (adding a new attribute to an object,
|
||||
say), but the graphics framework will not detect this 'typo' without
|
||||
taking special counter-measures.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
There are two verification techniques to avoid this situation.
|
||||
The default is for every object to check every assignment at run
|
||||
time, such that you can only assign to 'legal' attributes.
|
||||
This is what happens by default.
|
||||
As this imposes a small performance penalty, this behaviour can
|
||||
be turned off when you need it to be.
|
||||
""")
|
||||
|
||||
eg("""
|
||||
>>> r = Rect(10,10,200,100, fillColor=colors.red)
|
||||
>>>
|
||||
>>> r.fullColor = colors.green # note the typo
|
||||
>>> r.x = 'not a number' # illegal argument type
|
||||
>>> del r.width # that should confuse it
|
||||
""")
|
||||
|
||||
disc("""
|
||||
These statements would be caught by the compiler in a statically
|
||||
typed language, but Python lets you get away with it.
|
||||
The first error could leave you staring at the picture trying to
|
||||
figure out why the colors were wrong.
|
||||
The second error would probably become clear only later, when
|
||||
some back-end tries to draw the rectangle.
|
||||
The third, though less likely, results in an invalid object that
|
||||
would not know how to draw itself.
|
||||
""")
|
||||
|
||||
eg("""
|
||||
>>> r = shapes.Rect(10,10,200,80)
|
||||
>>> r.fullColor = colors.green
|
||||
Traceback (most recent call last):
|
||||
File "<interactive input>", line 1, in ?
|
||||
File "C:\code\users\andy\graphics\shapes.py", line 254, in __setattr__
|
||||
validateSetattr(self,attr,value) #from reportlab.lib.attrmap
|
||||
File "C:\code\users\andy\lib\attrmap.py", line 74, in validateSetattr
|
||||
raise AttributeError, "Illegal attribute '%s' in class %s" % (name, obj.__class__.__name__)
|
||||
AttributeError: Illegal attribute 'fullColor' in class Rect
|
||||
>>>
|
||||
""")
|
||||
|
||||
disc("""
|
||||
This imposes a performance penalty, so this behaviour can be turned
|
||||
off when you need it to be.
|
||||
To do this, you should use the following lines of code before you
|
||||
first import reportlab.graphics.shapes:
|
||||
""")
|
||||
|
||||
eg("""
|
||||
>>> import reportlab.rl_config
|
||||
>>> reportlab.rl_config.shapeChecking = 0
|
||||
>>> from reportlab.graphics import shapes
|
||||
>>>
|
||||
""")
|
||||
|
||||
disc("""
|
||||
Once you turn off $shapeChecking$, the classes are actually built
|
||||
without the verification hook; code should get faster, then.
|
||||
Currently the penalty seems to be about 25% on batches of charts,
|
||||
so it is hardly worth disabling.
|
||||
However, if we move the renderers to C in future (which is eminently
|
||||
possible), the remaining 75% would shrink to almost nothing and
|
||||
the saving from verification would be significant.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
Each object, including the drawing itself, has a $verify()$ method.
|
||||
This either succeeds, or raises an exception.
|
||||
If you turn off automatic verification, then you should explicitly
|
||||
call $verify()$ in testing when developing the code, or perhaps
|
||||
once in a batch process.
|
||||
""")
|
||||
|
||||
|
||||
heading2("Property Editing")
|
||||
|
||||
disc("""
|
||||
A cornerstone of the reportlab/graphics which we will cover below is
|
||||
that you can automatically document widgets.
|
||||
This means getting hold of all of their editable properties,
|
||||
including those of their subcomponents.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
Another goal is to be able to create GUIs and config files for
|
||||
drawings.
|
||||
A generic GUI can be built to show all editable properties
|
||||
of a drawing, and let you modify them and see the results.
|
||||
The Visual Basic or Delphi development environment are good
|
||||
examples of this kind of thing.
|
||||
In a batch charting application, a file could list all the
|
||||
properties of all the components in a chart, and be merged
|
||||
with a database query to make a batch of charts.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
To support these applications we have two interfaces, $getProperties$
|
||||
and $setProperties$, as well as a convenience method $dumpProperties$.
|
||||
The first returns a dictionary of the editable properties of an
|
||||
object; the second sets them en masse.
|
||||
If an object has publicly exposed 'children' then one can recursively
|
||||
set and get their properties too.
|
||||
This will make much more sense when we look at <i>Widgets</i> later on,
|
||||
but we need to put the support into the base of the framework.
|
||||
""")
|
||||
|
||||
eg("""
|
||||
>>> r = shapes.Rect(0,0,200,100)
|
||||
>>> import pprint
|
||||
>>> pprint.pprint(r.getProperties())
|
||||
{'fillColor': Color(0.00,0.00,0.00),
|
||||
'height': 100,
|
||||
'rx': 0,
|
||||
'ry': 0,
|
||||
'strokeColor': Color(0.00,0.00,0.00),
|
||||
'strokeDashArray': None,
|
||||
'strokeLineCap': 0,
|
||||
'strokeLineJoin': 0,
|
||||
'strokeMiterLimit': 0,
|
||||
'strokeWidth': 1,
|
||||
'width': 200,
|
||||
'x': 0,
|
||||
'y': 0}
|
||||
>>> r.setProperties({'x':20, 'y':30, 'strokeColor': colors.red})
|
||||
>>> r.dumpProperties()
|
||||
fillColor = Color(0.00,0.00,0.00)
|
||||
height = 100
|
||||
rx = 0
|
||||
ry = 0
|
||||
strokeColor = Color(1.00,0.00,0.00)
|
||||
strokeDashArray = None
|
||||
strokeLineCap = 0
|
||||
strokeLineJoin = 0
|
||||
strokeMiterLimit = 0
|
||||
strokeWidth = 1
|
||||
width = 200
|
||||
x = 20
|
||||
y = 30
|
||||
>>> """)
|
||||
|
||||
disc("""
|
||||
<i>Note: $pprint$ is the standard Python library module that allows
|
||||
you to 'pretty print' output over multiple lines rather than having
|
||||
one very long line.</i>
|
||||
""")
|
||||
|
||||
disc("""
|
||||
These three methods don't seem to do much here, but as we will see
|
||||
they make our widgets framework much more powerful when dealing with
|
||||
non-primitive objects.
|
||||
""")
|
||||
|
||||
|
||||
heading2("Naming Children")
|
||||
|
||||
disc("""
|
||||
You can add objects to the $Drawing$ and $Group$ objects.
|
||||
These normally go into a list of contents.
|
||||
However, you may also give objects a name when adding them.
|
||||
This allows you to refer to and possibly change any element
|
||||
of a drawing after constructing it.
|
||||
""")
|
||||
|
||||
eg("""
|
||||
>>> d = shapes.Drawing(400, 200)
|
||||
>>> s = shapes.String(10, 10, 'Hello World')
|
||||
>>> d.add(s, 'caption')
|
||||
>>> s.caption.text
|
||||
'Hello World'
|
||||
>>>
|
||||
""")
|
||||
|
||||
disc("""
|
||||
Note that you can use the same shape instance in several contexts
|
||||
in a drawing; if you choose to use the same $Circle$ object in many
|
||||
locations (e.g. a scatter plot) and use different names to access
|
||||
it, it will still be a shared object and the changes will be
|
||||
global.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
This provides one paradigm for creating and modifying interactive
|
||||
drawings.
|
||||
""")
|
||||
@@ -0,0 +1,416 @@
|
||||
#Copyright ReportLab Europe Ltd. 2000-2004
|
||||
#see license.txt for license details
|
||||
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/graphguide/ch3_shapes.py
|
||||
|
||||
from reportlab.tools.docco.rl_doc_utils import *
|
||||
from reportlab.graphics.shapes import *
|
||||
|
||||
heading1("Shapes")
|
||||
|
||||
disc("""
|
||||
This chapter describes the concept of shapes and their importance
|
||||
as building blocks for all output generated by the graphics library.
|
||||
Some properties of existing shapes and their relationship to
|
||||
diagrams are presented and the notion of having different renderers
|
||||
for different output formats is briefly introduced.
|
||||
""")
|
||||
|
||||
heading2("Available Shapes")
|
||||
|
||||
disc("""
|
||||
Drawings are made up of Shapes.
|
||||
Absolutely anything can be built up by combining the same set of
|
||||
primitive shapes.
|
||||
The module $shapes.py$ supplies a number of primitive shapes and
|
||||
constructs which can be added to a drawing.
|
||||
They are:
|
||||
""")
|
||||
|
||||
bullet("Rect")
|
||||
bullet("Circle")
|
||||
bullet("Ellipse")
|
||||
bullet("Wedge (a pie slice)")
|
||||
bullet("Polygon")
|
||||
bullet("Line")
|
||||
bullet("PolyLine")
|
||||
bullet("String")
|
||||
bullet("Group")
|
||||
bullet("Path (<i>not implemented yet, but will be added in the future</i>)")
|
||||
|
||||
disc("""
|
||||
The following drawing, taken from our test suite, shows most of the
|
||||
basic shapes (except for groups).
|
||||
Those with a filled green surface are also called <i>solid shapes</i>
|
||||
(these are $Rect$, $Circle$, $Ellipse$, $Wedge$ and $Polygon$).
|
||||
""")
|
||||
|
||||
from reportlab.graphics import testshapes
|
||||
|
||||
t = testshapes.getDrawing06()
|
||||
draw(t, "Basic shapes")
|
||||
|
||||
|
||||
heading2("Shape Properties")
|
||||
|
||||
disc("""
|
||||
Shapes have two kinds of properties - some to define their geometry
|
||||
and some to define their style.
|
||||
Let's create a red rectangle with 3-point thick green borders:
|
||||
""")
|
||||
|
||||
eg("""
|
||||
>>> from reportlab.graphics.shapes import Rect
|
||||
>>> from reportlab.lib.colors import red, green
|
||||
>>> r = Rect(5, 5, 200, 100)
|
||||
>>> r.fillColor = red
|
||||
>>> r.strokeColor = green
|
||||
>>> r.strokeWidth = 3
|
||||
>>>
|
||||
""")
|
||||
|
||||
from reportlab.graphics.shapes import Rect
|
||||
from reportlab.lib.colors import red, green
|
||||
d = Drawing(220, 120)
|
||||
r = Rect(5, 5, 200, 100)
|
||||
r.fillColor = red
|
||||
r.strokeColor = green
|
||||
r.strokeWidth = 3
|
||||
d.add(r)
|
||||
draw(d, "red rectangle with green border")
|
||||
|
||||
disc("""
|
||||
<i>Note: In future examples we will omit the import statements.</i>
|
||||
""")
|
||||
|
||||
disc("""
|
||||
All shapes have a number of properties which can be set.
|
||||
At an interactive prompt, we can use their <i>dumpProperties()</i>
|
||||
method to list these.
|
||||
Here's what you can use to configure a Rect:
|
||||
""")
|
||||
|
||||
eg("""
|
||||
>>> r.dumpProperties()
|
||||
fillColor = Color(1.00,0.00,0.00)
|
||||
height = 100
|
||||
rx = 0
|
||||
ry = 0
|
||||
strokeColor = Color(0.00,0.50,0.00)
|
||||
strokeDashArray = None
|
||||
strokeLineCap = 0
|
||||
strokeLineJoin = 0
|
||||
strokeMiterLimit = 0
|
||||
strokeWidth = 3
|
||||
width = 200
|
||||
x = 5
|
||||
y = 5
|
||||
>>>
|
||||
""")
|
||||
|
||||
disc("""
|
||||
Shapes generally have <i>style properties</i> and <i>geometry
|
||||
properties</i>.
|
||||
$x$, $y$, $width$ and $height$ are part of the geometry and must
|
||||
be provided when creating the rectangle, since it does not make
|
||||
much sense without those properties.
|
||||
The others are optional and come with sensible defaults.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
You may set other properties on subsequent lines, or by passing them
|
||||
as optional arguments to the constructor.
|
||||
We could also have created our rectangle this way:
|
||||
""")
|
||||
|
||||
eg("""
|
||||
>>> r = Rect(5, 5, 200, 100,
|
||||
fillColor=red,
|
||||
strokeColor=green,
|
||||
strokeWidth=3)
|
||||
""")
|
||||
|
||||
disc("""
|
||||
Let's run through the style properties. $fillColor$ is obvious.
|
||||
$stroke$ is publishing terminology for the edge of a shape;
|
||||
the stroke has a color, width, possibly a dash pattern, and
|
||||
some (rarely used) features for what happens when a line turns
|
||||
a corner.
|
||||
$rx$ and $ry$ are optional geometric properties and are used to
|
||||
define the corner radius for a rounded rectangle.
|
||||
""")
|
||||
|
||||
disc("All the other solid shapes share the same style properties.")
|
||||
|
||||
|
||||
heading2("Lines")
|
||||
|
||||
disc("""
|
||||
We provide single straight lines, PolyLines and curves.
|
||||
Lines have all the $stroke*$ properties, but no $fillColor$.
|
||||
Here are a few Line and PolyLine examples and the corresponding
|
||||
graphics output:
|
||||
""")
|
||||
|
||||
eg("""
|
||||
Line(50,50, 300,100,
|
||||
strokeColor=colors.blue, strokeWidth=5)
|
||||
Line(50,100, 300,50,
|
||||
strokeColor=colors.red,
|
||||
strokeWidth=10,
|
||||
strokeDashArray=[10, 20])
|
||||
PolyLine([120,110, 130,150, 140,110, 150,150, 160,110,
|
||||
170,150, 180,110, 190,150, 200,110],
|
||||
strokeWidth=2,
|
||||
strokeColor=colors.purple)
|
||||
""")
|
||||
|
||||
d = Drawing(400, 200)
|
||||
d.add(Line(50,50, 300,100,strokeColor=colors.blue, strokeWidth=5))
|
||||
d.add(Line(50,100, 300,50,
|
||||
strokeColor=colors.red,
|
||||
strokeWidth=10,
|
||||
strokeDashArray=[10, 20]))
|
||||
d.add(PolyLine([120,110, 130,150, 140,110, 150,150, 160,110,
|
||||
170,150, 180,110, 190,150, 200,110],
|
||||
strokeWidth=2,
|
||||
strokeColor=colors.purple))
|
||||
draw(d, "Line and PolyLine examples")
|
||||
|
||||
|
||||
heading2("Strings")
|
||||
|
||||
disc("""
|
||||
The ReportLab Graphics package is not designed for fancy text
|
||||
layout, but it can place strings at desired locations and with
|
||||
left/right/center alignment.
|
||||
Let's specify a $String$ object and look at its properties:
|
||||
""")
|
||||
|
||||
eg("""
|
||||
>>> s = String(10, 50, 'Hello World')
|
||||
>>> s.dumpProperties()
|
||||
fillColor = Color(0.00,0.00,0.00)
|
||||
fontName = Times-Roman
|
||||
fontSize = 10
|
||||
text = Hello World
|
||||
textAnchor = start
|
||||
x = 10
|
||||
y = 50
|
||||
>>>
|
||||
""")
|
||||
|
||||
disc("""
|
||||
Strings have a textAnchor property, which may have one of the
|
||||
values 'start', 'middle', 'end'.
|
||||
If this is set to 'start', x and y relate to the start of the
|
||||
string, and so on.
|
||||
This provides an easy way to align text.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
Strings use a common font standard: the Type 1 Postscript fonts
|
||||
present in Acrobat Reader.
|
||||
We can thus use the basic 14 fonts in ReportLab and get accurate
|
||||
metrics for them.
|
||||
We have recently also added support for extra Type 1 fonts
|
||||
and the renderers all know how to render Type 1 fonts.
|
||||
""")
|
||||
|
||||
##Until now we have worked with bitmap renderers which have to use
|
||||
##TrueType fonts and which make some substitutions; this could lead
|
||||
##to differences in text wrapping or even the number of labels on
|
||||
##a chart between renderers.
|
||||
|
||||
disc("""
|
||||
Here is a more fancy example using the code snippet below.
|
||||
Please consult the ReportLab User Guide to see how non-standard
|
||||
like 'LettErrorRobot-Chrome' fonts are being registered!
|
||||
""")
|
||||
|
||||
eg("""
|
||||
d = Drawing(400, 200)
|
||||
for size in range(12, 36, 4):
|
||||
d.add(String(10+size*2, 10+size*2, 'Hello World',
|
||||
fontName='Times-Roman',
|
||||
fontSize=size))
|
||||
|
||||
d.add(String(130, 120, 'Hello World',
|
||||
fontName='Courier',
|
||||
fontSize=36))
|
||||
|
||||
d.add(String(150, 160, 'Hello World',
|
||||
fontName='LettErrorRobot-Chrome',
|
||||
fontSize=36))
|
||||
""")
|
||||
|
||||
from reportlab.pdfbase import pdfmetrics
|
||||
from reportlab import rl_config
|
||||
rl_config.warnOnMissingFontGlyphs = 0
|
||||
afmFile, pfbFile = getJustFontPaths()
|
||||
T1face = pdfmetrics.EmbeddedType1Face(afmFile, pfbFile)
|
||||
T1faceName = 'LettErrorRobot-Chrome'
|
||||
pdfmetrics.registerTypeFace(T1face)
|
||||
T1font = pdfmetrics.Font(T1faceName, T1faceName, 'WinAnsiEncoding')
|
||||
pdfmetrics.registerFont(T1font)
|
||||
|
||||
d = Drawing(400, 200)
|
||||
for size in range(12, 36, 4):
|
||||
d.add(String(10+size*2, 10+size*2, 'Hello World',
|
||||
fontName='Times-Roman',
|
||||
fontSize=size))
|
||||
|
||||
d.add(String(130, 120, 'Hello World',
|
||||
fontName='Courier',
|
||||
fontSize=36))
|
||||
|
||||
d.add(String(150, 160, 'Hello World',
|
||||
fontName='LettErrorRobot-Chrome',
|
||||
fontSize=36))
|
||||
|
||||
draw(d, 'fancy font example')
|
||||
|
||||
|
||||
heading2("""Paths""")
|
||||
|
||||
disc("""
|
||||
Postscript paths are a widely understood concept in graphics.
|
||||
They are not implemented in $reportlab/graphics$ as yet, but they
|
||||
will be, soon.
|
||||
""")
|
||||
|
||||
# NB This commented out section is for 'future compatibility' - paths haven't
|
||||
# been implemented yet, but when they are we can uncomment this back in.
|
||||
|
||||
##disc("""Postscript paths are a widely understood concept in graphics. A Path
|
||||
## is a way of defining a region in space. You put an imaginary pen down,
|
||||
## draw straight and curved segments, and even pick the pen up and move
|
||||
## it. At the end of this you have described a region, which may consist
|
||||
## of several distinct close shapes or unclosed lines. At the end, this
|
||||
## 'path' is 'stroked and filled' according to its properties. A Path has
|
||||
## the same style properties as a solid shape. It can be used to create
|
||||
## any irregular shape.""")
|
||||
##
|
||||
##disc("""In Postscript-based imaging models such as PDF, Postscript and SVG,
|
||||
## everything is done with paths. All the specific shapes covered above
|
||||
## are instances of paths; even text strings (which are shapes in which
|
||||
## each character is an outline to be filled). Here we begin creating a
|
||||
## path with a straight line and a bezier curve:""")
|
||||
##
|
||||
##eg("""
|
||||
##>>> P = Path(0,0, strokeWidth=3, strokeColor=red)
|
||||
##>>> P.lineTo(0, 50)
|
||||
##>>> P.curveTo(10,50,80,80,100,30)
|
||||
##>>>
|
||||
##""")
|
||||
|
||||
##disc("""As well as being the only way to draw complex shapes, paths offer some
|
||||
## performance advantages in renderers which support them. If you want to
|
||||
## create a scatter plot with 5000 blue circles of different sizes, you
|
||||
## can create 5000 circles, or one path object. With the latter, you only
|
||||
## need to set the color and line width once. PINGO just remembers the
|
||||
## drawing sequence, and writes it out into the file. In renderers which
|
||||
## do not support paths, the renderer will still have to decompose it
|
||||
## into 5000 circles so you won't save anything.""")
|
||||
##
|
||||
##disc("""<b>Note that our current path implementation is an approximation; it
|
||||
## should be finished off accurately for PDF and PS.</b>""")
|
||||
|
||||
|
||||
heading2("Groups")
|
||||
|
||||
disc("""
|
||||
Finally, we have Group objects.
|
||||
A group has a list of contents, which are other nodes.
|
||||
It can also apply a transformation - its contents can be rotated,
|
||||
scaled or shifted.
|
||||
If you know the math, you can set the transform directly.
|
||||
Otherwise it provides methods to rotate, scale and so on.
|
||||
Here we make a group which is rotated and translated:
|
||||
""")
|
||||
|
||||
eg("""
|
||||
>>> g =Group(shape1, shape2, shape3)
|
||||
>>> g.rotate(30)
|
||||
>>> g.translate(50, 200)
|
||||
""")
|
||||
|
||||
disc("""
|
||||
Groups provide a tool for reuse.
|
||||
You can make a bunch of shapes to represent some component - say,
|
||||
a coordinate system - and put them in one group called "Axis".
|
||||
You can then put that group into other groups, each with a different
|
||||
translation and rotation, and you get a bunch of axis.
|
||||
It is still the same group, being drawn in different places.
|
||||
""")
|
||||
|
||||
disc("""Let's do this with some only slightly more code:""")
|
||||
|
||||
eg("""
|
||||
d = Drawing(400, 200)
|
||||
|
||||
Axis = Group(
|
||||
Line(0,0,100,0), # x axis
|
||||
Line(0,0,0,50), # y axis
|
||||
Line(0,10,10,10), # ticks on y axis
|
||||
Line(0,20,10,20),
|
||||
Line(0,30,10,30),
|
||||
Line(0,40,10,40),
|
||||
Line(10,0,10,10), # ticks on x axis
|
||||
Line(20,0,20,10),
|
||||
Line(30,0,30,10),
|
||||
Line(40,0,40,10),
|
||||
Line(50,0,50,10),
|
||||
Line(60,0,60,10),
|
||||
Line(70,0,70,10),
|
||||
Line(80,0,80,10),
|
||||
Line(90,0,90,10),
|
||||
String(20, 35, 'Axes', fill=colors.black)
|
||||
)
|
||||
|
||||
firstAxisGroup = Group(Axis)
|
||||
firstAxisGroup.translate(10,10)
|
||||
d.add(firstAxisGroup)
|
||||
|
||||
secondAxisGroup = Group(Axis)
|
||||
secondAxisGroup.translate(150,10)
|
||||
secondAxisGroup.rotate(15)
|
||||
|
||||
d.add(secondAxisGroup)
|
||||
|
||||
thirdAxisGroup = Group(Axis,
|
||||
transform=mmult(translate(300,10),
|
||||
rotate(30)))
|
||||
d.add(thirdAxisGroup)
|
||||
""")
|
||||
|
||||
d = Drawing(400, 200)
|
||||
Axis = Group(
|
||||
Line(0,0,100,0), # x axis
|
||||
Line(0,0,0,50), # y axis
|
||||
Line(0,10,10,10), # ticks on y axis
|
||||
Line(0,20,10,20),
|
||||
Line(0,30,10,30),
|
||||
Line(0,40,10,40),
|
||||
Line(10,0,10,10), # ticks on x axis
|
||||
Line(20,0,20,10),
|
||||
Line(30,0,30,10),
|
||||
Line(40,0,40,10),
|
||||
Line(50,0,50,10),
|
||||
Line(60,0,60,10),
|
||||
Line(70,0,70,10),
|
||||
Line(80,0,80,10),
|
||||
Line(90,0,90,10),
|
||||
String(20, 35, 'Axes', fill=colors.black)
|
||||
)
|
||||
firstAxisGroup = Group(Axis)
|
||||
firstAxisGroup.translate(10,10)
|
||||
d.add(firstAxisGroup)
|
||||
secondAxisGroup = Group(Axis)
|
||||
secondAxisGroup.translate(150,10)
|
||||
secondAxisGroup.rotate(15)
|
||||
d.add(secondAxisGroup)
|
||||
thirdAxisGroup = Group(Axis,
|
||||
transform=mmult(translate(300,10),
|
||||
rotate(30)))
|
||||
d.add(thirdAxisGroup)
|
||||
draw(d, "Groups examples")
|
||||
@@ -0,0 +1,422 @@
|
||||
#Copyright ReportLab Europe Ltd. 2000-2004
|
||||
#see license.txt for license details
|
||||
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/graphguide/ch4_widgets.py
|
||||
|
||||
from reportlab.tools.docco.rl_doc_utils import *
|
||||
from reportlab.graphics.shapes import *
|
||||
from reportlab.graphics.widgets import signsandsymbols
|
||||
|
||||
heading1("Widgets")
|
||||
|
||||
disc("""
|
||||
We now describe widgets and how they relate to shapes.
|
||||
Using many examples it is shown how widgets make reusable
|
||||
graphics components.
|
||||
""")
|
||||
|
||||
|
||||
heading2("Shapes vs. Widgets")
|
||||
|
||||
disc("""Up until now, Drawings have been 'pure data'. There is no code in them
|
||||
to actually do anything, except assist the programmer in checking and
|
||||
inspecting the drawing. In fact, that's the cornerstone of the whole
|
||||
concept and is what lets us achieve portability - a renderer only
|
||||
needs to implement the primitive shapes.""")
|
||||
|
||||
disc("""We want to build reusable graphic objects, including a powerful chart
|
||||
library. To do this we need to reuse more tangible things than
|
||||
rectangles and circles. We should be able to write objects for other
|
||||
to reuse - arrows, gears, text boxes, UML diagram nodes, even fully
|
||||
fledged charts.""")
|
||||
|
||||
disc("""
|
||||
The Widget standard is a standard built on top of the shapes module.
|
||||
Anyone can write new widgets, and we can build up libraries of them.
|
||||
Widgets support the $getProperties()$ and $setProperties()$ methods,
|
||||
so you can inspect and modify as well as document them in a uniform
|
||||
way.
|
||||
""")
|
||||
|
||||
bullet("A widget is a reusable shape ")
|
||||
bullet("""it can be initialized with no arguments
|
||||
when its $draw()$ method is called it creates a primitive Shape or a
|
||||
Group to represent itself""")
|
||||
bullet("""It can have any parameters you want, and they can drive the way it is
|
||||
drawn""")
|
||||
bullet("""it has a $demo()$ method which should return an attractively drawn
|
||||
example of itself in a 200x100 rectangle. This is the cornerstone of
|
||||
the automatic documentation tools. The $demo()$ method should also have
|
||||
a well written docstring, since that is printed too!""")
|
||||
|
||||
disc("""Widgets run contrary to the idea that a drawing is just a bundle of
|
||||
shapes; surely they have their own code? The way they work is that a
|
||||
widget can convert itself to a group of primitive shapes. If some of
|
||||
its components are themselves widgets, they will get converted too.
|
||||
This happens automatically during rendering; the renderer will not see
|
||||
your chart widget, but just a collection of rectangles, lines and
|
||||
strings. You can also explicitly 'flatten out' a drawing, causing all
|
||||
widgets to be converted to primitives.""")
|
||||
|
||||
|
||||
heading2("Using a Widget")
|
||||
|
||||
disc("""
|
||||
Let's imagine a simple new widget.
|
||||
We will use a widget to draw a face, then show how it was implemented.""")
|
||||
|
||||
eg("""
|
||||
>>> from reportlab.lib import colors
|
||||
>>> from reportlab.graphics import shapes
|
||||
>>> from reportlab.graphics import widgetbase
|
||||
>>> from reportlab.graphics import renderPDF
|
||||
>>> d = shapes.Drawing(200, 100)
|
||||
>>> f = widgetbase.Face()
|
||||
>>> f.skinColor = colors.yellow
|
||||
>>> f.mood = "sad"
|
||||
>>> d.add(f)
|
||||
>>> renderPDF.drawToFile(d, 'face.pdf', 'A Face')
|
||||
""")
|
||||
|
||||
from reportlab.graphics import widgetbase
|
||||
d = Drawing(200, 120)
|
||||
f = widgetbase.Face()
|
||||
f.x = 50
|
||||
f.y = 10
|
||||
f.skinColor = colors.yellow
|
||||
f.mood = "sad"
|
||||
d.add(f)
|
||||
draw(d, 'A sample widget')
|
||||
|
||||
disc("""
|
||||
Let's see what properties it has available, using the $setProperties()$
|
||||
method we have seen earlier:
|
||||
""")
|
||||
|
||||
eg("""
|
||||
>>> f.dumpProperties()
|
||||
eyeColor = Color(0.00,0.00,1.00)
|
||||
mood = sad
|
||||
size = 80
|
||||
skinColor = Color(1.00,1.00,0.00)
|
||||
x = 10
|
||||
y = 10
|
||||
>>>
|
||||
""")
|
||||
|
||||
disc("""
|
||||
One thing which seems strange about the above code is that we did not
|
||||
set the size or position when we made the face.
|
||||
This is a necessary trade-off to allow a uniform interface for
|
||||
constructing widgets and documenting them - they cannot require
|
||||
arguments in their $__init__()$ method.
|
||||
Instead, they are generally designed to fit in a 200 x 100
|
||||
window, and you move or resize them by setting properties such as
|
||||
x, y, width and so on after creation.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
In addition, a widget always provides a $demo()$ method.
|
||||
Simple ones like this always do something sensible before setting
|
||||
properties, but more complex ones like a chart would not have any
|
||||
data to plot.
|
||||
The documentation tool calls $demo()$ so that your fancy new chart
|
||||
class can create a drawing showing what it can do.
|
||||
""")
|
||||
|
||||
disc("""
|
||||
Here are a handful of simple widgets available in the module
|
||||
<i>signsandsymbols.py</i>:
|
||||
""")
|
||||
|
||||
from reportlab.graphics.shapes import Drawing
|
||||
from reportlab.graphics.widgets import signsandsymbols
|
||||
|
||||
d = Drawing(230, 230)
|
||||
|
||||
ne = signsandsymbols.NoEntry()
|
||||
ds = signsandsymbols.DangerSign()
|
||||
fd = signsandsymbols.FloppyDisk()
|
||||
ns = signsandsymbols.NoSmoking()
|
||||
|
||||
ne.x, ne.y = 10, 10
|
||||
ds.x, ds.y = 120, 10
|
||||
fd.x, fd.y = 10, 120
|
||||
ns.x, ns.y = 120, 120
|
||||
|
||||
d.add(ne)
|
||||
d.add(ds)
|
||||
d.add(fd)
|
||||
d.add(ns)
|
||||
|
||||
draw(d, 'A few samples from signsandsymbols.py')
|
||||
|
||||
disc("""
|
||||
And this is the code needed to generate them as seen in the drawing above:
|
||||
""")
|
||||
|
||||
eg("""
|
||||
from reportlab.graphics.shapes import Drawing
|
||||
from reportlab.graphics.widgets import signsandsymbols
|
||||
|
||||
d = Drawing(230, 230)
|
||||
|
||||
ne = signsandsymbols.NoEntry()
|
||||
ds = signsandsymbols.DangerSign()
|
||||
fd = signsandsymbols.FloppyDisk()
|
||||
ns = signsandsymbols.NoSmoking()
|
||||
|
||||
ne.x, ne.y = 10, 10
|
||||
ds.x, ds.y = 120, 10
|
||||
fd.x, fd.y = 10, 120
|
||||
ns.x, ns.y = 120, 120
|
||||
|
||||
d.add(ne)
|
||||
d.add(ds)
|
||||
d.add(fd)
|
||||
d.add(ns)
|
||||
""")
|
||||
|
||||
|
||||
heading2("Compound Widgets")
|
||||
|
||||
disc("""Let's imagine a compound widget which draws two faces side by side.
|
||||
This is easy to build when you have the Face widget.""")
|
||||
|
||||
eg("""
|
||||
>>> tf = widgetbase.TwoFaces()
|
||||
>>> tf.faceOne.mood
|
||||
'happy'
|
||||
>>> tf.faceTwo.mood
|
||||
'sad'
|
||||
>>> tf.dumpProperties()
|
||||
faceOne.eyeColor = Color(0.00,0.00,1.00)
|
||||
faceOne.mood = happy
|
||||
faceOne.size = 80
|
||||
faceOne.skinColor = None
|
||||
faceOne.x = 10
|
||||
faceOne.y = 10
|
||||
faceTwo.eyeColor = Color(0.00,0.00,1.00)
|
||||
faceTwo.mood = sad
|
||||
faceTwo.size = 80
|
||||
faceTwo.skinColor = None
|
||||
faceTwo.x = 100
|
||||
faceTwo.y = 10
|
||||
>>>
|
||||
""")
|
||||
|
||||
disc("""The attributes 'faceOne' and 'faceTwo' are deliberately exposed so you
|
||||
can get at them directly. There could also be top-level attributes,
|
||||
but there aren't in this case.""")
|
||||
|
||||
|
||||
heading2("Verifying Widgets")
|
||||
|
||||
disc("""The widget designer decides the policy on verification, but by default
|
||||
they work like shapes - checking every assignment - if the designer
|
||||
has provided the checking information.""")
|
||||
|
||||
|
||||
heading2("Implementing Widgets")
|
||||
|
||||
disc("""We tried to make it as easy to implement widgets as possible. Here's
|
||||
the code for a Face widget which does not do any type checking:""")
|
||||
|
||||
eg("""
|
||||
class Face(Widget):
|
||||
\"\"\"This draws a face with two eyes, mouth and nose.\"\"\"
|
||||
|
||||
def __init__(self):
|
||||
self.x = 10
|
||||
self.y = 10
|
||||
self.size = 80
|
||||
self.skinColor = None
|
||||
self.eyeColor = colors.blue
|
||||
self.mood = 'happy'
|
||||
|
||||
def draw(self):
|
||||
s = self.size # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
g.transform = [1,0,0,1,self.x, self.y]
|
||||
# background
|
||||
g.add(shapes.Circle(s * 0.5, s * 0.5, s * 0.5,
|
||||
fillColor=self.skinColor))
|
||||
# CODE OMITTED TO MAKE MORE SHAPES
|
||||
return g
|
||||
""")
|
||||
|
||||
disc("""We left out all the code to draw the shapes in this document, but you
|
||||
can find it in the distribution in $widgetbase.py$.""")
|
||||
|
||||
disc("""By default, any attribute without a leading underscore is returned by
|
||||
setProperties. This is a deliberate policy to encourage consistent
|
||||
coding conventions.""")
|
||||
|
||||
disc("""Once your widget works, you probably want to add support for
|
||||
verification. This involves adding a dictionary to the class called
|
||||
$_verifyMap$, which map from attribute names to 'checking functions'.
|
||||
The $widgetbase.py$ module defines a bunch of checking functions with names
|
||||
like $isNumber$, $isListOfShapes$ and so on. You can also simply use $None$,
|
||||
which means that the attribute must be present but can have any type.
|
||||
And you can and should write your own checking functions. We want to
|
||||
restrict the "mood" custom attribute to the values "happy", "sad" or
|
||||
"ok". So we do this:""")
|
||||
|
||||
eg("""
|
||||
class Face(Widget):
|
||||
\"\"\"This draws a face with two eyes. It exposes a
|
||||
couple of properties to configure itself and hides
|
||||
all other details\"\"\"
|
||||
def checkMood(moodName):
|
||||
return (moodName in ('happy','sad','ok'))
|
||||
_verifyMap = {
|
||||
'x': shapes.isNumber,
|
||||
'y': shapes.isNumber,
|
||||
'size': shapes.isNumber,
|
||||
'skinColor':shapes.isColorOrNone,
|
||||
'eyeColor': shapes.isColorOrNone,
|
||||
'mood': checkMood
|
||||
}
|
||||
""")
|
||||
|
||||
disc("""This checking will be performed on every attribute assignment; or, if
|
||||
$config.shapeChecking$ is off, whenever you call $myFace.verify()$.""")
|
||||
|
||||
|
||||
heading2("Documenting Widgets")
|
||||
|
||||
disc("""
|
||||
We are working on a generic tool to document any Python package or
|
||||
module; this is already checked into ReportLab and will be used to
|
||||
generate a reference for the ReportLab package.
|
||||
When it encounters widgets, it adds extra sections to the
|
||||
manual including:""")
|
||||
|
||||
bullet("the doc string for your widget class ")
|
||||
bullet("the code snippet from your <i>demo()</i> method, so people can see how to use it")
|
||||
bullet("the drawing produced by the <i>demo()</i> method ")
|
||||
bullet("the property dump for the widget in the drawing. ")
|
||||
|
||||
disc("""
|
||||
This tool will mean that we can have guaranteed up-to-date
|
||||
documentation on our widgets and charts, both on the web site
|
||||
and in print; and that you can do the same for your own widgets,
|
||||
too!
|
||||
""")
|
||||
|
||||
|
||||
heading2("Widget Design Strategies")
|
||||
|
||||
disc("""We could not come up with a consistent architecture for designing
|
||||
widgets, so we are leaving that problem to the authors! If you do not
|
||||
like the default verification strategy, or the way
|
||||
$setProperties/getProperties$ works, you can override them yourself.""")
|
||||
|
||||
disc("""For simple widgets it is recommended that you do what we did above:
|
||||
select non-overlapping properties, initialize every property on
|
||||
$__init__$ and construct everything when $draw()$ is called. You can
|
||||
instead have $__setattr__$ hooks and have things updated when certain
|
||||
attributes are set. Consider a pie chart. If you want to expose the
|
||||
individual wedges, you might write code like this:""")
|
||||
|
||||
eg("""
|
||||
from reportlab.graphics.charts import piecharts
|
||||
pc = piecharts.Pie()
|
||||
pc.defaultColors = [navy, blue, skyblue] #used in rotation
|
||||
pc.data = [10,30,50,25]
|
||||
pc.slices[7].strokeWidth = 5
|
||||
""")
|
||||
#removed 'pc.backColor = yellow' from above code example
|
||||
|
||||
disc("""The last line is problematic as we have only created four wedges - in
|
||||
fact we might not have created them yet. Does $pc.wedges[7]$ raise an
|
||||
error? Is it a prescription for what should happen if a seventh wedge
|
||||
is defined, used to override the default settings? We dump this
|
||||
problem squarely on the widget author for now, and recommend that you
|
||||
get a simple one working before exposing 'child objects' whose
|
||||
existence depends on other properties' values :-)""")
|
||||
|
||||
disc("""We also discussed rules by which parent widgets could pass properties
|
||||
to their children. There seems to be a general desire for a global way
|
||||
to say that 'all wedges get their lineWidth from the lineWidth of
|
||||
their parent' without a lot of repetitive coding. We do not have a
|
||||
universal solution, so again leave that to widget authors. We hope
|
||||
people will experiment with push-down, pull-down and pattern-matching
|
||||
approaches and come up with something nice. In the meantime, we
|
||||
certainly can write monolithic chart widgets which work like the ones
|
||||
in, say, Visual Basic and Delphi.""")
|
||||
|
||||
disc("""For now have a look at the following sample code using an early
|
||||
version of a pie chart widget and the output it generates:""")
|
||||
|
||||
eg("""
|
||||
from reportlab.lib.colors import *
|
||||
from reportlab.graphics import shapes,renderPDF
|
||||
from reportlab.graphics.charts.piecharts import Pie
|
||||
|
||||
d = Drawing(400,200)
|
||||
d.add(String(100,175,"Without labels", textAnchor="middle"))
|
||||
d.add(String(300,175,"With labels", textAnchor="middle"))
|
||||
|
||||
pc = Pie()
|
||||
pc.x = 25
|
||||
pc.y = 50
|
||||
pc.data = [10,20,30,40,50,60]
|
||||
pc.slices[0].popout = 5
|
||||
d.add(pc, 'pie1')
|
||||
|
||||
pc2 = Pie()
|
||||
pc2.x = 150
|
||||
pc2.y = 50
|
||||
pc2.data = [10,20,30,40,50,60]
|
||||
pc2.labels = ['a','b','c','d','e','f']
|
||||
d.add(pc2, 'pie2')
|
||||
|
||||
pc3 = Pie()
|
||||
pc3.x = 275
|
||||
pc3.y = 50
|
||||
pc3.data = [10,20,30,40,50,60]
|
||||
pc3.labels = ['a','b','c','d','e','f']
|
||||
pc3.wedges.labelRadius = 0.65
|
||||
pc3.wedges.fontName = "Helvetica-Bold"
|
||||
pc3.wedges.fontSize = 16
|
||||
pc3.wedges.fontColor = colors.yellow
|
||||
d.add(pc3, 'pie3')
|
||||
""")
|
||||
|
||||
# Hack to force a new paragraph before the todo() :-(
|
||||
disc("")
|
||||
|
||||
from reportlab.lib.colors import *
|
||||
from reportlab.graphics import shapes,renderPDF
|
||||
from reportlab.graphics.charts.piecharts import Pie
|
||||
|
||||
d = Drawing(400,200)
|
||||
d.add(String(100,175,"Without labels", textAnchor="middle"))
|
||||
d.add(String(300,175,"With labels", textAnchor="middle"))
|
||||
|
||||
pc = Pie()
|
||||
pc.x = 25
|
||||
pc.y = 50
|
||||
pc.data = [10,20,30,40,50,60]
|
||||
pc.slices[0].popout = 5
|
||||
d.add(pc, 'pie1')
|
||||
|
||||
pc2 = Pie()
|
||||
pc2.x = 150
|
||||
pc2.y = 50
|
||||
pc2.data = [10,20,30,40,50,60]
|
||||
pc2.labels = ['a','b','c','d','e','f']
|
||||
d.add(pc2, 'pie2')
|
||||
|
||||
pc3 = Pie()
|
||||
pc3.x = 275
|
||||
pc3.y = 50
|
||||
pc3.data = [10,20,30,40,50,60]
|
||||
pc3.labels = ['a','b','c','d','e','f']
|
||||
pc3.slices.labelRadius = 0.65
|
||||
pc3.slices.fontName = "Helvetica-Bold"
|
||||
pc3.slices.fontSize = 16
|
||||
pc3.slices.fontColor = colors.yellow
|
||||
d.add(pc3, 'pie3')
|
||||
|
||||
draw(d, 'Some sample Pies')
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
#!/bin/env python
|
||||
#Copyright ReportLab Europe Ltd. 2000-2004
|
||||
#see license.txt for license details
|
||||
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/graphguide/gengraphguide.py
|
||||
__version__=''' $Id: gengraphguide.py 2385 2004-06-17 15:26:05Z rgbecker $ '''
|
||||
__doc__ = """
|
||||
This module contains the script for building the graphics guide.
|
||||
"""
|
||||
def run(pagesize=None, verbose=1, outDir=None):
|
||||
import os
|
||||
from reportlab.tools.docco.rl_doc_utils import setStory, getStory, RLDocTemplate, defaultPageSize
|
||||
from reportlab.tools.docco import rl_doc_utils
|
||||
from reportlab.lib.utils import open_and_read, _RL_DIR
|
||||
if not outDir: outDir = os.path.join(_RL_DIR,'docs')
|
||||
destfn = os.path.join(outDir,'graphguide.pdf')
|
||||
doc = RLDocTemplate(destfn,pagesize = pagesize or defaultPageSize)
|
||||
|
||||
#this builds the story
|
||||
setStory()
|
||||
G = {}
|
||||
exec 'from reportlab.tools.docco.rl_doc_utils import *' in G, G
|
||||
doc = RLDocTemplate(destfn,pagesize = pagesize or defaultPageSize)
|
||||
for f in (
|
||||
'ch1_intro',
|
||||
'ch2_concepts',
|
||||
'ch3_shapes',
|
||||
'ch4_widgets',
|
||||
'ch5_charts',
|
||||
):
|
||||
exec open_and_read(f+'.py',mode='t') in G, G
|
||||
del G
|
||||
|
||||
story = getStory()
|
||||
if verbose: print 'Built story contains %d flowables...' % len(story)
|
||||
doc.build(story)
|
||||
if verbose: print 'Saved "%s"' % destfn
|
||||
|
||||
def makeSuite():
|
||||
"standard test harness support - run self as separate process"
|
||||
from reportlab.test.utils import ScriptThatMakesFileTest
|
||||
return ScriptThatMakesFileTest('../docs/graphguide', 'gengraphguide.py', 'graphguide.pdf')
|
||||
|
||||
def main():
|
||||
import sys
|
||||
verbose = '-s' not in sys.argv
|
||||
if not verbose: sys.argv.remove('-s')
|
||||
if len(sys.argv) > 1:
|
||||
try:
|
||||
pagesize = eval(sys.argv[1])
|
||||
except:
|
||||
print 'Expected page size in argument 1', sys.argv[1]
|
||||
raise
|
||||
print 'set page size to',sys.argv[1]
|
||||
else:
|
||||
pagesize = None
|
||||
run(pagesize,verbose)
|
||||
|
||||
if __name__=="__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user