Description
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
What needs to be done:
- Support the features of matplotlib-label-lines (notably outlining)
- Wire-in properly with the package, for example using a switch
follow_path=True|False
in thelabelLine[s]
functions. - 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