Skip to content

Commit

Permalink
Merge b93a36f into a888b50
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Apr 24, 2020
2 parents a888b50 + b93a36f commit b2d5b3a
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -20,7 +20,7 @@ env:
global:
- PYENV_VERSION=3.7
- PKG_TEST_PYTHON="--test-python=py37 --test-python=py27"
- CHANS_DEV="-c pyviz/label/dev -c bokeh/label/dev -c conda-forge"
- CHANS_DEV="-c pyviz/label/dev -c bokeh -c conda-forge"
- CHANS="-c pyviz"
- MPLBACKEND="Agg"
- PYTHON_VERSION=3.7
Expand Down
5 changes: 3 additions & 2 deletions examples/gallery/apps/bokeh/nytaxi_hover.py
Expand Up @@ -23,14 +23,15 @@
from holoviews import opts
from holoviews.operation.datashader import aggregate

hv.extension('bokeh')
renderer = hv.renderer('bokeh')

# Set plot and style options
opts.defaults(
opts.Curve(xaxis=None, yaxis=None, show_grid=False, show_frame=False,
color='orangered', framewise=True, width=100),
opts.Image(width=800, height=400, shared_axes=False, logz=True,
xaxis=None, yaxis=None, axiswise=True),
opts.Image(width=800, height=400, shared_axes=False, logz=True, colorbar=True,
xaxis=None, yaxis=None, axiswise=True, bgcolor='black'),
opts.HLine(color='white', line_width=1),
opts.Layout(shared_axes=False),
opts.VLine(color='white', line_width=1))
Expand Down
17 changes: 17 additions & 0 deletions holoviews/core/util.py
Expand Up @@ -1265,6 +1265,23 @@ def is_number(obj):
else: return False


def is_int(obj, int_like=False):
"""
Checks for int types including the native Python type and NumPy-like objects
Args:
obj: Object to check for integer type
int_like (boolean): Check for float types with integer value
Returns:
Boolean indicating whether the supplied value is of integer type.
"""
real_int = isinstance(obj, int) or getattr(getattr(obj, 'dtype', None), 'kind', 'o') in 'ui'
if real_int or (int_like and hasattr(obj, 'is_integer') and obj.is_integer()):
return True
return False


class ProgressIndicator(param.Parameterized):
"""
Baseclass for any ProgressIndicator that indicates progress
Expand Down
34 changes: 27 additions & 7 deletions holoviews/plotting/bokeh/element.py
Expand Up @@ -1615,7 +1615,7 @@ class ColorbarPlot(ElementPlot):
An explicit override of the color bar label, if set takes precedence
over the title key in colorbar_opts.""")

