Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Support callable for formatting of Sankey labels #19187

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jan 4, 2021
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
Support callable for formatting of Sankey labels
------------------------------------------------

The `format` parameter of `matplotlib.sankey.Sankey` can now accept callables.

This allows the use of an arbitrary function to label flows, for example allowing
the mapping of numbers to emoji.

.. plot::

import matplotlib.pyplot as plt
from matplotlib.sankey import Sankey
import math


def display_in_cats(values, min_cats, max_cats):
def display_in_cat_scale(value):
max_value = max(values, key=abs)
number_cats_to_show = \
max(min_cats, math.floor(abs(value) / max_value * max_cats))
return str(number_cats_to_show * '🐱')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least for me the way GH renders this I don't see the cat emoji, but it is in there. This renders as https://51382-1385122-gh.circle-artifacts.com/0/doc/build/html/users/next_whats_new/callables_for_formatting_sankey_labels.html
image


return display_in_cat_scale


flows = [35, 15, 40, -20, -15, -5, -40, -10]
orientations = [-1, 1, 0, 1, 1, 1, -1, -1]

# Cats are good, we want a strictly positive number of them
min_cats = 1
# More than four cats might be too much for some people
max_cats = 4

cats_format = display_in_cats(flows, min_cats, max_cats)

sankey = Sankey(flows=flows, orientations=orientations, format=cats_format,
offset=.1, head_angle=180, shoulder=0, scale=.010)

diagrams = sankey.finish()

diagrams[0].texts[2].set_text('')

plt.title(f'Sankey flows measured in cats \n'
f'🐱 = {max(flows, key=abs) / max_cats}')

plt.show()
18 changes: 13 additions & 5 deletions lib/matplotlib/sankey.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ def __init__(self, ax=None, scale=1.0, unit='', format='%G', gap=0.25,
unit : str
The physical unit associated with the flow quantities. If *unit*
is None, then none of the quantities are labeled.
format : str
A Python number formatting string to be used in labeling the flow
as a quantity (i.e., a number times a unit, where the unit is
given).
format : str or callable
A Python number formatting string or callable used to label the
flows with their quantities (i.e., a number times a unit, where the
unit is given). If a format string is given, the label will be
``format % quantity``. If a callable is given, it will be called
with ``quantity`` as an argument.
gap : float
Space between paths that break in/break away to/from the top or
bottom.
Expand Down Expand Up @@ -739,7 +741,13 @@ def _get_angle(a, r):
if label is None or angle is None:
label = ''
elif self.unit is not None:
quantity = self.format % abs(number) + self.unit
if isinstance(self.format, str):
quantity = self.format % abs(number) + self.unit
elif callable(self.format):
quantity = self.format(number)
else:
raise TypeError(
'format must be callable or a format string')
if label != '':
label += "\n"
label += quantity
Expand Down
12 changes: 12 additions & 0 deletions lib/matplotlib/tests/test_sankey.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,15 @@ def test_sankey():
def test_label():
s = Sankey(flows=[0.25], labels=['First'], orientations=[-1])
assert s.diagrams[0].texts[0].get_text() == 'First\n0.25'


def test_format_using_callable():
# test using callable by slightly incrementing above label example

def show_three_decimal_places(value):
return f'{value:.3f}'

s = Sankey(flows=[0.25], labels=['First'], orientations=[-1],
format=show_three_decimal_places)

assert s.diagrams[0].texts[0].get_text() == 'First\n0.250'