Skip to content

Commit

Permalink
Merge 7fe040a into 415271f
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Sep 16, 2021
2 parents 415271f + 7fe040a commit 5f1837c
Show file tree
Hide file tree
Showing 20 changed files with 142 additions and 69 deletions.
27 changes: 24 additions & 3 deletions .github/workflows/test.yml
Expand Up @@ -24,8 +24,7 @@ jobs:
DESC: "Python ${{ matrix.python-version }} tests"
HV_REQUIREMENTS: "unit_tests"
PYTHON_VERSION: ${{ matrix.python-version }}
CHANS_DEV: "-c pyviz/label/dev -c bokeh/label/dev -c conda-forge"
CHANS: "-c pyviz -c conda-forge"
CHANS_DEV: "-c pyviz/label/dev -c bokeh"
MPLBACKEND: "Agg"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
Expand All @@ -38,7 +37,6 @@ jobs:
- uses: conda-incubator/setup-miniconda@v2
with:
miniconda-version: "latest"
channels: conda-forge,defaults
- name: Fetch unshallow
run: git fetch --prune --tags --unshallow
- name: conda setup
Expand All @@ -47,12 +45,35 @@ jobs:
conda install -c pyviz "pyctdev>=0.5"
doit ecosystem_setup
doit env_create ${{ env.CHANS_DEV}} --python=${{ matrix.python-version }}
- name: doit env_capture
run: |
eval "$(conda shell.bash hook)"
conda activate test-environment
doit env_capture
- name: doit develop_install
if: matrix.os != 'macos-latest'
run: |
eval "$(conda shell.bash hook)"
conda activate test-environment
conda list
doit develop_install ${{ env.CHANS_DEV}} -o ${{ env.HV_REQUIREMENTS }}
conda install "panel=0.12.1" "nbconvert>5"
python -c "from param import version; print(version.Version.setup_version('.', 'holoviews', archive_commit='$Format:%h$'))"
echo "-----"
git describe
echo "======"
conda list
# Temporary step for Mac only due doit to develop_install failing
- name: doit develop_install on Mac
if: matrix.os == 'macos-latest'
run: |
eval "$(conda shell.bash hook)"
conda activate test-environment
conda install ${{ env.CHANS_DEV }} "pip<21.2.1"
conda list
doit develop_install ${{ env.CHANS_DEV}} -o ${{ env.HV_REQUIREMENTS }} || echo "Keep going"
pip install --no-deps --no-build-isolation -e .
conda install "panel=0.12.1" "nbconvert>5"
python -c "from param import version; print(version.Version.setup_version('.', 'holoviews', archive_commit='$Format:%h$'))"
echo "-----"
git describe
Expand Down
4 changes: 2 additions & 2 deletions holoviews/core/accessors.py
Expand Up @@ -7,6 +7,7 @@
import sys

from collections import OrderedDict
from functools import wraps
from types import FunctionType

import param
Expand All @@ -27,6 +28,7 @@ def __new__(mcs, classname, bases, classdict):

@classmethod
def pipelined(mcs, __call__):
@wraps(__call__)
def pipelined_call(*args, **kwargs):
from ..operation.element import method as method_op, factory
from .data import Dataset, MultiDimensionalMapping
Expand Down Expand Up @@ -82,8 +84,6 @@ def pipelined_call(*args, **kwargs):

return result

pipelined_call.__doc__ = __call__.__doc__

return pipelined_call


Expand Down
10 changes: 5 additions & 5 deletions holoviews/core/data/__init__.py
Expand Up @@ -10,6 +10,7 @@
import copy

from contextlib import contextmanager
from functools import wraps

import numpy as np
import param
Expand Down Expand Up @@ -193,6 +194,7 @@ def __new__(mcs, classname, bases, classdict):

@staticmethod
def pipelined(method_fn, method_name):
@wraps(method_fn)
def pipelined_fn(*args, **kwargs):
from ...operation.element import method as method_op
inst = args[0]
Expand Down Expand Up @@ -239,8 +241,6 @@ def pipelined_fn(*args, **kwargs):
inst._in_method = False
return result

pipelined_fn.__doc__ = method_fn.__doc__

return pipelined_fn


