Skip to content

Commit

Permalink
Allow string formatting for labels (#1140)
Browse files Browse the repository at this point in the history
Co-authored-by: Maxime Liquet <35924738+maximlt@users.noreply.github.com>
  • Loading branch information
ahuang11 and maximlt committed Oct 6, 2023
1 parent 5eb8dfe commit 6d0d859
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 2 deletions.
17 changes: 17 additions & 0 deletions examples/reference/pandas/labels.ipynb
Expand Up @@ -42,6 +42,23 @@
"df.hvplot.labels(x='Longitude', y='Latitude', text='City', text_baseline='bottom', hover=False) * \\\n",
"df.hvplot.labels(x='Longitude', y='Latitude', text='Country', text_baseline='top', hover=False)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It's also possible to provide a template string containing the names of the columns and reduce the font size."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df.hvplot.points(x='Longitude', y='Latitude', padding=0.2, hover_cols='all', width=300) * \\\n",
"df.hvplot.labels(x='Longitude', y='Latitude', text='@{City}, {Country}', text_baseline='bottom', text_font_size='10px', hover=False)"
]
}
],
"metadata": {
Expand Down
9 changes: 8 additions & 1 deletion hvplot/converter.py
Expand Up @@ -2086,7 +2086,14 @@ def labels(self, x=None, y=None, data=None):
self.use_index = False
data, x, y = self._process_chart_args(data, x, y, single_y=True)

text = self.kwds.get('text', [c for c in data.columns if c not in (x, y)][0])
text = self.kwds.get('text')
if not text:
text = [c for c in data.columns if c not in (x, y)][0]
elif text not in data.columns:
template_str = text # needed for dask lazy compute
data["label"] = data.apply(lambda row: template_str.format(**row), axis=1)
text = "label"

kdims, vdims = self._get_dimensions([x, y], [text])
cur_opts, compat_opts = self._get_compat_opts('Labels')
element = self._get_element('labels')
Expand Down
4 changes: 3 additions & 1 deletion hvplot/plotting/core.py
Expand Up @@ -1771,7 +1771,9 @@ def labels(self, x=None, y=None, text=None, **kwds):
y : string, optional
The coordinate variable along the y-axis
text : string, optional
The column to draw the text labels from
The column to draw the text labels from; it's also possible to
provide a template string containing the column names to
automatically format the text, e.g. "{col1}, {col2}".
**kwds : optional
Additional keywords arguments are documented in `hvplot.help('labels')`.
Expand Down
20 changes: 20 additions & 0 deletions hvplot/tests/testcharts.py
Expand Up @@ -3,6 +3,7 @@
from unittest import SkipTest, expectedFailure
from parameterized import parameterized

from holoviews.core.dimension import Dimension
from holoviews import NdOverlay, Store, dim, render
from holoviews.element import Curve, Area, Scatter, Points, Path, HeatMap
from holoviews.element.comparison import ComparisonTestCase
Expand Down Expand Up @@ -128,6 +129,11 @@ def setUp(self):
'time': pd.date_range('1/1/2000', periods=10, tz='UTC'),
'A': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
'B': list('abcdefghij')})
self.edge_df = pd.DataFrame({
"Latitude": [-34.58, -15.78, -33.45],
"Longitude": [-58.66, -47.91, -70.66],
"Volume {m3}": ["1", "2", "3"],
})

@parameterized.expand([('line', Curve), ('area', Area), ('scatter', Scatter)])
def test_wide_chart(self, kind, element):
Expand Down Expand Up @@ -347,6 +353,20 @@ def test_errorbars_no_hover(self):
bkplot = Store.renderers['bokeh'].get_plot(plot)
assert not bkplot.tools

def test_labels_format(self):
plot = self.df.hvplot("x", "y", text="({x}, {y})", kind="labels")
assert list(plot.dimensions()) == [Dimension('x'), Dimension('y'), Dimension('label')]
assert list(plot.data["label"]) == ['(1, 2)', '(3, 4)', '(5, 6)']

def test_labels_no_format_edge_case(self):
plot = self.edge_df.hvplot.labels("Longitude", "Latitude")
assert list(plot.dimensions()) == [Dimension('Longitude'), Dimension('Latitude'), Dimension('Volume {m3}')]
assert list(plot.data["Volume {m3}"]) == ['1', '2', '3']

def test_labels_format_float(self):
plot = self.edge_df.hvplot.labels("Longitude", "Latitude", text="{Longitude:.1f}E {Latitude:.2f}N")
assert list(plot.dimensions()) == [Dimension('Longitude'), Dimension('Latitude'), Dimension('label')]
assert list(plot.data["label"]) == ['-58.7E -34.58N', '-47.9E -15.78N', '-70.7E -33.45N']

class TestChart1DDask(TestChart1D):

Expand Down

0 comments on commit 6d0d859

Please sign in to comment.