Skip to content

Rendering Text!

elkplot can render text in a number of different fonts using the built in text function. Here are all the provided fonts plotted on letter paper:

All Fonts Plotted

The full list of fonts as you'd use them in code are: elkplot.ASTROLOGY, elkplot.CURSIVE, elkplot.CYRILLIC_1, elkplot.CYRILLIC, elkplot.FUTURAL, elkplot.FUTURAM, elkplot.GOTHGBT, elkplot.GOTHGRT, elkplot.GOTHICENG, elkplot.GOTHICGER, elkplot.GOTHICITA, elkplot.GOTHITT, elkplot.GREEK, elkplot.GREEKC, elkplot.GREEKS, elkplot.JAPANESE, elkplot.MARKERS, elkplot.MATHLOW, elkplot.MATHUPP, elkplot.METEOROLOGY, elkplot.MUSIC, elkplot.ROWMAND, elkplot.ROWMANS, elkplot.ROWMANT, elkplot.SCRIPTC, elkplot.SCRIPTS, elkplot.SYMBOLIC, elkplot.TIMESG, elkplot.TIMESI, elkplot.TIMESIB, elkplot.TIMESR, elkplot.TIMESRB.

Sample Code

import elkplot

size = 4 * elkplot.UNITS.inch, 2 * elkplot.UNITS.inch
font = elkplot.Font(elkplot.METEOROLOGY, 25)
text_drawing = font.wrap("The quick brown fox jumps over the lazy dog.", 3)
text_drawing = elkplot.center(text_drawing, *size)
elkplot.draw(text_drawing, *size, plot=False)

The above code results in the following plot (as viewed in the preview window). The paper is 4 inches wide, but the text has been wrapped to fit in a column 3 inches wide. Wrapped Text

Note that all the text generating functions return text that is situated at the origin - use functions like elkplot.center() or elkplot.scale_to_fit() to move and scale your text-drawing or use shapely.affinity.translate() to reposition the text-drawing to arbitrary positions.

Font

Source code in elkplot/text/hershey.py
class Font:
    def __init__(self, font: HersheyFont, point_size: float):
        """A class that renders text in a given font and point size"""
        self.font = font
        self.max_height = size(text(printable, font))[1]
        self.scale = ((point_size / 72) / self.max_height).magnitude

    def text(self, string: str) -> shapely.MultiLineString:
        """
        Render a string using this font's size and font in a single long line.
        Args:
            string: The text to be rendered

        Returns:
            The drawing of the text

        """
        t = text(string, self.font)
        t = affinity.scale(t, self.scale, self.scale, origin=(0, 0))
        return t

    def measure(self, string: str) -> tuple[pint.Quantity, pint.Quantity]:
        """Return the width and height of a given string rendered using this font/size combo"""
        t = self.text(string)
        return size(t)

    @elkplot.UNITS.wraps(None, [None, None, "inch", None, None], False)
    def wrap(
            self,
            string: str,
            width: float,
            line_spacing: float = 1,
            align: float = 0,
    ) -> shapely.MultiLineString:
        """
        Render a given string such that the text is confined to a column of a given width by inserting line breaks.
        Args:
            string: The text to be rendered
            width: The width of the column
            line_spacing: A multiplier on the gap between lines. Setting this to 0.5 would cut the space between lines
                in half, and setting this to 2 would double the space between lines.
            align: 0=align text left, 1=align text right, 2=align text center

        Returns:
            The drawing of the text

        """
        lines = word_wrap(string, width, self.measure)
        line_shapes = [self.text(line) for line in lines]
        max_width = max(size(t)[0] for t in line_shapes)
        spacing = line_spacing * self.max_height * self.scale
        result = []
        y = 0
        for line_shape in line_shapes:
            w, h = size(line_shape)
            if align == 0:
                x = 0
            elif align == 1:
                x = (max_width - w).m
            else:
                x = (max_width / 2 - w / 2).m
            line_shape = affinity.translate(line_shape, x, y)
            result.append(line_shape)
            y += spacing.m
        return shapely.union_all(result)

__init__(font, point_size)

A class that renders text in a given font and point size

Source code in elkplot/text/hershey.py
def __init__(self, font: HersheyFont, point_size: float):
    """A class that renders text in a given font and point size"""
    self.font = font
    self.max_height = size(text(printable, font))[1]
    self.scale = ((point_size / 72) / self.max_height).magnitude

measure(string)

Return the width and height of a given string rendered using this font/size combo

Source code in elkplot/text/hershey.py
def measure(self, string: str) -> tuple[pint.Quantity, pint.Quantity]:
    """Return the width and height of a given string rendered using this font/size combo"""
    t = self.text(string)
    return size(t)

text(string)

Render a string using this font's size and font in a single long line. Args: string: The text to be rendered

Returns:

Type Description
MultiLineString

The drawing of the text

Source code in elkplot/text/hershey.py
def text(self, string: str) -> shapely.MultiLineString:
    """
    Render a string using this font's size and font in a single long line.
    Args:
        string: The text to be rendered

    Returns:
        The drawing of the text

    """
    t = text(string, self.font)
    t = affinity.scale(t, self.scale, self.scale, origin=(0, 0))
    return t

wrap(string, width, line_spacing=1, align=0)

Render a given string such that the text is confined to a column of a given width by inserting line breaks. Args: string: The text to be rendered width: The width of the column line_spacing: A multiplier on the gap between lines. Setting this to 0.5 would cut the space between lines in half, and setting this to 2 would double the space between lines. align: 0=align text left, 1=align text right, 2=align text center

Returns:

Type Description
MultiLineString

The drawing of the text

Source code in elkplot/text/hershey.py
@elkplot.UNITS.wraps(None, [None, None, "inch", None, None], False)
def wrap(
        self,
        string: str,
        width: float,
        line_spacing: float = 1,
        align: float = 0,
) -> shapely.MultiLineString:
    """
    Render a given string such that the text is confined to a column of a given width by inserting line breaks.
    Args:
        string: The text to be rendered
        width: The width of the column
        line_spacing: A multiplier on the gap between lines. Setting this to 0.5 would cut the space between lines
            in half, and setting this to 2 would double the space between lines.
        align: 0=align text left, 1=align text right, 2=align text center

    Returns:
        The drawing of the text

    """
    lines = word_wrap(string, width, self.measure)
    line_shapes = [self.text(line) for line in lines]
    max_width = max(size(t)[0] for t in line_shapes)
    spacing = line_spacing * self.max_height * self.scale
    result = []
    y = 0
    for line_shape in line_shapes:
        w, h = size(line_shape)
        if align == 0:
            x = 0
        elif align == 1:
            x = (max_width - w).m
        else:
            x = (max_width / 2 - w / 2).m
        line_shape = affinity.translate(line_shape, x, y)
        result.append(line_shape)
        y += spacing.m
    return shapely.union_all(result)