Skip to content

Commit

Permalink
Replace HoloViews widgets with Panel (#3836)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr authored and jlstevens committed Aug 15, 2019
1 parent e2902ec commit 272391f
Show file tree
Hide file tree
Showing 41 changed files with 978 additions and 3,280 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Expand Up @@ -142,7 +142,7 @@ jobs:
- &doc_build
<<: *default
stage: docs_dev
env: DESC="docs" CHANS_DEV="-c pyviz/label/dev" HV_DOC_GALLERY='false' HV_REQUIREMENTS="doc"
env: DESC="docs" CHANS_DEV="-c pyviz/label/dev" HV_DOC_GALLERY='false' HV_DOC_REF_GALLERY='false' HV_REQUIREMENTS="doc" PANEL_EMBED='true' PANEL_EMBED_JSON='true' PANEL_EMBED_JSON_PREFIX='json'
script:
- bokeh sampledata
- conda install -c conda-forge awscli
Expand Down Expand Up @@ -171,7 +171,7 @@ jobs:

- <<: *gallery_build
stage: gallery_daily
env: DESC="gallery" CHANS_DEV="-c pyviz/label/dev" HV_DOC_GALLERY='true' HV_REQUIREMENTS="doc" BUCKET="build."
env: DESC="gallery" CHANS_DEV="-c pyviz/label/dev" HV_DOC_GALLERY='false' HV_DOC_REF_GALLERY='false' HV_REQUIREMENTS="doc" BUCKET="build."

- <<: *doc_build
stage: docs
Expand Down
2 changes: 1 addition & 1 deletion doc/nbpublisher
2 changes: 1 addition & 1 deletion examples/user_guide/17-Dashboards.ipynb
Expand Up @@ -155,7 +155,7 @@
"\n",
"smoothed = rolling(stock_dmap, rolling_window=rolling_window.param.value)\n",
"\n",
"pn.Row(pn.WidgetBox('## Stock Explorer', symbol, variable, window), smoothed.opts(width=500))"
"pn.Row(pn.WidgetBox('## Stock Explorer', symbol, variable, rolling_window), smoothed.opts(width=500))"
]
},
{
Expand Down
4 changes: 2 additions & 2 deletions examples/user_guide/Plots_and_Renderers.ipynb
Expand Up @@ -374,7 +374,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Rendering plots containing ``HoloMap`` and ``DynamicMap`` objects will automatically generate a widget class instance, which you can get a handle on with the ``get_widget`` method:"
"Rendering plots containing ``HoloMap`` and ``DynamicMap`` objects will automatically generate a Panel HoloViews pane which can be rendered in the notebook, saved or rendered as a server app:"
]
},
{
Expand All @@ -401,7 +401,7 @@
"metadata": {},
"outputs": [],
"source": [
"display_html(renderer.static_html(holomap), raw=True)"
"html = renderer.static_html(holomap)"
]
},
{
Expand Down
30 changes: 7 additions & 23 deletions holoviews/core/util.py
@@ -1,23 +1,23 @@
import os, sys, warnings, operator
import sys, warnings, operator
import json
import time
import types
import numbers
import inspect
import itertools
import string, fnmatch
import string
import unicodedata
import datetime as dt
from collections import defaultdict

from distutils.version import LooseVersion as _LooseVersion
from functools import partial
from collections import defaultdict
from contextlib import contextmanager
from distutils.version import LooseVersion as _LooseVersion

from threading import Thread, Event

import numpy as np
import param

import json

try:
from cyordereddict import OrderedDict
except:
Expand Down Expand Up @@ -1407,22 +1407,6 @@ def get_spec(obj):
obj.group, obj.label)


def find_file(folder, filename):
"""
Find a file given folder and filename. If the filename can be
resolved directly returns otherwise walks the supplied folder.
"""
matches = []
if os.path.isabs(filename) and os.path.isfile(filename):
return filename
for root, _, filenames in os.walk(folder):
for fn in fnmatch.filter(filenames, filename):
matches.append(os.path.join(root, fn))
if not matches:
raise IOError('File %s could not be found' % filename)
return matches[-1]


def is_dataframe(data):
"""
Checks whether the supplied data is of DataFrame type.
Expand Down
29 changes: 5 additions & 24 deletions holoviews/ipython/__init__.py
Expand Up @@ -8,14 +8,13 @@
from IPython.core.completer import IPCompleter
from IPython.display import HTML, publish_display_data
from param import ipython as param_ext
from pyviz_comms import nb_mime_js

from ..core.dimension import LabelledData
from ..core.tree import AttrTree
from ..core.options import Store
from ..element.comparison import ComparisonTestCase
from ..util import extension
from ..plotting.renderer import Renderer, MIME_TYPES
from ..plotting.renderer import Renderer
from .magics import load_magics
from .display_hooks import display # noqa (API import)
from .display_hooks import pprint_display, png_display, svg_display
Expand Down Expand Up @@ -172,15 +171,16 @@ def __call__(self, *args, **params):
css += '<style>div.container { width: %s%% }</style>' % p.width
if p.css:
css += '<style>%s</style>' % p.css

if css:
display(HTML(css))

resources = list(resources)
if len(resources) == 0: return

Renderer.load_nb()
for r in [r for r in resources if r != 'holoviews']:
Store.renderers[r].load_nb(inline=p.inline)
Renderer.load_nb()

if hasattr(ip, 'kernel') and not loaded:
Renderer.comm_manager.get_client_comm(notebook_extension._process_comm_msg,
Expand All @@ -191,8 +191,7 @@ def __call__(self, *args, **params):
bokeh_logo= p.logo and ('bokeh' in resources),
mpl_logo= p.logo and (('matplotlib' in resources)
or resources==['holoviews']),
plotly_logo= p.logo and ('plotly' in resources),
JS=('holoviews' in resources))
plotly_logo= p.logo and ('plotly' in resources))

@classmethod
def completions_sorting_key(cls, word):
Expand Down Expand Up @@ -246,35 +245,17 @@ def load_hvjs(cls, logo=False, bokeh_logo=False, mpl_logo=False, plotly_logo=Fal
Displays javascript and CSS to initialize HoloViews widgets.
"""
import jinja2
# Evaluate load_notebook.html template with widgetjs code
if JS:
widgetjs, widgetcss = Renderer.html_assets(extras=False, backends=[], script=True)
else:
widgetjs, widgetcss = '', ''

