~ubuntu-branches/debian/sid/pyx/sid

« back to all changes in this revision

Viewing changes to faq/plotting_graphs.rst

  • Committer: Package Import Robot
  • Author(s): Stuart Prescott
  • Date: 2012-12-17 13:45:12 UTC
  • mto: (9.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 10.
  • Revision ID: package-import@ubuntu.com-20121217134512-q85pr3q75fxii7mq
Tags: upstream-0.12.1
Import upstream version 0.12.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
==================
 
2
Plotting of graphs
 
3
==================
 
4
 
 
5
General aspects
 
6
===============
 
7
 
 
8
.. _mingraphdata:
 
9
 
 
10
How do I generate a graph from data as simply as possible?
 
11
----------------------------------------------------------
 
12
 
 
13
Suppose that you have a data file ``x.dat`` containing values for ``x`` and
 
14
``y`` in two columns. Then the following code will do the job::
 
15
 
 
16
   from pyx import *
 
17
 
 
18
   g = graph.graphxy(width=10)
 
19
   g.plot(graph.data.file("x.dat", x=1, y=2))
 
20
   g.writeEPSfile("x")
 
21
 
 
22
``graphxy`` creates a canvas (called ``g`` in this example) onto which the
 
23
graph will be drawn and it sets the default behavior including the axis. There
 
24
is, however, no default value for the width of the graph. In ``plot`` you have
 
25
to specify the name of the data file and the columns from which the data should
 
26
be taken. Finally, ``writeEPSfile`` will generate the postscript file ``x.eps``
 
27
which you can view or print.
 
28
 
 
29
A minimal example is also provided in the PyX distribution as
 
30
``examples/graphs/minimal.py``.
 
31
 
 
32
.. _mingraphfunc:
 
33
 
 
34
How do I generate a graph of a function as simply as possible?
 
35
--------------------------------------------------------------
 
36
 
 
37
The following example will draw a parabola::
 
38
 
 
39
   from pyx import *
 
40
 
 
41
   g = graph.graphxy(width=10,
 
42
                     x=graph.axis.linear(min=-2, max=2)
 
43
                     )
 
44
 
 
45
   g.plot(graph.data.function("y(x)=x**2"))
 
46
 
 
47
   g.writeEPSfile("x")
 
48
 
 
49
Most of the code has been explained in :ref:`mingraphdata`. The main
 
50
difference is that here you need to specify minimum and maximum for the
 
51
``x``-axis so that PyX knows in which range to evaluate the function.
 
52
 
 
53
Another, slightly more complex, example is also provided in the PyX
 
54
distribution as ``examples/graphs/piaxis.py``.
 
55
 
 
56
How can I stack graphs?
 
57
-----------------------
 
58
 
 
59
PyX always needs a canvas to draw on. One possibility therefore consists in
 
60
creating a new canvas with ::
 
61
 
 
62
   c = canvas.canvas()
 
63
 
 
64
and inserting the graphs into this canvas with ``c.insert(…)``. Here, ``…`` has
 
65
to be replaced by the name of the graph. Alternatively, the canvas created with
 
66
``graph.graphxy`` for one of the graphs can be used to insert the other graphs
 
67
even if they will be positioned outside the first graph.
 
68
 
 
69
The second issue to address is positioning of the graphs. By specifying
 
70
``xpos`` and ``ypos`` when calling ``graphxy`` you can define the position of a
 
71
graph. Later on, the position and size of a graph ``g`` can be referred to as
 
72
``g.xpos`` ``g.ypos`` ``g.width`` and ``g.height`` even if for example the
 
73
height has never been specified explicitly but is only defined by a PyX
 
74
default. 
 
75
 
 
76
The following example shows how to put graph ``gupper`` above graph ``glower``
 
77
on a canvas ``c``::
 
78
 
 
79
   from pyx import *
 
80
   from graph import graphxy
 
81
 
 
82
   c = canvas.canvas()
 
83
 
 
84
   glower = graphxy(width=10)
 
85
   glower.plot(...)
 
86
   c.insert(glower)
 
87
 
 
88
   gupper = graphxy(width=10, ypos=glower.ypos+glower.height+2)
 
89
   gupper.plot(...)
 
90
 
 
91
   c.insert(gupper)
 
92
   c.writeEPSfile(...)
 
93
 
 
94
where ``…`` has to be replaced by the appropriate information like data and
 
95
symbol specifications and the name of the output file. Here, ``c.insert`` is
 
96
used to actually insert the subcanvasses for the graphs into the main canvas
 
97
``c`` and ``c.writeEPSfile`` in the last line requests to write the contents of
 
98
this canvas to a file.
 
99
 
 
100
 
 
101
How can I plot grid data?
 
102
-------------------------
 
103
 
 
104
PyX offers support for plotting three-dimensional data as two-dimensional color
 
105
plots or grey-scale plots and of vector fields by providing ways to plot
 
106
rectangles and arrows in graphs. 
 
107
 
 
108
We start by considering the task of creating a two-dimensional color plot by
 
109
plotting a number of filled rectangles. One first needs to create a data set
 
110
which consists of five entries per data point. These are the lower left corner
 
111
(*x*\ :sub:`min`, *y*\ :sub:`min`) and the upper right corner (*x*\ :sub:`max`,
 
112
*y*\ :sub:`max`) of the triangle and a value between 0 and 1 determining the
 
113
color via a PyX color palette. The following code gives an idea of how to
 
114
proceed::
 
115
 
 
116
   g.plot(graph.data.file("datafile.dat", xmin=1, xmax=2, ymin=3, ymax=4, color=5),
 
117
                 [graph.style.rect(color.palette.ReverseRainbow)]
 
118
          )
 
119
   g.dodata()
 
120
 
 
121
Here, we assume that the data are stored in ``datafile.dat`` and the columns
 
122
contain *x*\ :sub:`min`, *x* :sub:`max`, *y*\ :sub:`min`, *y*\ :sub:`max`, and
 
123
the color value in this order. The columns are numbered from 1, since the 0th
 
124
column contains the line number. To determine the color, we use the
 
125
``ReverseRainbow`` palette. The last line instructs PyX to plot the rectangles
 
126
before plotting the axes. Otherwise, the axes might be covered partially by the
 
127
rectangles and, in particular, the ticks might not be visible. Gray-scale plots
 
128
can easily be generated by specifying the palette ``Gray`` or ``ReverseGray``
 
129
(cf. appendix C of the manual for a list of predefined palettes).
 
130
 
 
131
At first sight, it seems surprising that plotting of grid data requires the
 
132
specification of four coordinates for the rectangle. The reason is that this
 
133
allows to draw rectangles of varying sizes which may help to reduce the size of
 
134
the postscript file by combining rectangles of the same color in horizontal or
 
135
vertical direction. For example, it may be sufficient to plot a grey-scale
 
136
image in a small number of grey shades and then combining rectangles may be
 
137
appropriate. Note, though, that this step is part of the data creation and not
 
138
preformed by PyX. Another advantage of fully specifying each rectangle is that
 
139
it is straightforward to leave parts of the graph blank.
 
140
 
 
141
The same ideas as for the color plot can be applied to plot vector fields where
 
142
each data point is represented by an arrow. In this case a data point is
 
143
specified by the position of the arrow, its size and its direction as indicated
 
144
in the following code snippet::
 
145
 
 
146
   g.plot(graph.data.file("datafile.dat"), x=1, y=2, size=3, angle=4),
 
147
              [graph.style.arrow()]
 
148
          )
 
149
 
 
150
Complete code examples can be found in ``examples/graphs/mandel.py`` and
 
151
``examples/graphs/arrows.py`` .
 
152
 
 
153
.. _problemcoord:
 
154
 
 
155
How can I access points in problem coordinates of a graph?
 
156
----------------------------------------------------------
 
157
 
 
158
Sometimes it may be necessary to add graphical elements to a graph in addition
 
159
to the data or function(s) which have been plotted as described in 
 
160
:ref:`mingraphdata` and :ref:`mingraphfunc`. For a graph instance 
 
161
``g`` the positioning can easily be done in canvas coordinates by making
 
162
use of the origin (``g.xpos``, ``g.ypos``) and the width 
 
163
(``g.width``) and height (``g.height``) of the graph. 
 
164
 
 
165
Occasionally, it may be more convenient to specify the position of the
 
166
additional material in terms of problem coordinates. However, this requires
 
167
that the mapping from problem coordinates to canvas coordinates is known.  By
 
168
default this is not the case before the content of the canvas is written to the
 
169
output which is too late for our purpose. One therefore needs to explicitly
 
170
instruct PyX to determine this mapping. One possibility is to ask PyX to finish
 
171
the graph by means of ``g.finish()``. Now, problem coordinates can be used to
 
172
insert additional material which will end up in front of the graph. If this is
 
