Skip to content

Commit

Permalink
Fixed title formatter in GenericElementPlot (#4061)
Browse files Browse the repository at this point in the history
* fixed indentation mistake

* moved general part of _format_title into DimensionedPlot

* add deprecation warning

* friendlier deprecation warning

* tests for NdLayout and Element
  • Loading branch information
poplarShift authored and philippjfr committed Oct 27, 2019
1 parent c1efb5c commit f6afa0c
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 35 deletions.
75 changes: 43 additions & 32 deletions holoviews/plotting/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,42 @@ def _frame_title(self, key, group_size=2, separator='\n'):
return util.bytes_to_unicode(separator.join(g for g in groups if g))


def _format_title(self, key, dimensions=True, separator='\n'):
if self.title_format and util.config.future_deprecations:
self.param.warning('title_format is deprecated. Please use title instead')

label, group, type_name, dim_title = self._format_title_components(
key, dimensions=True, separator='\n'
)

custom_title = (self.title != self.param.params('title').default)
if custom_title and self.title_format:
self.warning('Both title and title_format set. Using title')
title_str = (
self.title if custom_title or self.title_format is None
else self.title_format
)

title = util.bytes_to_unicode(title_str).format(
label=util.bytes_to_unicode(label),
group=util.bytes_to_unicode(group),
type=type_name,
dimensions=dim_title
)
return title.strip(' \n')


def _format_title_components(self, key, dimensions=True, separator='\n'):
"""
Determine components of title as used by _format_title method.
To be overridden in child classes.
Return signature: (label, group, type_name, dim_title)
"""
return (self.label, self.group, type(self).__name__, '')


def _fontsize(self, key, label='fontsize', common=True):
if not self.fontsize: return {}

Expand Down Expand Up @@ -1242,33 +1278,19 @@ def _get_axis_labels(self, dimensions, xlabel=None, ylabel=None, zlabel=None):
return xlabel, ylabel, zlabel


def _format_title(self, key, dimensions=True, separator='\n'):
def _format_title_components(self, key, dimensions=True, separator='\n'):
frame = self._get_frame(key)
if frame is None: return None
type_name = type(frame).__name__
group = frame.group if frame.group != type_name else ''
label = frame.label

if self.layout_dimensions:
if self.layout_dimensions or dimensions:
dim_title = self._frame_title(key, separator=separator)
title = dim_title
else:
if dimensions:
dim_title = self._frame_title(key, separator=separator)
else:
dim_title = ''

custom_title = (self.title != self.param.params('title').default)
if custom_title and self.title_format:
self.warning('Both title and title_format set. Using title_format parameter')

title = self.title if custom_title or self.title_format is None else self.title_format
title_format = util.bytes_to_unicode(title)
title = title_format.format(label=util.bytes_to_unicode(label),
group=util.bytes_to_unicode(group),
type=type_name,
dimensions=dim_title)
return title.strip(' \n')
dim_title = ''

return (label, group, type_name, dim_title)


def update_frame(self, key, ranges=None):
Expand Down Expand Up @@ -1655,24 +1677,13 @@ def _get_frame(self, key):
return layout_frame


def _format_title(self, key, dimensions=True, separator='\n'):
def _format_title_components(self, key, dimensions=True, separator='\n'):
dim_title = self._frame_title(key, 3, separator) if dimensions else ''
layout = self.layout
type_name = type(self.layout).__name__
group = util.bytes_to_unicode(layout.group if layout.group != type_name else '')
label = util.bytes_to_unicode(layout.label)


custom_title = (self.title != self.param.params('title').default)
if custom_title and self.title_format:
self.warning('Both title and title_format set. Using title parameter')
title_str = self.title if custom_title or self.title_format is None else self.title_format

title = util.bytes_to_unicode(title_str).format(label=label,
group=group,
type=type_name,
dimensions=dim_title)
return title.strip(' \n')
return (label, group, type_name, dim_title)


class GenericLayoutPlot(GenericCompositePlot):
Expand Down
12 changes: 12 additions & 0 deletions holoviews/tests/plotting/bokeh/testelementplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from holoviews.element import Curve, Image, Scatter, Labels
from holoviews.streams import Stream, PointDraw
from holoviews.plotting.util import process_cmap
from holoviews.util import render

from .testplot import TestBokehPlot, bokeh_renderer
from ...utils import LoggingComparisonTestCase
Expand Down Expand Up @@ -101,6 +102,17 @@ def test_element_yaxis_right_bare(self):
self.assertEqual(yaxis.major_tick_line_color, None)
self.assertTrue(yaxis in plot.state.right)

def test_element_title_format(self):
title_str = ('Label: {label}, group: {group}, '
'dims: {dimensions}, type: {type}')
e = Scatter(
[],
label='the_label',
group='the_group',
).opts(title=title_str)
title = 'Label: the_label, group: the_group, dims: , type: Scatter'
self.assertEqual(render(e).title.text, title)

def test_element_xformatter_string(self):
curve = Curve(range(10)).options(xformatter='%d')
plot = bokeh_renderer.get_plot(curve)
Expand Down
42 changes: 39 additions & 3 deletions holoviews/tests/plotting/bokeh/testlayoutplot.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import re

import numpy as np

from holoviews.core import (HoloMap, GridSpace, Layout, Empty, Dataset,
NdOverlay, DynamicMap, Dimension)
from holoviews.element import Curve, Image, Points, Histogram
NdOverlay, NdLayout, DynamicMap, Dimension)
from holoviews.element import Curve, Image, Points, Histogram, Scatter
from holoviews.streams import Stream
from holoviews.util import render, opts

from .testplot import TestBokehPlot, bokeh_renderer

try:
from bokeh.layouts import Column, Row
from bokeh.models import Div, ToolbarBox, GlyphRenderer, Tabs, Panel, Spacer, GridBox
from bokeh.models import Div, ToolbarBox, GlyphRenderer, Tabs, Panel, Spacer, GridBox, Title
from bokeh.plotting import Figure
except:
pass
Expand Down Expand Up @@ -40,6 +43,39 @@ def test_layout_title(self):
'font-weight:bold;font-size:12pt">Default: 0</span>')
self.assertEqual(title.text, text)

def test_layout_title_format(self):
title_str = ('Label: {label}, group: {group}, '
'dims: {dimensions}, type: {type}')
layout = NdLayout(
{'Element 1': Scatter(
[],
label='ONE',
group='first',
), 'Element 2': Scatter(
[],
label='TWO',
group='second',
)},
kdims='MYDIM',
label='the_label',
group='the_group',
).opts(opts.NdLayout(title=title_str), opts.Scatter(title=title_str))
# Title of NdLayout
title = bokeh_renderer.get_plot(layout).handles['title']
self.assertIsInstance(title, Div)
text = 'Label: the_label, group: the_group, dims: , type: NdLayout'
self.assertEqual(re.split('>|</', title.text)[1], text)
# Titles of subplots
plot = render(layout)
titles = {
title.text for title in list(plot.select({'type': Title}))
}
titles_correct = {
'Label: ONE, group: first, dims: MYDIM: Element 1, type: Scatter',
'Label: TWO, group: second, dims: MYDIM: Element 2, type: Scatter',
}
self.assertEqual(titles_correct, titles)

def test_layout_title_fontsize(self):
hmap1 = HoloMap({a: Image(np.random.rand(10,10)) for a in range(3)})
hmap2 = HoloMap({a: Image(np.random.rand(10,10)) for a in range(3)})
Expand Down

0 comments on commit f6afa0c

Please sign in to comment.