Skip to content

Commit

Permalink
Merge pull request #355 from ioam/multiple_repr
Browse files Browse the repository at this point in the history
Support for multiple display output formats in the notebook
  • Loading branch information
philippjfr committed Dec 13, 2015
2 parents 6b9fe08 + f39cf84 commit abe6e6d
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 4 deletions.
4 changes: 4 additions & 0 deletions holoviews/core/options.py
Expand Up @@ -769,6 +769,10 @@ class Store(object):
# types grouped by the backend. Set using the register method.
registry = {}

# A list of formats to be published for display on the frontend (e.g
# IPython Notebook or a GUI application)
display_formats = ['html']

# Once register_plotting_classes is called, this OptionTree is
# populated for the given backend.
_options = {}
Expand Down
17 changes: 17 additions & 0 deletions holoviews/ipython/__init__.py
Expand Up @@ -105,6 +105,16 @@ class notebook_extension(param.ParameterizedFunction):
width = param.Number(default=None, bounds=(0, 100), doc="""
Width of the notebook as a percentage of the browser screen window width.""")

display_formats = param.List(default=['html'], doc="""
A list of formats that are rendered to the notebook where
multiple formats may be selected at once (although only one
format will be displayed).
Although the 'html' format is supported across backends, other
formats supported by the current backend (e.g 'png' and 'svg'
using the matplotlib backend) may be used. This may be useful to
export figures to other formats such as PDF with nbconvert. """)

ip = param.Parameter(default=None, doc="IPython kernel instance")

_loaded = False
Expand All @@ -113,6 +123,13 @@ def __call__(self, **params):
resources = self._get_resources(params)
ip = params.pop('ip', None)
p = param.ParamOverrides(self, params)
Store.display_formats = p.display_formats

if 'html' not in p.display_formats and len(p.display_formats) > 1:
msg = ('Output magic unable to control displayed format '
'as IPython notebook uses fixed precedence '
'between %r' % p.display_formats)
display(HTML('<b>Warning</b>: %s' % msg))

if notebook_extension._loaded == False:
ip = get_ipython() if ip is None else ip
Expand Down
54 changes: 53 additions & 1 deletion holoviews/ipython/display_hooks.py
Expand Up @@ -188,13 +188,59 @@ def display(obj, raw=False, **kwargs):


def pprint_display(obj):
# If pretty printing is off, return None (will fallback to repr)
if 'html' not in Store.display_formats:
return None

# If pretty printing is off, return None (fallback to next display format)
ip = get_ipython() # # pyflakes:ignore (in IPython namespace)
if not ip.display_formatter.formatters['text/plain'].pprint:
return None
return display(obj, raw=True)


@display_hook
def element_png_display(element, max_frames, max_branches):
"""
Used to render elements to PNG if requested in the display formats.
"""
if 'png' not in Store.display_formats:
return None
info = process_object(element)
if info: return info

backend = Store.current_backend
if type(element) not in Store.registry[backend]:
return None
renderer = Store.renderers[backend]
# Current renderer does not support PNG
if 'png' not in renderer.params('fig').objects:
return None

data, info = renderer(element, fmt='png')
return data


@display_hook
def element_svg_display(element, max_frames, max_branches):
"""
Used to render elements to SVG if requested in the display formats.
"""
if 'svg' not in Store.display_formats:
return None
info = process_object(element)
if info: return info

backend = Store.current_backend
if type(element) not in Store.registry[backend]:
return None
renderer = Store.renderers[backend]
# Current renderer does not support SVG
if 'svg' not in renderer.params('fig').objects:
return None
data, info = renderer(element, fmt='svg')
return data


# display_video output by default, but may be set to first_frame,
# middle_frame or last_frame (e.g. for testing purposes)
render_anim = None
Expand All @@ -205,3 +251,9 @@ def set_display_hooks(ip):
html_formatter.for_type(UniformNdMapping, pprint_display)
html_formatter.for_type(AdjointLayout, pprint_display)
html_formatter.for_type(Layout, pprint_display)

png_formatter = ip.display_formatter.formatters['image/png']
png_formatter.for_type(ViewableElement, element_png_display)

svg_formatter = ip.display_formatter.formatters['image/svg+xml']
svg_formatter.for_type(ViewableElement, element_svg_display)
15 changes: 12 additions & 3 deletions holoviews/ipython/magics.py
Expand Up @@ -60,6 +60,7 @@ def update_options(cls, options, items):
Allows updating options depending on class attributes
and unvalidated options.
"""
pass

@classmethod
def get_options(cls, line, options, linemagic):
Expand Down Expand Up @@ -98,10 +99,10 @@ def get_options(cls, line, options, linemagic):
raise ValueError("Value %r for key %r not between %s and %s" % info)
options[keyword] = value

return cls._validate(options, linemagic)
return cls._validate(options, items, linemagic)

@classmethod
def _validate(cls, options, linemagic):
def _validate(cls, options, items, linemagic):
"Allows subclasses to check options are valid."
raise NotImplementedError("OptionsMagic is an abstract base class.")

Expand Down Expand Up @@ -303,8 +304,16 @@ def _generate_docstring(cls):


@classmethod
def _validate(cls, options, linemagic):
def _validate(cls, options, items, linemagic):
"Validation of edge cases and incompatible options"

if 'html' in Store.display_formats:
pass
elif 'fig' in items and items['fig'] not in Store.display_formats:
msg = ("Output magic requesting figure format %r " % items['fig']
+ "not in display formats %r" % Store.display_formats)
display(HTML("<b>Warning:</b> %s" % msg))

backend = Store.current_backend
return Store.renderers[backend].validate(options)

Expand Down

0 comments on commit abe6e6d

Please sign in to comment.