# generativepy.graph module

Martin McBride, 2020-08-08

Tags graph

Categories generativepy generative art

The graph module provides the ability to draw graphs of mathematical functions. It can also be used in conjunction with the movie and tween modules to create animated graphs that can be converted to gifs or videos.

To draw a graph you must first create an `Axes`

object that defines size, location, and scale of the graph axes. You can then create one or more `Plot`

objects to draw the plots on the axes.

## Graph scaling

Graph are drawn in the current user space. The size and location of the axes are defined in current user parameters.

The text and gridlines of the axes are designed for graphs that are a few hundred units wide. If you use graphs that are significantly larger or smaller than that, you might find that the axes text looks too big or small, and the grid lines might look too thick or thin. There are two ways of fixing this:

- Use the axes
`with_feature_scale`

method. This scales all sizes and thicknesses up or down. So for example if your graph is 1000 units wide, you might want to apply a scale of around 2.0 to make the feature sizes proportionate to the graph size. - Alternatively, you can adjust all the features individually.

The second method allows you a great deal of control of the graph appearance. You can set the colours and styles of all the axis lines and text, and the background colour of the graph.

When you plot a curve:

- The curve line thickness, dash patterns etc are specified in user units.
- The curve points are mapped to the axis units (as you would expect, so that the curve appears in the right place on the graph).

## Example

Here is an example graph drawn using the `Axes`

object, and adding 3 curves:

The code for this can be found on github as *simplegraph.py*:

from generativepy import graph from generativepy.drawing import make_image, setup from generativepy.color import Color from generativepy.graph import Axes ''' Create a simple graph ''' def draw(ctx, width, height, frame_no, frame_count): setup(ctx, width, height, background=Color(1)) # Creates a set of axes. # Use the default size of 10 units, but offset the start toplace the origin inthe centre axes = Axes(ctx, (50, 50), 500, 500).of_start((-5, -5)) axes.draw() # Add various curves axes.clip() Plot(axes).of_function(lambda x: x * x).stroke(pattern=Color('red')) Plot(axes).of_xy_function(lambda x: 1.5 ** x).stroke(pattern=Color('green')) Plot(axes).of_polar_function(lambda x: 2 * x).stroke(pattern=Color('blue')) axes.unclip() make_image("/tmp/simplegraph.png", draw, 500, 500)

Notice that we surround the `Plot`

calls with `axes.clip()`

and `axes.unclip()`

to ensure that the curve is clipped to the area covered by the axes.

## Axes

The `Axes`

class draws graph axes, including the main axes, divisions, subdivisions, origin marker and division values. You simply need to create an `Axes`

object then call `draw`

to draw the axes.

### Axes constructor

Creates an `Axes`

object.

Axes(ctx, position, width, height)

Parameter | Type | Description |
---|---|---|

ctx | Context | The Pycairo Context to draw to |

position | (number, number) | A tuple of two numbers, giving the (x, y) position of the top left corner. |

width | number | The width. |

height | number | The height. |

Creates a set of axes for drawing a graph.

The `position`

gives the position of the top left of the axes in user coordinates. `width`

and `height`

give the size of the axes area, again in user coordinates.

### of_start

Sets the start of the axes values.

of_start(start)

Parameter | Type | Description |
---|---|---|

start | 2-tuple | The (x, y) value of the bottom left corner of the graph in graph coordinates. |

Gives the start of the axes range. This represents the (x, y) value of the bottom left corner of the axes, in the coordinated of the graph itself.

If you wanted the graph to show x values in the range -1 to +5, and y values in the range -3 to +4, you would set a `start`

of (-1, -3).

### of_extent

Sets the extent of the axes values.

of_extent(extent)

Parameter | Type | Description |
---|---|---|

extent | 2-tuple | The (x, y) of the axes in graph space. |

Gives the width and height of the axes range.

If you wanted the graph to show x values in the range -1 to +5, and y values in the range -3 to +3, you would set a `extent`

