Skip to content

Text on path effect #81

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions