Source code for plotnine.facets.labelling
import pandas as pd
from contextlib import suppress
from ..exceptions import PlotnineError
def collapse_label_lines(label_info):
"""
Concatenate all items in series into one item
"""
return pd.Series([', '.join(label_info)])
[docs]def label_value(label_info, multi_line=True):
"""
Convert series values to str and maybe concatenate them
Parameters
----------
label_info : series
Series whose values will be returned
multi_line : bool
Whether to place each variable on a separate line
Returns
-------
out : series
Label text strings
"""
label_info = label_info.astype(str)
if not multi_line:
label_info = collapse_label_lines(label_info)
return label_info
[docs]def label_both(label_info, multi_line=True, sep=': '):
"""
Concatenate the index and the value of the series.
Parameters
----------
label_info : series
Series whose values will be returned. It must have
an index made of variable names.
multi_line : bool
Whether to place each variable on a separate line
sep : str
Separation between variable name and value
Returns
-------
out : series
Label text strings
"""
label_info = label_info.astype(str)
for var in label_info.index:
label_info[var] = f'{var}{sep}{label_info[var]}'
if not multi_line:
label_info = collapse_label_lines(label_info)
return label_info
[docs]def label_context(label_info, multi_line=True, sep=': '):
"""
Create an unabiguous label string
If facetting over a single variable, `label_value` is
used, if two or more variables then `label_both` is used.
Parameters
----------
label_info : series
Series whose values will be returned. It must have
an index made of variable names
multi_line : bool
Whether to place each variable on a separate line
sep : str
Separation between variable name and value
Returns
-------
out : str
Contatenated label values (or pairs of variable names
& values)
"""
if len(label_info) == 1:
return label_value(label_info, multi_line)
else:
return label_both(label_info, multi_line, sep)
LABELLERS = {
'label_value': label_value,
'label_both': label_both,
'label_context': label_context}
[docs]def as_labeller(x, default=label_value, multi_line=True):
"""
Coerse to labeller function
Parameters
----------
x : function | dict
Object to coerce
default : function | str
Default labeller. If it is a string,
it should be the name of one the labelling
functions provided by plotnine.
multi_line : bool
Whether to place each variable on a separate line
Returns
-------
out : function
Labelling function
"""
if x is None:
x = default
# One of the labelling functions as string
with suppress(KeyError, TypeError):
x = LABELLERS[x]
# x is a labeller
with suppress(AttributeError):
if x.__name__ == '_labeller':
return x
def _labeller(label_info):
label_info = pd.Series(label_info).astype(str)
if callable(x) and x.__name__ in LABELLERS:
# labellers in this module
return x(label_info)
elif hasattr(x, '__contains__'):
# dictionary lookup
for var in label_info.index:
if label_info[var] in x:
label_info[var] = x[label_info[var]]
return label_info
elif callable(x):
# generic function
for var in label_info.index:
label_info[var] = x(label_info[var])
return label_info
else:
msg = "Could not use '{0}' for labelling."
raise PlotnineError(msg.format(x))
return _labeller
[docs]def labeller(rows=None, cols=None, multi_line=True,
default=label_value, **kwargs):
"""
Return a labeller function
Parameters
----------
rows : str | function | None
How to label the rows
cols : str | function | None
How to label the columns
multi_line : bool
Whether to place each variable on a separate line
default : function | str
Fallback labelling function. If it is a string,
it should be the name of one the labelling
functions provided by plotnine.
kwargs : dict
{variable name : function | string} pairs for
renaming variables. A function to rename the variable
or a string name.
Returns
-------
out : function
Function to do the labelling
"""
# Sort out the labellers along each dimension
rows_labeller = as_labeller(rows, default, multi_line)
cols_labeller = as_labeller(cols, default, multi_line)
def _labeller(label_info):
# When there is no variable specific labeller,
# use that of the dimension
if label_info._meta['dimension'] == 'rows':
margin_labeller = rows_labeller
else:
margin_labeller = cols_labeller
# Labelling functions expect string values
label_info = label_info.astype(str)
# Each facetting variable is labelled independently
for name, value in label_info.iteritems():
func = as_labeller(kwargs.get(name), margin_labeller)
new_info = func(label_info[[name]])
label_info[name] = new_info[name]
if not multi_line:
label_info = collapse_label_lines(label_info)
return label_info
return _labeller