173
not desired, one should only fix the layout of the graph by means of
 
174
``g.dolayout()``. Then, the additional material can be put onto the canvas
 
175
before the graph is drawn and it will therefore appear behind the graph.
 
176
 
 
177
The conversion of problem coordinates (``px``, ``py``) to canvas coordinates
 
178
(``x``, ``y``) is performed as follows::
 
179
 
 
180
   x, y = g.pos(px, py)
 
181
 
 
182
By default, the problem coordinates will refer to the ranges of the *x* and *y*
 
183
axes. If several axes with different ranges exist, the instances of the desired
 
184
axes should be passed to the ``pos`` method by means of the keyword arguments
 
185
``xaxis`` and ``yaxis``.
 
186
 
 
187
We remark that the drawing of lines parallel to one of the axes at specific
 
188
problem coordinates can also be done by adapting the method described in
 
189
:ref:`zeroline`.
 
190
 
 
191
I would like a key for only some of my data sets. How do I do that?
 
192
-------------------------------------------------------------------
 
193
 
 
194
.. todo::
 
195
 
 
196
   This still needs to be answered.
 
197
 
 
198
Axis properties
 
199
===============
 
200
 
 
201
How do I specify the tick increment?
 
202
------------------------------------
 
203
 
 
204
In the partition of a linear axis, the increments associated with ticks,
 
205
subticks etc. can be specified as argument of ``parter.linear``. In the
 
206
following example, ticks will be drawn at even values while subticks will be
 
207
drawn at all integers::
 
208
 
 
209
   from pyx.graph import axis
 
210
 
 
211
   tg = graph.graphxy(width=10,
 
212
                      x=axis.linear(min=1, max=10,
 
213
                                    parter=axis.parter.linear(tickdists=[2,1]))
 
214
                      )
 
215
 
 
216
.. _zeroline:
 
217
 
 
218
How do I plot the zero line?
 
219
----------------------------
 
220
 
 
221
PyX releases before 0.6 offered the possibility to stroke a zero line by 
 
222
specifying ``zeropathattrs`` in the painter constructor. In more recent 
 
223
releases, one proceeds as follows. First one has to fix the layout information 
 
224
of the graph by means of the ``finish`` or ``dolayout`` method (see 
 
225
:ref:`problemcoord` for a more detailed explanation). Then, the 
 
226
``xgridpath`` or ``ygridpath`` method of a graph will return a grid 
 
227
path parallel to the *y* or *x* axis, respectively, at the specified *y* value. 
 
228
As an example, a zero line in *x* direction can be drawn as follows::
 
229
 
 
230
   g.finish()
 
231
   g.stroke(g.ygridpath(0))
 
232
 
 
233
How can I add grid lines to a graph?
 
234
------------------------------------
 