of (6, 7). That is because the x axis has a range of 6 (from -1 to +5), and the y axis has a range of 7 (from -3 to +4).

### with_feature_scale

Scales the graph features.

with_feature_scale(scale)

Parameter | Type | Description |
---|---|---|

scale | number | The scale factor. |

Scales all the graph features by `scale`

. This affects all the visible elements of the axes:

- The axis, division and sub-division line thicknesses will be scaled.
- The axis text will be scaled.
- The size of the axis ticks and origin marker.

For example, a scale of 2 will make these features twice as big, 0.5 will make them half as big.

The scale factor is applied on top of any changes made by the axes styling functions below. For example if you set the axis line width to 3, and apply a scale factor of 2, the axis line width will be drawn as 6 units.

### with_divisions

Sets the division spacing.

with_divisions(divisions)

Parameter | Type | Description |
---|---|---|

divisions | 2-tuple | The (x, y) division sizes. |

Sets the division spacing in the x and y directions. For example, (1, 5) will create an x division for every one unit in the axes space, and a y divison for every 5 units.

If this function isn't called, the divisions are set to (1, 1).

### with_subdivisions

Sets the sub-division spacing.

with_subdivisions(divisions)

Parameter | Type | Description |
---|---|---|

factor | 2-tuple | The (x, y) sub-division factor. |

Calling this method enables sub-divisions and sets the sub-division factor.

A `factor`

of (5, 2) means that there will be 5 subdivisions per division on the x-axis, and y subdivisions per division on the y-axis.

If you do not call this function, no subdivisions will be shown.

### background

Sets the background fill.

background(pattern)

Parameter | Type | Description |
---|---|---|

pattern | Color or Pattern | The graph background pattern/colour. |

Sets the colour or pattern of the entire graph background. See the `pattern`

parameter of the `fill`

method of Shape.

### text_color

Sets the text fill.

text_color(pattern)

Parameter | Type | Description |
---|---|---|

pattern | Color or Pattern | The graph text pattern/colour. |

Sets the colour or pattern of the axis text. See the `pattern`

parameter of the `fill`

method of Shape.

If this function is not called, the text will be a dark grey colour.

### text_style

Sets the text font and size for the axes text.

text_style(font="arial", weight=FONT_WEIGHT_BOLD, slant=FONT_SLANT_NORMAL, size=15)

Parameter | Type | Description |
---|---|---|

font | string | Name of the font to use. |

weight | enum | Font weight, default to normal. |

slant | enum | Font slant, defalts to normal. |

size | number | The size of the text. |

`font`

is the name of the font, such as 'arial'.

`weight`

is the font weight, either `drawing.FONT_WEIGHT_NORMAL`

or `drawing.FONT_WEIGHT_BOLD`

.

`slant`

is the font slant, either `drawing.FONT_SLANT_NORMAL`

, `drawing.FONT_SLANT_ITALIC`

, or `drawing.FONT_SLANT_OBLIQUE`

.

`sizes`

sets the font size. This is approximately equal to the height of the font in user units. See the `size`

method for Text objects.

If this method is not called, the font defaults to 'arial', bold, size 15.

### axis_linestyle

Sets the line style of the graph axes.

axis_linestyle(pattern=Color(0), line_width=None, dash=None, cap=None, join=None, miter_limit=None)

Parameter | Type | Description |
---|---|---|

pattern | Color or Pattern | The stroke pattern/colour. |

line_width | number | The line width. |

dash | array of numbers | The dash style. |

cap | enum | The type of line cap. |

join | enum | The type of line join. |

miter_limit | number | The mitre limit. |

Sets the style of the main axis lines. See the `stroke`

method of Shape.

If this function is not called, the line will be dark grey with a width of 2.

### division_linestyle

Sets the line style of the graph axes.

division_linestyle(pattern=Color(0), line_width=None, dash=None, cap=None, join=None, miter_limit=None)

Parameter | Type | Description |
---|---|---|

pattern | Color or Pattern | The stroke pattern/colour. |

