diff --git a/labellines/core.py b/labellines/core.py index 93b9c85..7f544fb 100644 --- a/labellines/core.py +++ b/labellines/core.py @@ -5,7 +5,7 @@ from matplotlib.container import ErrorbarContainer from matplotlib.dates import DateConverter, num2date from more_itertools import always_iterable -from .line_label import LineLabel +from .line_label import CurvedText, LineLabel from .utils import ensure_float, maximum_bipartite_matching @@ -49,16 +49,19 @@ def labelLine( Optional arguments passed to ax.text """ + xx = line.get_xdata() + yy = line.get_ydata() try: - txt = LineLabel( - line, - x, - label=label, - align=align, - yoffset=yoffset, - yoffset_logspace=yoffset_logspace, - outline_color=outline_color, - outline_width=outline_width, + txt = CurvedText( + xx, + yy, + label, + axes=line.axes, + #align=align, + #yoffset=yoffset, + #yoffset_logspace=yoffset_logspace, + #outline_color=outline_color, + #outline_width=outline_width, **kwargs, ) except ValueError as err: diff --git a/labellines/line_label.py b/labellines/line_label.py index 2e7877d..c7b2139 100644 --- a/labellines/line_label.py +++ b/labellines/line_label.py @@ -5,10 +5,11 @@ from typing import TYPE_CHECKING import matplotlib.patheffects as patheffects import numpy as np from matplotlib.text import Text +import re if TYPE_CHECKING: from datetime import datetime - from typing import Any, Union + from typing import Any, Union, List from matplotlib.axes import Axes from matplotlib.lines import Line2D @@ -18,8 +19,191 @@ if TYPE_CHECKING: # Once support for python <3.8 is dropped this should be Literal["auto"] AutoLiteral = str +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"(? l_fig[-1]: + t.set_alpha(0.0) + rel_pos += w + continue + + elif c != ' ': + t.set_alpha(1.0) + + # finding the two data points between which the horizontal + # center point of the character will be situated + # left and right indices: + il = np.where(rel_pos+w/2 >= l_fig)[0][-1] + ir = np.where(rel_pos+w/2 <= l_fig)[0][0] + + # if we exactly hit a data point: + if ir == il: + ir += 1 + + # how much of the letter width was needed to find il: + used = l_fig[il]-rel_pos + rel_pos = l_fig[il] + + # relative distance between il and ir where the center + # of the character will be + fraction = (w/2-used)/r_fig_dist[il] + + ## setting the character position in data coordinates: + ## interpolate between the two points: + x = self.__x[il]+fraction*(self.__x[ir]-self.__x[il]) + y = self.__y[il]+fraction*(self.__y[ir]-self.__y[il]) + + # getting the offset when setting correct vertical alignment + # in data coordinates + t.set_va(self.get_va()) + bbox2 = t.get_window_extent(renderer=renderer) + + bbox1d = self.axes.transData.inverted().transform(bbox1) + bbox2d = self.axes.transData.inverted().transform(bbox2) + dr = np.array(bbox2d[0]-bbox1d[0]) + + # the rotation/stretch matrix + rad = rads[il] + rot_mat = np.array([ + [np.math.cos(rad), np.math.sin(rad)*aspect], + [-np.math.sin(rad)/aspect, np.math.cos(rad)] + ]) + + ## computing the offset vector of the rotated character + drp = np.dot(dr, rot_mat) + + # setting final position and rotation: + t.set_position(np.array([x, y]) + drp) + t.set_rotation(degs[il]) + + t.set_va('center') + t.set_ha('center') + + # updating rel_pos to right edge of character + rel_pos += w-used + +class LineLabel(CurvedText): """This artist adds a label onto a preexisting Line2D object""" _line: Line2D