Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing example of use of RequireJS for vega-embed #8

Closed
ajmazurie opened this issue Mar 7, 2016 · 18 comments
Closed

Missing example of use of RequireJS for vega-embed #8

ajmazurie opened this issue Mar 7, 2016 · 18 comments

Comments

@ajmazurie
Copy link

Hi,
I would like to dynamically load vega-embed and all its dependencies (vega and vega-lite, which themselves depend on d3, etc.) using the RequireJS library. From previous discussions (see vega/vega#171 among else) I know that vega and D3 are AMD-compatible, so this ought to be doable.

What I am missing is an example of use of vega-embed with RequireJS. The code below throws errors, and I'm not sure if it is due to an incompatibility of vega-embed with RequireJS or my incorrect use or the later library:

requirejs.config({
    paths: {
        d3: "https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js?noext",
        d3_geo_projection: "https://cdnjs.cloudflare.com/ajax/libs/d3-geo-projection/0.2.16/d3.geo.projection.min.js?noext",
        d3_layout_cloud: "https://vega.github.io/vega-editor/vendor/d3.layout.cloud.js?noext",
        topojson: "https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.20/topojson.min.js?noext",
        vg: "https://cdnjs.cloudflare.com/ajax/libs/vega/2.5.1/vega.min.js?noext",
        vl: "https://vega.github.io/vega-lite/vega-lite.js?noext",
        vg_embed: "https://vega.github.io/vega-editor/vendor/vega-embed.js?noext"
    },
    shim: {
        vg_embed: {deps: ["vg", "vl"]},
        vl: {deps: ["vg"]},
        vg: {deps: ["d3", "d3_geo_projection", "d3_layout_cloud", "topojson"]},
        d3_geo_projection: {deps: ["d3"]},
        d3_layout_cloud: {deps: ["d3"]}
    }
});

require(["vg", "vl", "vg_embed"], function(vg, vl, vg_embed) {
    var vg_specification = {
        mode: "vega-lite",
        spec: {
            "description": "A simple bar chart with embedded data.",
            "data": {
                "values": [
                    {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
                    {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
                    {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
                ]
            },
            "mark": "bar",
            "encoding": {
                "x": {"field": "a", "type": "ordinal"},
                "y": {"field": "b", "type": "quantitative"}
            }
        }};

    vg.embed("#vis", vg_specification,
        function (error, chart) {
            chart({el:"#vis"}).update();
        });
});

This throws a TypeError: Cannot read property 'util' of undefined and TypeError: Cannot read property 'embed' of undefined.

Best,
Aurélien

@aishfenton
Copy link

aishfenton commented Apr 22, 2016

@ajmazurie, did you get to the bottom of this? Up against the same issue.

@ajmazurie
Copy link
Author

ajmazurie commented Apr 22, 2016

No answer from the developers so far. And it looks like no commit has been made to this repository since February. It looks like the project has been put on the back burner :-\

@domoritz
Copy link
Member

Hi all. Vega-embed is not dead but we just haven't had anything to add since March ;-)

I'm not very familiar with RequireJS but the second error message TypeError: Cannot read property 'embed' of undefined sounds like vega-embed is not properly adding embed to the vg namespace defined by vega. Without RequireJS vega would create vg in the global namespace and vega-embed would add vg.embed.

That's all I can help so far because as I said I am not familiar with RequireJS. I'm happy to answer specific questions or review pull requests though.

@domoritz
Copy link
Member

I'm going to work a bit more on https://github.com/vega/ipython-vega in the coming weeks and might run into a similar issue. If I find something, I will share it with you.

@aishfenton
Copy link

Thanks Domoritz. I followed your example with ipython-vega for now (I'm implementing a Scala wrapper for Vega here, and used an iFrame with srcdoc instead. That gets around the issue, but it does feel a little heavy as you'll re-import the same JS scripts for each chart. Solving the RequireJS issue would be preferable.

@domoritz
Copy link
Member

If you only load vg embed, it works fine for me. See https://github.com/vega/ipython-vega/tree/rewrite

@aishfenton
Copy link

Ahh ok I see. I don't think that works if you're just using straight require-js (I now get vg not defined). But looking at your example I'm guessing that webpack does some magic?? Either way that seems like a way forward. Thanks.

@domoritz
Copy link
Member

Yeah, I guess webpack just pulls in all the requires. I'm glad the example helps you.

@peller
Copy link

peller commented May 2, 2016

Got everything working using straight requireJS in this fiddle

vega-embed uses both vg and vl globals, so we need to manually define the globals on those dependencies. See the extra define() calls for vg.global and vl.global. Also, the embed call is returned directly in the AMD definition, not hung off vg.

@ajmazurie
Copy link
Author

Thanks @peller ! This is exactly the kind of trick it would have taken me ages to come up with. I'll finally be able to add straightforward Vega grammar-based visualization capabilities to my Jupyter kernels. Thanks again!

@domoritz
Copy link
Member

domoritz commented May 2, 2016

Awesome. Just to document it here is the solution:

requirejs.config({
    paths: {
        d3: "https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js?noext",
        d3_geo_projection: "https://cdnjs.cloudflare.com/ajax/libs/d3-geo-projection/0.2.16/d3.geo.projection.min.js?noext",
        d3_layout_cloud: "https://vega.github.io/vega-editor/vendor/d3.layout.cloud.js?noext",
        topojson: "https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.20/topojson.min.js?noext",
        vg: "https://cdnjs.cloudflare.com/ajax/libs/vega/2.5.1/vega.min.js?noext",
        vl: "https://vega.github.io/vega-lite/vega-lite.js?noext",
        vg_embed: "https://vega.github.io/vega-editor/vendor/vega-embed.js?noext"
    },
    shim: {
        vg_embed: {deps: ["vg.global", "vl.global"]},
        vl: {deps: ["vg"]},
        vg: {deps: ["d3", "d3_geo_projection", "d3_layout_cloud", "topojson"]},
        d3_geo_projection: {deps: ["d3"]},
        d3_layout_cloud: {deps: ["d3"]}
    }
});

define('vg.global', ['vg'], function(vgGlobal) {
    window.vg = vgGlobal;
});

define('vl.global', ['vl'], function(vlGlobal) {
    window.vl = vlGlobal;
});



require(["vg_embed"], function(vg_embed) {
    var vg_specification = {
        mode: "vega-lite",
        spec: {
            "description": "A simple bar chart with embedded data.",
            "data": {
                "values": [
                    {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
                    {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
                    {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
                ]
            },
            "mark": "bar",
            "encoding": {
                "x": {"field": "a", "type": "ordinal"},
                "y": {"field": "b", "type": "quantitative"}
            }
        }};

    vg_embed("#vis", vg_specification,
        function (error, chart) {
            // do something that requires an update, then...
            chart.view.update();
        });
});

@ajmazurie
Copy link
Author

I'm having errors when attempting to have more than one <javascript> tag with the content above, even if referring to <div> with unique identifiers. Has anyone succeeded in embedding more than one Vega object in the same page?

The message is TypeError: Cannot read property 'view' of undefined

@domoritz
Copy link
Member

domoritz commented Jul 1, 2016

We constantly have more than one plot on the same page (e.g. https://vega.github.io/vega-lite/docs/mark.html). Not sure how this relates to requirejs.

@davidanthoff
Copy link

I can't get the solution posted here to work with the latest release, i.e. with vega-embed 3.0.0-rc7 and the whole vega 3.x and vega-lite 2.x stack. The vg_embed argument that I receive in the anonymous function that is passed to the require call always is just undefined.

Does anyone have an idea how to solve that?

@davidanthoff
Copy link

I figured it out. In the example above, one needs to change one part:

define('vg.global', ['vg'], function(vgGlobal) {
    window.vega = vgGlobal;
});

Specifically, one needs to assign to window.vega, not window.vg.

@tanyaschlusser
Copy link

Came across this googling. The solution has changed a little in recent versions (it's 2018) and now looks like:

<body>  
  <div id="vis"></div>
  <script>
requirejs.config({
  baseUrl: 'https://cdn.jsdelivr.net/npm/',
  paths: {
    "vega-embed":  "vega-embed@3?noext",
    "vega-lib": "vega-lib?noext",
    "vega-lite": "vega-lite@2?noext",
    "vega": "vega@3?noext"
  }
});


require(["vega-embed"], function(vegaEmbed) {
  const spec = {
    "$schema": "https://vega.github.io/schema/vega-lite/v2.json",
    "description": "A simple bar chart with embedded data.",
    "width": 360,
    "data": {
      "values": [
        {"a": "A","b": 28}, {"a": "B","b": 55}, {"a": "C","b": 43},
        {"a": "D","b": 91}, {"a": "E","b": 81}, {"a": "F","b": 53},
        {"a": "G","b": 19}, {"a": "H","b": 87}, {"a": "I","b": 52}
      ]
    },
    "mark": "bar",
    "encoding": {
      "x": {"field": "a", "type": "ordinal"},
      "y": {"field": "b", "type": "quantitative"},
      "tooltip": {"field": "b", "type": "quantitative"}
    }
  };

  vegaEmbed('#vis', spec, {defaultStyle: true}).catch(console.warn);
});

  </script>
</body>

@domoritz
Copy link
Member

Vega-Embed should now be compatible with requirejs. I made some major improvements by switching to rollup. See https://beta.observablehq.com/@domoritz/hello-vega-embed for an example.

I think the paths above are necessary to tell require where to find the libraries.

@domoritz
Copy link
Member

Thank you @tanyaschlusser for posting the code!

fedarko added a commit to biocore/qurro that referenced this issue Apr 22, 2019
Rather than through individual <script> tags.

Required a bit of fussing to get this to work (a few shims, etc.),
but overall fairly happy with this.

NOTE that the Vega* libs are now at their latest (ish) versions
(Vega 5.3.5, Vega-Lite 3.2.1, Vega-Embed 4.0.0) as of today (April 21,
2019). This produces a warning in the dev console about how the
Altair Vega-Lite spec is older than the Vega-Lite version used
(since Altair only outputs to Vega-Lite version 2.6.0 as of writing),
but 1) this doesn't seem to cause any problems and 2) I imagine this
will be fixed with future Altair releases.

(The reason we updated the Vega* libs here was that this was needed
to make them work nicely with RequireJS. See
vega/vega-embed#8 for context.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants