Module genpygoodies.formula
The formula module provides some utility functions and classes for creating formulas that appear and disappear in specific locations.
The code converts a formula from Latex to a PNG image that is then rendered as an image. The conversion is relatively timeconsuming (typically it takes a few seconds). When making movies is best to avoid creating formulas per frame, if possible. It is better to create a formula image just once outside the draw function.
Expand source code
# Author: Martin McBride
# Created: 20230603
# Copyright (C) 2023, Martin McBride
# License: MIT
"""
The formula module provides some utility functions and classes for creating formulas that appear and disappear in
specific locations.
The code converts a formula from Latex to a PNG image that is then rendered as an image. The conversion is relatively
timeconsuming (typically it takes a few seconds). When making movies is best to avoid creating formulas per frame, if
possible. It is better to create a formula image just once outside the draw function.
"""
from generativepy.color import Color
from generativepy.drawing import setup, make_image
from generativepy.formulas import rasterise_formula
from generativepy.tween import Tween
from generativepy.geometry import Image
_FORMULA_INDEX = 0 # Global index used to create temp filenames for formulas. Increment after each use
def make_formulas_png(filepath, formulas, color, dpi=600, gap=50, background=Color(1), packages=None):
"""
Create a PNG image of a list of latex formulas.
The formulas will be left aligned. The image will be sized so that there is a border of `gap` pixels around the formulas
in the final image. If there is more than one formula, each will be separated by `gap` pixels horizontally
**Parameters**
* `formulas`: list of str  Latex formula
* `color`: Color  Colour of formula.
* `dpi`: number  Controls formula size. See formula module of generativepy documentation.
* `gap`: number  Controls the width of the border around the edge of the formulas, and also the horizontal gap between the formulas.
* `packages`: sequence of str  tuple containing any required additional latex packages
**Returns**
A tuple (width, height) indicating the pixel size of the final image.
"""
global _FORMULA_INDEX
formula_count = len(formulas)
names = ["formula" + str(_FORMULA_INDEX + i) for i in range(formula_count)]
_FORMULA_INDEX += formula_count
images, sizes = zip(*[rasterise_formula(name, formula, color, dpi=dpi, packages=packages) for name, formula in zip(names, formulas)])
height = sum([size[1] for size in sizes]) + (formula_count + 1)*gap
width = max([size[0] for size in sizes]) + 2*gap
def draw(ctx, pixel_width, pixel_height, fn, frame_count):
setup(ctx, pixel_width, pixel_height, background=background)
ypos = gap
for image, size in zip(images, sizes):
Image(ctx).of_file_position(image, (gap, ypos)).paint()
ypos += size[1] + gap
make_image(filepath, draw, width, height)
return width, height
class formula_zoom_in():
def __init__(self, formula, position, color, appear_time=0, scale_duration=1, initial_scale=0.7, dpi=600, disappear_time=None, fade_duration=1, packages=[]):
"""
Displays a formula with a zoom animation.
**Parameters**
* `formula`: str  Latex formula
* `position`: (number, number)  Tuple giving position of centre of formula
* `color`: Color  Colour of formula.
* `appear_time`: number  Time in seconds when formula appears and zoom starts.
* `scale_duration`: number  Duration for formula to scale to full size. Default 1.
* `initial_scale`: number  Initial size of formula as fraction of full size. Default 0.7
* `dpi`: number  Controls formula size. See formula module of generativepy documentation.
* `disappear_time`: number  Time in seconds when formula starts to fade. Default `None` formula stays visible forever,
* `fade_duration`: number  Duration for formula to fade out. See usage.
* `packages`: sequence of str  list of names of Latex packages the `formula` uses.
**Returns**
A configured `formula_zoom_in` object.
**Usage**
This class displays a formula that zooms in at a certain time. It is best to have an understanding of the generativepy
formula module before attempting to use this class. It will explain important details such as the `dpi` and `packages`
parameters.
Fading is not currently implemented. The formula will behave as if the `fade_duration` is zero.
"""
global _FORMULA_INDEX
name = "formula" + str(_FORMULA_INDEX)
_FORMULA_INDEX += 1
self.image, self.size = rasterise_formula(name, formula, color, dpi=dpi, packages=packages)
self.position = position
self.scale = Tween(initial_scale).wait(appear_time).to_d(1, scale_duration)
self.alpha = Tween(0).wait(appear_time).set(1)
if disappear_time is not None:
self.alpha.wait(disappear_time).to_d(0, fade_duration)
def at(self, position):
"""
Changes the position of the formula. This is MUCH faster than creating a new formula object.
**Parameters**
* `position`: (number, number)  Tuple giving position of centre of formula
**Returns**
self
**Usage**
This can be used to change the display position of an existing formula after it has been created.
This is useful if the formula appears in a movie and you need to move the formula around for each frame. It allows
you to create the formula once and then move it on each frame.
"""
self.position = position
return self
def show(self, ctx, fn):
"""
Draws the formula in a frame
**Parameters**
* `ctx`: drawing context  Context to draw the formula into.
* `fn`: int  Current frame number.
**Returns**
None
**Usage**
Call this in the draw function of every frame where the formula should appear.
"""
if self.alpha[fn]:
Image(ctx).of_file_position(self.image, (self.position[0]  self.size[0] * self.scale[fn] / 2, self.position[1]  self.size[1] * self.scale[fn] / 2)).scale(self.scale[fn]).paint()
class formula_fade_in():
def __init__(self, formula, position, color, appear_time=0, appear_duration=1, dpi=600, disappear_time=None, fade_duration=1):
"""
Displays a formula with a fade animation. FADE IS NOT YET IMPLEMENTED see usage.
**Parameters**
* `formula`: str  Latex formula
* `position`: (number, number)  Tuple giving position of centre of formula
* `color`: Color  Colour of formula.
* `appear_time`: number  Time in seconds when formula appears and zoom starts.
* `appear_duration`: number  Duration for formula to fade in. See usage.
* `dpi`: number  Controls formula size. See formula module of generativepy documentation.
* `disappear_time`: number  Time in seconds when formula starts to fade. Default `None` formula stays visible forever,
* `fade_duration`: number  Duration for formula to fade out. See usage.
* `packages`: sequence of str  list of names of Latex packages the `formula` uses.
**Returns**
A configured `formula_fade_in` object.
**Usage**
Fading is not currently implemented. The formula will always be visible. The description below is for the intended
behaviour when it is fully implemented.
This class displays a formula that fades in at a certain time. It is best to have an understanding of the generativepy
formula module before attempting to use this class. It will explain important details such as the `dpi` and `packages`
parameters.
"""
global _FORMULA_INDEX
name = "formula" + str(_FORMULA_INDEX)
_FORMULA_INDEX += 1
self.image, self.size = rasterise_formula(name, formula, color, dpi=dpi)
self.position = position
self.alpha = Tween(0).wait(appear_time).to_d(1, appear_duration)
if disappear_time is not None:
self.alpha.wait(disappear_time).to_d(0, fade_duration)
def at(self, position):
"""
Changes the position of the formula. This is MUCH faster than creating a new formula object.
**Parameters**
* `position`: (number, number)  Tuple giving position of centre of formula
**Returns**
self
**Usage**
This can be used to change the display position of an existing formula after it has been created.
This is useful if the formula appears in a movie and you need to move the formula around for each frame. It allows
you to create the formula once and then move it on each frame.
"""
self.position = position
return self
def show(self, ctx, fn):
"""
Draws the formula in a frame
**Parameters**
* `ctx`: drawing context  Context to draw the formula into.
* `fn`: int  Current frame number.
**Returns**
None
**Usage**
Call this in the draw function of every frame where the formula should appear.
"""
# if self.alpha[fn]:
# Image(ctx).of_file_position(self.image, self.position)
Image(ctx).of_file_position(self.image, self.position)
Functions
def make_formulas_png(filepath, formulas, color, dpi=600, gap=50, background=<generativepy.color.Color object>, packages=None)

Create a PNG image of a list of latex formulas.
The formulas will be left aligned. The image will be sized so that there is a border of
gap
pixels around the formulas in the final image. If there is more than one formula, each will be separated bygap
pixels horizontallyParameters
formulas
: list of str  Latex formulacolor
: Color  Colour of formula.dpi
: number  Controls formula size. See formula module of generativepy documentation.gap
: number  Controls the width of the border around the edge of the formulas, and also the horizontal gap between the formulas.packages
: sequence of str  tuple containing any required additional latex packages
Returns
A tuple (width, height) indicating the pixel size of the final image.
Expand source code
def make_formulas_png(filepath, formulas, color, dpi=600, gap=50, background=Color(1), packages=None): """ Create a PNG image of a list of latex formulas. The formulas will be left aligned. The image will be sized so that there is a border of `gap` pixels around the formulas in the final image. If there is more than one formula, each will be separated by `gap` pixels horizontally **Parameters** * `formulas`: list of str  Latex formula * `color`: Color  Colour of formula. * `dpi`: number  Controls formula size. See formula module of generativepy documentation. * `gap`: number  Controls the width of the border around the edge of the formulas, and also the horizontal gap between the formulas. * `packages`: sequence of str  tuple containing any required additional latex packages **Returns** A tuple (width, height) indicating the pixel size of the final image. """ global _FORMULA_INDEX formula_count = len(formulas) names = ["formula" + str(_FORMULA_INDEX + i) for i in range(formula_count)] _FORMULA_INDEX += formula_count images, sizes = zip(*[rasterise_formula(name, formula, color, dpi=dpi, packages=packages) for name, formula in zip(names, formulas)]) height = sum([size[1] for size in sizes]) + (formula_count + 1)*gap width = max([size[0] for size in sizes]) + 2*gap def draw(ctx, pixel_width, pixel_height, fn, frame_count): setup(ctx, pixel_width, pixel_height, background=background) ypos = gap for image, size in zip(images, sizes): Image(ctx).of_file_position(image, (gap, ypos)).paint() ypos += size[1] + gap make_image(filepath, draw, width, height) return width, height
Classes
class formula_fade_in (formula, position, color, appear_time=0, appear_duration=1, dpi=600, disappear_time=None, fade_duration=1)