# Add classic notebook MIME renderer
widgetjs += nb_mime_js

templateLoader = jinja2.FileSystemLoader(os.path.dirname(os.path.abspath(__file__)))
jinjaEnv = jinja2.Environment(loader=templateLoader)
template = jinjaEnv.get_template('load_notebook.html')
html = template.render({'widgetcss': widgetcss,
'logo': logo,
html = template.render({'logo': logo,
'bokeh_logo': bokeh_logo,
'mpl_logo': mpl_logo,
'plotly_logo': plotly_logo,
'message': message})
publish_display_data(data={'text/html': html})

# Vanilla JS mime type is only consumed by classic notebook
# Custom mime type is only consumed by JupyterLab
if JS:
mimebundle = {
MIME_TYPES['js'] : widgetjs,
MIME_TYPES['jlab-hv-load'] : widgetjs
}
publish_display_data(data=mimebundle)


@param.parameterized.bothmethod
def tab_completion_docstring(self_or_cls):
Expand Down
2 changes: 0 additions & 2 deletions holoviews/ipython/load_notebook.html
@@ -1,5 +1,3 @@
{{ widgetcss }}

{% if logo %}
<div class="logo-block">
<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz
Expand Down
12 changes: 0 additions & 12 deletions holoviews/plotting/bokeh/bokehwidgets.css

This file was deleted.

68 changes: 0 additions & 68 deletions holoviews/plotting/bokeh/bokehwidgets.js

This file was deleted.

80 changes: 2 additions & 78 deletions holoviews/plotting/bokeh/plot.py
@@ -1,13 +1,11 @@
from __future__ import absolute_import, division, unicode_literals

import json
from itertools import groupby
from collections import defaultdict

import numpy as np
import param

from bokeh.io import curdoc
from bokeh.layouts import gridplot
from bokeh.models import (ColumnDataSource, Column, Row, Div)
from bokeh.models.widgets import Panel, Tabs
Expand All @@ -24,7 +22,7 @@
from ..links import Link
from ..plot import (
DimensionedPlot, GenericCompositePlot, GenericLayoutPlot,
GenericElementPlot, GenericOverlayPlot
GenericElementPlot, GenericOverlayPlot, GenericAdjointLayoutPlot
)
from ..util import attach_streams, displayable, collate
from .callbacks import LinkCallback
Expand Down Expand Up @@ -78,50 +76,10 @@ class BokehPlot(DimensionedPlot):

backend = 'bokeh'

@property
def document(self):
return self._document

@property
def id(self):
return self.root.ref['id'] if self.root else None

@property
def root(self):
if self._root:
return self._root
elif 'plot' in self.handles and self.top_level:
return self.state
else:
return None

@document.setter
def document(self, doc):
if (doc and hasattr(doc, 'on_session_destroyed') and
self.root is self.handles.get('plot') and not isinstance(self, AdjointLayoutPlot)):
doc.on_session_destroyed(self._session_destroy)
if self._document:
if isinstance(self._document._session_destroyed_callbacks, set):
self._document._session_destroyed_callbacks.discard(self._session_destroy)
else:
self._document._session_destroyed_callbacks.pop(self._session_destroy, None)

self._document = doc
if self.subplots:
for plot in self.subplots.values():
if plot is not None:
plot.document = doc


def _session_destroy(self, session_context):
self.cleanup()

def __init__(self, *args, **params):
root = params.pop('root', None)
super(BokehPlot, self).__init__(*args, **params)
self._document = None
self._root = root


def get_data(self, element, ranges, style):
"""
Expand Down Expand Up @@ -176,36 +134,6 @@ def _construct_callbacks(self):
cbs.append(cb(self, cb_streams, source))
return cbs

def refresh(self, **kwargs):
if self.renderer.mode == 'server' and curdoc() is not self.document:
# If we do not have the Document lock, schedule refresh as callback
self.document.add_next_tick_callback(self.refresh)
else:
super(BokehPlot, self).refresh(**kwargs)

def push(self):
"""
Pushes updated plot data via the Comm.
"""
if self.renderer.mode == 'server':
return
if self.comm is None:
raise Exception('Renderer does not have a comm.')

if self._root and 'embedded' in self._root.tags:
# Allows external libraries to prevent comm updates
return

msg = self.renderer.diff(self, binary=True)
if msg is None:
return
self.comm.send(msg.header_json)
self.comm.send(msg.metadata_json)
self.comm.send(msg.content_json)
for header, payload in msg.buffers:
self.comm.send(json.dumps(header))
self.comm.send(buffers=[payload])


def set_root(self, root):
"""
Expand Down Expand Up @@ -1075,11 +1003,7 @@ def update_frame(self, key, ranges=None):



class AdjointLayoutPlot(BokehPlot):

layout_dict = {'Single': {'positions': ['main']},
'Dual': {'positions': ['main', 'right']},
'Triple': {'positions': ['main', 'right', 'top']}}
class AdjointLayoutPlot(BokehPlot, GenericAdjointLayoutPlot):

registry = {}

Expand Down

0 comments on commit 272391f

Please sign in to comment.