Skip to content

Commit

Permalink
Factored Layout/Overlay path finding code out into utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Feb 14, 2017
1 parent 2e024e1 commit 8ff53b0
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 35 deletions.
52 changes: 18 additions & 34 deletions holoviews/core/layout.py
Expand Up @@ -16,8 +16,7 @@
from .dimension import Dimension, Dimensioned, ViewableElement
from .ndmapping import OrderedDict, NdMapping, UniformNdMapping
from .tree import AttrTree
from .util import (int_to_roman, sanitize_identifier, group_sanitizer,
label_sanitizer, unique_array)
from .util import (unique_array, get_path, make_path_unique)
from . import traversal


Expand Down Expand Up @@ -330,31 +329,7 @@ def collate(cls, data, kdims=None, key_dimensions=None):


@classmethod
def _get_path(cls, item):
sanitizers = [group_sanitizer, label_sanitizer]
capitalize = lambda x: x[0].upper() + x[1:]
if isinstance(item, tuple):
path, item = item
new_path = cls._get_path(item)
path = path[:2] if item.label and path[1] == new_path[1] else path[:1]
else:
path = (item.group, item.label) if item.label else (item.group,)
return tuple(capitalize(fn(p)) for (p, fn) in zip(path, sanitizers))


@classmethod
def new_path(cls, path, paths, counts):
while path in paths:
count = counts[path]
counts[path] += 1
path = path + (int_to_roman(count),)
if len(path) == 1:
path = path + (int_to_roman(counts.get(path, 1)),)
return path


@classmethod
def _unpack_paths(cls, objs, paths, items, counts):
def _unpack_paths(cls, objs, items, counts):
"""
Recursively unpacks lists and Layout-like objects, accumulating
into the supplied list of items.
Expand All @@ -364,38 +339,47 @@ def _unpack_paths(cls, objs, paths, items, counts):
for item in objs:
path, obj = item if isinstance(item, tuple) else (None, item)
if type(obj) is cls:
cls._unpack_paths(obj, paths, items, counts)
cls._unpack_paths(obj, items, counts)
continue
path = cls._get_path(item)
new_path = cls.new_path(path, paths, counts)
paths.append(new_path)
path = get_path(item)
new_path = make_path_unique(path, counts)
items.append((new_path, obj))


@classmethod
def _initial_paths(cls, items, paths=None):
"""
Recurses the passed items finding paths for each. Useful for
determining which paths are not unique and have to be resolved.
"""
if paths is None:
paths = []
for item in items:
path, item = item if isinstance(item, tuple) else (None, item)
if type(item) is cls:
cls._initial_paths(item.items(), paths)
continue
paths.append(cls._get_path(item))
paths.append(get_path(item))
return paths


@classmethod
def _process_items(cls, vals):
"""
Processes a list of Labelled types unpacking any objects of
the same type (e.g. a Layout) and finding unique paths for
all the items in the list.
"""
if type(vals) is cls:
return vals.data
elif not isinstance(vals, (list, tuple)):
vals = [vals]
paths = cls._initial_paths(vals)
path_counter = Counter(paths)
paths, items = [k for k, v in path_counter.items() if v > 1], []
items = []
counts = defaultdict(lambda: 1)
cls._unpack_paths(vals, paths, items, counts)
counts.update({k: 1 for k, v in path_counter.items() if v > 1})
cls._unpack_paths(vals, items, counts)
return items


Expand Down
37 changes: 36 additions & 1 deletion holoviews/core/util.py
Expand Up @@ -4,7 +4,7 @@
import string, fnmatch
import unicodedata
import datetime as dt
from collections import defaultdict
from collections import defaultdict, Counter

import numpy as np
import param
Expand Down Expand Up @@ -1002,6 +1002,41 @@ def unpack_group(group, getter):
yield (wrap_tuple(key), obj)


def capitalize(string):
"""
Capitalizes the first letter of a string.
"""
return string[0].upper() + string[1:]


def get_path(item):
"""
Gets a path from an Labelled object or from a tuple of an existing
path and a labelled object. The path strings are sanitized and
capitalized.
"""
sanitizers = [group_sanitizer, label_sanitizer]
if isinstance(item, tuple):
path, item = item
new_path = get_path(item)
path = path[:2] if item.label and path[1] == new_path[1] else path[:1]
else:
path = (item.group, item.label) if item.label else (item.group,)
return tuple(capitalize(fn(p)) for (p, fn) in zip(path, sanitizers))


def make_path_unique(path, counts):
"""
Given a path, a list of existing paths and counts for each of the
existing paths.
"""
while path in counts:
count = counts[path]
counts[path] += 1
path = path + (int_to_roman(count),)
if len(path) == 1:
path = path + (int_to_roman(counts.get(path, 1)),)
return path


class ndmapping_groupby(param.ParameterizedFunction):
Expand Down

0 comments on commit 8ff53b0

Please sign in to comment.