Displays a formula with a fade animation. FADE IS NOT YET IMPLEMENTED see usage.
Parameters
formula
: str  Latex formulaposition
: (number, number)  Tuple giving position of centre of formulacolor
: Color  Colour of formula.appear_time
: number  Time in seconds when formula appears and zoom starts.appear_duration
: number  Duration for formula to fade in. See usage.dpi
: number  Controls formula size. See formula module of generativepy documentation.disappear_time
: number  Time in seconds when formula starts to fade. DefaultNone
formula stays visible forever,fade_duration
: number  Duration for formula to fade out. See usage.packages
: sequence of str  list of names of Latex packages theformula
uses.
Returns
A configured
formula_fade_in
object.Usage Fading is not currently implemented. The formula will always be visible. The description below is for the intended behaviour when it is fully implemented.
This class displays a formula that fades in at a certain time. It is best to have an understanding of the generativepy formula module before attempting to use this class. It will explain important details such as the
dpi
andpackages
parameters.Expand source code
class formula_fade_in(): def __init__(self, formula, position, color, appear_time=0, appear_duration=1, dpi=600, disappear_time=None, fade_duration=1): """ Displays a formula with a fade animation. FADE IS NOT YET IMPLEMENTED see usage. **Parameters** * `formula`: str  Latex formula * `position`: (number, number)  Tuple giving position of centre of formula * `color`: Color  Colour of formula. * `appear_time`: number  Time in seconds when formula appears and zoom starts. * `appear_duration`: number  Duration for formula to fade in. See usage. * `dpi`: number  Controls formula size. See formula module of generativepy documentation. * `disappear_time`: number  Time in seconds when formula starts to fade. Default `None` formula stays visible forever, * `fade_duration`: number  Duration for formula to fade out. See usage. * `packages`: sequence of str  list of names of Latex packages the `formula` uses. **Returns** A configured `formula_fade_in` object. **Usage** Fading is not currently implemented. The formula will always be visible. The description below is for the intended behaviour when it is fully implemented. This class displays a formula that fades in at a certain time. It is best to have an understanding of the generativepy formula module before attempting to use this class. It will explain important details such as the `dpi` and `packages` parameters. """ global _FORMULA_INDEX name = "formula" + str(_FORMULA_INDEX) _FORMULA_INDEX += 1 self.image, self.size = rasterise_formula(name, formula, color, dpi=dpi) self.position = position self.alpha = Tween(0).wait(appear_time).to_d(1, appear_duration) if disappear_time is not None: self.alpha.wait(disappear_time).to_d(0, fade_duration) def at(self, position): """ Changes the position of the formula. This is MUCH faster than creating a new formula object. **Parameters** * `position`: (number, number)  Tuple giving position of centre of formula **Returns** self **Usage** This can be used to change the display position of an existing formula after it has been created. This is useful if the formula appears in a movie and you need to move the formula around for each frame. It allows you to create the formula once and then move it on each frame. """ self.position = position return self def show(self, ctx, fn): """ Draws the formula in a frame **Parameters** * `ctx`: drawing context  Context to draw the formula into. * `fn`: int  Current frame number. **Returns** None **Usage** Call this in the draw function of every frame where the formula should appear. """ # if self.alpha[fn]: # Image(ctx).of_file_position(self.image, self.position) Image(ctx).of_file_position(self.image, self.position)
Methods
def at(self, position)

