Skip to content

Text on path effect #81

Open
Open
@cphyc

Description

@cphyc

Following a discussion on Twitter (https://twitter.com/matplotlib/status/1480027041315667971) it would be great to implement a “text-on-path” effect.

This would notably be made possible by reusing the following snippet https://stackoverflow.com/questions/19353576/curved-text-rendering-in-matplotlib (after asking for the OP permission), which implements a CurvedText artist as a replacement for the Text artist.

This would perfectly fit in after #74 is merged in (thanks @HPLegion!!).

State

Using the StackOverflow snippet above and the tokenizer below (see the diff.txt), I was able to achieve the following
image

What needs to be done:

  1. Support the features of matplotlib-label-lines (notably outlining)
  2. Wire-in properly with the package, for example using a switch follow_path=True|False in the labelLine[s] functions.
  3. Come up with a clever solution for math (see below)?

Further thoughts on math text

One of the difficulties in handling this would be math texts. Indeed, the “natural” approach to adding text on a line is by splitting it character-wise and adding each character in sequence on the line. Unfortunately, this doesn't work for math text,s as how a character will be displayed depends on the current context:

$a^2$          % will display: a², so the ^should be ignored and the 2 be a superscript
$\mathrm{abc}$ % will display abc in roman (not italic) so should we expand it to \mathrm{a}\mathrm{b}\mathrm{c} ?!
$\dfrac{1}{2}$ % will display 1/2 (in a fraction), so it should not be expanded at all and just put on the line as is.

Note that one easy workaround would simply be to consider a math string as a single character and do not do any expansion whatsoever. The text could then be placed token by token, where each token would either be a character or a math expression ($…$). Here is an example of a tokenizer (to be tested thoroughly):

import re
from typing import List
def tokenize_string(text: str) -> List[str]:
    # Make sure the string has only valid math (i.e. there is an even number of `$`)
    valid_math = len(re.findall(r"(?<!\\)\$", text)) % 2 == 0

    if not valid_math:
        return [c for c in text]

    math_mode = False
    tokens = []
    i = 0
    prev_c = None
    for i, c in enumerate(text):
        if c == "$" and prev_c != "\\":
            if math_mode:
                tokens.append("$" + current_token + "$")
                math_mode = False
            else:
                math_mode = True
                current_token = ""
        elif math_mode:
            current_token += c
        else:
            tokens.append(c)
        prev_c = c
    return tokens

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions