-
Notifications
You must be signed in to change notification settings - Fork 29
Description
I would like to add custom labels to the labelLines method. This is already supported via labelLine, however, adding the same functionality to labelLines would save some boilerplate code.
Feature description
- add labels as arg to labelLines
- use labels if supplied for allLabels instead of the labels from ax.get_legend_handles_labels()
- labels should either be a list of length lines/all_lines or a string
- test solution + test cases
Suggested solution
I think the implementation should not be too difficult, but I am a first time user of this module so I dont know if I am missing something. I am replacing allLabels with the custom labels and check if everything seems to line up. I see that there are already check for the label content so I did not touch any code not in core.py.
# in \labellines\core.py
# ln 84 ff
def labelLines(
lines=None,
labels=None,
# ...
**kwargs,
):
"""Label all lines with their respective legends.
Parameters
----------
lines : list of matplotlib lines, optional.
Lines to label. If empty, label all lines that have a label.
labels : list of strings, optional.
Labels for each line. Must match lines.
# ...
"""
# ...
# !! new code after ln 131 ff
# if lines has been supplied and contains Line2D objects use those for all_lines,
# disregard any other Line2D objects in ax
if lines is not None:
assert np.all([isinstance(l, Line2D) for l in lines]), \
f"Objects in lines must be matplotlib.line.Line2D objects.\n" \
f"\t Object type at lines[0]: {type(lines[0])} "
all_lines = lines
else: # old code here that iterates over the handles from the figure
all_lines = []
for h in handles:
if isinstance(h, ErrorbarContainer):
line = h.lines[0]
else:
line = h
# If the user provided a list of lines to label, only label those
if (lines is not None) and (line not in lines):
continue
all_lines.append(line)
# !! new code after ln 141 ff
if labels is not None:
assert len(labels) == len(all_lines) or isinstance(labels, str), \
f"Number of labels must be equal to one or the number of lines to label.\n" \
f"\t len(labels): {len(labels)}, len(lines to label): {len(all_lines)}"
assert lines is not None, f"If labels is supplied manually lines must also be supplied manually."
allLabels = labels
# TODO: unsure: if lines is not supplied but labels is supplied raise exception
# to make sure that each line gets the right label
# Check that the lines passed to the function have all a label
# other code is unchanged
# ...
Additional context
Issues with suggested solution
- TODO above is partially addressed below (ln 141)
- supplying lines and labels together is required with this change. This should not be needed but makes sure that the user labels the each label is assigned to the correct line.
Notes
To be even more fancy a string formatter should be able to be passed as labels together with values /or with reference to the data in Line2D to automatically format the labels on the lines, but I have not gotten around to this yet. This could also build on the mpl methods for string formatting.