Changes the position of the formula. This is MUCH faster than creating a new formula object.
Parameters
position
: (number, number)  Tuple giving position of centre of formula
Returns
self
Usage This can be used to change the display position of an existing formula after it has been created.
This is useful if the formula appears in a movie and you need to move the formula around for each frame. It allows you to create the formula once and then move it on each frame.
Expand source code
def at(self, position): """ Changes the position of the formula. This is MUCH faster than creating a new formula object. **Parameters** * `position`: (number, number)  Tuple giving position of centre of formula **Returns** self **Usage** This can be used to change the display position of an existing formula after it has been created. This is useful if the formula appears in a movie and you need to move the formula around for each frame. It allows you to create the formula once and then move it on each frame. """ self.position = position return self
def show(self, ctx, fn)

Draws the formula in a frame
Parameters
ctx
: drawing context  Context to draw the formula into.fn
: int  Current frame number.
Returns
None
Usage Call this in the draw function of every frame where the formula should appear.
Expand source code
def show(self, ctx, fn): """ Draws the formula in a frame **Parameters** * `ctx`: drawing context  Context to draw the formula into. * `fn`: int  Current frame number. **Returns** None **Usage** Call this in the draw function of every frame where the formula should appear. """ # if self.alpha[fn]: # Image(ctx).of_file_position(self.image, self.position) Image(ctx).of_file_position(self.image, self.position)
class formula_zoom_in (formula, position, color, appear_time=0, scale_duration=1, initial_scale=0.7, dpi=600, disappear_time=None, fade_duration=1, packages=[])

