We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Multiple views in JupyterLab blank with default html renderer
To reproduce:

1. Create an environment with JupyterLab 1.2.6 and altair 4.0.1:

```
conda create -c conda-forge -yn testenv jupyterlab altair pandas
conda activate testenv
```

2. Start JupyterLab:
```
jupyter lab
```
3. Create a new notebook with an example plot:

```
import altair as alt
import numpy as np
import pandas as pd

# Compute x^2 + y^2 across a 2D grid
x, y = np.meshgrid(range(-5, 5), range(-5, 5))
z = x ** 2 + y ** 2

# Convert this grid to columnar data expected by Altair
source = pd.DataFrame({'x': x.ravel(),
                     'y': y.ravel(),
                     'z': z.ravel()})

alt.Chart(source).mark_rect().encode(
    x='x:O',
    y='y:O',
    color='z:Q'
)
```
4. Right-click on the plot and choose "Create New view for output" to open a new jlab tab for the plot. The new tab is blank:
<img width="622" alt="Screen Shot 2020-02-24 at 11 22 23 AM" src="https://user-images.githubusercontent.com/192614/75183729-f70da980-56f7-11ea-8e25-bf11bfda8b9f.png">

I also see the same issue if opening a new view of the notebook (right-clicking on the file's tab, selecting "New View for Notebook"

I think at least part of the problem is that the plot div has a hard-coded id, and ids should be unique on a page, so viewing the same output multiple times can be a problem. There may be other issues with the js not knowing to redraw the plot in the new jlab tab, etc.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `altair/utils/html.py`
Content:
```
1 from __future__ import unicode_literals
2 import json
3 import jinja2
4 
5 
6 HTML_TEMPLATE = jinja2.Template("""
7 {%- if fullhtml -%}
8 <!DOCTYPE html>
9 <html>
10 <head>
11 {%- endif %}
12   <style>
13     .error {
14         color: red;
15     }
16   </style>
17 {%- if not requirejs %}
18   <script type="text/javascript" src="{{ base_url }}/vega@{{ vega_version }}"></script>
19   {%- if mode == 'vega-lite' %}
20   <script type="text/javascript" src="{{ base_url }}/vega-lite@{{ vegalite_version }}"></script>
21   {%- endif %}
22   <script type="text/javascript" src="{{ base_url }}/vega-embed@{{ vegaembed_version }}"></script>
23 {%- endif %}
24 {%- if fullhtml %}
25 {%- if requirejs %}
26 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
27 <script>
28 requirejs.config({
29     "paths": {
30         "vega": "{{ base_url }}/vega@{{ vega_version }}?noext",
31         "vega-lib": "{{ base_url }}/vega-lib?noext",
32         "vega-lite": "{{ base_url }}/vega-lite@{{ vegalite_version }}?noext",
33         "vega-embed": "{{ base_url }}/vega-embed@{{ vegaembed_version }}?noext",
34     }
35 });
36 </script>
37 {%- endif %}
38 </head>
39 <body>
40 {%- endif %}
41   <div id="{{ output_div }}"></div>
42   <script>
43     {%- if requirejs and not fullhtml %}
44     requirejs.config({
45         "paths": {
46             "vega": "{{ base_url }}/vega@{{ vega_version }}?noext",
47             "vega-lib": "{{ base_url }}/vega-lib?noext",
48             "vega-lite": "{{ base_url }}/vega-lite@{{ vegalite_version }}?noext",
49             "vega-embed": "{{ base_url }}/vega-embed@{{ vegaembed_version }}?noext",
50         }
51     });
52     {% endif %}
53     {% if requirejs -%}
54     require(['vega-embed'],
55     {%- else -%}
56     (
57     {%- endif -%}
58     function(vegaEmbed) {
59       var spec = {{ spec }};
60       var embedOpt = {{ embed_options }};
61 
62       function showError(el, error){
63           el.innerHTML = ('<div class="error" style="color:red;">'
64                           + '<p>JavaScript Error: ' + error.message + '</p>'
65                           + "<p>This usually means there's a typo in your chart specification. "
66                           + "See the javascript console for the full traceback.</p>"
67                           + '</div>');
68           throw error;
69       }
70       const el = document.getElementById('{{ output_div }}');
71       vegaEmbed("#{{ output_div }}", spec, embedOpt)
72         .catch(error => showError(el, error));
73     }){% if not requirejs %}(vegaEmbed){% endif %};
74 
75   </script>
76 {%- if fullhtml %}
77 </body>
78 </html>
79 {%- endif %}
80 """
81 )
82 
83 
84 HTML_TEMPLATE_UNIVERSAL = jinja2.Template("""
85 <div id="{{ output_div }}"></div>
86 <script type="text/javascript">
87   (function(spec, embedOpt){
88     const outputDiv = document.getElementById("{{ output_div }}");
89     const paths = {
90       "vega": "{{ base_url }}/vega@{{ vega_version }}?noext",
91       "vega-lib": "{{ base_url }}/vega-lib?noext",
92       "vega-lite": "{{ base_url }}/vega-lite@{{ vegalite_version }}?noext",
93       "vega-embed": "{{ base_url }}/vega-embed@{{ vegaembed_version }}?noext",
94     };
95 
96     function loadScript(lib) {
97       return new Promise(function(resolve, reject) {
98         var s = document.createElement('script');
99         s.src = paths[lib];
100         s.async = true;
101         s.onload = () => resolve(paths[lib]);
102         s.onerror = () => reject(`Error loading script: ${paths[lib]}`);
103         document.getElementsByTagName("head")[0].appendChild(s);
104       });
105     }
106 
107     function showError(err) {
108       outputDiv.innerHTML = `<div class="error" style="color:red;">${err}</div>`;
109       throw err;
110     }
111 
112     function displayChart(vegaEmbed) {
113       vegaEmbed(outputDiv, spec, embedOpt)
114         .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));
115     }
116 
117     if(typeof define === "function" && define.amd) {
118       requirejs.config({paths});
119       require(["vega-embed"], displayChart, err => showError(`Error loading script: ${err.message}`));
120     } else if (typeof vegaEmbed === "function") {
121       displayChart(vegaEmbed);
122     } else {
123       loadScript("vega")
124         .then(() => loadScript("vega-lite"))
125         .then(() => loadScript("vega-embed"))
126         .catch(showError)
127         .then(() => displayChart(vegaEmbed));
128     }
129   })({{ spec }}, {{ embed_options }});
130 </script>
131 """)
132 
133 
134 TEMPLATES = {
135     'standard': HTML_TEMPLATE,
136     'universal': HTML_TEMPLATE_UNIVERSAL,
137 }
138 
139 
140 def spec_to_html(spec, mode,
141                  vega_version, vegaembed_version, vegalite_version=None,
142                  base_url="https://cdn.jsdelivr.net/npm/",
143                  output_div='vis', embed_options=None, json_kwds=None,
144                  fullhtml=True, requirejs=False, template='standard'):
145     """Embed a Vega/Vega-Lite spec into an HTML page
146 
147     Parameters
148     ----------
149     spec : dict
150         a dictionary representing a vega-lite plot spec.
151     mode : string {'vega' | 'vega-lite'}
152         The rendering mode. This value is overridden by embed_options['mode'],
153         if it is present.
154     vega_version : string
155         For html output, the version of vega.js to use.
156     vegalite_version : string
157         For html output, the version of vegalite.js to use.
158     vegaembed_version : string
159         For html output, the version of vegaembed.js to use.
160     base_url : string (optional)
161         The base url from which to load the javascript libraries.
162     output_div : string (optional)
163         The id of the div element where the plot will be shown.
164     embed_options : dict (optional)
165         Dictionary of options to pass to the vega-embed script. Default
166         entry is {'mode': mode}.
167     json_kwds : dict (optional)
168         Dictionary of keywords to pass to json.dumps().
169     fullhtml : boolean (optional)
170         If True (default) then return a full html page. If False, then return
171         an HTML snippet that can be embedded into an HTML page.
172     requirejs : boolean (optional)
173         If False (default) then load libraries from base_url using <script>
174         tags. If True, then load libraries using requirejs
175     template : jinja2.Template or string (optional)
176         Specify the template to use (default = 'standard'). If template is a
177         string, it must be one of {'universal', 'standard'}. Otherwise, it
178         can be a jinja2.Template object containing a custom template.
179 
180     Returns
181     -------
182     output : string
183         an HTML string for rendering the chart.
184     """
185     embed_options = embed_options or {}
186     json_kwds = json_kwds or {}
187 
188     mode = embed_options.setdefault('mode', mode)
189 
190     if mode not in ['vega', 'vega-lite']:
191         raise ValueError("mode must be either 'vega' or 'vega-lite'")
192 
193     if vega_version is None:
194         raise ValueError("must specify vega_version")
195 
196     if vegaembed_version is None:
197         raise ValueError("must specify vegaembed_version")
198 
199     if mode == 'vega-lite' and vegalite_version is None:
200         raise ValueError("must specify vega-lite version for mode='vega-lite'")
201 
202     template = TEMPLATES.get(template, template)
203     if not hasattr(template, 'render'):
204         raise ValueError("Invalid template: {0}".format(template))
205 
206     return template.render(
207         spec=json.dumps(spec, **json_kwds),
208         embed_options=json.dumps(embed_options),
209         mode=mode,
210         vega_version=vega_version,
211         vegalite_version=vegalite_version,
212         vegaembed_version=vegaembed_version,
213         base_url=base_url,
214         output_div=output_div,
215         fullhtml=fullhtml,
216         requirejs=requirejs
217     )
218
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/altair/utils/html.py b/altair/utils/html.py
--- a/altair/utils/html.py
+++ b/altair/utils/html.py
@@ -85,7 +85,10 @@
 <div id="{{ output_div }}"></div>
 <script type="text/javascript">
   (function(spec, embedOpt){
-    const outputDiv = document.getElementById("{{ output_div }}");
+    let outputDiv = document.currentScript.previousElementSibling;
+    if (outputDiv.id !== "{{ output_div }}") {
+      outputDiv = document.getElementById("{{ output_div }}");
+    }
     const paths = {
       "vega": "{{ base_url }}/vega@{{ vega_version }}?noext",
       "vega-lib": "{{ base_url }}/vega-lib?noext",

{"golden_diff": "diff --git a/altair/utils/html.py b/altair/utils/html.py\n--- a/altair/utils/html.py\n+++ b/altair/utils/html.py\n@@ -85,7 +85,10 @@\n <div id=\"{{ output_div }}\"></div>\n <script type=\"text/javascript\">\n   (function(spec, embedOpt){\n-    const outputDiv = document.getElementById(\"{{ output_div }}\");\n+    let outputDiv = document.currentScript.previousElementSibling;\n+    if (outputDiv.id !== \"{{ output_div }}\") {\n+      outputDiv = document.getElementById(\"{{ output_div }}\");\n+    }\n     const paths = {\n       \"vega\": \"{{ base_url }}/vega@{{ vega_version }}?noext\",\n       \"vega-lib\": \"{{ base_url }}/vega-lib?noext\",\n", "issue": "Multiple views in JupyterLab blank with default html renderer\nTo reproduce:\r\n\r\n1. Create an environment with JupyterLab 1.2.6 and altair 4.0.1:\r\n\r\n```\r\nconda create -c conda-forge -yn testenv jupyterlab altair pandas\r\nconda activate testenv\r\n```\r\n\r\n2. Start JupyterLab:\r\n```\r\njupyter lab\r\n```\r\n3. Create a new notebook with an example plot:\r\n\r\n```\r\nimport altair as alt\r\nimport numpy as np\r\nimport pandas as pd\r\n\r\n# Compute x^2 + y^2 across a 2D grid\r\nx, y = np.meshgrid(range(-5, 5), range(-5, 5))\r\nz = x ** 2 + y ** 2\r\n\r\n# Convert this grid to columnar data expected by Altair\r\nsource = pd.DataFrame({'x': x.ravel(),\r\n                     'y': y.ravel(),\r\n                     'z': z.ravel()})\r\n\r\nalt.Chart(source).mark_rect().encode(\r\n    x='x:O',\r\n    y='y:O',\r\n    color='z:Q'\r\n)\r\n```\r\n4. Right-click on the plot and choose \"Create New view for output\" to open a new jlab tab for the plot. The new tab is blank:\r\n<img width=\"622\" alt=\"Screen Shot 2020-02-24 at 11 22 23 AM\" src=\"https://user-images.githubusercontent.com/192614/75183729-f70da980-56f7-11ea-8e25-bf11bfda8b9f.png\">\r\n\r\nI also see the same issue if opening a new view of the notebook (right-clicking on the file's tab, selecting \"New View for Notebook\"\r\n\r\nI think at least part of the problem is that the plot div has a hard-coded id, and ids should be unique on a page, so viewing the same output multiple times can be a problem. There may be other issues with the js not knowing to redraw the plot in the new jlab tab, etc.\r\n\n", "before_files": [{"content": "from __future__ import unicode_literals\nimport json\nimport jinja2\n\n\nHTML_TEMPLATE = jinja2.Template(\"\"\"\n{%- if fullhtml -%}\n<!DOCTYPE html>\n<html>\n<head>\n{%- endif %}\n  <style>\n    .error {\n        color: red;\n    }\n  </style>\n{%- if not requirejs %}\n  <script type=\"text/javascript\" src=\"{{ base_url }}/vega@{{ vega_version }}\"></script>\n  {%- if mode == 'vega-lite' %}\n  <script type=\"text/javascript\" src=\"{{ base_url }}/vega-lite@{{ vegalite_version }}\"></script>\n  {%- endif %}\n  <script type=\"text/javascript\" src=\"{{ base_url }}/vega-embed@{{ vegaembed_version }}\"></script>\n{%- endif %}\n{%- if fullhtml %}\n{%- if requirejs %}\n<script type=\"text/javascript\" src=\"https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js\"></script>\n<script>\nrequirejs.config({\n    \"paths\": {\n        \"vega\": \"{{ base_url }}/vega@{{ vega_version }}?noext\",\n        \"vega-lib\": \"{{ base_url }}/vega-lib?noext\",\n        \"vega-lite\": \"{{ base_url }}/vega-lite@{{ vegalite_version }}?noext\",\n        \"vega-embed\": \"{{ base_url }}/vega-embed@{{ vegaembed_version }}?noext\",\n    }\n});\n</script>\n{%- endif %}\n</head>\n<body>\n{%- endif %}\n  <div id=\"{{ output_div }}\"></div>\n  <script>\n    {%- if requirejs and not fullhtml %}\n    requirejs.config({\n        \"paths\": {\n            \"vega\": \"{{ base_url }}/vega@{{ vega_version }}?noext\",\n            \"vega-lib\": \"{{ base_url }}/vega-lib?noext\",\n            \"vega-lite\": \"{{ base_url }}/vega-lite@{{ vegalite_version }}?noext\",\n            \"vega-embed\": \"{{ base_url }}/vega-embed@{{ vegaembed_version }}?noext\",\n        }\n    });\n    {% endif %}\n    {% if requirejs -%}\n    require(['vega-embed'],\n    {%- else -%}\n    (\n    {%- endif -%}\n    function(vegaEmbed) {\n      var spec = {{ spec }};\n      var embedOpt = {{ embed_options }};\n\n      function showError(el, error){\n          el.innerHTML = ('<div class=\"error\" style=\"color:red;\">'\n                          + '<p>JavaScript Error: ' + error.message + '</p>'\n                          + \"<p>This usually means there's a typo in your chart specification. \"\n                          + \"See the javascript console for the full traceback.</p>\"\n                          + '</div>');\n          throw error;\n      }\n      const el = document.getElementById('{{ output_div }}');\n      vegaEmbed(\"#{{ output_div }}\", spec, embedOpt)\n        .catch(error => showError(el, error));\n    }){% if not requirejs %}(vegaEmbed){% endif %};\n\n  </script>\n{%- if fullhtml %}\n</body>\n</html>\n{%- endif %}\n\"\"\"\n)\n\n\nHTML_TEMPLATE_UNIVERSAL = jinja2.Template(\"\"\"\n<div id=\"{{ output_div }}\"></div>\n<script type=\"text/javascript\">\n  (function(spec, embedOpt){\n    const outputDiv = document.getElementById(\"{{ output_div }}\");\n    const paths = {\n      \"vega\": \"{{ base_url }}/vega@{{ vega_version }}?noext\",\n      \"vega-lib\": \"{{ base_url }}/vega-lib?noext\",\n      \"vega-lite\": \"{{ base_url }}/vega-lite@{{ vegalite_version }}?noext\",\n      \"vega-embed\": \"{{ base_url }}/vega-embed@{{ vegaembed_version }}?noext\",\n    };\n\n    function loadScript(lib) {\n      return new Promise(function(resolve, reject) {\n        var s = document.createElement('script');\n        s.src = paths[lib];\n        s.async = true;\n        s.onload = () => resolve(paths[lib]);\n        s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n        document.getElementsByTagName(\"head\")[0].appendChild(s);\n      });\n    }\n\n    function showError(err) {\n      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n      throw err;\n    }\n\n    function displayChart(vegaEmbed) {\n      vegaEmbed(outputDiv, spec, embedOpt)\n        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n    }\n\n    if(typeof define === \"function\" && define.amd) {\n      requirejs.config({paths});\n      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n    } else if (typeof vegaEmbed === \"function\") {\n      displayChart(vegaEmbed);\n    } else {\n      loadScript(\"vega\")\n        .then(() => loadScript(\"vega-lite\"))\n        .then(() => loadScript(\"vega-embed\"))\n        .catch(showError)\n        .then(() => displayChart(vegaEmbed));\n    }\n  })({{ spec }}, {{ embed_options }});\n</script>\n\"\"\")\n\n\nTEMPLATES = {\n    'standard': HTML_TEMPLATE,\n    'universal': HTML_TEMPLATE_UNIVERSAL,\n}\n\n\ndef spec_to_html(spec, mode,\n                 vega_version, vegaembed_version, vegalite_version=None,\n                 base_url=\"https://cdn.jsdelivr.net/npm/\",\n                 output_div='vis', embed_options=None, json_kwds=None,\n                 fullhtml=True, requirejs=False, template='standard'):\n    \"\"\"Embed a Vega/Vega-Lite spec into an HTML page\n\n    Parameters\n    ----------\n    spec : dict\n        a dictionary representing a vega-lite plot spec.\n    mode : string {'vega' | 'vega-lite'}\n        The rendering mode. This value is overridden by embed_options['mode'],\n        if it is present.\n    vega_version : string\n        For html output, the version of vega.js to use.\n    vegalite_version : string\n        For html output, the version of vegalite.js to use.\n    vegaembed_version : string\n        For html output, the version of vegaembed.js to use.\n    base_url : string (optional)\n        The base url from which to load the javascript libraries.\n    output_div : string (optional)\n        The id of the div element where the plot will be shown.\n    embed_options : dict (optional)\n        Dictionary of options to pass to the vega-embed script. Default\n        entry is {'mode': mode}.\n    json_kwds : dict (optional)\n        Dictionary of keywords to pass to json.dumps().\n    fullhtml : boolean (optional)\n        If True (default) then return a full html page. If False, then return\n        an HTML snippet that can be embedded into an HTML page.\n    requirejs : boolean (optional)\n        If False (default) then load libraries from base_url using <script>\n        tags. If True, then load libraries using requirejs\n    template : jinja2.Template or string (optional)\n        Specify the template to use (default = 'standard'). If template is a\n        string, it must be one of {'universal', 'standard'}. Otherwise, it\n        can be a jinja2.Template object containing a custom template.\n\n    Returns\n    -------\n    output : string\n        an HTML string for rendering the chart.\n    \"\"\"\n    embed_options = embed_options or {}\n    json_kwds = json_kwds or {}\n\n    mode = embed_options.setdefault('mode', mode)\n\n    if mode not in ['vega', 'vega-lite']:\n        raise ValueError(\"mode must be either 'vega' or 'vega-lite'\")\n\n    if vega_version is None:\n        raise ValueError(\"must specify vega_version\")\n\n    if vegaembed_version is None:\n        raise ValueError(\"must specify vegaembed_version\")\n\n    if mode == 'vega-lite' and vegalite_version is None:\n        raise ValueError(\"must specify vega-lite version for mode='vega-lite'\")\n\n    template = TEMPLATES.get(template, template)\n    if not hasattr(template, 'render'):\n        raise ValueError(\"Invalid template: {0}\".format(template))\n\n    return template.render(\n        spec=json.dumps(spec, **json_kwds),\n        embed_options=json.dumps(embed_options),\n        mode=mode,\n        vega_version=vega_version,\n        vegalite_version=vegalite_version,\n        vegaembed_version=vegaembed_version,\n        base_url=base_url,\n        output_div=output_div,\n        fullhtml=fullhtml,\n        requirejs=requirejs\n    )\n", "path": "altair/utils/html.py"}], "after_files": [{"content": "from __future__ import unicode_literals\nimport json\nimport jinja2\n\n\nHTML_TEMPLATE = jinja2.Template(\"\"\"\n{%- if fullhtml -%}\n<!DOCTYPE html>\n<html>\n<head>\n{%- endif %}\n  <style>\n    .error {\n        color: red;\n    }\n  </style>\n{%- if not requirejs %}\n  <script type=\"text/javascript\" src=\"{{ base_url }}/vega@{{ vega_version }}\"></script>\n  {%- if mode == 'vega-lite' %}\n  <script type=\"text/javascript\" src=\"{{ base_url }}/vega-lite@{{ vegalite_version }}\"></script>\n  {%- endif %}\n  <script type=\"text/javascript\" src=\"{{ base_url }}/vega-embed@{{ vegaembed_version }}\"></script>\n{%- endif %}\n{%- if fullhtml %}\n{%- if requirejs %}\n<script type=\"text/javascript\" src=\"https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js\"></script>\n<script>\nrequirejs.config({\n    \"paths\": {\n        \"vega\": \"{{ base_url }}/vega@{{ vega_version }}?noext\",\n        \"vega-lib\": \"{{ base_url }}/vega-lib?noext\",\n        \"vega-lite\": \"{{ base_url }}/vega-lite@{{ vegalite_version }}?noext\",\n        \"vega-embed\": \"{{ base_url }}/vega-embed@{{ vegaembed_version }}?noext\",\n    }\n});\n</script>\n{%- endif %}\n</head>\n<body>\n{%- endif %}\n  <div id=\"{{ output_div }}\"></div>\n  <script>\n    {%- if requirejs and not fullhtml %}\n    requirejs.config({\n        \"paths\": {\n            \"vega\": \"{{ base_url }}/vega@{{ vega_version }}?noext\",\n            \"vega-lib\": \"{{ base_url }}/vega-lib?noext\",\n            \"vega-lite\": \"{{ base_url }}/vega-lite@{{ vegalite_version }}?noext\",\n            \"vega-embed\": \"{{ base_url }}/vega-embed@{{ vegaembed_version }}?noext\",\n        }\n    });\n    {% endif %}\n    {% if requirejs -%}\n    require(['vega-embed'],\n    {%- else -%}\n    (\n    {%- endif -%}\n    function(vegaEmbed) {\n      var spec = {{ spec }};\n      var embedOpt = {{ embed_options }};\n\n      function showError(el, error){\n          el.innerHTML = ('<div class=\"error\" style=\"color:red;\">'\n                          + '<p>JavaScript Error: ' + error.message + '</p>'\n                          + \"<p>This usually means there's a typo in your chart specification. \"\n                          + \"See the javascript console for the full traceback.</p>\"\n                          + '</div>');\n          throw error;\n      }\n      const el = document.getElementById('{{ output_div }}');\n      vegaEmbed(\"#{{ output_div }}\", spec, embedOpt)\n        .catch(error => showError(el, error));\n    }){% if not requirejs %}(vegaEmbed){% endif %};\n\n  </script>\n{%- if fullhtml %}\n</body>\n</html>\n{%- endif %}\n\"\"\"\n)\n\n\nHTML_TEMPLATE_UNIVERSAL = jinja2.Template(\"\"\"\n<div id=\"{{ output_div }}\"></div>\n<script type=\"text/javascript\">\n  (function(spec, embedOpt){\n    let outputDiv = document.currentScript.previousElementSibling;\n    if (outputDiv.id !== \"{{ output_div }}\") {\n      outputDiv = document.getElementById(\"{{ output_div }}\");\n    }\n    const paths = {\n      \"vega\": \"{{ base_url }}/vega@{{ vega_version }}?noext\",\n      \"vega-lib\": \"{{ base_url }}/vega-lib?noext\",\n      \"vega-lite\": \"{{ base_url }}/vega-lite@{{ vegalite_version }}?noext\",\n      \"vega-embed\": \"{{ base_url }}/vega-embed@{{ vegaembed_version }}?noext\",\n    };\n\n    function loadScript(lib) {\n      return new Promise(function(resolve, reject) {\n        var s = document.createElement('script');\n        s.src = paths[lib];\n        s.async = true;\n        s.onload = () => resolve(paths[lib]);\n        s.onerror = () => reject(`Error loading script: ${paths[lib]}`);\n        document.getElementsByTagName(\"head\")[0].appendChild(s);\n      });\n    }\n\n    function showError(err) {\n      outputDiv.innerHTML = `<div class=\"error\" style=\"color:red;\">${err}</div>`;\n      throw err;\n    }\n\n    function displayChart(vegaEmbed) {\n      vegaEmbed(outputDiv, spec, embedOpt)\n        .catch(err => showError(`Javascript Error: ${err.message}<br>This usually means there's a typo in your chart specification. See the javascript console for the full traceback.`));\n    }\n\n    if(typeof define === \"function\" && define.amd) {\n      requirejs.config({paths});\n      require([\"vega-embed\"], displayChart, err => showError(`Error loading script: ${err.message}`));\n    } else if (typeof vegaEmbed === \"function\") {\n      displayChart(vegaEmbed);\n    } else {\n      loadScript(\"vega\")\n        .then(() => loadScript(\"vega-lite\"))\n        .then(() => loadScript(\"vega-embed\"))\n        .catch(showError)\n        .then(() => displayChart(vegaEmbed));\n    }\n  })({{ spec }}, {{ embed_options }});\n</script>\n\"\"\")\n\n\nTEMPLATES = {\n    'standard': HTML_TEMPLATE,\n    'universal': HTML_TEMPLATE_UNIVERSAL,\n}\n\n\ndef spec_to_html(spec, mode,\n                 vega_version, vegaembed_version, vegalite_version=None,\n                 base_url=\"https://cdn.jsdelivr.net/npm/\",\n                 output_div='vis', embed_options=None, json_kwds=None,\n                 fullhtml=True, requirejs=False, template='standard'):\n    \"\"\"Embed a Vega/Vega-Lite spec into an HTML page\n\n    Parameters\n    ----------\n    spec : dict\n        a dictionary representing a vega-lite plot spec.\n    mode : string {'vega' | 'vega-lite'}\n        The rendering mode. This value is overridden by embed_options['mode'],\n        if it is present.\n    vega_version : string\n        For html output, the version of vega.js to use.\n    vegalite_version : string\n        For html output, the version of vegalite.js to use.\n    vegaembed_version : string\n        For html output, the version of vegaembed.js to use.\n    base_url : string (optional)\n        The base url from which to load the javascript libraries.\n    output_div : string (optional)\n        The id of the div element where the plot will be shown.\n    embed_options : dict (optional)\n        Dictionary of options to pass to the vega-embed script. Default\n        entry is {'mode': mode}.\n    json_kwds : dict (optional)\n        Dictionary of keywords to pass to json.dumps().\n    fullhtml : boolean (optional)\n        If True (default) then return a full html page. If False, then return\n        an HTML snippet that can be embedded into an HTML page.\n    requirejs : boolean (optional)\n        If False (default) then load libraries from base_url using <script>\n        tags. If True, then load libraries using requirejs\n    template : jinja2.Template or string (optional)\n        Specify the template to use (default = 'standard'). If template is a\n        string, it must be one of {'universal', 'standard'}. Otherwise, it\n        can be a jinja2.Template object containing a custom template.\n\n    Returns\n    -------\n    output : string\n        an HTML string for rendering the chart.\n    \"\"\"\n    embed_options = embed_options or {}\n    json_kwds = json_kwds or {}\n\n    mode = embed_options.setdefault('mode', mode)\n\n    if mode not in ['vega', 'vega-lite']:\n        raise ValueError(\"mode must be either 'vega' or 'vega-lite'\")\n\n    if vega_version is None:\n        raise ValueError(\"must specify vega_version\")\n\n    if vegaembed_version is None:\n        raise ValueError(\"must specify vegaembed_version\")\n\n    if mode == 'vega-lite' and vegalite_version is None:\n        raise ValueError(\"must specify vega-lite version for mode='vega-lite'\")\n\n    template = TEMPLATES.get(template, template)\n    if not hasattr(template, 'render'):\n        raise ValueError(\"Invalid template: {0}\".format(template))\n\n    return template.render(\n        spec=json.dumps(spec, **json_kwds),\n        embed_options=json.dumps(embed_options),\n        mode=mode,\n        vega_version=vega_version,\n        vegalite_version=vegalite_version,\n        vegaembed_version=vegaembed_version,\n        base_url=base_url,\n        output_div=output_div,\n        fullhtml=fullhtml,\n        requirejs=requirejs\n    )\n", "path": "altair/utils/html.py"}]}