Skip to content
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

Allow string formatting for labels #1140

Merged
merged 9 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions examples/reference/pandas/labels.ipynb
Original file line number Diff line number Diff line change
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."
ahuang11 marked this conversation as resolved.
Show resolved Hide resolved
]
},
{
"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
Original file line number Diff line number Diff line change
Expand Up @@ -2088,7 +2088,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]
ahuang11 marked this conversation as resolved.
Show resolved Hide resolved
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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