line_width | number | The line width. |

dash | array of numbers | The dash style. |

cap | enum | The type of line cap. |

join | enum | The type of line join. |

miter_limit | number | The mitre limit. |

Sets the style of the division lines. See the `stroke`

method of Shape.

If this function is not called, the line will be light blue with a width of 2.

### subdivision_linestyle

Sets the line style of the graph axes.

subdivision_linestyle(pattern=Color(0), line_width=None, dash=None, cap=None, join=None, miter_limit=None)

Parameter | Type | Description |
---|---|---|

pattern | Color or Pattern | The stroke pattern/colour. |

line_width | number | The line width. |

dash | array of numbers | The dash style. |

cap | enum | The type of line cap. |

join | enum | The type of line join. |

miter_limit | number | The mitre limit. |

Sets the style of the subdivision lines. See the `stroke`

method of Shape.

If this function is not called, the line will be very light blue with a width of 2.

### draw

Draws the axes using the Context supplied in the `Axes`

constructor.

draw()

### clip

Establishes a clipping path that covers the area of the axes. Anything drawn while the clip path is active will be clipped to the axes area.

clip()

### unclip

Removes a clipping path previously set up by `clip()`

.

unclip()

## Plot

The `Plot`

class can draw various types of curve:

`of_function`

for plotting functions of the form y = f(x).`of_xy_function`

for plotting inverse functions of the form x = f(y).`of_polar_function`

for plotting polar functions of the form r = f(a).

A `Plot`

is a `Shape`

object.

To draw a plot:

- Create a
`Plot`

object. - Call
`of_function`

or one of the other plotting method to define the curve. - Call the
`stroke`

function to draw the curve.

In most cases you will probably wish to clip the plot to the area covered by the axes. This is not done automatically, but it can be achieved by calling `axes.clip()`

before using the `Plot`

object, then calling `axes.unlcip()`

after. See the example code above.

### Plot constructor

Creates a `Plot`

object.

Plot(axes)

Parameter | Type | Description |
---|---|---|

axes | Axes | The Axes object the plot will be drawn against. |

### of_function

Plots a function of the form y = f(x)

of_function(fn, extent=None, precision=100)

Parameter | Type | Description |
---|---|---|

fn | function | A Python function that takes a single number parameter and returns a number. |

extent | 2-tuple | The range of x values. |

precision | int | The number of points to plot. |

If the `extent`

is not supplied, the graph will be plotted for values of x that cover the full range of the `axes`

. The `extent`

can be used to limit the range to less than the full extent of the axes.

The precision determines how many points are used to draw the graph. If the number is set too low, the graph won't look smooth.

### of_xy_function

Plots a function of the form x = f(y)

of_xy_function(fn, extent=None, precision=100)

Parameter | Type | Description |
---|---|---|

fn | function | A Python function that takes a single number parameter and returns a number. |

extent | 2-tuple | The range of y values. |

precision | int | The number of points to plot. |

If the `extent`

is not supplied, the graph will be plotted for values of y that cover the full range of the `axes`

. The `extent`

can be used to limit the range to less than the full extent of the axes.

The precision determines how many points are used to draw the graph. If the number is set too low, the graph won't look smooth.

### of_polar_function

Plots a function of the form r = f(theta)

of_polar_function(fn, extent=None, precision=100)

Parameter | Type | Description |
---|---|---|

fn | function | A Python function that takes a single number parameter and returns a number. |

extent | 2-tuple | The range of theta values. |

precision | int | The number of points to plot. |

If the `extent`

is not supplied, the graph will be plotted for values of theta from 0 to `2*pi`

. The `extent`

can be used to alter that range.

The precision determines how many points are used to draw the graph. If the number is set too low, the graph won't look smooth.

### stroke

The `stroke`

method of `Plot`

has the same parameters as the `stroke`

method of Shape. It will draw the shape defined by the supplied function.

The default `line_width`

of the stroke for `Plot`

is 2 (rather than 1 that is the default for most shapes).