generativepy.graph module

By 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.

with_division_formatters

with_division_formatters(x_div_formatter=None, y_div_formatter=None)
Parameter Type Description
x_div_formatter Function Formatter function
y_div_formatter Function Formatter function

Override the text formatting for division labels and the x and y axes. For example:

  • Instead of 1, 2, 3... you can override the labels to display π, 2π, 3π...
  • Instead of -2, -1, 1, 2... you can override the labels to display [blank] -a, a, [blank]...
  • Instead of 90, 180, 360... you can override the labels to display 90°, 180°, 270°...

The formatter function must have the signature:

formatter(value, div)

Here value is the value of the division, and div is the spacing between divisions. The function should return a string that will be displayed for that division. It can also be an empty string to display nothing for that division, which allows selected divisions to be unlabelled.

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.

transform_from_graph

transform_from_graph(point)
Parameter Type Description
point (number, number) Point in graph coordinates.

Converts a point in graph coordinates to a point in user space coordinates. This is useful for placing text lables or other features relative to graph features.

Returns (x, y) coordinates in user space.

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).

See also

If you found this article useful, you might be interested in the book NumPy Recipes or other books by the same author.

Join the PythonInformer Newsletter

Sign up using this form to receive an email when new content is added:

Popular tags

2d arrays abstract data type alignment and angle animation arc array arrays bar chart bar style behavioural pattern bezier curve built-in function callable object chain circle classes clipping close closure cmyk colour combinations comparison operator comprehension context context manager conversion count creational pattern data science data types decorator design pattern device space dictionary drawing duck typing efficiency ellipse else encryption enumerate fill filter font font style for loop formula function function composition function plot functools game development generativepy tutorial generator geometry gif global variable gradient greyscale higher order function hsl html image image processing imagesurface immutable object in operator index inner function input installing iter iterable iterator itertools join l system lambda function latex len lerp line line plot line style linear gradient linspace list list comprehension logical operator lru_cache magic method mandelbrot mandelbrot set map marker style matplotlib monad mutability named parameter numeric python numpy object open operator optimisation optional parameter or pandas partial application path pattern permutations pie chart pil pillow polygon pong positional parameter print product programming paradigms programming techniques pure function python standard library radial gradient range recipes rectangle recursion reduce regular polygon repeat rgb rotation roundrect scaling scatter plot scipy sector segment sequence setup shape singleton slice slicing sound spirograph sprite square str stream string stroke structural pattern subpath symmetric encryption template tex text text metrics tinkerbell fractal transform translation transparency triangle truthy value tuple turtle unpacking user space vectorisation webserver website while loop zip zip_longest