From f08a089612acaffca9abfc095721ef2cce8880e5 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Wed, 22 Jun 2016 14:50:18 +0100 Subject: [PATCH 1/4] Added support for tick formatters in bokeh --- holoviews/plotting/bokeh/element.py | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/holoviews/plotting/bokeh/element.py b/holoviews/plotting/bokeh/element.py index a4b0f9989f..4830c38803 100644 --- a/holoviews/plotting/bokeh/element.py +++ b/holoviews/plotting/bokeh/element.py @@ -6,7 +6,6 @@ from bokeh.models import Range, HoverTool, Renderer from bokeh.models.tickers import Ticker, BasicTicker, FixedTicker from bokeh.models.widgets import Panel, Tabs -from distutils.version import LooseVersion try: from bokeh import mpl @@ -25,6 +24,11 @@ from .plot import BokehPlot from .util import mpl_to_bokeh, convert_datetime, update_plot, bokeh_version +if bokeh_version >= '0.12': + from bokeh.models import FuncTickFormatter +else: + FuncTickFormatter = None + # Define shared style properties for bokeh plots line_properties = ['line_width', 'line_color', 'line_alpha', @@ -270,8 +274,7 @@ def _init_plot(self, key, element, plots, ranges=None): else: title = '' - if LooseVersion(bokeh.__version__) >= LooseVersion('0.10'): - properties['webgl'] = self.renderer.webgl + properties['webgl'] = self.renderer.webgl return bokeh.plotting.Figure(x_axis_type=x_axis_type, y_axis_type=y_axis_type, title=title, tools=tools, **properties) @@ -325,7 +328,7 @@ def _init_axes(self, plot): plot.yaxis[:] = plot.right - def _axis_properties(self, axis, key, plot, element): + def _axis_properties(self, axis, key, plot, element, ax_mapping={'x': 0, 'y': 1}): """ Returns a dictionary of axis properties depending on the specified axis. @@ -351,6 +354,24 @@ def _axis_properties(self, axis, key, plot, element): pass else: axis_props['ticker'] = FixedTicker(ticks=ticker) + + dim = element.get_dimension(ax_mapping[axis]) + if ax_mapping and dim: + formatter = None + if dim.value_format: + formatter = dim.value_format + elif dim.type in dim.type_formatters: + formatter = dim.type_formatters[dim.type] + if formatter: + try: + formatter = FuncTickFormatter.from_py_func(formatter) + except: + self.warning('%s dimension formatter could not be ' + 'converted to tick formatter. Ensure ' + 'flexx is installed and pyscript can ' + 'compile the function.' % dim.name) + else: + axis_props['formatter'] = formatter return axis_props From 46b785be98d5f9e25a5bbf0b747fb2bed74b71e9 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Wed, 22 Jun 2016 15:27:00 +0100 Subject: [PATCH 2/4] Improved bokeh tick formatter error messages --- holoviews/plotting/bokeh/element.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/holoviews/plotting/bokeh/element.py b/holoviews/plotting/bokeh/element.py index 4830c38803..5659b32d34 100644 --- a/holoviews/plotting/bokeh/element.py +++ b/holoviews/plotting/bokeh/element.py @@ -363,13 +363,18 @@ def _axis_properties(self, axis, key, plot, element, ax_mapping={'x': 0, 'y': 1} elif dim.type in dim.type_formatters: formatter = dim.type_formatters[dim.type] if formatter: + msg = ('%s dimension formatter could not be ' + 'converted to tick formatter. ' % dim.name) try: formatter = FuncTickFormatter.from_py_func(formatter) - except: - self.warning('%s dimension formatter could not be ' - 'converted to tick formatter. Ensure ' - 'flexx is installed and pyscript can ' - 'compile the function.' % dim.name) + except RuntimeError: + self.warning(msg+'Ensure Flexx is installed ' + '("conda install -c bokeh flexx" or ' + '"pip install flexx")') + except Exception as e: + error = 'Pyscript raised an error: {0}'.format(e) + error = error.replace('%', '%%') + self.warning(msg+error) else: axis_props['formatter'] = formatter return axis_props From 6238c52ea2d72207f399c85b38753612fa2f8593 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Wed, 22 Jun 2016 15:29:34 +0100 Subject: [PATCH 3/4] Ensured bokeh 0.11 does not try to use FuncTickFormatter --- holoviews/plotting/bokeh/element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/holoviews/plotting/bokeh/element.py b/holoviews/plotting/bokeh/element.py index 5659b32d34..f96d7ea714 100644 --- a/holoviews/plotting/bokeh/element.py +++ b/holoviews/plotting/bokeh/element.py @@ -356,7 +356,7 @@ def _axis_properties(self, axis, key, plot, element, ax_mapping={'x': 0, 'y': 1} axis_props['ticker'] = FixedTicker(ticks=ticker) dim = element.get_dimension(ax_mapping[axis]) - if ax_mapping and dim: + if FuncTickFormatter is not None and ax_mapping and dim: formatter = None if dim.value_format: formatter = dim.value_format From 35a16586e8521a2da38800a89e4c1344d9597676 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 27 Jun 2016 14:27:15 +0100 Subject: [PATCH 4/4] Allow single argument function as matplotlib tick formatter --- holoviews/plotting/mpl/util.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/holoviews/plotting/mpl/util.py b/holoviews/plotting/mpl/util.py index 5fa833e2a7..51e2e07ec1 100644 --- a/holoviews/plotting/mpl/util.py +++ b/holoviews/plotting/mpl/util.py @@ -1,4 +1,5 @@ import re +import inspect import numpy as np from matplotlib import ticker @@ -14,7 +15,13 @@ def wrap_formatter(formatter): if isinstance(formatter, ticker.Formatter): return formatter elif callable(formatter): - return ticker.FuncFormatter(formatter) + args = [arg for arg in inspect.getargspec(formatter).args + if arg != 'self'] + wrapped = formatter + if len(args) == 1: + def wrapped(val, pos=None): + return formatter(val) + return ticker.FuncFormatter(wrapped) elif isinstance(formatter, basestring): if re.findall(r"\{(\w+)\}", formatter): return ticker.StrMethodFormatter(formatter)