clim = param.NumericTuple(default=(np.nan, np.nan), length=2, doc="""
clim = param.Tuple(default=(np.nan, np.nan), length=2, doc="""
User-specified colorbar axis range limits for the plot, as a tuple (low,high).
If specified, takes precedence over data and dimension ranges.""")

Expand Down Expand Up @@ -1723,19 +1723,25 @@ def _get_colormapper(self, eldim, element, ranges, style, factors=None, colors=N
ncolors = None if factors is None else len(factors)
if eldim:
# check if there's an actual value (not np.nan)
if dim_name in ranges:
if all(util.isfinite(cl) for cl in self.clim):
low, high = self.clim
elif dim_name in ranges:
low, high = ranges[dim_name]['combined']
dlow, dhigh = ranges[dim_name]['data']
if (util.is_int(low, int_like=True) and
util.is_int(high, int_like=True) and
util.is_int(dlow) and
util.is_int(dhigh)):
low, high = int(low), int(high)
elif isinstance(eldim, dim):
low, high = np.nan, np.nan
else:
low, high = element.range(eldim.name)
if self.symmetric:
sym_max = max(abs(low), high)
low, high = -sym_max, sym_max
if util.isfinite(self.clim[0]):
low = self.clim[0]
if util.isfinite(self.clim[1]):
high = self.clim[1]
low = self.clim[0] if util.isfinite(self.clim[0]) else low
high = self.clim[1] if util.isfinite(self.clim[1]) else high
else:
low, high = None, None

Expand Down Expand Up @@ -1832,7 +1838,21 @@ def _get_color_data(self, element, ranges, style, name='color', factors=None, co

def _get_cmapper_opts(self, low, high, factors, colors):
if factors is None:
colormapper = LogColorMapper if self.logz else LinearColorMapper
colormapper = LinearColorMapper
if self.logz:
colormapper = LogColorMapper
if util.is_int(low) and util.is_int(high) and low == 0:
low = 1
if 'min' not in colors:
# Make integer 0 be transparent
colors['min'] = 'rgba(0, 0, 0, 0)'
elif util.is_number(low) and low <= 0:
self.param.warning(
"Log color mapper lower bound <= 0 and will not "
"render corrrectly. Ensure you set a positive "
"lower bound on the color dimension or using "
"the `clim` option."
)
if isinstance(low, (bool, np.bool_)): low = int(low)
if isinstance(high, (bool, np.bool_)): high = int(high)
# Pad zero-range to avoid breaking colorbar (as of bokeh 1.0.4)
Expand Down
2 changes: 2 additions & 0 deletions holoviews/plotting/util.py
Expand Up @@ -884,6 +884,8 @@ def process_cmap(cmap, ncolors=None, provider=None, categorical=False):

if isinstance(cmap, Cycle):
palette = [rgb2hex(c) if isinstance(c, tuple) else c for c in cmap.values]
elif isinstance(cmap, tuple):
palette = list(cmap)
elif isinstance(cmap, list):
palette = cmap
elif isinstance(cmap, basestring):
Expand Down
21 changes: 18 additions & 3 deletions holoviews/tests/plotting/bokeh/testelementplot.py
Expand Up @@ -81,13 +81,13 @@ def test_element_font_scaling_fontsize_override_specific(self):
else:
self.assertEqual(yaxis.axis_label_text_font_size, '26px')
self.assertEqual(yaxis.major_label_text_font_size, '22px')

def test_element_xaxis_top(self):
curve = Curve(range(10)).options(xaxis='top')
plot = bokeh_renderer.get_plot(curve)
xaxis = plot.handles['xaxis']
self.assertTrue(xaxis in plot.state.above)

def test_element_xaxis_bare(self):
curve = Curve(range(10)).options(xaxis='bare')
plot = bokeh_renderer.get_plot(curve)
Expand Down Expand Up @@ -772,7 +772,7 @@ def test_element_data_aspect_frame_height_responsive(self):



class TestColorbarPlot(TestBokehPlot):
class TestColorbarPlot(LoggingComparisonTestCase, TestBokehPlot):

def test_colormapper_symmetric(self):
img = Image(np.array([[0, 1], [2, 3]])).options(symmetric=True)
Expand All @@ -781,6 +781,21 @@ def test_colormapper_symmetric(self):
self.assertEqual(cmapper.low, -3)
self.assertEqual(cmapper.high, 3)

def test_colormapper_logz_int_zero_bound(self):
img = Image(np.array([[0, 1], [2, 3]])).options(logz=True)
plot = bokeh_renderer.get_plot(img)
cmapper = plot.handles['color_mapper']
self.assertEqual(cmapper.low, 1)
self.assertEqual(cmapper.high, 3)

def test_colormapper_logz_float_zero_bound(self):
img = Image(np.array([[0, 1], [2, 3.]])).options(logz=True)
plot = bokeh_renderer.get_plot(img)
cmapper = plot.handles['color_mapper']
self.assertEqual(cmapper.low, 0)
self.assertEqual(cmapper.high, 3)
self.log_handler.assertContains('WARNING', "Log color mapper lower bound <= 0")

def test_colormapper_color_levels(self):
cmap = process_cmap('viridis', provider='bokeh')
img = Image(np.array([[0, 1], [2, 3]])).options(color_levels=5, cmap=cmap)
Expand Down

0 comments on commit b2d5b3a

Please sign in to comment.