Repository: altair-viz/altair
Pull request #1123 (2018-08-31 08:36:17)

Refactor HTML output methods
- adds ``alt.Chart.to_html()`` method
- adds Kaggle renderer, and refactors Colab renderer
- adds ability to specify whether html output is full or partial, as well as whether or not it uses require.js
- adds ``jinja2`` to the core requirements for better HTML templating


Patch:
diff --git a/altair/utils/__init__.py b/altair/utils/__init__.py
index a1c2a38c..786c9ad2 100644
--- a/altair/utils/__init__.py
+++ b/altair/utils/__init__.py
@@ -5,22 +5,22 @@ from .core import (
     use_signature,
     update_subtraits,
     update_nested,
-    write_file_or_filename,
     display_traceback,
     SchemaBase,
     Undefined
 )
+from .html import spec_to_html
 from .plugin_registry import PluginRegistry
 
 
 __all__ = (
     'infer_vegalite_type',
     'sanitize_dataframe',
+    'spec_to_html',
     'parse_shorthand',
     'use_signature',
     'update_subtraits',
     'update_nested',
-    'write_file_or_filename',
     'display_traceback',
     'SchemaBase',
     'Undefined',
diff --git a/altair/utils/core.py b/altair/utils/core.py
index 51c16589..a0d3d8d5 100644
--- a/altair/utils/core.py
+++ b/altair/utils/core.py
@@ -386,15 +386,6 @@ def update_nested(original, update, copy=False):
     return original
 
 
-def write_file_or_filename(fp, content, mode='w'):
-    """Write content to fp, whether fp is a string or a file-like object"""
-    if isinstance(fp, six.string_types):
-        with open(fp, mode) as f:
-            f.write(content)
-    else:
-        fp.write(content)
-
-
 def display_traceback(in_ipython=True):
     exc_info = sys.exc_info()
 
diff --git a/altair/utils/display.py b/altair/utils/display.py
index 71e1634a..a02b0a8c 100644
--- a/altair/utils/display.py
+++ b/altair/utils/display.py
@@ -6,6 +6,7 @@ from typing import Callable, Dict
 from jsonschema import validate
 
 from .plugin_registry import PluginRegistry
+from .mimebundle import spec_to_mimebundle
 
 
 # ==============================================================================
@@ -100,3 +101,22 @@ def json_renderer_base(spec, str_repr, **options):
     """
     return default_renderer_base(spec, mime_type='application/json',
                                  str_repr=str_repr, **options)
+
+
+class HTMLRenderer(object):
+    """Object to render charts as HTML, with a unique output div each time"""
+    def __init__(self, output_div='altair-viz-{}', **kwargs):
+        self._output_div = output_div
+        self._output_count = 0
+        self.kwargs = kwargs
+
+    @property
+    def output_div(self):
+        self._output_count += 1
+        return self._output_div.format(self._output_count)
+
+    def __call__(self, spec, **metadata):
+        kwargs = self.kwargs.copy()
+        kwargs.update(metadata)
+        return spec_to_mimebundle(spec, format='html',
+                                  output_div=self.output_div, **kwargs)
diff --git a/altair/utils/html.py b/altair/utils/html.py
index 1afd22d4..37831ee0 100644
--- a/altair/utils/html.py
+++ b/altair/utils/html.py
@@ -1,76 +1,103 @@
 from __future__ import unicode_literals
 import json
+import jinja2
 
 
-TOP = """
+HTML_TEMPLATE = jinja2.Template("""
+{%- if fullhtml -%}
 <!DOCTYPE html>
 <html>
 <head>
+{%- endif %}
   <style>
-    .vega-actions a {{
+    .vega-actions a {
         margin-right: 12px;
         color: #757575;
         font-weight: normal;
         font-size: 13px;
-    }}
-    .error {{
+    }
+    .error {
         color: red;
-    }}
+    }
   </style>
-"""
-
-VEGA_SCRIPTS = """
-<script src="{base_url}/vega@{vega_version}"></script>
-<script src="{base_url}/vega-embed@{vegaembed_version}"></script>
-"""
-
-VEGALITE_SCRIPTS = """
-<script src="{base_url}/vega@{vega_version}"></script>
-<script src="{base_url}/vega-lite@{vegalite_version}"></script>
-<script src="{base_url}/vega-embed@{vegaembed_version}"></script>
-"""
-
-BOTTOM = """
+{%- if not requirejs %}
+  <script type="text/javascript" src="{{ base_url }}/vega@{{ vega_version }}"></script>
+  {%- if mode == 'vega-lite' %}
+  <script type="text/javascript" src="{{ base_url }}/vega-lite@{{ vegalite_version }}"></script>
+  {%- endif %}
+  <script type="text/javascript" src="{{ base_url }}/vega-embed@{{ vegaembed_version }}"></script>
+{%- endif %}
+{%- if fullhtml %}
+{%- if requirejs %}
+<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
+<script>
+requirejs.config({
+    "paths": {
+        "vega": "{{ base_url }}/vega@{{ vega_version }}?noext",
+        "vega-lib": "{{ base_url }}/vega-lib?noext",
+        "vega-lite": "{{ base_url }}/vega-lite@{{ vegalite_version }}?noext",
+        "vega-embed": "{{ base_url }}/vega-embed@{{ vegaembed_version }}?noext",
+    }
+});
+</script>
+{%- endif %}
 </head>
 <body>
-  <div id="{output_div}"></div>
-  <script type="text/javascript">
-    var spec = {spec};
-    var embed_opt = {embed_opt};
+{%- endif %}
+  <div id="{{ output_div }}"></div>
+  <script>
+    {%- if requirejs %}
+    {%- if not fullhtml %}
+    requirejs.config({
+        "paths": {
+            "vega": "{{ base_url }}/vega@{{ vega_version }}?noext",
+            "vega-lib": "{{ base_url }}/vega-lib?noext",
+            "vega-lite": "{{ base_url }}/vega-lite@{{ vegalite_version }}?noext",
+            "vega-embed": "{{ base_url }}/vega-embed@{{ vegaembed_version }}?noext",
+        }
+    });
+    {%- endif %}
+    require(['vega-embed'], function(vegaEmbed){
+    {%- endif %}
+      var spec = {{ spec }};
+      var embedOpt = {{ embed_options }};
+
+      function showError(el, error){
+          el.innerHTML = ('<div class="error" style="color:red;">'
+                          + '<p>JavaScript Error: ' + error.message + '</p>'
+                          + "<p>This usually means there's a typo in your chart specification. "
+                          + "See the javascript console for the full traceback.</p>"
+                          + '</div>');
+          throw error;
+      }
+      const el = document.getElementById('{{ output_div }}');
+      vegaEmbed("#{{ output_div }}", spec, embedOpt)
+        .catch(error => showError(el, error));
+    {%- if requirejs %}
+    });
+    {%- endif %}
 
-    function showError(el, error){{
-        el.innerHTML = ('<div class="error">'
-                        + '<p>JavaScript Error: ' + error.message + '</p>'
-                        + "<p>This usually means there's a typo in your chart specification. "
-                        + "See the javascript console for the full traceback.</p>"
-                        + '</div>');
-        throw error;
-    }}
-    const el = document.getElementById('{output_div}');
-    vegaEmbed("#{output_div}", spec, embed_opt)
-      .catch(error => showError(el, error));
   </script>
+{%- if fullhtml %}
 </body>
 </html>
+{%- endif %}
 """
-
-
-HTML_TEMPLATE = {
-  'vega-lite': TOP + VEGALITE_SCRIPTS + BOTTOM,
-  'vega': TOP + VEGA_SCRIPTS + BOTTOM
-}
+)
 
 
 def spec_to_html(spec, mode,
                  vega_version, vegaembed_version, vegalite_version=None,
                  base_url="https://cdn.jsdelivr.net/npm/",
-                 output_div='vis', embed_options=None, json_kwds=None):
+                 output_div='vis', embed_options=None, json_kwds=None,
+                 fullhtml=True, requirejs=False):
     """Embed a Vega/Vega-Lite spec into an HTML page
 
     Parameters
     ----------
     spec : dict
         a dictionary representing a vega-lite plot spec.
+    fullhtml : boo
     mode : string {'vega' | 'vega-lite'}
         The rendering mode. This value is overridden by embed_options['mode'],
         if it is present.
@@ -88,11 +115,17 @@ def spec_to_html(spec, mode,
         Dictionary of options to pass to the vega-embed script.
     json_kwds : dict (optional)
         Dictionary of keywords to pass to json.dumps().
+    fullhtml : boolean (optional)
+        If True (default) then return a full html page. If False, then return
+        an HTML snippet that can be embedded into an HTML page.
+    requirejs : boolean (optional)
+        If False (default) then load libraries from base_url using <script>
+        tags. If True, then load libraries using requirejs
 
     Returns
     -------
-    output : dict
-        a mime-bundle representing the image
+    output : string
+        an HTML string for rendering the chart.
     """
     embed_options = embed_options or {}
     json_kwds = json_kwds or {}