Expand Down Expand Up @@ -1214,17 +1214,17 @@ def clone(self, data=None, shared_data=True, new_type=None, link=True,

# Overrides of superclass methods that are needed so that PipelineMeta
# will find them to wrap with pipeline support
@wraps(Dimensioned.options)
def options(self, *args, **kwargs):
return super(Dataset, self).options(*args, **kwargs)
options.__doc__ = Dimensioned.options.__doc__

@wraps(LabelledData.map)
def map(self, *args, **kwargs):
return super(Dataset, self).map(*args, **kwargs)
map.__doc__ = LabelledData.map.__doc__

@wraps(LabelledData.relabel)
def relabel(self, *args, **kwargs):
return super(Dataset, self).relabel(*args, **kwargs)
relabel.__doc__ = LabelledData.relabel.__doc__

@property
def iloc(self):
Expand Down
6 changes: 1 addition & 5 deletions holoviews/core/data/cudf.py
Expand Up @@ -239,7 +239,6 @@ def select_mask(cls, dataset, selection):
mask &= new_mask
return mask


@classmethod
def select(cls, dataset, selection_mask=None, **selection):
df = dataset.data
Expand All @@ -248,26 +247,23 @@ def select(cls, dataset, selection_mask=None, **selection):

indexed = cls.indexed(dataset, selection)
if selection_mask is not None:
df = df[selection_mask]
df = df.loc[selection_mask]
if indexed and len(df) == 1 and len(dataset.vdims) == 1:
return df[dataset.vdims[0].name].iloc[0]
return df


@classmethod
def concat_fn(cls, dataframes, **kwargs):
import cudf
return cudf.concat(dataframes, **kwargs)


@classmethod
def add_dimension(cls, dataset, dimension, dim_pos, values, vdim):
data = dataset.data.copy()
if dimension.name not in data:
data[dimension.name] = values
return data


@classmethod
def aggregate(cls, dataset, dimensions, function, **kwargs):
data = dataset.data
Expand Down
2 changes: 1 addition & 1 deletion holoviews/core/data/interface.py
Expand Up @@ -205,7 +205,7 @@ def initialize(cls, eltype, data, kdims, vdims, datatype=None):
vdims = pvals.get('vdims') if vdims is None else vdims

# Process Element data
if (hasattr(data, 'interface') and issubclass(data.interface, Interface)):
if hasattr(data, 'interface') and isinstance(data.interface, type) and issubclass(data.interface, Interface):
if datatype is None:
datatype = [dt for dt in data.datatype if dt in eltype.datatype]
if not datatype:
Expand Down
5 changes: 2 additions & 3 deletions holoviews/core/dimension.py
Expand Up @@ -1227,7 +1227,7 @@ def __call__(self, options=None, **kwargs):

return self.opts(options, **kwargs)

def options(self, *args, **kwargs):
def options(self, *args, clone=True, **kwargs):
"""Applies simplified option definition returning a new object.
Applies options on an object or nested group of objects in a
Expand Down Expand Up @@ -1266,9 +1266,8 @@ def options(self, *args, **kwargs):
Returns the cloned object with the options applied
"""
backend = kwargs.get('backend', None)
clone = kwargs.pop('clone', True)

if len(args) == 0 and len(kwargs)==0:
if not (args or kwargs):
options = None
elif args and isinstance(args[0], basestring):
options = {args[0]: kwargs}
Expand Down
14 changes: 9 additions & 5 deletions holoviews/core/options.py
Expand Up @@ -1621,7 +1621,7 @@ def expand_compositor_keys(cls, spec):


@classmethod
def create_custom_trees(cls, obj, options=None):
def create_custom_trees(cls, obj, options=None, backend=None):
"""
Returns the appropriate set of customized subtree clones for
an object, suitable for merging with Store.custom_options (i.e
Expand All @@ -1637,17 +1637,21 @@ def create_custom_trees(cls, obj, options=None):
obj_ids = [None] if len(obj_ids)==0 else obj_ids

used_obj_types = [(opt.split('.')[0],) for opt in options]
available_options = Store.options()
backend = backend or Store.current_backend
available_options = Store.options(backend=backend)
used_options = {}
for obj_type in available_options:
if obj_type in used_obj_types:
opts_groups = available_options[obj_type].groups
used_options[obj_type] = {
grp: Options(allowed_keywords=opt.allowed_keywords)
grp: Options(
allowed_keywords=opt.allowed_keywords,
backend=backend,
)
for (grp, opt) in opts_groups.items()
}

custom_options = Store.custom_options()
custom_options = Store.custom_options(backend=backend)
for tree_id in obj_ids:
if tree_id is not None and tree_id in custom_options:
original = custom_options[tree_id]
Expand Down Expand Up @@ -1834,7 +1838,7 @@ def set_options(cls, obj, options=None, backend=None, **kwargs):
# 'style': Options('style', cmap='Blues')]}
options = cls.merge_options(Store.options(backend=backend).groups.keys(), options, **kwargs)
spec, compositor_applied = cls.expand_compositor_keys(options)
custom_trees, id_mapping = cls.create_custom_trees(obj, spec)
custom_trees, id_mapping = cls.create_custom_trees(obj, spec, backend=backend)
cls.update_backends(id_mapping, custom_trees, backend=backend)

# Propagate ids to the objects
Expand Down
2 changes: 1 addition & 1 deletion holoviews/element/chart.py
Expand Up @@ -282,7 +282,7 @@ def stack(cls, areas, baseline_name='Baseline'):
baseline = None
stacked = areas.clone(shared_data=False)
for key, sdf in df.groupby(level=levels):
sdf = sdf.droplevel(levels).reindex(index=df.index.levels[-1], fill_value=0)
sdf = sdf.droplevel(levels).reindex(index=df.index.unique(-1), fill_value=0)
if baseline is None:
sdf[baseline_name] = 0
else:
Expand Down
37 changes: 33 additions & 4 deletions holoviews/element/selection.py
Expand Up @@ -3,6 +3,8 @@
elements.
"""

import sys

import numpy as np

from ..core import Dataset, NdOverlay, util
Expand Down Expand Up @@ -77,21 +79,48 @@ def spatial_select_gridded(xvals, yvals, geometry):
return mask.reshape(xvals.shape)

def spatial_select_columnar(xvals, yvals, geometry):
if 'cudf' in sys.modules:
import cudf
if isinstance(xvals, cudf.Series):
xvals = xvals.values.astype('float')
yvals = yvals.values.astype('float')
try:
import cuspatial
result = cuspatial.point_in_polygon(
xvals,
yvals,
cudf.Series([0], index=["selection"]),
[0],
geometry[:, 0],
geometry[:, 1],
)
return result.values
except Exception:
xvals = np.asarray(xvals)
yvals = np.asarray(yvals)
x0, x1 = geometry[:, 0].min(), geometry[:, 0].max()
y0, y1 = geometry[:, 1].min(), geometry[:, 1].max()
mask = (xvals>=x0) & (xvals<=x1) & (yvals>=y0) & (yvals<=y1)
masked_xvals = xvals[mask]
masked_yvals = yvals[mask]
try:
from spatialpandas.geometry import Polygon, PointArray
points = PointArray((xvals.astype('float'), yvals.astype('float')))
points = PointArray((masked_xvals.astype('float'), masked_yvals.astype('float')))
poly = Polygon([np.concatenate([geometry, geometry[:1]]).flatten()])
return points.intersects(poly)
geom_mask = points.intersects(poly)
except Exception:
pass
try:
from shapely.geometry import Point, Polygon
points = (Point(x, y) for x, y in zip(xvals, yvals))
points = (Point(x, y) for x, y in zip(masked_xvals, masked_yvals))
poly = Polygon(geometry)
return np.array([poly.contains(p) for p in points])
geom_mask = np.array([poly.contains(p) for p in points])
except ImportError:
raise ImportError("Lasso selection on tabular data requires "
"either spatialpandas or shapely to be available.")
mask[np.where(mask)[0]] = geom_mask
return mask


def spatial_select(xvals, yvals, geometry):
if xvals.ndim > 1:
Expand Down
15 changes: 10 additions & 5 deletions holoviews/plotting/bokeh/element.py
Expand Up @@ -1233,9 +1233,9 @@ def _filter_properties(self, properties, glyph_type, allowed):
for gtype in ((glyph_type, '') if glyph_type else ('',)):
for prop in ('color', 'alpha'):
glyph_prop = properties.get(gtype+prop)
if glyph_prop and ('line_'+prop not in glyph_props or gtype):
if glyph_prop is not None and ('line_'+prop not in glyph_props or gtype):
glyph_props['line_'+prop] = glyph_prop
if glyph_prop and ('fill_'+prop not in glyph_props or gtype):
if glyph_prop is not None and ('fill_'+prop not in glyph_props or gtype):
glyph_props['fill_'+prop] = glyph_prop

props = {k[len(gtype):]: v for k, v in glyph_props.items()
Expand Down Expand Up @@ -1334,15 +1334,15 @@ def _postprocess_hover(self, renderer, source):
if not isinstance(hover.tooltips, util.basestring) and 'hv_created' in hover.tags:
for k, values in source.data.items():
key = '@{%s}' % k
if key in hover.formatters:
continue
if ((isinstance(value, np.ndarray) and value.dtype.kind == 'M') or
(len(values) and isinstance(values[0], util.datetime_types))):
hover.tooltips = [(l, f+'{%F %T}' if f == key else f) for l, f in hover.tooltips]
hover.formatters[key] = "datetime"

if hover.renderers == 'auto':
hover.renderers = []
hover.renderers.append(renderer)
if renderer not in hover.renderers:
hover.renderers.append(renderer)

def _init_glyphs(self, plot, element, ranges, source):
style_element = element.last if self.batched else element
Expand Down Expand Up @@ -1463,6 +1463,8 @@ def _update_glyphs(self, element, ranges, style):
if glyph:
properties = self._glyph_properties(plot, element, source, ranges, style)
renderer = self.handles.get('glyph_renderer')
if 'visible' in style and hasattr(renderer, 'visible'):
renderer.visible = style['visible']
with abbreviated_exception():
self._update_glyph(renderer, properties, mapping, glyph, source, data)
elif not self.static_source:
Expand Down Expand Up @@ -1539,6 +1541,9 @@ def update_frame(self, key, ranges=None, plot=None, element=None):

if 'hover' in self.handles:
self._update_hover(element)
if 'cds' in self.handles:
cds = self.handles['cds']
self._postprocess_hover(renderer, cds)

self._update_glyphs(element, ranges, self.style[self.cyclic_index])
self._execute_hooks(element)
Expand Down

0 comments on commit 5f1837c

Please sign in to comment.