235
 
 
236
Specifying ``gridattrs`` for the painter of an axis will generate grid lines
 
237
orthogonal to this axis. At least an empty list is needed like in ::
 
238
 
 
239
   g = graph.graphxy(width=10,
 
240
                     x=graph.axis.linear(painter=graph.axis.painter.regular(gridattrs=[])),
 
241
                     y=graph.axis.linear()
 
242
                     )
 
243
 
 
244
where grid lines in vertical direction are drawn in default style.
 
245
 
 
246
Occassionally, one might want to draw grid lines corresponding to ticks and
 
247
subticks in a different style. This can be achieved by specifiying changeable
 
248
attributes using ``changelist``. The following code ::
 
249
 
 
250
   my_xpainter = graph.axis.painter.regular(gridattrs=
 
251
                       [attr.changelist([style.linestyle.solid, style.linestyle.dashed])]
 
252
                                            )
 
253
   my_ypainter = graph.axis.painter.regular(gridattrs=
 
254
                       [attr.changelist([color.rgb.red, color.rgb.blue])]
 
255
                                            )
 
256
 
 
257
   g = graph.graphxy(width=10,
 
258
                     x=graph.axis.linear(painter=my_xpainter),
 
259
                     y=graph.axis.linear(painter=my_ypainter)
 
260
                     )
 
261
 
 
262
will create vertical solid and dashed grid lines for ticks and subticks,
 
263
respectively. The horizontal grid lines will be red for ticks and blue for
 
264
subticks. The changeable attributes are applied in a cyclic manner. Therefore,
 
265
in this example grid lines at subsubticks would be plotted in the same style as
 
266
for ticks. If this is not desired, the list of attributes should be extended by
 
267
an appropriate third style. The keyword ``None`` will switch off the respective
 
268
level of grid lines in case you want to draw them only e.g.  for ticks but not
 
269
subticks.
 
270
 
 
271
Data properties
 
272
===============
 
273
 
 
274
How do I choose the symbol and its attributes?
 
275
----------------------------------------------
 
276
 
 
277
Suppose a graph called ``g`` has been initialized, e.g. by using
 
278
``graph.graphxy``. Then, data and the style of their representation in the
 
279
graph are defined by calling ``g.plot`` like in the following example in which
 
280
filled circles are requested::
 
281
 
 
282
   g.plot(graph.data.file("test.dat"),
 
283
          [graph.style.symbol(graph.style.symbol.circle, symbolattrs=[deco.filled])]
 
284
          )
 
285
 
 
286
As another example, if the linewidth of the symbol is too thin for your
 
287
purposes, you could use something like::
 
288
 
 
289
   [graph.style.symbol(graph.style.symbol.plus, symbolattrs=[style.linewidth.Thick])]
 
290
 
 
291
How do I choose the color of the symbols?
 
292
-----------------------------------------
 
293
 
 
294
Colors are not properties of the symbol as such and can therefore not be
 
295
specified in ``symbolattrs`` directly. The color is rather related to the
 
296
plotting of the symbol as defined by ``deco.stroked`` or ``deco.filled``. 
 
297
With ::
 
298
 
 
299
   graph.style.symbol(graph.style.symbol.circle,
 
300
                      symbolattrs=[deco.stroked([color.rgb.red]),
 
301
                                   deco.filled([color.rgb.green])]
 
302
                      )
 
303
 
 
304
you will obtain a circle filled in green with a red borderline.
 
305
 
 
306
How do I choose the line style?
 
307
-------------------------------
 
308
 
 
309
If you do not want to use symbols, you can set the line style as in this
 
310
example ::
 
311
 
 
312
   g.plot(graph.data.file("test.dat"),
 
313
          [graph.style.line([style.linewidth.Thin])]
 
314
          )
 
315
 
 
316
where the linewidth is set.
 
317
 
 
318
If you also want to use symbols, you can combine the symbol and the
 
319
line style as in ::
 