Displays a formula with a zoom animation.
Parameters
formula
: str  Latex formulaposition
: (number, number)  Tuple giving position of centre of formulacolor
: Color  Colour of formula.appear_time
: number  Time in seconds when formula appears and zoom starts.scale_duration
: number  Duration for formula to scale to full size. Default 1.initial_scale
: number  Initial size of formula as fraction of full size. Default 0.7dpi
: number  Controls formula size. See formula module of generativepy documentation.disappear_time
: number  Time in seconds when formula starts to fade. DefaultNone
formula stays visible forever,fade_duration
: number  Duration for formula to fade out. See usage.packages
: sequence of str  list of names of Latex packages theformula
uses.
Returns
A configured
formula_zoom_in
object.Usage This class displays a formula that zooms in at a certain time. It is best to have an understanding of the generativepy formula module before attempting to use this class. It will explain important details such as the
dpi
andpackages
parameters.Fading is not currently implemented. The formula will behave as if the
fade_duration
is zero.Expand source code
class formula_zoom_in(): def __init__(self, formula, position, color, appear_time=0, scale_duration=1, initial_scale=0.7, dpi=600, disappear_time=None, fade_duration=1, packages=[]): """ Displays a formula with a zoom animation. **Parameters** * `formula`: str  Latex formula * `position`: (number, number)  Tuple giving position of centre of formula * `color`: Color  Colour of formula. * `appear_time`: number  Time in seconds when formula appears and zoom starts. * `scale_duration`: number  Duration for formula to scale to full size. Default 1. * `initial_scale`: number  Initial size of formula as fraction of full size. Default 0.7 * `dpi`: number  Controls formula size. See formula module of generativepy documentation. * `disappear_time`: number  Time in seconds when formula starts to fade. Default `None` formula stays visible forever, * `fade_duration`: number  Duration for formula to fade out. See usage. * `packages`: sequence of str  list of names of Latex packages the `formula` uses. **Returns** A configured `formula_zoom_in` object. **Usage** This class displays a formula that zooms in at a certain time. It is best to have an understanding of the generativepy formula module before attempting to use this class. It will explain important details such as the `dpi` and `packages` parameters. Fading is not currently implemented. The formula will behave as if the `fade_duration` is zero. """ global _FORMULA_INDEX name = "formula" + str(_FORMULA_INDEX) _FORMULA_INDEX += 1 self.image, self.size = rasterise_formula(name, formula, color, dpi=dpi, packages=packages) self.position = position self.scale = Tween(initial_scale).wait(appear_time).to_d(1, scale_duration) self.alpha = Tween(0).wait(appear_time).set(1) if disappear_time is not None: self.alpha.wait(disappear_time).to_d(0, fade_duration) def at(self, position): """ Changes the position of the formula. This is MUCH faster than creating a new formula object. **Parameters** * `position`: (number, number)  Tuple giving position of centre of formula **Returns** self **Usage** This can be used to change the display position of an existing formula after it has been created. This is useful if the formula appears in a movie and you need to move the formula around for each frame. It allows you to create the formula once and then move it on each frame. """ self.position = position return self def show(self, ctx, fn): """ Draws the formula in a frame **Parameters** * `ctx`: drawing context  Context to draw the formula into. * `fn`: int  Current frame number. **Returns** None **Usage** Call this in the draw function of every frame where the formula should appear. """ if self.alpha[fn]: Image(ctx).of_file_position(self.image, (self.position[0]  self.size[0] * self.scale[fn] / 2, self.position[1]  self.size[1] * self.scale[fn] / 2)).scale(self.scale[fn]).paint()
Methods
def at(self, position)

Changes the position of the formula. This is MUCH faster than creating a new formula object.
Parameters
position
: (number, number)  Tuple giving position of centre of formula
Returns
self
Usage This can be used to change the display position of an existing formula after it has been created.
This is useful if the formula appears in a movie and you need to move the formula around for each frame. It allows you to create the formula once and then move it on each frame.
Expand source code
def at(self, position): """ Changes the position of the formula. This is MUCH faster than creating a new formula object. **Parameters** * `position`: (number, number)  Tuple giving position of centre of formula **Returns** self **Usage** This can be used to change the display position of an existing formula after it has been created. This is useful if the formula appears in a movie and you need to move the formula around for each frame. It allows you to create the formula once and then move it on each frame. """ self.position = position return self
def show(self, ctx, fn)

Draws the formula in a frame
Parameters
ctx
: drawing context  Context to draw the formula into.fn
: int  Current frame number.
Returns
None
Usage Call this in the draw function of every frame where the formula should appear.
Expand source code
def show(self, ctx, fn): """ Draws the formula in a frame **Parameters** * `ctx`: drawing context  Context to draw the formula into. * `fn`: int  Current frame number. **Returns** None **Usage** Call this in the draw function of every frame where the formula should appear. """ if self.alpha[fn]: Image(ctx).of_file_position(self.image, (self.position[0]  self.size[0] * self.scale[fn] / 2, self.position[1]  self.size[1] * self.scale[fn] / 2)).scale(self.scale[fn]).paint()