@@ -109,15 +142,13 @@ def spec_to_html(spec, mode,
         raise ValueError("must specify vegaembed_version")
 
     if mode == 'vega-lite' and vegalite_version is None:
-        raise ValueError("must specify vega-lite version")
-
-    template = HTML_TEMPLATE[mode]
+        raise ValueError("must specify vega-lite version for mode='vega-lite'")
 
-    spec_html = template.format(spec=json.dumps(spec, **json_kwds),
-                                embed_opt=json.dumps(embed_options),
+    return HTML_TEMPLATE.render(spec=json.dumps(spec, **json_kwds),
+                                embed_options=json.dumps(embed_options),
+                                mode=mode,
                                 vega_version=vega_version,
                                 vegalite_version=vegalite_version,
                                 vegaembed_version=vegaembed_version,
-                                base_url=base_url,
-                                output_div=output_div)
-    return spec_html
+                                base_url=base_url, output_div=output_div,
+                                fullhtml=fullhtml, requirejs=requirejs)
diff --git a/altair/utils/save.py b/altair/utils/save.py
index 814190f3..6ffa4668 100644
--- a/altair/utils/save.py
+++ b/altair/utils/save.py
@@ -2,10 +2,18 @@ import json
 
 import six
 
-from .core import write_file_or_filename
 from .mimebundle import spec_to_mimebundle
 
 
+def write_file_or_filename(fp, content, mode='w'):
+    """Write content to fp, whether fp is a string or a file-like object"""
+    if isinstance(fp, six.string_types):
+        with open(fp, mode) as f:
+            f.write(content)
+    else:
+        fp.write(content)
+
+
 def save(chart, fp, vega_version, vegaembed_version,
          format=None, mode=None, vegalite_version=None,
          embed_options=None, json_kwds=None, webdriver='chrome',
diff --git a/altair/vega/display.py b/altair/vega/display.py
index 2be6e0c4..adc3167c 100644
--- a/altair/vega/display.py
+++ b/altair/vega/display.py
@@ -1,5 +1,5 @@
 from ..utils.display import Displayable, default_renderer_base, json_renderer_base
-from ..utils.display import MimeBundleType, RendererType
+from ..utils.display import MimeBundleType, RendererType, HTMLRenderer
 
 
 __all__ = (
@@ -7,5 +7,6 @@ __all__ = (
     "default_renderer_base",
     "json_renderer_base",
     "MimeBundleType",
-    "RendererType"
+    "RendererType",
+    "HTMLRenderer",
 )
diff --git a/altair/vega/v2/display.py b/altair/vega/v2/display.py
index a4a1584c..05d4731b 100644
--- a/altair/vega/v2/display.py
+++ b/altair/vega/v2/display.py
@@ -5,6 +5,11 @@ from ..display import Displayable
 from ..display import default_renderer_base
 from ..display import json_renderer_base
 from ..display import RendererType
+from ..display import HTMLRenderer
+
+from .schema import SCHEMA_VERSION
+VEGA_VERSION = SCHEMA_VERSION.lstrip('v')
+VEGAEMBED_VERSION = '3'
 
 
 
@@ -44,9 +49,24 @@ def json_renderer(spec):
     return json_renderer_base(spec, DEFAULT_DISPLAY)
 
 
+colab_renderer = HTMLRenderer(mode='vega',
+                              fullhtml=True, requirejs=False,
+                              output_div='altair-viz',
+                              vega_version=VEGA_VERSION,
+                              vegaembed_version=VEGAEMBED_VERSION)
+
+
+kaggle_renderer = HTMLRenderer(mode='vega',
+                               fullhtml=False, requirejs=True,
+                               vega_version=VEGA_VERSION,
+                               vegaembed_version=VEGAEMBED_VERSION)
+
+
 renderers.register('default', default_renderer)
 renderers.register('jupyterlab', default_renderer)
 renderers.register('nteract', default_renderer)
+renderers.register('colab', colab_renderer)
+renderers.register('kaggle', kaggle_renderer)
 renderers.register('json', json_renderer)
 renderers.enable('default')
 
diff --git a/altair/vega/v3/display.py b/altair/vega/v3/display.py
index e3e65d73..897741d5 100644
--- a/altair/vega/v3/display.py
+++ b/altair/vega/v3/display.py
@@ -5,6 +5,11 @@ from ..display import Displayable
 from ..display import default_renderer_base
 from ..display import json_renderer_base
 from ..display import RendererType
+from ..display import HTMLRenderer
+
+from .schema import SCHEMA_VERSION
+VEGA_VERSION = SCHEMA_VERSION.lstrip('v')
+VEGAEMBED_VERSION = '3'
 
 
 
@@ -44,9 +49,24 @@ def json_renderer(spec):
     return json_renderer_base(spec, DEFAULT_DISPLAY)
 
 
+colab_renderer = HTMLRenderer(mode='vega',
+                              fullhtml=True, requirejs=False,
+                              output_div='altair-viz',
+                              vega_version=VEGA_VERSION,
+                              vegaembed_version=VEGAEMBED_VERSION)
+
+
+kaggle_renderer = HTMLRenderer(mode='vega',
+                               fullhtml=False, requirejs=True,
+                               vega_version=VEGA_VERSION,
+                               vegaembed_version=VEGAEMBED_VERSION)
+
+
 renderers.register('default', default_renderer)
 renderers.register('jupyterlab', default_renderer)
 renderers.register('nteract', default_renderer)
+renderers.register('colab', colab_renderer)
+renderers.register('kaggle', kaggle_renderer)
 renderers.register('json', json_renderer)
 renderers.enable('default')
 
diff --git a/altair/vega/v4/display.py b/altair/vega/v4/display.py
index 7a6476d8..840b075b 100644
--- a/altair/vega/v4/display.py
+++ b/altair/vega/v4/display.py
@@ -5,6 +5,11 @@ from ..display import Displayable
 from ..display import default_renderer_base
 from ..display import json_renderer_base
 from ..display import RendererType
+from ..display import HTMLRenderer
+
+from .schema import SCHEMA_VERSION
+VEGA_VERSION = SCHEMA_VERSION.lstrip('v')
+VEGAEMBED_VERSION = '3'
 
 
 
@@ -44,9 +49,24 @@ def json_renderer(spec):
     return json_renderer_base(spec, DEFAULT_DISPLAY)
 
 
+colab_renderer = HTMLRenderer(mode='vega',
+                              fullhtml=True, requirejs=False,
+                              output_div='altair-viz',
+                              vega_version=VEGA_VERSION,
+                              vegaembed_version=VEGAEMBED_VERSION)
+
+
+kaggle_renderer = HTMLRenderer(mode='vega',
+                               fullhtml=False, requirejs=True,
+                               vega_version=VEGA_VERSION,
+                               vegaembed_version=VEGAEMBED_VERSION)
+
+
 renderers.register('default', default_renderer)
 renderers.register('jupyterlab', default_renderer)
 renderers.register('nteract', default_renderer)
+renderers.register('colab', colab_renderer)
+renderers.register('kaggle', kaggle_renderer)
 renderers.register('json', json_renderer)
 renderers.enable('default')
 
diff --git a/altair/vegalite/display.py b/altair/vegalite/display.py
index db0fe43c..91c5f33e 100644
--- a/altair/vegalite/display.py
+++ b/altair/vegalite/display.py
@@ -1,10 +1,11 @@
 from ..utils.display import Displayable, default_renderer_base, json_renderer_base
-from ..utils.display import RendererRegistry
+from ..utils.display import RendererRegistry, HTMLRenderer
 
 
 __all__ = (
     "Displayable",
     "default_renderer_base",
     "json_renderer_base",
-    "RendererRegistry"
+    "RendererRegistry",
+    "HTMLRenderer",
 )
diff --git a/altair/vegalite/v1/display.py b/altair/vegalite/v1/display.py
index 8d9b6a75..0d95cc19 100644
--- a/altair/vegalite/v1/display.py
+++ b/altair/vegalite/v1/display.py
@@ -6,6 +6,7 @@ from ..display import Displayable
 from ..display import default_renderer_base
 from ..display import json_renderer_base
 from ..display import RendererRegistry
+from ..display import HTMLRenderer
 
 from .schema import SCHEMA_VERSION
 VEGALITE_VERSION = SCHEMA_VERSION.lstrip('v')
@@ -65,23 +66,28 @@ def svg_renderer(spec, **metadata):
                               vegalite_version=VEGALITE_VERSION,
                               **metadata)
 
-
-def colab_renderer(spec, **metadata):
-    return spec_to_mimebundle(spec, format='html',
-                              mode='vega-lite',
+colab_renderer = HTMLRenderer(mode='vega-lite',
+                              fullhtml=True, requirejs=False,
+                              output_div='altair-viz',
                               vega_version=VEGA_VERSION,
                               vegaembed_version=VEGAEMBED_VERSION,
-                              vegalite_version=VEGALITE_VERSION,
-                              **metadata)
+                              vegalite_version=VEGALITE_VERSION)
+
+kaggle_renderer = HTMLRenderer(mode='vega-lite',
+                               fullhtml=False, requirejs=True,
+                               vega_version=VEGA_VERSION,
+                               vegaembed_version=VEGAEMBED_VERSION,
+                               vegalite_version=VEGALITE_VERSION)
 
 
 renderers.register('default', default_renderer)
 renderers.register('jupyterlab', default_renderer)
 renderers.register('nteract', default_renderer)
+renderers.register('colab', colab_renderer)
+renderers.register('kaggle', kaggle_renderer)
 renderers.register('json', json_renderer)
 renderers.register('png', png_renderer)
 renderers.register('svg', svg_renderer)
-renderers.register('colab', colab_renderer)
 renderers.enable('default')
 
 
diff --git a/altair/vegalite/v2/api.py b/altair/vegalite/v2/api.py
index 0314c9e1..99c45688 100644
--- a/altair/vegalite/v2/api.py
+++ b/altair/vegalite/v2/api.py
@@ -432,6 +432,17 @@ class TopLevelMixin(mixins.ConfigMethodMixin):
 
         return dct
 
+    def to_html(self, base_url="https://cdn.jsdelivr.net/npm/",
+                output_div='vis', embed_options=None, json_kwds=None,
+                fullhtml=True, requirejs=False):
+        return utils.spec_to_html(self.to_dict(), mode='vega-lite',
+                                  vegalite_version=VEGALITE_VERSION,
+                                  vegaembed_version=VEGAEMBED_VERSION,
+                                  vega_version=VEGA_VERSION,
+                                  base_url=base_url, output_div=output_div,
+                                  embed_options=embed_options, json_kwds=json_kwds,
+                                  fullhtml=fullhtml, requirejs=requirejs)
+
     def savechart(self, fp, format=None, **kwargs):
         """Save a chart to file in a variety of formats
 
diff --git a/altair/vegalite/v2/display.py b/altair/vegalite/v2/display.py
index 64b82a48..f645dc04 100644
--- a/altair/vegalite/v2/display.py
+++ b/altair/vegalite/v2/display.py
@@ -5,11 +5,12 @@ from ..display import Displayable
 from ..display import default_renderer_base
 from ..display import json_renderer_base
 from ..display import RendererRegistry
+from ..display import HTMLRenderer
 
 from .schema import SCHEMA_VERSION
 VEGALITE_VERSION = SCHEMA_VERSION.lstrip('v')
-VEGA_VERSION = '3.3.1'
-VEGAEMBED_VERSION = '3.14'
+VEGA_VERSION = '4'
+VEGAEMBED_VERSION = '3'
 
 
 # ==============================================================================
@@ -65,21 +66,27 @@ def svg_renderer(spec, **metadata):
                               vegalite_version=VEGALITE_VERSION,
                               **metadata)
 
-def colab_renderer(spec, **metadata):
-    return spec_to_mimebundle(spec, format='html',
-                              mode='vega-lite',
+colab_renderer = HTMLRenderer(mode='vega-lite',
+                              fullhtml=True, requirejs=False,
+                              output_div='altair-viz',
                               vega_version=VEGA_VERSION,
                               vegaembed_version=VEGAEMBED_VERSION,
-                              vegalite_version=VEGALITE_VERSION,
-                              **metadata)
+                              vegalite_version=VEGALITE_VERSION)
+
+kaggle_renderer = HTMLRenderer(mode='vega-lite',
+                               fullhtml=False, requirejs=True,
+                               vega_version=VEGA_VERSION,
+                               vegaembed_version=VEGAEMBED_VERSION,
+                               vegalite_version=VEGALITE_VERSION)
 
 renderers.register('default', default_renderer)
 renderers.register('jupyterlab', default_renderer)
 renderers.register('nteract', default_renderer)
+renderers.register('colab', colab_renderer)
+renderers.register('kaggle', kaggle_renderer)
 renderers.register('json', json_renderer)
 renderers.register('png', png_renderer)
 renderers.register('svg', svg_renderer)
-renderers.register('colab', colab_renderer)
 renderers.enable('default')
 
 
diff --git a/requirements.txt b/requirements.txt
index 5134e8e7..f64384f2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,5 @@
 entrypoints
+jinja2
 jsonschema
 numpy
 pandas
diff --git a/requirements_dev.txt b/requirements_dev.txt
index 59bdb8de..8f38b3ae 100644
--- a/requirements_dev.txt
+++ b/requirements_dev.txt
@@ -1,6 +1,5 @@
 flake8
 pytest
-jinja2
 sphinx
 m2r
 docutils


Test patch:
diff --git a/altair/utils/tests/test_html.py b/altair/utils/tests/test_html.py
new file mode 100644
index 00000000..2abc8678
--- /dev/null
+++ b/altair/utils/tests/test_html.py
@@ -0,0 +1,48 @@
+import pytest
+
+from ..html import spec_to_html
+
+
+@pytest.fixture
+def spec():
+    return {
+      'data': {'url': 'data.json'},
+      'mark': 'point',
+      'encoding': {
+        'x': {'field': 'x', 'type': 'quantitative'},
+        'y': {'field': 'y', 'type': 'quantitative'}
+      }
+    }
+
+
+@pytest.mark.parametrize('requirejs', [True, False])
+@pytest.mark.parametrize('fullhtml', [True, False])
+def test_spec_to_html(requirejs, fullhtml, spec):
+    # We can't test that the html actually renders, but we'll test aspects of
+    # it to make certain that the keywords are respected.
+    vegaembed_version="3.12",
+    vegalite_version="3.0",
+    vega_version="4.0"
+
+    html = spec_to_html(spec, mode='vega-lite',
+                        requirejs=requirejs, fullhtml=fullhtml,
+                        vegalite_version=vegalite_version,
+                        vegaembed_version=vegaembed_version,
+                        vega_version=vega_version)
+    html = html.strip()
+
+    if fullhtml:
+        assert html.startswith("<!DOCTYPE html>")
+        assert html.endswith("</html>")
+    else:
+        assert html.startswith("<style>")
+        assert html.endswith("</script>")
+
+    if requirejs:
+        assert "require(" in html
+    else:
+        assert "require(" not in html
+
+    assert "vega-lite@{}".format(vegalite_version) in html
+    assert "vega@{}".format(vega_version) in html
+    assert "vega-embed@{}".format(vegaembed_version) in html
diff --git a/altair/vegalite/v2/tests/test_api.py b/altair/vegalite/v2/tests/test_api.py
index dbb101eb..ecff7504 100644
--- a/altair/vegalite/v2/tests/test_api.py
+++ b/altair/vegalite/v2/tests/test_api.py
@@ -211,7 +211,7 @@ def test_save(format, basic_chart):
 
     elif format == 'html':
         content = out.read()
-        assert content.startswith('\n<!DOCTYPE html>')
+        assert content.startswith('<!DOCTYPE html>')
 
 
 def test_facet_parse():
diff --git a/altair/vegalite/v2/tests/test_renderers.py b/altair/vegalite/v2/tests/test_renderers.py
index 1d800ef4..2be4ef4a 100644
--- a/altair/vegalite/v2/tests/test_renderers.py
+++ b/altair/vegalite/v2/tests/test_renderers.py
@@ -15,14 +15,14 @@ def test_colab_renderer_embed_options(chart):
     with alt.renderers.enable('colab', embed_options=dict(actions=False)):
         bundle = chart._repr_mimebundle_(None, None)
         html = bundle['text/html']
-        assert ('embed_opt = {"actions": false, "mode": "vega-lite"}' in html or
-                'embed_opt = {"mode": "vega-lite", "actions": false}' in html)
+        assert ('embedOpt = {"actions": false, "mode": "vega-lite"}' in html or
+                'embedOpt = {"mode": "vega-lite", "actions": false}' in html)
 
     with alt.renderers.enable('colab', embed_options=dict(actions=True)):
         bundle = chart._repr_mimebundle_(None, None)
         html = bundle['text/html']
-        assert ('embed_opt = {"actions": true, "mode": "vega-lite"}' in html or
-                'embed_opt = {"mode": "vega-lite", "actions": true}' in html)
+        assert ('embedOpt = {"actions": true, "mode": "vega-lite"}' in html or
+                'embedOpt = {"mode": "vega-lite", "actions": true}' in html)
 
 
 def test_default_renderer_embed_options(chart, renderer='default'):