320
 
 
321
   g.plot(graph.data.file("test.dat"),
 
322
          [graph.style.line(lineattrs=[style.linewidth.Thin,
 
323
                                       style.linestyle.dashed]),
 
324
           graph.style.symbol(graph.style.symbolline.circle,
 
325
                              symbolattrs=[deco.filled])
 
326
           ]
 
327
          )
 
328
 
 
329
to plot the symbols on top of a thin, dashed line. You may alter the
 
330
order of the styles to plot the line on top of the symbols.
 
331
 
 
332
How can I change the color of symbols or lines according to a palette?
 
333
----------------------------------------------------------------------
 
334
 
 
335
If several data sets should be plotted in different colors, one can specify in
 
336
``symbolattrs`` and/or ``lineattrs`` a palette like ``color.palette.Rainbow``.
 
337
Equidistant colors are chosen spanning the palette from one end to the other.
 
338
For example, for three data sets the colors are chosen from the palette at 0,
 
339
0.5, and 1. For the rainbow palette, this would correspond to red, green, and
 
340
blue, respectively.
 
341
 
 
342
In the following example, symbols vary in form and change their color according 
 
343
to the rainbow palette at the same time as the connecting lines::
 
344
 
 
345
   mystyle = [graph.style.symbol(graph.style.symbol.changecircle,
 
346
                                 symbolattrs=[color.palette.Rainbow]),
 
347
              graph.style.line(lineattrs=[color.palette.Rainbow])]
 
348
 
 
349
See question :ref:`changelist` for a more complete example demonstrating how to
 
350
use this style definition and for a comment on the necessity of defining
 
351
``mystyle`` (you are of course free to choose a different name).
 
352
 
 
353
.. _changelist:
 
354
 
 
355
How can I specify changing colors (or other attributes) for symbols or lines?
 
356
-----------------------------------------------------------------------------
 
357
 
 
358
In ``symbolattrs`` and/or ``lineattrs`` so-called changelist can be used. As an
 
359
example ::
 
360
 
 
361
   mystyle = graph.style.symbol(symbolattrs=
 
362
                                [attr.changelist([color.rgb.red, color.rgb.green])])
 
363
   g.plot(graph.data.file("x.dat", x=1, y=2), [mystyle])
 
364
   g.plot(graph.data.file("y.dat", x=1, y=2), [mystyle])
 
365
   g.plot(graph.data.file("z.dat", x=1, y=2), [mystyle])
 
366
 
 
367
will switch between red and green symbols each time a new data set is plotted.
 
368
Several changelists can be specified. They are cycled independently and need
 
369
not be of the same length. It should be noted that the definition of
 
370
``mystyle`` in this example ensures that there is only one instance of the
 
371
definition of ``symbolattrs``. Putting an explicit definition of
 
372
``symbolattrs`` in each call to ``plot`` would not lead to the desired result
 
373
because each time a new instance would be created which then starts with the
 
374
first item in the changelist.
 
375
 
 
376
It may be necessary to repeat attributes in order that several changelists
 
377
cooperate to produce the desired result.  A common situation is that one would
 
378
like to cycle through a list of symbols which should be used in alternating
 
379
colors. This can be achieved with the following code::
 
380
 
 
381
   mystyle = graph.style.symbol(
 
382
                   graph.style.symbol.changetriangletwice,
 
383
                   symbolattrs=[attr.changelist([color.rgb.red, color.rgb.green])])
 
384
 
 
385
which will produce a red triangle, a green triangle, a red circle, a green
 
386
circle and so on for diamond and square because ``changetriangletwice`` lists
 
387
each symbol twice. If instead of changing between colors one would like to
 
388
change between filled and open symbols, one can make use of a predefined
 
389
changelist ::
 
390
 
 
391
   mystyle = graph.style.symbol(
 
392
                   graph.style.symbol.changetriangletwice,
 
393
                   symbolattrs=[graph.style.symbol.changefilledstroked])